0
votes

I have followed the android guidelines for asking for permissions for Android Devices running VERSION.M and above namely (runtime-permissions), but the permission request dialogue is not shown, instead, the permission is automatically denied.

I am requesting users for READ/WRITE CONTACTS permission as well as other permissions as indicated by my manifest below.

The app requests for other permissions, such as access files, phone, SMS but does not request for read contacts permission.

Here is my manifest file

<uses-permission
    android:name="android.permission.AUTHENTICATE_ACCOUNTS"
    tools:remove="android:maxSdkVersion"/>

<uses-permission
    android:name="android.permission.GET_ACCOUNTS"
    tools:remove="android:maxSdkVersion"/>

<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="Manifest.permission.READ_CONTACTS"
    tools:remove="android:maxSdkVersion"/>
<uses-permission android:name="Manifest.permission.WRITE_CONTACTS"
    tools:remove="android:maxSdkVersion"/>
<uses-permission android:name="Manifest.permission.CONTACTS"/>

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_CALL_STATE" />

<!-- For sending/receiving events -->
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.RAISED_THREAD_PRIORITY" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

<!-- Normal -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

<!-- So we can add a TextSecure 'Account' -->
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

<!-- For conversation 'shortcuts' on the desktop -->
<uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />

<!-- For fixing MMS -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

<uses-feature
    android:name="android.hardware.microphone"
    android:required="false" />
<uses-feature
    android:name="android.hardware.wifi"
    android:required="false" />
<uses-feature
    android:name="android.hardware.portrait"
    android:required="false" />
<uses-feature
    android:name="android.hardware.touchscreen"
    android:required="false" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="com.google.android.providers.gsf.permmission.READ_GSERVICES" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
    android:name="android.permission.BROADCAST_WAP_PUSH"
    tools:ignore="ProtectedPermissions" />

<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Here is my explicit read contact permission request block

private void loadDeviceContactsOnAndroid_M() {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (checkSelfPermission(Manifest.permission_group.CONTACTS) == PackageManager.PERMISSION_GRANTED) {
            Log.e(getClass().getSimpleName(), "Read contacts permission granted");
            loadAndDisplayConfiguredRecipients();
        } else {
            Log.e(getClass().getSimpleName(), "Read contacts permission Not granted");

            if (shouldShowRequestPermissionRationale(Manifest.permission_group.CONTACTS)) {
                Toast.makeText(getApplicationContext(), "mPHR messaging feature requires your contacts", Toast.LENGTH_LONG).show();
            }

            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission_group.CONTACTS}, 101);
        }
    } else
        Toast.makeText(getApplicationContext(), "Android Version is " + Build.VERSION.SDK_INT, Toast.LENGTH_LONG).show();
}

Here is my onRequestPermissionResult callback method

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == 101) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "Hurray permission granted ", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "Until you grant the permission, we cannot display the names", Toast.LENGTH_SHORT).show();
        }
    }
}

Here is my contacts loader method block

Cursor cursor = contactController.querySystemContacts("");
    if (cursor.moveToFirst()) {
        do {
            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            messageRecipients.add(name);
        } while (cursor.moveToNext());
    }

    cursor.close();

The application does not request the user for the contacts permission and when I bypass this and try to go ahead and access the contact on device I get the permission denied security error;

java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{13c53b7 14017:my/app/package/name/u0a183} 

(pid=159017, uid=10183) 

requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS

I am running my tests on Android 8 physical devices.

When I use the same code for say, ACCESS_COARSE_LOCATION_PERMISSION it works perfectly but fails when I use READ_CONTACT or WRITE_CONTACTS

2

2 Answers

1
votes

I have not tried your code, but please do not use checkSelfPermission directly. Use ContextCompat.checkSelfPermission method instead as google recommends.

if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR)
    != PackageManager.PERMISSION_GRANTED) {
    // Permission is not granted
}

https://developer.android.com/training/permissions/requesting#java

When I add code for permission check, I was doing permission check individually which means that I was checking permission one by one rather than checking permission group. So I will try it later. But for now, please try with ContextCompat method.

EDIT:

Please do not request by permission group. The permission request model in Android M is for individual permission only. So here is what you can do.

private void checkPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED
            || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.READ_CONTACTS) || ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.WRITE_CONTACTS)) {
            Toast.makeText(this, "Necessary permissions are not granted",
                    Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS},
                    MY_PERMISSIONS_REQUEST_CODE);
        }
    } else {
        // Permission has already been granted
    }
}

EDIT:

Please do not use the followings in your manifest.

<uses-permission android:name="Manifest.permission.READ_CONTACTS"
    tools:remove="android:maxSdkVersion"/>
<uses-permission android:name="Manifest.permission.WRITE_CONTACTS"
    tools:remove="android:maxSdkVersion"/>
<uses-permission android:name="Manifest.permission.CONTACTS"/>

You can just replace them with the followings.

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
1
votes

You can either request for permission on the start of the application or runtime when you need to use it. Try this library (https://github.com/nabinbhandari/Android-Permissions). It gives you lots of options like when the user deny or grant the permission and also you can ask for multiple permissions.

Example

Single Permission

Permissions.check(this/*context*/, Manifest.permission.READ_CONTACTS, null, new PermissionHandler() {
@Override
public void onGranted() {
    // do your task.
}});

multiple permission

String[] permissions = {Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE};Permissions.check(this/*context*/, permissions, null/*rationale*/, null/*options*/, new PermissionHandler() {
@Override
public void onGranted() {
    // do your task.
}});

NOTE Using libraries is not a good practice unless they are well maintained