9

My app is attempting to access the device's location and I have included the following in the AndroidManifest.xml:

<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.app">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application>
        <meta-data android:name="com.google.android.gms.version" />
    </application>

</manifest>

I have implemented the GoogleApiClient.ConnectionCallbacks as follows to access the location service:

public class BackgroundLocationService implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    private static final String TAG = BackgroundLocationService.class.getSimpleName();

    private static GoogleApiClient googleApiClient;
    private static PendingIntent locationCallback;

    public static int LOCATION_INTERVAL = 10000;
    public static int FAST_INTERVAL = 5000;

    @Override
    public void onConnected(Bundle bundle) {
        Log.i(TAG, "Connected to Google API");

        LocationRequest request = new LocationRequest();
        request.setInterval(LOCATION_INTERVAL);
        request.setFastestInterval(FAST_INTERVAL);
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, request, locationCallback);
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(TAG, Integer.toString(i));
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i(TAG, connectionResult.toString());
    }
}

When I trigger the location service call, the following exception is thrown:

java.lang.SecurityException: Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations.
    at android.os.Parcel.readException(Parcel.java:1599)
    at android.os.Parcel.readException(Parcel.java:1552)
    at com.google.android.gms.location.internal.zzi$zza$zza.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzk.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzl.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzd$7.zza(Unknown Source)
    at com.google.android.gms.location.internal.zzd$7.zza(Unknown Source)
    at com.google.android.gms.internal.zzlb$zza.zzb(Unknown Source)
    at com.google.android.gms.internal.zzlf.zza(Unknown Source)
    at com.google.android.gms.internal.zzlf.zzb(Unknown Source)
    at com.google.android.gms.internal.zzli.zzb(Unknown Source)
    at com.google.android.gms.location.internal.zzd.requestLocationUpdates(Unknown Source)
    at com.localz.spotzpush.sdk.service.BackgroundLocationService.onConnected(BackgroundLocationService.java:45)
    at com.google.android.gms.common.internal.zzk.zzh(Unknown Source)
    at com.google.android.gms.internal.zzlg.zznU(Unknown Source)
    at com.google.android.gms.internal.zzlg.onConnected(Unknown Source)
    at com.google.android.gms.internal.zzli$2.onConnected(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zzg.zzpf(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zza.zzc(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zza.zzt(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zzc.zzph(Unknown Source)
    at com.google.android.gms.common.internal.zzj$zzb.handleMessage(Unknown Source)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

I am using an actual device to produce this issue and have been scratching my head on why the exception is thrown.

gyamana
  • 1,202
  • 1
  • 16
  • 28

4 Answers4

16

The issue was caused by a new feature for Android 6.0.

Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app.

http://developer.android.com/training/permissions/requesting.html

To get around the issue when the permission is not explicitly granted, I had put in a check to wrap location service calls (as per the Google Documentation, slightly modified).

int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);

if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
    //Execute location service call if user has explicitly granted ACCESS_FINE_LOCATION..
}

The Google Documentation also steps through how to request for the permissions that are needed.

UPDATED 12th Oct 2016

Adding in @Siddharth's update to include a more helpful answer for checkSelfPermission()

//For this example, run the check onResume()
@Override
public void onResume() {

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {

        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {

            // Show an expanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.

        } else {

            // No explanation needed, we can request the permission.
            // PERMISSION_REQUEST_ACCESS_FINE_LOCATION can be any unique int
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_ACCESS_FINE_LOCATION: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}
Community
  • 1
  • 1
gyamana
  • 1,202
  • 1
  • 16
  • 28
  • 1
    I am getting java.lang.SecurityException: Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations. crash with Target SDK 22 on Android 5.1 (Device is S plus (GiONEE_WBL7511)) Any clues? – satish123 Sep 17 '16 at 10:34
  • Please review my answer and make appropriate corrections. I'll delete my answer if you can make corrections to your answer. – Siddharth Oct 12 '16 at 04:07
  • @Siddharth, OK, thanks for that, will update my answer now – gyamana Oct 12 '16 at 04:13
  • Also, updating Android Studio to the latest version will allow it to automatically check, flag and resolve this issue. – gyamana Oct 18 '16 at 01:45
  • @arpitgoyal2008 did you manage to solve this issue ? I am facing similar issues on Galaxy J3 and J3 pro. Strange for a mobile running on Android 5.1 – Jaswanth Manigundan Oct 09 '17 at 01:25
2

Extract from Google Documentation. Seems like the most accepted answer on this thread is missing some critical information about the call back of the async checkSelfPermission.

Please confirm. If not, I'll delete this answer.

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}
Siddharth
  • 9,349
  • 16
  • 86
  • 148
0

Default implmentation of LocationSource doesn't necessarily have to use GPS to return accurate locations.

If i remove the permission "ACCESS_FINE_LOCATION" in the Manifest file, as soon as I try to display the map, the app crashes

This is because the default implementation uses LocationClient with LocationRequest.PRIORITY_HIGH_ACCURACY.

GoogleMap.setMyLocationEnabled when you request only ACCESS_COARSE_LOCATION permission, but switches to LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY.

See this Android: Google Maps location with low battery usage

Community
  • 1
  • 1
Anoop M Maddasseri
  • 10,213
  • 3
  • 52
  • 73
0

For everybody else having an error with gyamana's answer at Manifest.permission.ACCESS_FINE_LOCATION error. Make sure you are using android.Manifest instead of my.app.package.Manifest.

F34R
  • 23
  • 5