diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt index 06772d87..dc22ef1b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt @@ -1,9 +1,17 @@ package com.simplemobiletools.smsmessenger.activities +import android.database.Cursor import android.os.Bundle +import android.provider.ContactsContract +import android.provider.ContactsContract.CommonDataKinds +import android.text.TextUtils import android.view.WindowManager +import com.simplemobiletools.commons.extensions.getIntValue +import com.simplemobiletools.commons.extensions.getStringValue import com.simplemobiletools.commons.extensions.updateTextColors +import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS import com.simplemobiletools.smsmessenger.R +import com.simplemobiletools.smsmessenger.models.Contact import kotlinx.android.synthetic.main.activity_new_message.* class NewMessageActivity : SimpleActivity() { @@ -15,5 +23,118 @@ class NewMessageActivity : SimpleActivity() { window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) new_message_to.requestFocus() + + // Contact permission is not mandatory, but without it we won't be able to show any suggestions during typing + handlePermission(PERMISSION_READ_CONTACTS) { + initContacts() + } + } + + private fun initContacts() { + val names = getNames() + val contacts = getPhoneNumbers() + contacts.forEach { + val contactId = it.contactId + val contact = names.firstOrNull { it.contactId == contactId } + val name = contact?.name + if (name != null) { + it.name = name + } + + val photoUri = contact?.photoUri + if (photoUri != null) { + it.photoUri = photoUri + } + } + } + + private fun getNames(): List { + val contacts = ArrayList() + val uri = ContactsContract.Data.CONTENT_URI + val projection = arrayOf( + ContactsContract.Data.CONTACT_ID, + CommonDataKinds.StructuredName.PREFIX, + CommonDataKinds.StructuredName.GIVEN_NAME, + CommonDataKinds.StructuredName.MIDDLE_NAME, + CommonDataKinds.StructuredName.FAMILY_NAME, + CommonDataKinds.StructuredName.SUFFIX, + CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI, + CommonDataKinds.Organization.COMPANY, + CommonDataKinds.Organization.TITLE, + ContactsContract.Data.MIMETYPE + ) + + val selection = "${ContactsContract.Data.MIMETYPE} = ? OR ${ContactsContract.Data.MIMETYPE} = ?" + val selectionArgs = arrayOf( + CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, + CommonDataKinds.Organization.CONTENT_ITEM_TYPE + ) + + var cursor: Cursor? = null + try { + cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) + if (cursor?.moveToFirst() == true) { + do { + val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) + val mimetype = cursor.getStringValue(ContactsContract.Data.MIMETYPE) + val photoUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" + val isPerson = mimetype == CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + if (isPerson) { + val prefix = cursor.getStringValue(CommonDataKinds.StructuredName.PREFIX) ?: "" + val firstName = cursor.getStringValue(CommonDataKinds.StructuredName.GIVEN_NAME) ?: "" + val middleName = cursor.getStringValue(CommonDataKinds.StructuredName.MIDDLE_NAME) ?: "" + val familyName = cursor.getStringValue(CommonDataKinds.StructuredName.FAMILY_NAME) ?: "" + val suffix = cursor.getStringValue(CommonDataKinds.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 = Contact(id, fullName, photoUri, "") + contacts.add(contact) + } + } + + val isOrganization = mimetype == CommonDataKinds.Organization.CONTENT_ITEM_TYPE + if (isOrganization) { + val company = cursor.getStringValue(CommonDataKinds.Organization.COMPANY) ?: "" + val jobTitle = cursor.getStringValue(CommonDataKinds.Organization.TITLE) ?: "" + if (company.isNotEmpty() || jobTitle.isNotEmpty()) { + val fullName = "$company $jobTitle".trim() + val contact = Contact(id, fullName, photoUri, "") + contacts.add(contact) + } + } + } while (cursor.moveToNext()) + } + } catch (ignored: Exception) { + } finally { + cursor?.close() + } + return contacts + } + + private fun getPhoneNumbers(): ArrayList { + val contacts = ArrayList() + val uri = CommonDataKinds.Phone.CONTENT_URI + val projection = arrayOf( + ContactsContract.Data.CONTACT_ID, + CommonDataKinds.Phone.NORMALIZED_NUMBER + ) + + var cursor: Cursor? = null + try { + cursor = contentResolver.query(uri, projection, null, null, null) + if (cursor?.moveToFirst() == true) { + do { + val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) + val phoneNumber = cursor.getStringValue(CommonDataKinds.Phone.NORMALIZED_NUMBER) ?: continue + val contact = Contact(id, "", "", phoneNumber) + contacts.add(contact) + } while (cursor.moveToNext()) + } + } catch (ignored: Exception) { + } finally { + cursor?.close() + } + return contacts } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Contact.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Contact.kt new file mode 100644 index 00000000..b58967c0 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Contact.kt @@ -0,0 +1,35 @@ +package com.simplemobiletools.smsmessenger.models + +import android.content.Context +import android.graphics.drawable.Drawable +import android.widget.ImageView +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.request.RequestOptions + +data class Contact( + val contactId: Int, + var name: String, + var photoUri: String, + var phoneNumber: String +) { + fun updateImage(context: Context, imageView: ImageView, placeholder: Drawable) { + if (photoUri.isEmpty()) { + imageView.setImageDrawable(placeholder) + } else { + val options = RequestOptions() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .error(placeholder) + .centerCrop() + + Glide.with(context) + .load(photoUri) + .transition(DrawableTransitionOptions.withCrossFade()) + .placeholder(placeholder) + .apply(options) + .apply(RequestOptions.circleCropTransform()) + .into(imageView) + } + } +}