How to get name from contacts list - android

I am able to get user phone numbers from the contacts list, but i also need names with the numbers,
I know if i use custom adapter then i can get name and number both, but i want to use the default contact picker.
This is my code.
private fun launchMultiplePhonePicker() {
val phonebookIntent = Intent("intent.action.INTERACTION_TOPMENU")
phonebookIntent.putExtra("additional", "phone-multi")
phonebookIntent.putExtra("maxRecipientCount", 20)
phonebookIntent.putExtra("FromMMS", true)
startActivityForResult(phonebookIntent, 110)
}
This does work fine, but only returns phone numbers, and not contact names in onActivityResult.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val bundle = data?.extras
val result = bundle?.getString("result")
val contacts = bundle?.getStringArrayList("result")
}
Edit:
I found out that intent.action.INTERACTION_TOPMENU may not work in all devices, so i used the following approach, its giving me the names with number, but not allowing me to select multiple contacts.
val intent = Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI)
startActivityForResult(intent, 10101)

My simple solution to get contacts, may be it will help you
Data class to hold extracted values:
data class ContactModel(val phoneNumber: String, val displayName: String)
Get contacts and map to model
val result = arrayListOf<ContactModel>()
val cursor.context.contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, ContactsContract.Contacts.SORT_KEY_PRIMARY + " ASC")
cursor?.let {
val nameIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val phoneIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
while (it.moveToNext()) {
val name = cursor.getString(nameIndex)
val phone = cursor.getString(phoneIndex)
var num = phone
.replace(" ", "")
.replace("-", "")
.replace("(", "")
.replace(")", "")
val contactModel = ContactModel(num, name)
//Prevents duplicated contacts on some devices
if (it.position != 0) {
if (contactModel != result[result.size - 1]) {
result.add(contactModel)
}
} else {
result.add(contactModel)
}
}
}

If you have a list of phone numbers and you need to get the display names, you can use ContactsContract.PhoneLookup, something like this:
private fun phoneToName(phone: String): String? {
val uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone))
var cur = getContentResolver().query(uri, arrayOf(PhoneLookup.DISPLAY_NAME), null, null, null)
if (cur.moveToFirst()) {
return cur.getString(0)
}
cur.close()
return null
}
P.S. just note that "intent.action.INTERACTION_TOPMENU" is not an official Android API, and is probably not supported by all devices.
EDIT: there's no official way of using the phone-picker for multiple contacts, either you implement your own contact list and let the user choose multiple contacts within your app, or you can allow the user to pick contacts multiple times until they finish.

Related

Edit contact name, phones, emails data

I am trying to edit contacts from my app so I implemented the following function :
private fun updateContact(contact: Contact) {
val contentProviderOperations = ArrayList<ContentProviderOperation>()
val contentValues = ContentValues().apply {
put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, contact.first_name)
put(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, contact.last_name)
put(
ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
contact.first_name + " " + contact.last_name
)
}
contact.phones_list.forEach { phone ->
contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone.number)
contentValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, phone.type)
}
contact.emails_list.forEach { email ->
contentValues.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email.address)
contentValues.put(ContactsContract.CommonDataKinds.Email.TYPE, email.type)
}
contentProviderOperations.add(
ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(
ContactsContract.Data.CONTACT_ID + "=?",
arrayOf(contact.id.toString())
)
.withValues(contentValues)
.build()
)
contentResolver.applyBatch(ContactsContract.AUTHORITY, contentProviderOperations)
}
this is my Contact data class :
data class Contact(
var id: Long,
var lookup_key: String,
var display_name: String,
var first_name: String,
var last_name: String,
var phones_list: MutableList<Phone>,
var emails_list: MutableList<Email>,
var photo_uri: Uri? = null
)
This function is supposed to edit all of the contact data(first name, last name, all phone nubmers, all emails) acrroding to its id which I already have from previously retrieving the contact.
When the function is executed it throws no exception so it seems to be working fine but when I go to the original contacts app in my phone the contact that was supposed to be edited disappears and It does not longer appear..
Any suggestions what could have gone wrong?
Thanks

Get contacts in Android without duplicates

