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