Fixed Android Auto favorites no having generated avatar if no picture available + make them round

This commit is contained in:
Sylvain Berfini 2024-08-12 14:36:41 +02:00
parent 12c112fa39
commit b58a23b60d
5 changed files with 67 additions and 26 deletions

View file

@ -48,7 +48,7 @@ class AvatarGenerator(private val context: Context) {
initials = label
}
private fun preBuild(): Bitmap {
fun buildBitmap(): Bitmap {
val textPainter = getTextPainter()
val painter = getPainter()
@ -68,12 +68,12 @@ class AvatarGenerator(private val context: Context) {
return bitmap
}
fun build(): BitmapDrawable {
return BitmapDrawable(context.resources, preBuild())
fun buildDrawable(): BitmapDrawable {
return BitmapDrawable(context.resources, buildBitmap())
}
fun buildIcon(): IconCompat {
return IconCompat.createWithAdaptiveBitmap(preBuild())
return IconCompat.createWithAdaptiveBitmap(buildBitmap())
}
private fun getTextPainter(): TextPaint {

View file

@ -647,11 +647,12 @@ class ContactsManager @UiThread constructor() {
}
@WorkerThread
fun Friend.getAvatarBitmap(): Bitmap? {
fun Friend.getAvatarBitmap(round: Boolean = false): Bitmap? {
try {
return ImageUtils.getBitmap(
coreContext.context,
photo ?: getNativeContactPictureUri()?.toString()
photo ?: getNativeContactPictureUri()?.toString(),
round
)
} catch (numberFormatException: NumberFormatException) {
// Expected for contacts created by Linphone

View file

@ -31,9 +31,11 @@ import androidx.car.app.model.Template
import androidx.core.graphics.drawable.IconCompat
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.contacts.getNativeContactPictureUri
import org.linphone.contacts.AvatarGenerator
import org.linphone.contacts.getAvatarBitmap
import org.linphone.core.MagicSearch
import org.linphone.core.tools.Log
import org.linphone.utils.AppUtils
import org.linphone.utils.LinphoneUtils
class AAScreen(context: CarContext) : Screen(context) {
@ -63,20 +65,20 @@ class AAScreen(context: CarContext) : Screen(context) {
val friend = result.friend ?: continue
builder.setTitle(friend.name)
val pictureUri = friend.getNativeContactPictureUri()
if (pictureUri != null) {
Log.i(
"$TAG Creating car icon for friend [${friend.name}] with URI [$pictureUri]"
Log.i("$TAG Creating car icon for friend [${friend.name}]")
try {
val bitmap = friend.getAvatarBitmap(true) ?: AvatarGenerator(
coreContext.context
).setInitials(
AppUtils.getInitials(friend.name.orEmpty())
).buildBitmap()
builder.setImage(
CarIcon.Builder(IconCompat.createWithBitmap(bitmap))
.build(),
GridItem.IMAGE_TYPE_LARGE
)
try {
builder.setImage(
CarIcon.Builder(IconCompat.createWithContentUri(pictureUri))
.build(),
GridItem.IMAGE_TYPE_LARGE
)
} catch (e: Exception) {
Log.e("$TAG Exception trying to create CarIcon: $e")
}
} catch (e: Exception) {
Log.e("$TAG Exception trying to create CarIcon: $e")
}
builder.setOnClickListener {
@ -86,8 +88,12 @@ class AAScreen(context: CarContext) : Screen(context) {
coreContext.startAudioCall(address)
}
}
val item = builder.build()
favorites.add(item)
try {
val item = builder.build()
favorites.add(item)
} catch (e: Exception) {
Log.e("$TAG Failed to build grid item: $e")
}
}
loading = false
Log.i("$TAG Processed [${favorites.size}] favorites")

View file

@ -414,7 +414,7 @@ fun ImageView.loadCallAvatarWithCoil(model: AbstractAvatarModel?) {
fun ImageView.loadInitialsAvatarWithCoil(initials: String?) {
val builder = AvatarGenerator(context)
builder.setInitials(initials.orEmpty())
load(builder.build())
load(builder.buildDrawable())
}
@SuppressLint("ResourceType")

View file

@ -21,7 +21,12 @@ package org.linphone.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.ImageDecoder
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import androidx.annotation.AnyThread
@ -46,13 +51,14 @@ class ImageUtils {
if (textSize > 0) {
builder.setTextSize(AppUtils.getDimension(textSize))
}
return builder.build()
return builder.buildDrawable()
}
@WorkerThread
fun getBitmap(
context: Context,
path: String?
path: String?,
round: Boolean = false
): Bitmap? {
Log.d("$TAG Trying to create Bitmap from path [$path]")
if (path != null) {
@ -64,12 +70,17 @@ class ImageUtils {
}
// We make a copy to ensure Bitmap will be Software and not Hardware, required for shortcuts
return ImageDecoder.decodeBitmap(
val bitmap = ImageDecoder.decodeBitmap(
ImageDecoder.createSource(context.contentResolver, fromPictureUri)
).copy(
Bitmap.Config.ARGB_8888,
true
)
return if (round) {
getRoundBitmap(bitmap)
} else {
bitmap
}
} catch (fnfe: FileNotFoundException) {
Log.e("$TAG File [$path] not found: $fnfe")
return null
@ -82,5 +93,28 @@ class ImageUtils {
Log.e("$TAG Can't get bitmap from null URI")
return null
}
@AnyThread
private fun getRoundBitmap(bitmap: Bitmap): Bitmap {
val output =
Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val color = -0xbdbdbe
val paint = Paint()
val rect =
Rect(0, 0, bitmap.width, bitmap.height)
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
paint.color = color
canvas.drawCircle(
bitmap.width / 2.toFloat(),
bitmap.height / 2.toFloat(),
bitmap.width / 2.toFloat(),
paint
)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}
}
}