I've got the following code to retrieve a contact list with Name + PhoneNumber:
#SuppressLint("Range")
fun getNamePhoneDetails(): ArrayList<List<String>>? {
val names = ArrayList<List<String>>()
val cr = contentResolver
val cur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
null, null, null)
if (cur!!.count > 0) {
while (cur.moveToNext()) {
val id = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NAME_RAW_CONTACT_ID))
val name = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
val number = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
names.add(listOf(id, name, number))
}
}
return names
}
The output is correct once no contact has two phone numbers. However once any contact has two phone numbers I get the contact twice. It has the same id and name, but a different phone number. How can I make it so that the returned list does not have a contact twice but all phone numbers inside a list?
Something like
[1, Name Name, [phonenumber1, phonenumber2]],[2, Name Name, [phonenumber1]]
Then I could just iterate through the phonenumberlist and have all numbers as valid strings.
You should rather create a POJO Object and than assign the data into it and return a list of that POJO Object and then you can make use of distinct extension on the list to get a filtered result they way you want it .
This is how you can achieve what you want :
Create a POJO Object :
data class Contact(
val id : String ,
val name : String,
val number : String)
And then when retrieveing the data you can do the following :
#SuppressLint("Range")
fun getNamePhoneDetails(): MutableList<Contact>? {
val names = MutableList<Contact>()
val cr = contentResolver
val cur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
null, null, null)
if (cur!!.count > 0) {
while (cur.moveToNext()) {
val id = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NAME_RAW_CONTACT_ID))
val name = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
val number = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
names.add(Contact(id , name , number))
}
}
return names
}
And then while retreiving the data you need to just filter the list in the following manner :
val list = getNamePhoneDetails()
list.distinctBy { it.number }.forEach { println(it) }

While comparing the two arraylists of firebase Realtime data returns an empty arraylist

Working on a chatting app I want to get the list of users(B, C, D,..) whose contacts are saved in the user (A) mobile phone.
First I fetch user(A) contacts from the phone and store them in an ArrayList (phoneContactArrayList). Secondly, I fetch the user's phone numbers registered on my app and also store them in ArrayList (dbContactArrayList).
Now I want to compare both of these array lists and get the common contacts numbers out of them, which are those contacts(B, C, D,...) of the user(A) registered on my app and the user(A) can contact them via my app.
For this here is the method to fetch contacts from the User(A) mobile phones.
private fun getContactList() {
phoneContactArrayList = ArrayList()
val cr = contentResolver
val cur = cr.query(
ContactsContract.Contacts.CONTENT_URI,
null, null, null, null
)
if (cur?.count ?: 0 > 0) {
while (cur != null && cur.moveToNext()) {
val id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID))
val name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
if (cur.getInt(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
val pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
arrayOf(id), null
)
while (pCur!!.moveToNext()) {
phoneContactArrayList?.clear()
val phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
phoneContactArrayList!!.add(phoneNo)
Log.i("Users Ph.Contacts List=" , phoneContactArrayList.toString())
// all users contacts are shown successfully as I check in Logcat
}
pCur.close()
}
}
}
cur?.close()
}
Here is the method for fetching the users registered on my app via firebase authentication.
private fun getFirebaseContacts() {
dbContactArrayList = ArrayList()
FirebaseDatabase.getInstance().getReference("UserProfile")
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(contactList: DataSnapshot) {
try {
dbContactArrayList?.clear()
for (eachContactList in contactList.children) {
// Log.e("TAG", "onDataChange: " + eachContactList.value.toString())
var contactModel: SignUpEntity =
eachContactList.getValue(SignUpEntity::class.java)!!
val mData = contactModel.userPhone
if (mData != null) {
dbContactArrayList?.add(mData)
}
Toast.makeText(applicationContext,"Firebase Users List=${dbContactArrayList.toString()}",
Toast.LENGTH_SHORT
).show() // successfully toast the numbers registered on app
}
} catch (e: Exception) {
//Log.e("Exception",e.toString())
}
}
override fun onCancelled(p0: DatabaseError) {
TODO("Not yet implemented")
}
})
}
And here is the method in which both ArrayList are compared to get the common contacts, the resultArrayList is always empty.
private fun getMatchedContacts(dbContactArrayList: ArrayList<String>?, phoneContactArrayList: ArrayList<String>?) { // here on debugging I get to know both arrayLists are of size 0.
resultArrayList = ArrayList()
for (s in phoneContactArrayList!!) {
resultArrayList?.clear()
if (dbContactArrayList!!.contains(s) && !resultArrayList!!.contains(s)) {
resultArrayList!!.add(s)
}
}
Log.e("Result Values", resultArrayList.toString())
}
It's because your resultArrayList is being cleared at each iteration of your for loop. Try to remove resultArrayList?.clear().
private fun getMatchedContacts(dbContactArrayList: ArrayList<String>?, phoneContactArrayList: ArrayList<String>?) { // here on debugging I get to know both arrayLists are of size 0.
resultArrayList = ArrayList()
for (s in phoneContactArrayList!!) {
if (dbContactArrayList!!.contains(s) && !resultArrayList!!.contains(s)) {
resultArrayList!!.add(s)
}
}
Log.e("Result Values", resultArrayList.toString())
}
If you only want to get the common elements of two lists, then in Kotlin it will be as simple as:
val l1 = listOf(1, 2, 3, 4, 5)
val l2 = listOf(1, 3, 5, 7, 9)
val common = l1.filter { i -> l2.contains(i) }
Log.d(TAG, common.toString())
The result will be:
[1, 3, 5]

Android: get contacts with anniversary date event

