Search code examples
androidpermissionsandroid-6.0-marshmallowlocation-servicesgoogle-client

Using Google SettingsAPI and PermissionModel API in tandem


I am looking at the Play Services 7.0 documentation that can be found here:

http://android-developers.blogspot.in/2015/03/google-play-services-70-places-everyone.html?m=1

https://developers.google.com/android/reference/com/google/android/gms/location/SettingsApi

As we can see Android has simplified the way that the apps can enable the location by simply making it a one tap affair, which is great.

However what i cannot wrap my head around is how will this work in conjuction with the permissions Model.

I shall try to make my query as clear and simple as possible.

For example quoting the docs:

To use this API, first create a GoogleApiClient which supports at least LocationServices.API. Then connect the client to Google Play services:

mGoogleApiClient = new GoogleApiClient.Builder(context)
     .addApi(LocationServices.API)
     .addConnectionCallbacks(this)
     .addOnConnectionFailedListener(this)
     .build()
 ...
 mGoogleApiClient.connect();

Then create a LocationSettingsRequest.Builder and add all of the LocationRequests that the app will be using:

 LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
     .addLocationRequest(mLocationRequestHighAccuracy)
     .addLocationRequest(mLocationRequestBalancedPowerAccuracy);

Then check whether current location settings are satisfied:

 PendingResult<LocationSettingsResult> result =
         LocationServices.SettingsApi.checkLocationSettings(mGoogleClient, builder.build());

When the PendingResult returns, the client can check the location settings by looking at the status code from the LocationSettingsResult object. The client can also retrieve the current state of the relevant location settings by calling getLocationSettingsStates():

result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
     @Override
     public void onResult(LocationSettingsResult result) {
         final Status status = result.getStatus();
         final LocationSettingsStates = result.getLocationSettingsStates();
         switch (status.getStatusCode()) {
             case LocationSettingsStatusCodes.SUCCESS:
                 // All location settings are satisfied. The client can initialize location
                 // requests here.
                 ...
                 break;
             case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                 // Location settings are not satisfied. But could be fixed by showing the user
                 // a dialog.
                 try {
                     // Show the dialog by calling startResolutionForResult(),
                     // and check the result in onActivityResult().
                     status.startResolutionForResult(
                         OuterClass.this,
                         REQUEST_CHECK_SETTINGS);
                 } catch (SendIntentException e) {
                     // Ignore the error.
                 }
                 break;
             case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                 // Location settings are not satisfied. However, we have no way to fix the
                 // settings so we won't show the dialog.
                 ...
                 break;
         }
     }
 });

If the status code is RESOLUTION_REQUIRED, the client can call startResolutionForResult(Activity, int) to bring up a dialog, asking for user's permission to modify the location settings to satisfy those requests. The result of the dialog will be returned via onActivityResult(int, int, Intent). If the client is interested in which location providers are available, it can retrieve a LocationSettingsStates from the Intent by calling fromIntent(Intent):

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     final LocationSettingsStates states = LocationSettingsStates.fromIntent(intent);
     switch (requestCode) {
         case REQUEST_CHECK_SETTINGS:
             switch (resultCode) {
                 case Activity.RESULT_OK:
                     // All required changes were successfully made
                     ...
                     break;
                 case Activity.RESULT_CANCELED:
                     // The user was asked to change settings, but chose not to
                     ...
                     break;
                 default:
                     break;
             }
             break;
     }
 }

The above snippet will show the user a location dialog with a Yes and No option, which enables location on clicking Yes. But the document doesn't state anything about actually creating that dialog. Is that handled by the system itself? If so, what method needs to be used?

Also when trying to use the LocationServicesAPI with the permission model, how is the flow supposed to work?

Does that mean we show the permission model dialog requesting ACCESS_FINE_LOCATION permission first and if that permission is granted, we then go about showing the "location needs to be enabled" dialog? Is that the Android recommended way. I am not seeing any documentation on that.

TL;DR

  1. How do we use the new permission model API and the LocationServicesAPI together, since both of them involve multiple popus. Is there an android recommended way?

  2. If the user grants the ACCESS_FINE_LOCATION permission but does not agree to enable location, how is that flow supposed to work.

  3. If the user grants the ACCESS_FINE_LOCATION permission and agrees to enable location initially, but disables location later on, how is that flow supposed to work.

  4. How do we create the one-tap affair dialog for asking user to enable location services (I am NOT REFERRING to the permission dialog). The Google Maps app uses a dialog which seems to be a system provided dialog. I however cannot find any documentation to it.

Any answers, thoughts on this will be much appreciated!

And if there are any corrections need to be made, please leave a comment instead of downvoting.

Thanks!


Solution

    1. How do we use the new permission model API and the LocationServicesAPI together, since both of them involve multiple popus. Is there an android recommended way?

    They are completely independent. The SettingsApi does not require any runtime permissions at all as you are not actually getting any location data. It just allows you ask the user to enable the appropriate services/settings so that your LocationRequest will receive the quality of data it expects.

    The larger issue I think you are asking for is: "if I should ask for both, which order should I ask them in?" I think, in most cases, asking for the runtime permission first and then asking to enable location settings makes the most sense as the runtime permission would be required to get any use out of any changes to the user's location settings. Asking for the location permission first also can give users the context they need to know why you are asking for them to enable location settings.

    1. If the user grants the ACCESS_FINE_LOCATION permission but does not agree to enable location, how is that flow supposed to work.

    Then you won't get any data.

    1. If the user grants the ACCESS_FINE_LOCATION permission and agrees to enable location initially, but disables location later on, how is that flow supposed to work.

    You should check both the runtime permission and use the SettingsApi each time if you want to ensure that you'll get location data back.

    1. How do we create the one-tap affair dialog for asking user to enable location services (I am NOT REFERRING to the permission dialog). The Google Maps app uses a dialog which seems to be a system provided dialog. I however cannot find any documentation to it.

    The SettingsApi is the closest option for developers to enable location settings at a system level.