properly handle displaying local private photos

This commit is contained in:
tibbi 2018-02-11 23:24:16 +01:00
parent 192658c0d3
commit 0b9b1b7f1a
11 changed files with 106 additions and 46 deletions

View File

@ -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'

View File

@ -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<Drawable> {

View File

@ -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)))
}

View File

@ -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

View File

@ -199,16 +199,26 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: MutableList<Co
contact_tmb.beVisibleIf(showContactThumbnails)
if (showContactThumbnails) {
if (contact.photoUri.isNotEmpty()) {
val options = RequestOptions()
.signature(ObjectKey(contact.photoUri))
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.error(contactDrawable)
.centerCrop()
when {
contact.photoUri.isNotEmpty() -> {
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)
}
}
}

View File

@ -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()
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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<String>, 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<String>? = null): ArrayList<Contact> {
val contacts = ArrayList<Contact>()
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<List<Event>>() {}.type
val events = Gson().fromJson<ArrayList<Event>>(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)
}
}

View File

@ -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++
}

View File

@ -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<PhoneNumber>, var emails: ArrayList<Email>, var events: ArrayList<Event>, var source: String,
var starred: Int, val contactId: Int, val thumbnailUri: String) : Comparable<Contact> {
var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?) : Comparable<Contact> {
companion object {
var sorting = 0
}