Android Contacts Extraction

Android contacts extraction

i believe CONTENT_VCARD_URI is what you're looking for, at least for android 2.0 (api level 5).

i just lucked up and found it.

Select and extract contact details using Intent and ActivityResultContracts

It seems using ActivityResultContracts.PickContact() is the issue.

I had to modify the code using Intent and ActivityResultContracts.StartActivityForResult() to get my desired result. Here is the new code

@Composable
@Preview
fun openAndSelectContact() {
val context = LocalContext.current

//create a intent variable
val contactIntent = Intent(Intent.ACTION_PICK).apply {
type = ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE
}

val launchContactForResult = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { result ->

if (result.resultCode == Activity.RESULT_OK) {
val contactUri: Uri? = result?.data?.data

val projection: Array<String> = arrayOf(
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
)

contactUri?.let {
context.contentResolver.query(it, projection, null, null, null).use { cursor ->
// If the cursor returned is valid, get the phone number and (or) name
if (cursor!!.moveToFirst()) {
val numberIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val number = cursor.getString(numberIndex)

val nameIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val name = cursor.getString(nameIndex)
// Do something with the phone number
Toast.makeText(
context,
"Number is $number & Name is $name",
Toast.LENGTH_SHORT
).show()
}
}
}
}
}

val launchContactPermission = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
launchContactForResult.launch(contactIntent)
} else {
Toast.makeText(context, "Permission Denied!", Toast.LENGTH_SHORT)
.show()
}

}

Button(
content = { Text("IMPORT FROM CONTACT") },
onClick = {
when (PackageManager.PERMISSION_GRANTED) {
//First time asking for permission ... to be granted by user
ContextCompat.checkSelfPermission(
context,
Manifest.permission.READ_CONTACTS
) -> {
launchContactForResult.launch(contactIntent)
}
else -> {
//If permission has been already granted
launchContactPermission.launch(Manifest.permission.READ_CONTACTS)
}
}
}
)
}

Extract a contact's photo

openContactPhotoInputStream() takes the uri of the contact, try calling it with the ContactsContract.Contacts._ID column instead of the PHOTO_ID column and you should see better results.

There's a bunch of relevant discussion here with some code to check out:

How do I load a contact Photo?

Note that in some cases you'll see a photo in the native contacts app which won't load through the content resolver. Some sync info, like Facebook for example, is flagged to be used only by the contacts app itself and doesn't get exported to other apps :-(

However, using the contactUri should take care of at least some of your issues.

extracting selected contacts from android phone

You need to create your own ListView of Contacts with CHOICE_MODE_MULTIPLE and use a CheckTextView for the individual item layout. Below is a complete example. It has the Done button on the action bar.

public class PickContactsActivity extends ListActivity {
private SimpleCursorAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getListView().setItemsCanFocus(false);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME},
null, null, "UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_multiple_choice,
cursor,
new String[] { ContactsContract.Contacts.DISPLAY_NAME },
new int[] { android.R.id.text1 }, 0);
setListAdapter(mAdapter);
}

private List<Uri> pickContacts() {
SparseBooleanArray a = getListView().getCheckedItemPositions();
List<Uri> contacts = new ArrayList<Uri>();
for (int i=0; i<a.size(); i++) {
if (a.valueAt(i)) {
Cursor c = (Cursor)mAdapter.getItem(a.keyAt(i));
Long id = c.getLong(c.getColumnIndex(ContactsContract.Contacts._ID));
contacts.add(ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id));
}
}
return contacts;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.action_pick:
List<Uri> contacts = pickContacts();
StringBuilder sb = new StringBuilder("Selected Contacts\n");
for(Uri c : contacts)
sb.append(c).append("\n");
Toast.makeText(this, sb.toString(), Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
}

The Done action is defined in res/menu/main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/action_pick" android:showAsAction="ifRoom" android:title="Done"/>
</menu>

Finally, make sure you have the permission to read contacts. Add this to AndroidManifest.xml

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

Just remove the code that shows the Toast message and use the List of Uri perform your database operations.



Related Topics



Leave a reply



Submit