Last Updated: February 25, 2016
·
4.647K
· daisy1754

FusedLocationProviderApi doesn't work without network location provider: use SettingsApi for checking and setting up user's configuration

TL;DR
- FusedLocationProviderApi sometimes doesn't work even when your user believes GPS is on
- You can use SettingsApi to check user's configuration and help them setting up necessary location preference

Google introduced FusedLocationProviderApi to Google Play Service library in Google I/O 2013. It provides a battery-efficient, better location service by utilizing both GPS-based location and network-based location.

However, I noticed FusedLocationProviderApi doesn't give any location when user's setting is like below:

Picture

Why? Because user just allowing location access to app, but he/she doesn't allow location access to Google (!)

It seems in old age, Android has separate preference titled Google app location settings. However, we no longer have it in my Android L. What I see is a three-level settings: "High accuracy", "Battery saving" and "Device only". And to my surprise, user need to allow location access from Google app if he/she choose "High accuracy" or "Battery saving" mode.

Picture

Confusing? Here is a good news - Google recently introduced SettingsApi to check if user satisfy this complex requirement and if not, you can show a dialog to let user recover from the invalid status without leaving app. Some first-party app, like Google map also uses the same dialog.

Picture

You can check following code to check user's location setting:

PendingResult<> result = LocationServices.SettingsApi.checkLocationSettings(
  mGoogleApiClient,
  new LocationSettingsRequest.Builder().addLocationRequest(createLocationRequest()).build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
  @Override
  public void onResult(LocationSettingsResult locationSettingsResult) {
    final Status status = locationSettingsResult.getStatus();
    switch (status.getStatusCode()) {
      case LocationSettingsStatusCodes.SUCCESS:
        // Location is available
        break;
      case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
        // Location is not available, but we can ask permission from users
        break;
      case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
        // Location is not available, and we cannot recover from the situation
        break;
    }}});
}

If we reach LocationSettingsStatusCodes.RESOLUTION_REQUIRED, user's setting is not sufficient for LocationRequest. You can use

status.startResolutionForResult(this /* activity */, REQUEST_LOCATION_SET);

to show a dialog to ask user to turn on GPS or Wifi location provider and listen whether user accept it or not at Activity#onResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == REQUEST_LOCATION_SET) {
    switch (resultCode) {
      case Activity.RESULT_OK:
        // TODO
        break;
      case Activity.RESULT_CANCELED:
        // TODO
        break;
    }
  }
}