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:
https://developer.android.com/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..

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Sid
  • 2,792
  • 9
  • 55
  • 111

2 Answers2

1

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.

Andy
  • 10,553
  • 21
  • 75
  • 125
-2

Android 6.0 (API 23) needs this uses permission in the manifest, just as yours.

Put this in you Manifest.

<uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" />
Edd Perez
  • 11
  • 1