Fix security exception (Nearby places not loading after permissions granted) (#1440)

* Update changelog.md

* Versioning for v2.7.0

* Add logging to onPermissionsRequestResult

* Request location updates onStatusChanged

* Copy onResume() actions into onPermissionsRequestResult

* Added getLastKnownLocation method and hooked it up to refreshView

* Remove unnecessary calls, add more logging

* Add check to prevent NPE

* Check that curLatLng exists before getting Mapbox instance

* Moar logging

* Make curLatLang clearer

* Not a good hack - put curLatLang into the bundle separately

* Add TODO

* Rename variables for clarity

* Check for Network Provider as well, tidy up getLKL()

* Add Javadocs

* Remove unnecessary method in onStatusChanged

* Add checkGPS comment

* Remove unnecessary logs

* Add TODO

* Call bundle.clear() before inserting CurLatLng
This commit is contained in:
Josephine Lim 2018-04-18 21:30:13 +10:00 committed by neslihanturan
parent 9a3b6fc964
commit 3b129a6ea4
4 changed files with 58 additions and 16 deletions

View file

@ -79,6 +79,23 @@ public class LocationServiceManager implements LocationListener {
Manifest.permission.ACCESS_FINE_LOCATION); Manifest.permission.ACCESS_FINE_LOCATION);
} }
/**
* Gets the last known location in cases where there wasn't time to register a listener
* (e.g. when Location permission just granted)
* @return last known LatLng
*/
public LatLng getLKL() {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKL == null) {
lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
return LatLng.from(lastKL);
} else {
return null;
}
}
public LatLng getLastLocation() { public LatLng getLastLocation() {
if (lastLocation == null) { if (lastLocation == null) {
return null; return null;
@ -249,6 +266,7 @@ public class LocationServiceManager implements LocationListener {
public enum LocationChangeType{ public enum LocationChangeType{
LOCATION_SIGNIFICANTLY_CHANGED, //Went out of borders of nearby markers LOCATION_SIGNIFICANTLY_CHANGED, //Went out of borders of nearby markers
LOCATION_SLIGHTLY_CHANGED, //User might be walking or driving LOCATION_SLIGHTLY_CHANGED, //User might be walking or driving
LOCATION_NOT_CHANGED LOCATION_NOT_CHANGED,
PERMISSION_JUST_GRANTED
} }
} }

View file

@ -13,14 +13,12 @@ import android.support.design.widget.BottomSheetBehavior;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.Toast;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
@ -81,6 +79,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
private BroadcastReceiver broadcastReceiver; private BroadcastReceiver broadcastReceiver;
private LatLng lastKnownLocation;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -158,7 +157,11 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
switch (requestCode) { switch (requestCode) {
case LOCATION_REQUEST: { case LOCATION_REQUEST: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED); Timber.d("Location permission granted, refreshing view");
//Still need to check if GPS is enabled
checkGps();
lastKnownLocation = locationManager.getLKL();
refreshView(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED);
} else { } else {
//If permission not granted, go to page that says Nearby Places cannot be displayed //If permission not granted, go to page that says Nearby Places cannot be displayed
hideProgressBar(); hideProgressBar();
@ -347,21 +350,33 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
} }
curLatLang = lastLocation; curLatLang = lastLocation;
if (locationChangeType.equals(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED)) {
curLatLang = lastKnownLocation;
}
if (curLatLang == null) { if (curLatLang == null) {
Timber.d("Skipping update of nearby places as location is unavailable"); Timber.d("Skipping update of nearby places as location is unavailable");
return; return;
} }
if (locationChangeType if (locationChangeType.equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)
.equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) { || locationChangeType.equals(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED)) {
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
//TODO: This hack inserts curLatLng before populatePlaces is called (see #1440). Ideally a proper fix should be found
Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriSerializer())
.create();
String gsonCurLatLng = gson.toJson(curLatLang);
bundle.clear();
bundle.putString("CurLatLng", gsonCurLatLng);
placesDisposable = Observable.fromCallable(() -> nearbyController placesDisposable = Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLang)) .loadAttractionsFromLocation(curLatLang))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::populatePlaces); .subscribe(this::populatePlaces);
} else if (locationChangeType } else if (locationChangeType.equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) {
.equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriSerializer()) .registerTypeAdapter(Uri.class, new UriSerializer())
.create(); .create();
@ -384,14 +399,14 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
if (placeList.size() == 0) { if (placeList.size() == 0) {
ViewUtil.showSnackbar(findViewById(R.id.container), R.string.no_nearby); ViewUtil.showSnackbar(findViewById(R.id.container), R.string.no_nearby);
} }
bundle.clear();
bundle.putString("PlaceList", gsonPlaceList); bundle.putString("PlaceList", gsonPlaceList);
bundle.putString("CurLatLng", gsonCurLatLng); //bundle.putString("CurLatLng", gsonCurLatLng);
bundle.putString("BoundaryCoord", gsonBoundaryCoordinates); bundle.putString("BoundaryCoord", gsonBoundaryCoordinates);
// First time to init fragments // First time to init fragments
if (nearbyMapFragment == null) { if (nearbyMapFragment == null) {
Timber.d("Init map fragment for the first time");
lockNearbyView(true); lockNearbyView(true);
setMapFragment(); setMapFragment();
setListFragment(); setListFragment();
@ -399,6 +414,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
lockNearbyView(false); lockNearbyView(false);
} else { } else {
// There are fragments, just update the map and list // There are fragments, just update the map and list
Timber.d("Map fragment already exists, just update the map and list");
updateMapFragment(false); updateMapFragment(false);
updateListFragment(); updateListFragment();
} }

