4

I am trying to programmatically obtain the user's profile information in an Android application. This works fine on a Pixel phone but doesn't return any results on a Samsung phone. For example:

String contactId = null;

// getting contacts ID
Cursor cursorID = getContentResolver().query(ContactsContract.Profile.CONTENT_URI,
            new String[]{ContactsContract.Contacts._ID},
            null, null, null);

if (cursorID.moveToFirst()) {
    contactId = cursorID.getString(cursorID.getColumnIndex(ContactsContract.Contacts._ID));
}

On the Pixel this returns the contact id of the phone's owner. On the Galaxy the cursor is empty. I'm assuming this is because Samsung is using some proprietary version of contacts that is not exposed through the standard Android API. Can anyone confirm? Is there an alternative for Samsung devices?

user1686620
  • 2,801
  • 4
  • 18
  • 21
  • Did you make sure ask for runtime permissions? – SteelToe Sep 26 '18 at 17:23
  • I think so. It is working fine on one phone. In the manifest I request a bunch of permissions including: – user1686620 Sep 26 '18 at 17:35
  • You have to request the permissions at runtime. See this article https://developer.android.com/training/permissions/requesting – SteelToe Sep 26 '18 at 17:47
  • Yes I plan on doing just that but while testing I have manually granted access to contacts on both phones. Before doing this I was getting a security exception. After granting access I no longer get an exception on either phone, on the Pixel phone I get the profile information, on the Samsung phone I just get zero results. – user1686620 Sep 26 '18 at 18:25

1 Answers1

1

Yep you will certainly end up with null values in the following cases:

  1. You haven't created the user profile in your contacts session yet.

  2. If you haven't linked your mail account with the profile.

You might end up with SecurityException and to avoid that i have modified the code as per the documentaion

You will surely receive a warning saying cursor finalized without prior close(), it is a best practice to close the cursors if you are not going to use urther.

don't forget to include permissions in manifest child section.

MANIFEST FILE:

      <?xml version="1.0" encoding="utf-8"?>
    <manifest 


     xmlns:android="http://schemas.android.com
      /apk/res/android"
     package="com.example.ganesh.contacts">
     <uses-permission 

    android:name="android.permission.READ_CONTACTS" 
   />


       <application
        android:allowBackup="true"
       android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"

       android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/AppTheme">
       <activity android:name=".MainActivity">
        <intent-filter>
            <action 
         android:name="android.intent.action.MAIN" />

            <category 

      android:name="android.intent.category.LAUNCHER" 
            />
        </intent-filter>
                  </activity>
               </application>

             </manifest>

ACTIVITY CODE:

public class MainActivity extends 
     AppCompatActivity implements 
      View.OnClickListener {
        String contactId = null;
        Button button;
        TextView textView;
         @Override
         protected void onCreate(Bundle 
             savedInstanceState) {
         super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
         button=findViewById(R.id.button);
         textView=findViewById(R.id.textView);
        button.setOnClickListener(this);

         }

@Override
public void onClick(View v) {
    onReadContacts();
}

private void onReadContacts() {
    // Here, thisActivity is the current activity
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_CONTACTS)
            != PackageManager.PERMISSION_GRANTED) {

        // Permission is not granted
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.READ_CONTACTS)) {
            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.
        } else {
            // No explanation needed; request the permission
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_CONTACTS},
                    101);

            // 101 is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    } else {
        // Permission has already been granted
        Cursor c = getApplication().getContentResolver().query(ContactsContract.Profile.CONTENT_URI, null, null, null, null);
        c.moveToFirst();
        textView.setText(c.getString(c.getColumnIndex("display_name")));
        Cursor cursorID = getContentResolver().query(ContactsContract.Profile.CONTENT_URI,
                new String[]{ContactsContract.Contacts._ID},
                null, null, null);

        if (cursorID.moveToFirst()) {
            contactId = cursorID.getString(cursorID.getColumnIndex(ContactsContract.Contacts._ID));
            Toast.makeText(this,contactId,Toast.LENGTH_LONG).show();
        }

        c.close();
        cursorID.close();


    }
}
@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 101
                : {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Cursor c = getApplication().getContentResolver().query(ContactsContract.Profile.CONTENT_URI, null, null, null, null);
                c.moveToFirst();
                textView.setText(c.getString(c.getColumnIndex("display_name")));
                Cursor cursorID = getContentResolver().query(ContactsContract.Profile.CONTENT_URI,
                        new String[]{ContactsContract.Contacts._ID},
                        null, null, null);

                if (cursorID.moveToFirst()) {
                    contactId = cursorID.getString(cursorID.getColumnIndex(ContactsContract.Contacts._ID));
                    Toast.makeText(this,contactId,Toast.LENGTH_LONG).show();
                }

                c.close();
                cursorID.close();

                // permission was granted, yay! Do the
                // contacts-related task you need to do.
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.

            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request.
    }
}


}

if you find difficulty in the indentation of my code please go through this google drive link.

Nick Cardoso
  • 20,807
  • 14
  • 73
  • 124