12

I have a problem when running my app on Android OS 4.0 and requesting READ_EXTERNAL_STORAGE permission with:

ActivityCompat.requestPermissions(ctx, requestedPermissions, requestCode);

I always get on the callback

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) { 

grantResults != PackageManager.PERMISSION_GRANTED

Checking the permission with ActivityCompat.checkSelfPermission is always returning permissionDenied.

It works well on OS 6.0 by requesting the permission with system dialog. Android OS 4.x excepted the 4.0 the permission is always granted. OS 4.0 the other permissions (Camera,Calendar,Contact,Phone) are behaving well except the READ_EXTERNAL_STORAGE causing this issue.

Maybe an OS issue?

frogatto
  • 28,539
  • 11
  • 83
  • 129
skirix
  • 253
  • 2
  • 12
  • This is weird. Can you try using normal method of permission that is .requestPermission( requestedPermissions, requestCode); – dex Nov 02 '15 at 16:38
  • 1
    http://stackoverflow.com/questions/32129716/how-does-storage-access-change-on-android-6 – frogatto Nov 02 '15 at 16:48
  • @dex The problem is that activity related methods for permissions are only accessible on API 23 – skirix Nov 02 '15 at 16:49
  • @Skirx : Yes you need to set targetSDK = 23 and compileSDK = 23 to use them, if you not setting these then you will not able to support Android M any how – dex Nov 02 '15 at 16:51
  • @dex The problem here is that I'am setting android:minSdkVersion="14" and android:targetSdkVersion="23". and as you can see on the question below getting permissionDenied on 4.0.3. if i set android:minSdkVersion="23" and android:targetSdkVersion="23" it works only on OS 6.0 and the behaviour is normal, no problems. Here the problem is that the checkSelfPermission must return Granted on OS 4.0.3 instead of Denied. CompatLibrary issue I think – skirix Nov 02 '15 at 17:04
  • @skirix I am not asking to change the minSDK. I am saying change the compileSDK and TargetSDK and use activity method. if you are using gradle android { compileSdkVersion 23 buildToolsVersion '23.0.0'.... } – dex Nov 02 '15 at 17:08
  • @abforce Thank you for the edit and the answer – skirix Nov 02 '15 at 18:13

2 Answers2

11

What ActivityCompat.requestPermissions() does is:

  • call through to the real requestPermissions() if you are on Android 6.0+, or

  • use PackageManager to see if you hold the requested permissions on older versions of Android

The problem with READ_EXTERNAL_STORAGE is that it was added in API Level 16 (Android 4.1). You cannot hold it on older versions of Android than that, for the simple reason that it did not exist.

Either:

  • Set your minSdkVersion to 16, or

  • Put your own logic in to handle this case, recognizing that READ_EXTERNAL_STORAGE is irrelevant prior to API Level 16

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 7
    A simple workaround is to ask for the `WRITE_EXTERNAL_STORAGE` permission instead, which is API 4. In M, `WRITE` and `READ` live in the same permission group, so asking for the former will grant access to the latter as well. The only downside is that versions prior to 4.1 will see that a new permission is required, if you were previously only asking for `READ`. – Sebastiano Nov 09 '15 at 14:01
  • 1
    @dextor: That assumes that Android will always ask the user for rights at the level of the permission group, not the level of the permission. I would not make that assumption. – CommonsWare Nov 09 '15 at 14:23
0

I discovered this issue when dealing with FOREGROUND_SERVICE on Android 8.0. My solution unfortunately depends on the exception handling, but it does not require dealing with the API level the permission is supported from. You can check if permission exists on current API level with this method:

private boolean permissionExistsOnCurrentApiLevel(String permission) {
    try {
        getPackageManager().getPermissionInfo(permission, PackageManager.GET_META_DATA);
    } catch (PackageManager.NameNotFoundException e) {
        return false;
    }

    return true;
}

With this method you can implement you own version of ContextCompat.checkSelfPermission where all non-existing permission are automatically considered to be granted:

private int myCheckSelfPermission(@NonNull Context context, @NonNull String permission) {
    if(!permissionExistsOnCurrentApiLevel(permission)) {
        return PackageManager.PERMISSION_GRANTED;
    }

    return ContextCompat.checkSelfPermission(this, permission);
}
gingo
  • 3,149
  • 1
  • 23
  • 32