View file

@ -82,8 +82,11 @@ public class NearbyListFragment extends DaggerFragment {
} }
public void updateNearbyListSignificantly() { public void updateNearbyListSignificantly() {
adapterFactory.updateAdapterData(getPlaceListFromBundle(bundleForUpdates), try {
(RVRendererAdapter<Place>) recyclerView.getAdapter()); adapterFactory.updateAdapterData(getPlaceListFromBundle(bundleForUpdates), (RVRendererAdapter<Place>) recyclerView.getAdapter());
} catch (NullPointerException e) {
Timber.e("Null pointer exception from calling recyclerView.getAdapter()");
}
} }
private List<Place> getPlaceListFromBundle(Bundle bundle) { private List<Place> getPlaceListFromBundle(Bundle bundle) {

View file

@ -126,6 +126,7 @@ public class NearbyMapFragment extends DaggerFragment {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Timber.d("Nearby map fragment created");
controller = new ContributionController(this); controller = new ContributionController(this);
directUpload = new DirectUpload(this, controller); directUpload = new DirectUpload(this, controller);
@ -151,9 +152,11 @@ public class NearbyMapFragment extends DaggerFragment {
getActivity()); getActivity());
boundaryCoordinates = gson.fromJson(gsonBoundaryCoordinates, gsonBoundaryCoordinatesType); boundaryCoordinates = gson.fromJson(gsonBoundaryCoordinates, gsonBoundaryCoordinatesType);
} }
Mapbox.getInstance(getActivity(), if (curLatLng != null) {
getString(R.string.mapbox_commons_app_token)); Mapbox.getInstance(getActivity(),
MapboxTelemetry.getInstance().setTelemetryEnabled(false); getString(R.string.mapbox_commons_app_token));
MapboxTelemetry.getInstance().setTelemetryEnabled(false);
}
setRetainInstance(true); setRetainInstance(true);
} }
@ -161,7 +164,9 @@ public class NearbyMapFragment extends DaggerFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
Timber.d("onCreateView called");
if (curLatLng != null) { if (curLatLng != null) {
Timber.d("curLatLng found, setting up map view...");
setupMapView(savedInstanceState); setupMapView(savedInstanceState);
} }