adding some contact related helper functions
This commit is contained in:
parent
bab24f92ec
commit
dd287c9d0b
5 changed files with 193 additions and 49 deletions
|
@ -7,7 +7,7 @@ buildscript {
|
|||
propMinSdkVersion = 21
|
||||
propTargetSdkVersion = propCompileSdkVersion
|
||||
propVersionCode = 1
|
||||
propVersionName = '5.27.9'
|
||||
propVersionName = '5.27.10'
|
||||
kotlin_version = '1.3.72'
|
||||
}
|
||||
|
||||
|
|
|
@ -1006,51 +1006,3 @@ fun Context.getColoredGroupIcon(title: String): Drawable {
|
|||
(icon as LayerDrawable).findDrawableByLayerId(R.id.attendee_circular_background).applyColorFilter(bgColor)
|
||||
return icon
|
||||
}
|
||||
|
||||
fun Context.getNameFromPhoneNumber(number: String): String {
|
||||
if (!hasPermission(PERMISSION_READ_CONTACTS)) {
|
||||
return number
|
||||
}
|
||||
|
||||
val uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number))
|
||||
val projection = arrayOf(
|
||||
ContactsContract.PhoneLookup.DISPLAY_NAME
|
||||
)
|
||||
|
||||
try {
|
||||
val cursor = contentResolver.query(uri, projection, null, null, null)
|
||||
cursor.use {
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
return cursor.getStringValue(ContactsContract.PhoneLookup.DISPLAY_NAME)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
}
|
||||
|
||||
return number
|
||||
}
|
||||
|
||||
fun Context.getPhotoUriFromPhoneNumber(number: String): String {
|
||||
if (!hasPermission(PERMISSION_READ_CONTACTS)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
val uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number))
|
||||
val projection = arrayOf(
|
||||
ContactsContract.PhoneLookup.PHOTO_URI
|
||||
)
|
||||
|
||||
try {
|
||||
val cursor = contentResolver.query(uri, projection, null, null, null)
|
||||
cursor.use {
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
return cursor.getStringValue(ContactsContract.PhoneLookup.PHOTO_URI) ?: ""
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.graphics.BitmapFactory
|
|||
import android.graphics.Point
|
||||
import android.os.StatFs
|
||||
import android.provider.MediaStore
|
||||
import android.telephony.PhoneNumberUtils
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.TextUtils
|
||||
|
@ -206,6 +207,8 @@ fun String.trimToComparableNumber(): String {
|
|||
// get the contact names first letter at showing the placeholder without image
|
||||
fun String.getNameLetter() = normalizeString().toCharArray().getOrNull(0)?.toString()?.toUpperCase(Locale.getDefault()) ?: "A"
|
||||
|
||||
fun String.normalizePhoneNumber() = PhoneNumberUtils.normalizeNumber(this)
|
||||
|
||||
fun String.getMimeType(): String {
|
||||
val typesMap = HashMap<String, String>().apply {
|
||||
put("323", "text/h323")
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
package com.simplemobiletools.commons.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import android.provider.ContactsContract.CommonDataKinds
|
||||
import android.provider.ContactsContract.CommonDataKinds.Organization
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredName
|
||||
import android.provider.ContactsContract.PhoneLookup
|
||||
import android.text.TextUtils
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.models.SimpleContact
|
||||
|
||||
class ContactsHelper(val context: Context) {
|
||||
fun getAvailableContacts(callback: (ArrayList<SimpleContact>) -> Unit) {
|
||||
ensureBackgroundThread {
|
||||
val names = getContactNames()
|
||||
var allContacts = getContactPhoneNumbers()
|
||||
allContacts.forEach {
|
||||
val contactId = it.id
|
||||
val contact = names.firstOrNull { it.id == contactId }
|
||||
val name = contact?.name
|
||||
if (name != null) {
|
||||
it.name = name
|
||||
}
|
||||
|
||||
val photoUri = contact?.photoUri
|
||||
if (photoUri != null) {
|
||||
it.photoUri = photoUri
|
||||
}
|
||||
}
|
||||
|
||||
allContacts = allContacts.filter { it.name.isNotEmpty() }.distinctBy {
|
||||
val startIndex = Math.max(0, it.phoneNumber.length - 9)
|
||||
it.phoneNumber.substring(startIndex)
|
||||
}.toMutableList() as ArrayList<SimpleContact>
|
||||
|
||||
allContacts.sort()
|
||||
callback(allContacts)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getContactNames(): List<SimpleContact> {
|
||||
val contacts = ArrayList<SimpleContact>()
|
||||
val uri = ContactsContract.Data.CONTENT_URI
|
||||
val projection = arrayOf(
|
||||
ContactsContract.Data.CONTACT_ID,
|
||||
StructuredName.PREFIX,
|
||||
StructuredName.GIVEN_NAME,
|
||||
StructuredName.MIDDLE_NAME,
|
||||
StructuredName.FAMILY_NAME,
|
||||
StructuredName.SUFFIX,
|
||||
StructuredName.PHOTO_THUMBNAIL_URI,
|
||||
Organization.COMPANY,
|
||||
Organization.TITLE,
|
||||
ContactsContract.Data.MIMETYPE
|
||||
)
|
||||
|
||||
val selection = "${ContactsContract.Data.MIMETYPE} = ? OR ${ContactsContract.Data.MIMETYPE} = ?"
|
||||
val selectionArgs = arrayOf(
|
||||
StructuredName.CONTENT_ITEM_TYPE,
|
||||
Organization.CONTENT_ITEM_TYPE
|
||||
)
|
||||
|
||||
context.queryCursor(uri, projection, selection, selectionArgs) { cursor ->
|
||||
val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||
val mimetype = cursor.getStringValue(ContactsContract.Data.MIMETYPE)
|
||||
val photoUri = cursor.getStringValue(StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
|
||||
val isPerson = mimetype == StructuredName.CONTENT_ITEM_TYPE
|
||||
if (isPerson) {
|
||||
val prefix = cursor.getStringValue(StructuredName.PREFIX) ?: ""
|
||||
val firstName = cursor.getStringValue(StructuredName.GIVEN_NAME) ?: ""
|
||||
val middleName = cursor.getStringValue(StructuredName.MIDDLE_NAME) ?: ""
|
||||
val familyName = cursor.getStringValue(StructuredName.FAMILY_NAME) ?: ""
|
||||
val suffix = cursor.getStringValue(StructuredName.SUFFIX) ?: ""
|
||||
if (firstName.isNotEmpty() || middleName.isNotEmpty() || familyName.isNotEmpty()) {
|
||||
val names = arrayOf(prefix, firstName, middleName, familyName, suffix).filter { it.isNotEmpty() }
|
||||
val fullName = TextUtils.join(" ", names)
|
||||
val contact = SimpleContact(id, fullName, photoUri, "")
|
||||
contacts.add(contact)
|
||||
}
|
||||
}
|
||||
|
||||
val isOrganization = mimetype == Organization.CONTENT_ITEM_TYPE
|
||||
if (isOrganization) {
|
||||
val company = cursor.getStringValue(Organization.COMPANY) ?: ""
|
||||
val jobTitle = cursor.getStringValue(Organization.TITLE) ?: ""
|
||||
if (company.isNotEmpty() || jobTitle.isNotEmpty()) {
|
||||
val fullName = "$company $jobTitle".trim()
|
||||
val contact = SimpleContact(id, fullName, photoUri, "")
|
||||
contacts.add(contact)
|
||||
}
|
||||
}
|
||||
}
|
||||
return contacts
|
||||
}
|
||||
|
||||
private fun getContactPhoneNumbers(): ArrayList<SimpleContact> {
|
||||
val contacts = ArrayList<SimpleContact>()
|
||||
val uri = CommonDataKinds.Phone.CONTENT_URI
|
||||
val projection = arrayOf(
|
||||
ContactsContract.Data.CONTACT_ID,
|
||||
CommonDataKinds.Phone.NORMALIZED_NUMBER
|
||||
)
|
||||
|
||||
context.queryCursor(uri, projection) { cursor ->
|
||||
val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||
val phoneNumber = cursor.getStringValue(CommonDataKinds.Phone.NORMALIZED_NUMBER)
|
||||
if (phoneNumber != null) {
|
||||
val contact = SimpleContact(id, "", "", phoneNumber)
|
||||
contacts.add(contact)
|
||||
}
|
||||
}
|
||||
return contacts
|
||||
}
|
||||
|
||||
|
||||
fun getNameFromPhoneNumber(number: String): String {
|
||||
if (!context.hasPermission(PERMISSION_READ_CONTACTS)) {
|
||||
return number
|
||||
}
|
||||
|
||||
val uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number))
|
||||
val projection = arrayOf(
|
||||
PhoneLookup.DISPLAY_NAME
|
||||
)
|
||||
|
||||
try {
|
||||
val cursor = context.contentResolver.query(uri, projection, null, null, null)
|
||||
cursor.use {
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
return cursor.getStringValue(PhoneLookup.DISPLAY_NAME)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
|
||||
return number
|
||||
}
|
||||
|
||||
fun getPhotoUriFromPhoneNumber(number: String): String {
|
||||
if (!context.hasPermission(PERMISSION_READ_CONTACTS)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
val uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number))
|
||||
val projection = arrayOf(
|
||||
PhoneLookup.PHOTO_URI
|
||||
)
|
||||
|
||||
try {
|
||||
val cursor = context.contentResolver.query(uri, projection, null, null, null)
|
||||
cursor.use {
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
return cursor.getStringValue(PhoneLookup.PHOTO_URI) ?: ""
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.simplemobiletools.commons.models
|
||||
|
||||
import com.simplemobiletools.commons.extensions.normalizeString
|
||||
|
||||
data class SimpleContact(val id: Int, var name: String, var photoUri: String, var phoneNumber: String) : Comparable<SimpleContact> {
|
||||
override fun compareTo(other: SimpleContact): Int {
|
||||
val firstString = name.normalizeString()
|
||||
val secondString = other.name.normalizeString()
|
||||
|
||||
return if (firstString.firstOrNull()?.isLetter() == true && secondString.firstOrNull()?.isLetter() == false) {
|
||||
-1
|
||||
} else if (firstString.firstOrNull()?.isLetter() == false && secondString.firstOrNull()?.isLetter() == true) {
|
||||
1
|
||||
} else {
|
||||
if (firstString.isEmpty() && secondString.isNotEmpty()) {
|
||||
1
|
||||
} else if (firstString.isNotEmpty() && secondString.isEmpty()) {
|
||||
-1
|
||||
} else {
|
||||
firstString.compareTo(secondString, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue