Sid Sid - 3 months ago 58
Android Question

Read Contacts permission is denied on Android 6.0

I want to access Read Contacts permission from android. I have specified permission in manifest file.

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


It's working on Device 4.4.2 but crashes on 6.0 with an exception:

FATAL EXCEPTION: main
Process: com.example.siddhi.meavita, PID: 17612
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.siddhi.meavita/com.example.siddhi.meavita.ContactList}: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{44abcb5 17612:com.example.siddhi.meavita/u0a158} (pid=17612, uid=10158) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS


So I looked around SO to find the solution and I came to know android 6.0 onwards it has a permission model to request for permissions.

So I read this link:

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


and followed the code suggested here :

Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord in Android Studio

And I wrote the code this way:

public class ContactList extends ListActivity {


private ArrayList<contact> contact_list = null;
private contactAdapter mContactAdapter = null;

private ArrayList<contact> items;
boolean[] isChecked;
Cursor mCursor;
ListView lv;
public int RQS_PICK_CONTACT = 1;
private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_contacts_list);

int permissionCheck = ContextCompat.checkSelfPermission(ContactList.this,
Manifest.permission.READ_CONTACTS);

contact_list = new ArrayList<contact>();

lv = getListView();

getContacts();

}

@SuppressWarnings("unused")
private void getContacts() {


String[] projection = new String[] {
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER,
ContactsContract.Contacts._ID };


mCursor = managedQuery(ContactsContract.Contacts.CONTENT_URI, null, null, null,null);

while (mCursor.moveToNext()) {
contact contact = new contact();

String contactId = mCursor.getString(mCursor.getColumnIndex(ContactsContract.Contacts._ID));
contact.setContactName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
contact_list.add(contact);
}
isChecked = new boolean[mCursor.getCount()];

for (int i = 0; i < isChecked.length; i++) {
isChecked[i] = false;
}

showContacts();

}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == RQS_PICK_CONTACT) {
if (resultCode == RESULT_OK) {

getContacts();

}
}
}

public class contactAdapter extends ArrayAdapter<contact> {

public contactAdapter(Context context, int textViewResourceId, ArrayList<contact> items1) {
super(context, textViewResourceId, items1);
items = items1;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder mViewHolder;

mViewHolder = new ViewHolder();
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.contact_list_item, parent, false);
mViewHolder.cb = (CheckBox) convertView.findViewById(R.id.checkBox);
mViewHolder.name = (TextView) convertView.findViewById(R.id.name);

convertView.setTag(mViewHolder);

if (isChecked[position] == true)
mViewHolder.cb.setChecked(true);
else
mViewHolder.cb.setChecked(false);
mViewHolder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean ischecked) {
if (buttonView.isChecked())
isChecked[position] = true;
else
isChecked[position] = false;
}
});

contact contacts = items.get(position);
if (contacts != null) {
if (mViewHolder.cb != null) {
mViewHolder.name.setText(contacts.getContactName());
}
}

return convertView;
}
}

public class ViewHolder {
CheckBox cb;
TextView name;
}

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


private void showContacts()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {

requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
//After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
}

else {

this.mContactAdapter = new contactAdapter(this, R.layout.contact_list_item, contact_list);
lv.setAdapter(this.mContactAdapter);
mCursor.close();
}

}

}


Still it gives an exception. What's going wrong here? Thank you..

Answer

I'm not 100% familiar with obtaining contacts, but from what I notice your getContacts() method is always being called when the Fragment is created. So let's assume the user never granted the permission. You are still trying to setup the contacts list. Don't even bother setting up the list in the first place if the permission has not been granted yet. So something like:

//onCreate
lv = getListView();

if(ContextCompat.checkSelfPermission(this,
    Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
         getContacts();
 }

Also, you might want to change your logic to accommodate this. So remove that permission check in showContacts() if it has been requested and move that in onCreate. getContacts should only be called if you have the permission.

Comments