1package eu.siacs.conversations.ui;
2
3import android.content.ActivityNotFoundException;
4import android.content.ClipData;
5import android.content.ClipboardManager;
6import android.content.Intent;
7import android.content.pm.ActivityInfo;
8import android.location.Location;
9import android.location.LocationListener;
10import android.net.Uri;
11import android.os.Bundle;
12import android.view.Menu;
13import android.view.MenuItem;
14import android.view.View;
15import android.widget.Toast;
16
17import androidx.annotation.NonNull;
18import androidx.databinding.DataBindingUtil;
19
20import org.jetbrains.annotations.NotNull;
21import org.osmdroid.util.GeoPoint;
22
23import java.util.HashMap;
24import java.util.regex.Matcher;
25import java.util.regex.Pattern;
26
27import eu.siacs.conversations.Config;
28import eu.siacs.conversations.R;
29import eu.siacs.conversations.databinding.ActivityShowLocationBinding;
30import eu.siacs.conversations.ui.util.LocationHelper;
31import eu.siacs.conversations.ui.util.UriHelper;
32import eu.siacs.conversations.ui.widget.Marker;
33import eu.siacs.conversations.ui.widget.MyLocation;
34import eu.siacs.conversations.utils.LocationProvider;
35
36public class ShowLocationActivity extends LocationActivity implements LocationListener {
37
38 private GeoPoint loc = LocationProvider.FALLBACK;
39 private ActivityShowLocationBinding binding;
40
41 private Uri createGeoUri() {
42 return Uri.parse("geo:" + this.loc.getLatitude() + "," + this.loc.getLongitude());
43 }
44
45 @Override
46 protected void onCreate(final Bundle savedInstanceState) {
47 super.onCreate(savedInstanceState);
48
49 this.binding = DataBindingUtil.setContentView(this, R.layout.activity_show_location);
50 setSupportActionBar(binding.toolbar);
51
52 configureActionBar(getSupportActionBar());
53 setupMapView(this.binding.map, this.loc);
54
55 this.binding.fab.setOnClickListener(view -> startNavigation());
56
57 final Intent intent = getIntent();
58 if (intent != null) {
59 final String action = intent.getAction();
60 if (action == null) {
61 return;
62 }
63 switch (action) {
64 case "eu.siacs.conversations.location.show":
65 if (intent.hasExtra("longitude") && intent.hasExtra("latitude")) {
66 final double longitude = intent.getDoubleExtra("longitude", 0);
67 final double latitude = intent.getDoubleExtra("latitude", 0);
68 this.loc = new GeoPoint(latitude, longitude);
69 }
70 break;
71 case Intent.ACTION_VIEW:
72 final Uri geoUri = intent.getData();
73
74 // Attempt to set zoom level if the geo URI specifies it
75 if (geoUri != null) {
76 final HashMap<String, String> query =
77 UriHelper.parseQueryString(geoUri.getQuery());
78
79 // Check for zoom level.
80 final String z = query.get("z");
81 if (z != null) {
82 try {
83 mapController.setZoom(Double.valueOf(z));
84 } catch (final Exception ignored) {
85 }
86 }
87
88 // Check for the actual geo query.
89 boolean posInQuery = false;
90 final String q = query.get("q");
91 if (q != null) {
92 final Pattern latlng =
93 Pattern.compile(
94 "/^([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)(\\(.*\\))?/");
95 final Matcher m = latlng.matcher(q);
96 if (m.matches()) {
97 try {
98 this.loc =
99 new GeoPoint(
100 Double.valueOf(m.group(1)),
101 Double.valueOf(m.group(3)));
102 posInQuery = true;
103 } catch (final Exception ignored) {
104 }
105 }
106 }
107
108 final String schemeSpecificPart = geoUri.getSchemeSpecificPart();
109 if (schemeSpecificPart != null && !schemeSpecificPart.isEmpty()) {
110 try {
111 final GeoPoint latlong =
112 LocationHelper.parseLatLong(schemeSpecificPart);
113 if (latlong != null && !posInQuery) {
114 this.loc = latlong;
115 }
116 } catch (final NumberFormatException ignored) {
117 }
118 }
119 }
120
121 break;
122 }
123 updateLocationMarkers();
124 }
125 }
126
127 @Override
128 protected void gotoLoc(final boolean setZoomLevel) {
129 if (this.loc != null && mapController != null) {
130 if (setZoomLevel) {
131 mapController.setZoom(Config.Map.FINAL_ZOOM_LEVEL);
132 }
133 mapController.animateTo(new GeoPoint(this.loc));
134 }
135 }
136
137 @Override
138 public void onRequestPermissionsResult(
139 final int requestCode,
140 @NonNull final String[] permissions,
141 @NonNull final int[] grantResults) {
142 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
143 updateUi();
144 }
145
146 @Override
147 protected void setMyLoc(final Location location) {
148 this.myLoc = location;
149 }
150
151 @Override
152 public boolean onCreateOptionsMenu(@NotNull final Menu menu) {
153 // Inflate the menu; this adds items to the action bar if it is present.
154 getMenuInflater().inflate(R.menu.menu_show_location, menu);
155 updateUi();
156 return true;
157 }
158
159 @Override
160 protected void updateLocationMarkers() {
161 super.updateLocationMarkers();
162 if (this.myLoc != null) {
163 this.binding.map.getOverlays().add(new MyLocation(this, null, this.myLoc));
164 }
165 this.binding.map.getOverlays().add(new Marker(this.marker_icon, this.loc));
166 }
167
168 @Override
169 protected void onPause() {
170 super.onPause();
171 }
172
173 @Override
174 public boolean onOptionsItemSelected(final MenuItem item) {
175 switch (item.getItemId()) {
176 case R.id.action_copy_location:
177 final ClipboardManager clipboard =
178 (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
179 if (clipboard != null) {
180 final ClipData clip =
181 ClipData.newPlainText("location", createGeoUri().toString());
182 clipboard.setPrimaryClip(clip);
183 Toast.makeText(this, R.string.url_copied_to_clipboard, Toast.LENGTH_SHORT)
184 .show();
185 }
186 return true;
187 case R.id.action_share_location:
188 final Intent shareIntent = new Intent();
189 shareIntent.setAction(Intent.ACTION_SEND);
190 shareIntent.putExtra(Intent.EXTRA_TEXT, createGeoUri().toString());
191 shareIntent.setType("text/plain");
192 try {
193 startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with)));
194 } catch (final ActivityNotFoundException e) {
195 // This should happen only on faulty androids because normally chooser is always
196 // available
197 Toast.makeText(
198 this,
199 R.string.no_application_found_to_open_file,
200 Toast.LENGTH_SHORT)
201 .show();
202 }
203 return true;
204 }
205 return super.onOptionsItemSelected(item);
206 }
207
208 private void startNavigation() {
209 final Intent intent = getStartNavigationIntent();
210 startActivity(intent);
211 }
212
213 private Intent getStartNavigationIntent() {
214 return new Intent(
215 Intent.ACTION_VIEW,
216 Uri.parse(
217 "google.navigation:q="
218 + this.loc.getLatitude()
219 + ","
220 + this.loc.getLongitude()));
221 }
222
223 @Override
224 protected void updateUi() {
225 final Intent intent = getStartNavigationIntent();
226 final ActivityInfo activityInfo = intent.resolveActivityInfo(getPackageManager(), 0);
227 this.binding.fab.setVisibility(activityInfo == null ? View.GONE : View.VISIBLE);
228 }
229
230 @Override
231 public void onLocationChanged(@NotNull final Location location) {
232 if (LocationHelper.isBetterLocation(location, this.myLoc)) {
233 this.myLoc = location;
234 updateLocationMarkers();
235 }
236 }
237
238 @Override
239 public void onStatusChanged(final String provider, final int status, final Bundle extras) {}
240
241 @Override
242 public void onProviderEnabled(@NotNull final String provider) {}
243
244 @Override
245 public void onProviderDisabled(@NotNull final String provider) {}
246}