45

CheckSelfPermission method is not working as expected and it is always returning zero in android 6.0(Marshmallow). Because the target sdk is 22 and i am using http Client for network connection. Following is the code snippet.

private void insertDummyContactWrapper() {
    List<String> permissionsNeeded = new ArrayList<String>();

    final List<String> permissionsList = new ArrayList<String>();
    if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
        permissionsNeeded.add("GPS");
    if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
        permissionsNeeded.add("Read Contacts");
    if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
        permissionsNeeded.add("Write Contacts");

    if (permissionsList.size() > 0) {
        if (permissionsNeeded.size() > 0) {
            // Need Rationale
            String message = "You need to grant access to " + permissionsNeeded.get(0);
            for (int i = 1; i < permissionsNeeded.size(); i++)
                message = message + ", " + permissionsNeeded.get(i);
            showMessageOKCancel(message,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                        }
                    });
            return;
        }
        requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
        return;
    }

    insertDummyContact();
}

@TargetApi(Build.VERSION_CODES.M)
private boolean addPermission(List<String> permissionsList, String permission) {
    if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
        permissionsList.add(permission);
        // Check for Rationale Option
        if (!shouldShowRequestPermissionRationale(permission)) return false;
    }
    return true;
}

private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setPositiveButton("OK", okListener)
            .setNegativeButton("Cancel", null)
            .create()
            .show();
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: {
            Map<String, Integer> perms = new HashMap<String, Integer>();
            // Initial
            perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
            // Fill with results
            for (int i = 0; i < permissions.length; i++)
                perms.put(permissions[i], grantResults[i]);
            // Check for ACCESS_FINE_LOCATION
            if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
                // All Permissions Granted
                insertDummyContact();
            } else {
                // Permission Denied
                Toast.makeText(MainActivity.this, "Some Permission is Denied", Toast.LENGTH_SHORT)
                        .show();
            }
        }
        break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}"
Julien-L
  • 5,267
  • 3
  • 34
  • 51
Mithun S
  • 453
  • 1
  • 4
  • 9
  • Possible duplicate of [Marshmallow Permissions not working for TargetVersion below 23](http://stackoverflow.com/questions/33232865/marshmallow-permissions-not-working-for-targetversion-below-23) – Dhaval Patel Oct 29 '15 at 06:27

3 Answers3

93
  1. If your application is targeting API level before 23 (Android M) then both: ContextCompat#checkSelfPermission and Context#checkSelfPermission won't work and always return 0 (PERMISSION_GRANTED). Even if you run the application on Android 6.0 (API 23).

  2. It isn't fully true that if you targeting API level before 23 then you don't have to take care of permissions. If your application is targeting API level before 23 and target device Android version is:

    • Android < 6.0: Everything will be ok.
    • Android 6.0: Application's run-time permissions will be granted by default (compatibility mode applies), but the user can change run-time permissions in Android Settings, then you may have problems.
  3. As I said in the 1st point, if you targeting API level before 23 on Android 6.0 then ContextCompat#checkSelfPermission and Context#checkSelfPermission won't work. Fortunately you can use PermissionChecker#checkSelfPermission to check run-time permissions.

Example code:

    public boolean selfPermissionGranted(String permission) {
        // For Android < Android M, self permissions are always granted.
        boolean result = true;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            
            if (targetSdkVersion >= Build.VERSION_CODES.M) {
                // targetSdkVersion >= Android M, we can
                // use Context#checkSelfPermission
                result = context.checkSelfPermission(permission)
                        == PackageManager.PERMISSION_GRANTED;
            } else {
                // targetSdkVersion < Android M, we have to use PermissionChecker
                result = PermissionChecker.checkSelfPermission(context, permission)
                        == PermissionChecker.PERMISSION_GRANTED;
            }
        }

        return result;
    }

To get target Sdk Version you can use:

    try {
        final PackageInfo info = context.getPackageManager().getPackageInfo(
                context.getPackageName(), 0);
        targetSdkVersion = info.applicationInfo.targetSdkVersion;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }

It works on Nexus 5 with Android M.