I want to fetch a list of local contacts with an anniversary date set.
I'm doing the following:
object WithAnniversary {
const val INDEX_CONTACT_ID = 0
const val INDEX_CONTACT_NAME = 1
const val INDEX_CONTACT_ANNIVERSARY = 2
const val INDEX_CONTACT_PHOTO = 3
val PROJECTION = arrayOf(
CommonDataKinds.Event.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
CommonDataKinds.Event.START_DATE,
CommonDataKinds.Phone.PHOTO_URI
)
const val WHERE = "${ContactsContract.Data.MIMETYPE} = ? AND " +
"${CommonDataKinds.Event.TYPE} = " +
"${CommonDataKinds.Event.TYPE_ANNIVERSARY}"
val SELECTION = arrayOf(CommonDataKinds.Event.CONTENT_ITEM_TYPE)
val SORT_ORDER: String? = null
}
#Throws(Exception::class)
fun obtainContactsWithAnniversaries(): List<Contact> {
val list = mutableListOf<Contact>()
val cursor = context.contentResolver.query(
ContactsContract.Data.CONTENT_URI,
WithAnniversary.PROJECTION,
WithAnniversary.WHERE,
WithAnniversary.SELECTION,
WithAnniversary.SORT_ORDER
)
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getLong(WithAnniversary.INDEX_CONTACT_ID)
val name = cursor.getString(WithAnniversary.INDEX_CONTACT_NAME)
val date = cursor.getString(WithAnniversary.INDEX_CONTACT_ANNIVERSARY)
val avatarUri = cursor.getString(WithAnniversary.INDEX_CONTACT_PHOTO)
try {
val contact = contactFactory.create(id.toString(), name, null, date, avatarUri)
list.add(contact)
} catch (e: Exception) {
Log.d(TAG, "Could not parse contact with name: $name")
}
}
cursor.close()
return list.sorted()
} else {
throw Exception("Unable to retrieve contacts, returned cursor is null")
}
}
I use the exact same process for retrieving contacts with birthday dates, but using TYPE_BIRTHDAY instead of TYPE_ANNIVERSARY, but for some reason this doesn't work for anniversaries.
I have checked my local contact list and I have some contacts with birthdays and anniversaries. I can retrieve a list with contacts with birthdays but the list of contacts with anniversaries is empty.
Any help will be appreciated.
I assume the issue is with the conversion of the cursor row to your custom Contact class.
When I replace that part with just a log your code works for me:
...
while (cursor.moveToNext()) {
val id = cursor.getLong(WithAnniversary.INDEX_CONTACT_ID)
val name = cursor.getString(WithAnniversary.INDEX_CONTACT_NAME)
val date = cursor.getString(WithAnniversary.INDEX_CONTACT_ANNIVERSARY)
val avatarUri = cursor.getString(WithAnniversary.INDEX_CONTACT_PHOTO)
Log.d("TEMP", "contact $id $name $date $avatarUri")
}
...
Log:
D/TEMP: contact 98014 Test1 1979-10-06 content://com.android.contacts/contacts/98014/photo
contact 4603 test 1990-07-22 content://com.android.contacts/contacts/4603/photo
contact 98341 Voice Mail 2013-11-06 null

Getting specific event from calendar in android by _ID

I have an event id sored in my android app.
Now I want to get this specific event from calendar. Is that possible?
I have found various answers on how to get events from calendar, but none was working for my requirements.
Here is documented how to get events from specific calendar.
Constraints are set using CalendarContract.Calendars I believe I need to use CalendarContract.Events._ID
Here is what I've tried
private fun getCalendarEvents(ids: List<Long>): List<Pair<String, Long>> {
val EVENT_PROJECTION: Array<String> = arrayOf(
CalendarContract.Events._ID,
CalendarContract.Events.TITLE
)
val PROJECTION_ID_INDEX: Int = 0
val PROJECTION_TITLE_INDEX: Int = 1
val uri: Uri = CONTENT_URI
val keys: String = ids.fold("") { acc, it -> "$acc, $it" }
val selection: String = "${CalendarContract.Calendars._ID} IN ?"
val selectionArgs: Array<String> = arrayOf("($keys)")
val cur: Cursor = contentResolver.query(uri, EVENT_PROJECTION, selection, selectionArgs, null)!!
val result: MutableList<Pair<String, Long>> =
emptyList<Pair<String, Long>>().toMutableList()
while (cur.moveToNext()) {
val ID: Long = cur.getLong(PROJECTION_ID_INDEX)
val TITLE: String = cur.getString(PROJECTION_TITLE_INDEX)
result += Pair(TITLE, ID)
}
return result
}
It tries to load all events which have _ID in ids list and returns (Title, Id) pairs.
Is there any easy was how to accomplis this? There is an easy way for inserting, editing and deleting events here so I guess there must be something like that for fetching events as well.
Thank for help.

Categories

Resources