1package eu.siacs.conversations.ui;
2
3import android.Manifest;
4import android.content.Intent;
5import android.content.pm.PackageManager;
6import android.location.Location;
7import android.location.LocationListener;
8import android.os.Build;
9import android.os.Bundle;
10import android.view.View;
11
12import androidx.annotation.NonNull;
13import androidx.databinding.DataBindingUtil;
14
15import com.google.android.material.snackbar.Snackbar;
16import com.google.common.math.DoubleMath;
17
18import org.osmdroid.api.IGeoPoint;
19import org.osmdroid.util.GeoPoint;
20
21import java.math.RoundingMode;
22
23import eu.siacs.conversations.Config;
24import eu.siacs.conversations.R;
25import eu.siacs.conversations.databinding.ActivityShareLocationBinding;
26import eu.siacs.conversations.ui.util.LocationHelper;
27import eu.siacs.conversations.ui.widget.Marker;
28import eu.siacs.conversations.ui.widget.MyLocation;
29import eu.siacs.conversations.utils.LocationProvider;
30import eu.siacs.conversations.utils.ThemeHelper;
31
32public class ShareLocationActivity extends LocationActivity implements LocationListener {
33
34 private Snackbar snackBar;
35 private ActivityShareLocationBinding binding;
36 private boolean marker_fixed_to_loc = false;
37 private static final String KEY_FIXED_TO_LOC = "fixed_to_loc";
38 private Boolean noAskAgain = false;
39
40 @Override
41 protected void onSaveInstanceState(@NonNull final Bundle outState) {
42 super.onSaveInstanceState(outState);
43
44 outState.putBoolean(KEY_FIXED_TO_LOC, marker_fixed_to_loc);
45 }
46
47 @Override
48 protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
49 super.onRestoreInstanceState(savedInstanceState);
50
51 if (savedInstanceState.containsKey(KEY_FIXED_TO_LOC)) {
52 this.marker_fixed_to_loc = savedInstanceState.getBoolean(KEY_FIXED_TO_LOC);
53 }
54 }
55
56 @Override
57 protected void onCreate(final Bundle savedInstanceState) {
58 super.onCreate(savedInstanceState);
59
60 this.binding = DataBindingUtil.setContentView(this, R.layout.activity_share_location);
61 setSupportActionBar(binding.toolbar);
62 configureActionBar(getSupportActionBar());
63 setupMapView(binding.map, LocationProvider.getGeoPoint(this));
64
65 this.binding.cancelButton.setOnClickListener(view -> {
66 setResult(RESULT_CANCELED);
67 finish();
68 });
69
70 this.snackBar = Snackbar.make(this.binding.snackbarCoordinator, R.string.location_disabled, Snackbar.LENGTH_INDEFINITE);
71 this.snackBar.setAction(R.string.enable, view -> {
72 if (isLocationEnabledAndAllowed()) {
73 updateUi();
74 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasLocationPermissions()) {
75 requestPermissions(REQUEST_CODE_SNACKBAR_PRESSED);
76 } else if (!isLocationEnabled()) {
77 startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
78 }
79 });
80 ThemeHelper.fix(this.snackBar);
81
82 this.binding.shareButton.setOnClickListener(this::shareLocation);
83
84 this.marker_fixed_to_loc = isLocationEnabledAndAllowed();
85
86 this.binding.fab.setOnClickListener(view -> {
87 if (!marker_fixed_to_loc) {
88 if (!isLocationEnabled()) {
89 startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
90 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
91 requestPermissions(REQUEST_CODE_FAB_PRESSED);
92 }
93 }
94 toggleFixedLocation();
95 });
96 }
97
98 private void shareLocation(final View view) {
99 final Intent result = new Intent();
100 if (marker_fixed_to_loc && myLoc != null) {
101 result.putExtra("latitude", myLoc.getLatitude());
102 result.putExtra("longitude", myLoc.getLongitude());
103 result.putExtra("altitude", myLoc.getAltitude());
104 result.putExtra("accuracy", DoubleMath.roundToInt(myLoc.getAccuracy(), RoundingMode.HALF_UP));
105 } else {
106 final IGeoPoint markerPoint = this.binding.map.getMapCenter();
107 result.putExtra("latitude", markerPoint.getLatitude());
108 result.putExtra("longitude", markerPoint.getLongitude());
109 }
110 setResult(RESULT_OK, result);
111 finish();
112 }
113
114 @Override
115 public void onRequestPermissionsResult(final int requestCode,
116 @NonNull final String[] permissions,
117 @NonNull final int[] grantResults) {
118 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
119
120 if (grantResults.length > 0 &&
121 grantResults[0] != PackageManager.PERMISSION_GRANTED &&
122 Build.VERSION.SDK_INT >= 23 &&
123 permissions.length > 0 &&
124 (
125 Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) ||
126 Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) ||
127 Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0])
128 ) &&
129 !shouldShowRequestPermissionRationale(permissions[0])) {
130 noAskAgain = true;
131 }
132
133 if (!noAskAgain && requestCode == REQUEST_CODE_SNACKBAR_PRESSED && !isLocationEnabled() && hasLocationPermissions()) {
134 startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
135 }
136 updateUi();
137 }
138
139 @Override
140 protected void gotoLoc(final boolean setZoomLevel) {
141 if (this.myLoc != null && mapController != null) {
142 if (setZoomLevel) {
143 mapController.setZoom(Config.Map.FINAL_ZOOM_LEVEL);
144 }
145 mapController.animateTo(new GeoPoint(this.myLoc));
146 }
147 }
148
149 @Override
150 protected void setMyLoc(final Location location) {
151 this.myLoc = location;
152 }
153
154 @Override
155 protected void onPause() {
156 super.onPause();
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 if (this.marker_fixed_to_loc) {
165 this.binding.map.getOverlays().add(new Marker(marker_icon, new GeoPoint(this.myLoc)));
166 } else {
167 this.binding.map.getOverlays().add(new Marker(marker_icon));
168 }
169 } else {
170 this.binding.map.getOverlays().add(new Marker(marker_icon));
171 }
172 }
173
174 @Override
175 public void onLocationChanged(final Location location) {
176 if (this.myLoc == null) {
177 this.marker_fixed_to_loc = true;
178 }
179 updateUi();
180 if (LocationHelper.isBetterLocation(location, this.myLoc)) {
181 final Location oldLoc = this.myLoc;
182 this.myLoc = location;
183
184 // Don't jump back to the users location if they're not moving (more or less).
185 if (oldLoc == null || (this.marker_fixed_to_loc && this.myLoc.distanceTo(oldLoc) > 1)) {
186 gotoLoc();
187 }
188
189 updateLocationMarkers();
190 }
191 }
192
193 @Override
194 public void onStatusChanged(final String provider, final int status, final Bundle extras) {
195
196 }
197
198 @Override
199 public void onProviderEnabled(final String provider) {
200
201 }
202
203 @Override
204 public void onProviderDisabled(final String provider) {
205
206 }
207
208 private boolean isLocationEnabledAndAllowed() {
209 return this.hasLocationFeature && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || this.hasLocationPermissions()) && this.isLocationEnabled();
210 }
211
212 private void toggleFixedLocation() {
213 this.marker_fixed_to_loc = isLocationEnabledAndAllowed() && !this.marker_fixed_to_loc;
214 if (this.marker_fixed_to_loc) {
215 gotoLoc(false);
216 }
217 updateLocationMarkers();
218 updateUi();
219 }
220
221 @Override
222 protected void updateUi() {
223 if (!hasLocationFeature || noAskAgain || isLocationEnabledAndAllowed()) {
224 this.snackBar.dismiss();
225 } else {
226 this.snackBar.show();
227 }
228
229 if (isLocationEnabledAndAllowed()) {
230 this.binding.fab.setVisibility(View.VISIBLE);
231 runOnUiThread(() -> {
232 this.binding.fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_white_24dp :
233 R.drawable.ic_gps_not_fixed_white_24dp);
234 this.binding.fab.setContentDescription(getResources().getString(
235 marker_fixed_to_loc ? R.string.action_unfix_from_location : R.string.action_fix_to_location
236 ));
237 this.binding.fab.invalidate();
238 });
239 } else {
240 this.binding.fab.setVisibility(View.GONE);
241 }
242 }
243}