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