Fix security exception crash while accessing network location provider (#1498)

* Fix security exception crash while accessing network location provider

* Added java docs
This commit is contained in:
Vivek Maskara 2018-05-15 12:55:37 +05:30 committed by Josephine Lim
parent 93b0db9ecd
commit d891b8f310
2 changed files with 61 additions and 11 deletions

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.location; package fr.free.nrw.commons.location;
import android.Manifest; import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@ -10,9 +11,10 @@ import android.location.LocationManager;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.util.Log;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import timber.log.Timber; import timber.log.Timber;
@ -29,6 +31,7 @@ public class LocationServiceManager implements LocationListener {
private Location lastLocation; private Location lastLocation;
private final List<LocationUpdateListener> locationListeners = new CopyOnWriteArrayList<>(); private final List<LocationUpdateListener> locationListeners = new CopyOnWriteArrayList<>();
private boolean isLocationManagerRegistered = false; private boolean isLocationManagerRegistered = false;
private Set<Activity> locationExplanationDisplayed = new HashSet<>();
/** /**
* Constructs a new instance of LocationServiceManager. * Constructs a new instance of LocationServiceManager.
@ -51,7 +54,6 @@ public class LocationServiceManager implements LocationListener {
/** /**
* Returns whether the location permission is granted. * Returns whether the location permission is granted.
*
* @return true if the location permission is granted * @return true if the location permission is granted
*/ */
public boolean isLocationPermissionGranted() { public boolean isLocationPermissionGranted() {
@ -73,10 +75,23 @@ public class LocationServiceManager implements LocationListener {
LOCATION_REQUEST); LOCATION_REQUEST);
} }
/**
* The permission explanation dialog box is now displayed just once for a particular activity. We are subscribing
* to updates from multiple providers so its important to show the dialog just once. Otherwise it will be displayed
* once for every provider, which in our case currently is 2.
* @param activity
* @return
*/
public boolean isPermissionExplanationRequired(Activity activity) { public boolean isPermissionExplanationRequired(Activity activity) {
return !activity.isFinishing() && if (activity.isFinishing()) {
ActivityCompat.shouldShowRequestPermissionRationale(activity, return false;
Manifest.permission.ACCESS_FINE_LOCATION); }
boolean showRequestPermissionRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION);
if (showRequestPermissionRationale && !locationExplanationDisplayed.contains(activity)) {
locationExplanationDisplayed.add(activity);
return true;
}
return false;
} }
/** /**
@ -84,8 +99,9 @@ public class LocationServiceManager implements LocationListener {
* (e.g. when Location permission just granted) * (e.g. when Location permission just granted)
* @return last known LatLng * @return last known LatLng
*/ */
@SuppressLint("MissingPermission")
public LatLng getLKL() { public LatLng getLKL() {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (isLocationPermissionGranted()) {
Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKL == null) { if (lastKL == null) {
lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
@ -107,9 +123,10 @@ public class LocationServiceManager implements LocationListener {
* Registers a LocationManager to listen for current location. * Registers a LocationManager to listen for current location.
*/ */
public void registerLocationManager() { public void registerLocationManager() {
if (!isLocationManagerRegistered) if (!isLocationManagerRegistered) {
isLocationManagerRegistered = requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER) isLocationManagerRegistered = requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER)
&& requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); && requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
}
} }
/** /**
@ -142,7 +159,7 @@ public class LocationServiceManager implements LocationListener {
* @return LOCATION_SIGNIFICANTLY_CHANGED if location changed significantly * @return LOCATION_SIGNIFICANTLY_CHANGED if location changed significantly
* LOCATION_SLIGHTLY_CHANGED if location changed slightly * LOCATION_SLIGHTLY_CHANGED if location changed slightly
*/ */
protected LocationChangeType isBetterLocation(Location location, Location currentBestLocation) { private LocationChangeType isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) { if (currentBestLocation == null) {
// A new location is always better than no location // A new location is always better than no location

View file

@ -322,7 +322,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
locationManager.addLocationListener(this); locationManager.addLocationListener(this);
locationManager.registerLocationManager(); registerLocationUpdates();
} }
@Override @Override
@ -400,7 +400,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
return; return;
} }
locationManager.registerLocationManager(); registerLocationUpdates();
LatLng lastLocation = locationManager.getLastLocation(); LatLng lastLocation = locationManager.getLastLocation();
if (curLatLng != null && curLatLng.equals(lastLocation)) { //refresh view only if location has changed if (curLatLng != null && curLatLng.equals(lastLocation)) { //refresh view only if location has changed
@ -450,6 +450,39 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
} }
} }
/**
* This method first checks if the location permissions has been granted and then register the location manager for updates.
*/
private void registerLocationUpdates() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (locationManager.isLocationPermissionGranted()) {
locationManager.registerLocationManager();
} else {
// Should we show an explanation?
if (locationManager.isPermissionExplanationRequired(this)) {
new AlertDialog.Builder(this)
.setMessage(getString(R.string.location_permission_rationale_nearby))
.setPositiveButton("OK", (dialog, which) -> {
requestLocationPermissions();
dialog.dismiss();
})
.setNegativeButton("Cancel", (dialog, id) -> {
showLocationPermissionDeniedErrorDialog();
dialog.cancel();
})
.create()
.show();
} else {
// No explanation needed, we can request the permission.
requestLocationPermissions();
}
}
} else {
locationManager.registerLocationManager();
}
}
private void populatePlaces(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { private void populatePlaces(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
List<Place> placeList = nearbyPlacesInfo.placeList; List<Place> placeList = nearbyPlacesInfo.placeList;
LatLng[] boundaryCoordinates = nearbyPlacesInfo.boundaryCoordinates; LatLng[] boundaryCoordinates = nearbyPlacesInfo.boundaryCoordinates;
@ -530,7 +563,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
locationManager.removeLocationListener(this); locationManager.removeLocationListener(this);
} else { } else {
lockNearbyView = false; lockNearbyView = false;
locationManager.registerLocationManager(); registerLocationUpdates();
locationManager.addLocationListener(this); locationManager.addLocationListener(this);
} }
} }