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