ACCESS_FINE_LOCATION SecurityException despite specifying the permission in the manifest file

13,275

Solution 1

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
    }
}

Solution 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
    }
}
Share:
13,275
gyamana
Author by

gyamana

Updated on July 24, 2022

Comments

  • gyamana
    gyamana almost 2 years

    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.

  • satish123
    satish123 over 7 years
    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?
  • Siddharth
    Siddharth over 7 years
    Please review my answer and make appropriate corrections. I'll delete my answer if you can make corrections to your answer.
  • gyamana
    gyamana over 7 years
    @Siddharth, OK, thanks for that, will update my answer now
  • gyamana
    gyamana over 7 years
    Also, updating Android Studio to the latest version will allow it to automatically check, flag and resolve this issue.
  • Ajay
    Ajay over 7 years
    How could request permission from service?
  • Jaswanth Manigundan
    Jaswanth Manigundan over 6 years
    @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