MikePtr
  • 1,661
  • 1
  • 16
  • 18
  • 1
    What's the point of using `PermissionChecker#checkSelfPermission` if you're not targeting at least SDK 23? Permissions are *always* granted, even on an SDK 23 device, when targeting SDK 22 or lower. – Marc Plano-Lesay Jan 20 '16 at 16:23
  • 7
    Permissions are granted automatically after installation, but an user can turn run-time permissions off after installation. It's why we'd like to check if permissions are granted. – MikePtr Jan 21 '16 at 10:08
  • @MikePtr Is it safe to ask for permissions if target is less than 23 and running on 23 ? will the normal way of asking permission work ? – Ahmed Jun 21 '16 at 23:45
  • Yes, it's safe. "As I said in the 1st point, if you targeting an API level before 23 on Android 6.0 then ContextCompat#checkSelfPermission and Context#checkSelfPermission doesn't work. " – MikePtr Jun 23 '16 at 06:56
  • 1
    I don't understand why we have to make a fork in our code or remember to update from PermissionChecker to ContextCompat depending on the target SDK, does PermissionChecker stop working properly when your app targets SDK 23? – Sebas LG Jul 12 '16 at 07:24
  • 2
    This should be the Accepted Answer as its much more comprehensive & the only answer that handles PermissionChecker scenario. Thanks! – AlexVPerl Aug 30 '16 at 22:37
  • I am able to check permissions using the PermissionChecker however my calls to request permissions are always interrupted. Does anyone know why this is? Is it related? I have added the requested permissions to the manifest. – masterwok Dec 28 '16 at 19:33
  • What does it mean "interrupted"? Please provide more information. – MikePtr Dec 29 '16 at 11:50
  • Android Studio says that `Condition 'targetSdkVersion >= Build.VERSION_CODES.M' is always 'true'` (importing `android.R.attr.targetSdkVersion`). Instead, if I use that try-catch block to obtain target SDK version, Android Studio says this: `Cannot assign a value to final variable 'targetSdkVersion`. What's wrong? – smartmouse May 17 '17 at 21:21
  • For the above example you shouldn't import any android.R.attr.targetSdkVersion. targetSdkVersion is an integer value declared in a class. – MikePtr May 23 '17 at 07:13
  • nice explain dude. final got the answer – Anil Ugale Jun 15 '17 at 07:15
18

The method Context#checkSelfPermission(String) was added to the API 23. Also below API 23 it's pointless as the permission is always granted. Make a check for the API version before handling the permissions

private void insertDummyContactWrapper() {
    // the only way we insert the dummy contact if if we are below M.
    // Else we continue on and prompt the user for permissions
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        insertDummyContact();
        return;
    }

    List<String> permissionsNeeded = new ArrayList<String>();

    final List<String> permissionsList = new ArrayList<String>();
    if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
        permissionsNeeded.add("GPS");
    if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
        permissionsNeeded.add("Read Contacts");
    if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
        permissionsNeeded.add("Write Contacts");
    if (permissionsList.size() > 0) {
        if (permissionsNeeded.size() > 0) {
            // Need Rationale
            String message = "You need to grant access to " + permissionsNeeded.get(0);
            for (int i = 1; i < permissionsNeeded.size(); i++)
                message = message + ", " + permissionsNeeded.get(i);
            showMessageOKCancel(message,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                        }
                    });
            return;
        }
        requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
    }
}

Reference: http://developer.android.com/reference/android/content/Context.html#checkSelfPermission(java.lang.String)

JBirdVegas
  • 10,855
  • 2
  • 44
  • 50
  • Well the link you provide don't specify at all that it shouldn't work on API <23. In fact, it probably simply chains to `checkPermission (String permission, int pid, int uid)` which is there since API 1. – Marc Plano-Lesay Oct 29 '15 at 06:43
  • The link shows that `checkSelfPermission` did not exist before API 23. It's not relevant if it chains as the method won't ever do anything below API 23. No matter what you do the runtime permissions will not work below 23. Check for the API of at least 23 before doing any permission handling. You will never get the runtime permissions to work below 23. – JBirdVegas Oct 29 '15 at 12:28
  • 1
    Well I just re-read my comment, I was definitely *not* awake this morning. Indeed the method will just crash in API < 23… But there is always the possibility to use the support-v4 library, which provides `checkSelfPermission` (http://developer.android.com/reference/android/support/v4/content/ContextCompat.html#checkSelfPermission%28android.content.Context,%20java.lang.String%29). This one works (and always returns `PERMISSION_GRANTED` on API < 23). – Marc Plano-Lesay Oct 29 '15 at 12:54
  • @Kernald, ahh ok i didn't know you were using the support library. In that case is the problem solved? – JBirdVegas Oct 29 '15 at 13:47
  • I'm not the one who posted the question, just read and commented your answer too early in the morning ;-) – Marc Plano-Lesay Oct 29 '15 at 18:32
5

When targeting an API level before 23, a compatibility mode applies. The old permission behavior is running, even on devices running Android 6. To use the new permission system, you have to target API 23 (or higher in the future).

The full behavior is specified on the documentation: https://developer.android.com/training/permissions/requesting.html

Marc Plano-Lesay
  • 6,808
  • 10
  • 44
  • 75