Access All Contacts Using the Content Provider Concept in Android App Development
In this tutorial, you'll learn about the Content Provider in Android, and how to use it to access all the device's contacts within an application.
Join the DZone community and get the full member experience.
Join For FreeIn the Android system, applications are not allowed to directly access other applications' internal data. The Android framework enforces a robust data sharing model: Content Provider. Also, a helper class is needed for this purpose: this is Content Resolver. The Android.Content package contains these classes for accessing and publishing data. A content supplier is a holder of special content, it gives well-defined APIs to read, insert, update, and delete that data. The content provider can internally use any place to store its data, like a local file, local database, or some remote service. The Content Resolver is responsible for finding the correct content provider. The Content Resolver decides which provider to use based on the URI. The Content Resolver and Content Provider classes work together to ensure secure access to other applications’ data. In this blog, we will learn how to access all contacts from our phone with the help of the Content Provider and display a phone number with a name in a text view.
Purpose
Access all contacts from the Contacts app of the Android system and show it to a text view label.
Scope
IDE: Android Studio, Eclipse.
Procedure
To retrieve contacts from the Android system, we also need to know what cursor is. Cursor is a class which represents the result of a query and basically points to one row of the query result. With the getString(columnIndex)
method, you can access the column data for the current position of the result. The columnIndex is the number of the column you are accessing. When we want to retrieve data from the cursor, we have to first move to the first record, so we have to use moveToFirst
, and for next records, we need to use moveToNext
.
Step 1
First, we need to access permission of read and write data, and for this, we need to write permission in the Android Manifest file, like below:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
Here is an exception. From Android 6.0 Marshmallow, the application will not be granted any permissions at installation time. Instead, the application has to ask the user for permissions one-by-one at runtime with an alert message. The developer has to call for it manually.
Step 2
Next, in the main layout, we are giving a simple button and two text views. On a button click event, we will access all contacts on our device and display the contact names with their number on those text views. Here is the layout XML code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btnload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="View contacts"
android:textSize="25sp"
android:layout_marginTop="20dp"/>
<TextView
android:id="@+id/txtname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
<TextView
android:id="@+id/txtphno"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
</LinearLayout>
Step 3
In the MainActivity page, first, we define all the views of the main layout, like below:
Button btnview;
TextView txtname,txtphno;
static final int PICK_CONTACT = 1;
String st;
final private int REQUEST_MULTIPLE_PERMISSIONS = 124;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contact);
AccessContact();
btnview = (Button) findViewById(R.id.btnload);
txtname=(TextView) findViewById(R.id.txtname);
txtphno=(TextView) findViewById(R.id.txtphno);
Here we are calling the AccessContact function for runtime permissions, as discussed above.
private void AccessContact()
{
List<String> permissionsNeeded = new ArrayList<String>();
final List<String> permissionsList = new ArrayList<String>();
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) {
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_MULTIPLE_PERMISSIONS);
}
});
return;
}
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_MULTIPLE_PERMISSIONS);
return;
}
}
Here we have requested read and write contact permissions at runtime. For this, we have added all the permission in a List<String>.
private boolean addPermission(List<String> permissionsList, String permission) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
If it is termed beyond this approval assumed, the application will quickly crash. If permission has already been granted, then the process will execute directly. Otherwise, request Permissions will be called to launch a permission request dialog, like below.
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(Main2Activity.this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
}
Step 4
Now, for a button click event, we need to call PICK_CONTACT Intent
, like below:
btnview.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT);
}
});
Step 5
Next, for the onActivityResult function, we pick a contact and display it in a text view, like below:
public void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
switch (reqCode) {
case (PICK_CONTACT):
if (resultCode == Activity.RESULT_OK) {
Uri contactData = data.getData();
Cursor c = managedQuery(contactData, null, null, null, null);
if (c.moveToFirst()) {
String id = c.getString(c.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
String hasPhone = c.getString(c.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
try {
if (hasPhone.equalsIgnoreCase("1")) {
Cursor phones = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id,
null, null);
phones.moveToFirst();
String cNumber = phones.getString(phones.getColumnIndex("data1"));
System.out.println("number is:" + cNumber);
txtphno.setText("Phone Number is: "+cNumber);
}
String name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
txtname.setText("Name is: "+name);
}
catch (Exception ex)
{
st.getMessage();
}
}
}
break;
}
}
As explained before, through the Cursor and Content Resolver, we are picking the contact id, and through the getstring()
method, we are getting phone numbers with a display name.
Conclusion
From the above description, it is clear how we can use the Content Resolver to interact with other apps, like Contacts. We can also create our own content provider so that other apps can interact with our app's internal data with security.
Opinions expressed by DZone contributors are their own.
Comments