mirror of
https://github.com/home-assistant/android
synced 2024-10-01 13:53:53 +00:00
Support showing all frames of animated gif image in Android 14+ (#4284)
* Support showing all frames of animated gif when sent as image in Android 14+ * Use unique image names and delete existing files that are no longer needed * Fix lint * update behavior to keep 2 days of images
This commit is contained in:
parent
b23b1838d0
commit
ef6327ffb3
|
@ -13,6 +13,7 @@ import android.content.Intent
|
|||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.Icon
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.media.RingtoneManager
|
||||
|
@ -38,6 +39,7 @@ import androidx.core.app.NotificationCompat
|
|||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.RemoteInput
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
|
@ -85,6 +87,9 @@ import java.io.File
|
|||
import java.io.FileOutputStream
|
||||
import java.net.URL
|
||||
import java.net.URLDecoder
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
|
@ -1205,8 +1210,15 @@ class MessagingManager @Inject constructor(
|
|||
builder
|
||||
.setLargeIcon(bitmap)
|
||||
.setStyle(
|
||||
NotificationCompat.BigPictureStyle()
|
||||
.bigPicture(bitmap)
|
||||
NotificationCompat.BigPictureStyle().also { style ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
saveTempAnimatedImage(serverId, url, !UrlUtil.isAbsoluteUrl(dataImage))?.let { filePath ->
|
||||
style.bigPicture(Icon.createWithContentUri(filePath))
|
||||
} ?: { style.bigPicture(bitmap) }
|
||||
} else {
|
||||
style.bigPicture(bitmap)
|
||||
}
|
||||
}
|
||||
.bigLargeIcon(null as Bitmap?)
|
||||
)
|
||||
}
|
||||
|
@ -1239,6 +1251,42 @@ class MessagingManager @Inject constructor(
|
|||
return@withContext image
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
private suspend fun saveTempAnimatedImage(serverId: Int, url: URL?, requiresAuth: Boolean = false): Uri? =
|
||||
withContext(
|
||||
Dispatchers.IO
|
||||
) {
|
||||
if (url == null || url.path.endsWith("gif").not()) {
|
||||
return@withContext null
|
||||
}
|
||||
|
||||
// delete previous images that are no longer needed
|
||||
val imageCutoff = LocalDateTime.now().minusDays(2)
|
||||
context.externalCacheDir?.listFiles()?.filter { file ->
|
||||
file.absolutePath.endsWith("_animated_notification.gif") &&
|
||||
imageCutoff.isAfter(LocalDateTime.ofInstant(Instant.ofEpochMilli(file.lastModified()), ZoneId.systemDefault()))
|
||||
}?.forEach { expired -> expired.delete() }
|
||||
|
||||
val file = File(context.externalCacheDir, "${System.currentTimeMillis()}_animated_notification.gif")
|
||||
try {
|
||||
val request = Request.Builder().apply {
|
||||
url(url)
|
||||
if (requiresAuth) {
|
||||
addHeader("Authorization", serverManager.authenticationRepository(serverId).buildBearerToken())
|
||||
}
|
||||
}.build()
|
||||
|
||||
val response = okHttpClient.newCall(request).execute()
|
||||
val bytes = response.body?.bytes() ?: return@withContext null
|
||||
file.writeBytes(bytes)
|
||||
|
||||
response.close()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Couldn't download image for notification", e)
|
||||
}
|
||||
return@withContext FileProvider.getUriForFile(context, "${context.packageName}.provider", file)
|
||||
}
|
||||
|
||||
private suspend fun handleVideo(
|
||||
builder: NotificationCompat.Builder,
|
||||
data: Map<String, String>
|
||||
|
|
Loading…
Reference in a new issue