diff --git a/app/build.gradle b/app/build.gradle index ab8a2dea..09d798c5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,7 +45,7 @@ ext { } dependencies { - implementation 'com.simplemobiletools:commons:3.11.3' + implementation 'com.simplemobiletools:commons:3.11.5' implementation 'joda-time:joda-time:2.9.9' implementation 'com.facebook.stetho:stetho:1.5.0' implementation 'com.google.code.gson:gson:2.8.2' diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt index 01f9ff0e..0df9d306 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ContactActivity.kt @@ -1,5 +1,6 @@ package com.simplemobiletools.contacts.activities +import android.graphics.Bitmap import android.graphics.drawable.Drawable import android.provider.ContactsContract import android.widget.ImageView @@ -41,16 +42,17 @@ abstract class ContactActivity : SimpleActivity() { photoView.setPadding(padding, padding, padding, padding) photoView.setImageBitmap(placeholder) currentContactPhotoPath = "" + contact!!.photo = null } - fun updateContactPhoto(path: String, photoView: ImageView) { + fun updateContactPhoto(path: String, photoView: ImageView, bitmap: Bitmap? = null) { currentContactPhotoPath = path val options = RequestOptions() .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .centerCrop() Glide.with(this) - .load(path) + .load(bitmap ?: path) .transition(DrawableTransitionOptions.withCrossFade()) .apply(options) .listener(object : RequestListener { diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt index 814096f4..479acb66 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/EditContactActivity.kt @@ -146,10 +146,10 @@ class EditContactActivity : ContactActivity() { contact_photo.background = ColorDrawable(config.primaryColor) - if (contact!!.photoUri.isEmpty()) { + if (contact!!.photoUri.isEmpty() && contact!!.photo == null) { showPhotoPlaceholder(contact_photo) } else { - updateContactPhoto(contact!!.photoUri, contact_photo) + updateContactPhoto(contact!!.photoUri, contact_photo, contact!!.photo) } val textColor = config.textColor @@ -283,7 +283,7 @@ class EditContactActivity : ContactActivity() { private fun setupNewContact() { window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) supportActionBar?.title = resources.getString(R.string.new_contact) - contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "") + contact = Contact(0, "", "", "", "", ArrayList(), ArrayList(), ArrayList(), config.lastUsedContactSource, 0, 0, "", null) contact_source.text = getPublicContactSource(contact!!.source) contact_source.setOnClickListener { showContactSourcePicker(contact!!.source) { @@ -577,7 +577,7 @@ class EditContactActivity : ContactActivity() { RadioItem(CHOOSE_PHOTO, getString(R.string.choose_photo)) ) - if (currentContactPhotoPath.isNotEmpty()) { + if (currentContactPhotoPath.isNotEmpty() || contact!!.photo != null) { items.add(RadioItem(REMOVE_PHOTO, getString(R.string.remove_photo))) } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt index 8ba8ba9d..61530bbc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/activities/ViewContactActivity.kt @@ -98,10 +98,10 @@ class ViewContactActivity : ContactActivity() { contact_photo.background = ColorDrawable(config.primaryColor) - if (contact!!.photoUri.isEmpty()) { + if (contact!!.photoUri.isEmpty() && contact!!.photo == null) { showPhotoPlaceholder(contact_photo) } else { - updateContactPhoto(contact!!.photoUri, contact_photo) + updateContactPhoto(contact!!.photoUri, contact_photo, contact!!.photo) } val textColor = config.textColor diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt index 681f1d27..59f61dc4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/adapters/ContactsAdapter.kt @@ -199,16 +199,26 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList { + val options = RequestOptions() + .signature(ObjectKey(contact.photoUri)) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .error(contactDrawable) + .centerCrop() - Glide.with(activity).load(contact.photoUri).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb) - } else { - contact_tmb.setImageDrawable(contactDrawable) + Glide.with(activity).load(contact.photoUri).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb) + } + contact.photo != null -> { + val options = RequestOptions() + .signature(ObjectKey(contact.photo!!)) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .error(contactDrawable) + .centerCrop() + + Glide.with(activity).load(contact.photo).transition(DrawableTransitionOptions.withCrossFade()).apply(options).into(contact_tmb) + } + else -> contact_tmb.setImageDrawable(contactDrawable) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Bitmap.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Bitmap.kt new file mode 100644 index 00000000..55983f24 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Bitmap.kt @@ -0,0 +1,15 @@ +package com.simplemobiletools.contacts.extensions + +import android.graphics.Bitmap +import java.io.ByteArrayOutputStream + +fun Bitmap.getByteArray(): ByteArray { + var baos: ByteArrayOutputStream? = null + try { + baos = ByteArrayOutputStream() + compress(Bitmap.CompressFormat.JPEG, 80, baos) + return baos.toByteArray() + } finally { + baos?.close() + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt index b855371d..19d18f9b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/extensions/Context.kt @@ -128,3 +128,18 @@ fun Context.getCachePhoto(): File { } fun Context.getCachePhotoUri(file: File = getCachePhoto()) = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", file) + +fun Context.getPhotoThumbnailSize(): Int { + val uri = ContactsContract.DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI + val projection = arrayOf(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) + var cursor: Cursor? = null + try { + cursor = contentResolver.query(uri, projection, null, null, null) + if (cursor?.moveToFirst() == true) { + return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) + } + } finally { + cursor?.close() + } + return 0 +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt index cef49fb6..4ba069b1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/ContactsHelper.kt @@ -23,6 +23,8 @@ import com.simplemobiletools.commons.helpers.SORT_DESCENDING import com.simplemobiletools.contacts.R import com.simplemobiletools.contacts.extensions.config import com.simplemobiletools.contacts.extensions.dbHelper +import com.simplemobiletools.contacts.extensions.getByteArray +import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.* import java.io.ByteArrayOutputStream import java.util.* @@ -54,7 +56,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri) + val contact = Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri, null) contacts.put(id, contact) } while (cursor.moveToNext()) } @@ -224,7 +226,7 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val starred = cursor.getIntValue(CommonDataKinds.StructuredName.STARRED) val contactId = cursor.getIntValue(ContactsContract.Data.CONTACT_ID) val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: "" - return Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri) + return Contact(id, firstName, middleName, surname, photoUri, number, emails, events, accountName, starred, contactId, thumbnailUri, null) } } finally { cursor?.close() @@ -429,12 +431,12 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val photoUri = Uri.parse(contact.photoUri) val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri) - val thumbnailSize = getThumbnailSize() + val thumbnailSize = activity.getPhotoThumbnailSize() val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false) - val scaledSizePhotoData = bitmapToByteArray(scaledPhoto) + val scaledSizePhotoData = scaledPhoto.getByteArray() scaledPhoto.recycle() - val fullSizePhotoData = bitmapToByteArray(bitmap) + val fullSizePhotoData = bitmap.getByteArray() bitmap.recycle() ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).apply { @@ -522,11 +524,11 @@ class ContactsHelper(val activity: BaseSimpleActivity) { val photoUri = Uri.parse(contact.photoUri) val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri) - val thumbnailSize = getThumbnailSize() + val thumbnailSize = activity.getPhotoThumbnailSize() val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false) - scaledSizePhotoData = bitmapToByteArray(scaledPhoto) + scaledSizePhotoData = scaledPhoto.getByteArray() - fullSizePhotoData = bitmapToByteArray(bitmap) + fullSizePhotoData = bitmap.getByteArray() scaledPhoto.recycle() bitmap.recycle() @@ -677,19 +679,4 @@ class ContactsHelper(val activity: BaseSimpleActivity) { activity.showErrorToast(e) } } - - private fun getThumbnailSize(): Int { - val uri = ContactsContract.DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI - val projection = arrayOf(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) - var cursor: Cursor? = null - try { - cursor = activity.contentResolver.query(uri, projection, null, null, null) - if (cursor?.moveToFirst() == true) { - return cursor.getIntValue(ContactsContract.DisplayPhoto.THUMBNAIL_MAX_DIM) - } - } finally { - cursor?.close() - } - return 0 - } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt index 10ebc310..126316b0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/DBHelper.kt @@ -4,17 +4,23 @@ import android.content.ContentValues import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.provider.MediaStore import android.text.TextUtils import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import com.simplemobiletools.commons.extensions.getBlobValue import com.simplemobiletools.commons.extensions.getIntValue import com.simplemobiletools.commons.extensions.getStringValue +import com.simplemobiletools.contacts.extensions.getByteArray +import com.simplemobiletools.contacts.extensions.getPhotoThumbnailSize import com.simplemobiletools.contacts.models.Contact import com.simplemobiletools.contacts.models.Email import com.simplemobiletools.contacts.models.Event import com.simplemobiletools.contacts.models.PhoneNumber - class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { private val CONTACTS_TABLE_NAME = "contacts" private val COL_ID = "id" @@ -86,9 +92,26 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont put(COL_EMAILS, Gson().toJson(contact.emails)) put(COL_EVENTS, Gson().toJson(contact.events)) put(COL_STARRED, contact.starred) + + if (contact.photoUri.isNotEmpty()) { + put(COL_PHOTO, getPhotoByteArray(contact.photoUri)) + } else if (contact.photo == null) { + putNull(COL_PHOTO) + } } } + private fun getPhotoByteArray(uri: String): ByteArray { + val photoUri = Uri.parse(uri) + val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, photoUri) + + val thumbnailSize = context.getPhotoThumbnailSize() + val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false) + val scaledSizePhotoData = scaledPhoto.getByteArray() + scaledPhoto.recycle() + return scaledSizePhotoData + } + fun toggleFavorites(ids: Array, addToFavorites: Boolean) { val contactValues = ContentValues() contactValues.put(COL_STARRED, if (addToFavorites) 1 else 0) @@ -100,7 +123,7 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont fun getContacts(selection: String? = null, selectionArgs: Array? = null): ArrayList { val contacts = ArrayList() - val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED) + val projection = arrayOf(COL_ID, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_PHONE_NUMBERS, COL_EMAILS, COL_EVENTS, COL_STARRED, COL_PHOTO) val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null) cursor.use { while (cursor.moveToNext()) { @@ -121,8 +144,15 @@ class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(cont val eventsToken = object : TypeToken>() {}.type val events = Gson().fromJson>(eventsJson, eventsToken) ?: ArrayList(1) + val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null + val photo = if (photoByteArray?.isNotEmpty() == true) { + BitmapFactory.decodeByteArray(photoByteArray, 0, photoByteArray.size) + } else { + null + } + val starred = cursor.getIntValue(COL_STARRED) - val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, SMT_PRIVATE, starred, id, "") + val contact = Contact(id, firstName, middleName, surname, "", phoneNumbers, emails, events, SMT_PRIVATE, starred, id, "", photo) contacts.add(contact) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt index 5d991428..c69a5402 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/helpers/VcfImporter.kt @@ -199,7 +199,7 @@ class VcfImporter(val activity: SimpleActivity) { } private fun saveContact(source: String) { - val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curEvents, source, 0, 0, "") + val contact = Contact(0, curFirstName, curMiddleName, curSurname, curPhotoUri, curPhoneNumbers, curEmails, curEvents, source, 0, 0, "", null) if (ContactsHelper(activity).insertContact(contact)) { contactsImported++ } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt index b41e6e6b..f98b9770 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/models/Contact.kt @@ -1,12 +1,13 @@ package com.simplemobiletools.contacts.models +import android.graphics.Bitmap import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME import com.simplemobiletools.commons.helpers.SORT_DESCENDING data class Contact(val id: Int, var firstName: String, var middleName: String, var surname: String, var photoUri: String, var phoneNumbers: ArrayList, var emails: ArrayList, var events: ArrayList, var source: String, - var starred: Int, val contactId: Int, val thumbnailUri: String) : Comparable { + var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?) : Comparable { companion object { var sorting = 0 }