Add BitmapProvider class

This commit is contained in:
vfsfitvnm
2022-06-28 16:03:19 +02:00
parent aa02242cc6
commit 72eb9d4c7d
2 changed files with 93 additions and 40 deletions

View File

@@ -0,0 +1,71 @@
package it.vfsfitvnm.vimusic.service
import android.content.Context
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import androidx.core.graphics.applyCanvas
import coil.Coil
import coil.request.Disposable
import coil.request.ImageRequest
import it.vfsfitvnm.vimusic.utils.thumbnail
context(Context)
class BitmapProvider(
private val bitmapSize: Int,
private val colorProvider: (isSystemInDarkMode: Boolean) -> Int
) {
private var lastUri: Uri? = null
private var lastBitmap: Bitmap? = null
private var lastIsSystemInDarkMode = false
private var lastEnqueued: Disposable? = null
private lateinit var defaultBitmap: Bitmap
val bitmap: Bitmap
get() = lastBitmap ?: defaultBitmap
init {
setDefaultBitmap()
}
fun setDefaultBitmap(): Boolean {
val isSystemInDarkMode = resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
if (::defaultBitmap.isInitialized && isSystemInDarkMode == lastIsSystemInDarkMode) return false
lastIsSystemInDarkMode = isSystemInDarkMode
defaultBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888).applyCanvas {
drawColor(colorProvider(isSystemInDarkMode))
}
return lastBitmap == null
}
fun load(uri: Uri?, onDone: (Bitmap) -> Unit) {
if (lastUri == uri) return
lastEnqueued?.dispose()
lastUri = uri
lastEnqueued = Coil.imageLoader(applicationContext).enqueue(
ImageRequest.Builder(applicationContext)
.data(uri.thumbnail(bitmapSize))
.listener(
onError = { _, _ ->
lastBitmap = null
onDone(bitmap)
},
onSuccess = { _, result ->
lastBitmap = (result.drawable as BitmapDrawable).bitmap
onDone(bitmap)
}
)
.build()
)
}
}

View File

@@ -1,4 +1,4 @@
package it.vfsfitvnm.vimusic.services
package it.vfsfitvnm.vimusic.service
import android.app.Notification
import android.app.NotificationChannel
@@ -7,8 +7,8 @@ import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.support.v4.media.MediaMetadataCompat
@@ -19,7 +19,6 @@ import android.support.v4.media.session.PlaybackStateCompat.*
import androidx.annotation.DrawableRes
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat.startForegroundService
import androidx.core.graphics.drawable.toBitmap
import androidx.core.net.toUri
import androidx.media.session.MediaButtonReceiver
import androidx.media3.common.*
@@ -36,8 +35,6 @@ import androidx.media3.exoplayer.analytics.AnalyticsListener
import androidx.media3.exoplayer.analytics.PlaybackStats
import androidx.media3.exoplayer.analytics.PlaybackStatsListener
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import coil.Coil
import coil.request.ImageRequest
import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.MainActivity
import it.vfsfitvnm.vimusic.R
@@ -73,12 +70,10 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
private var timerJob: TimerJob? = null
private var notificationThumbnailSize: Int = 0
private var lastArtworkUri: Uri? = null
private var lastBitmap: Bitmap? = null
private var radio: YouTubeRadio? = null
private lateinit var bitmapProvider: BitmapProvider
private val coroutineScope = CoroutineScope(Dispatchers.IO) + Job()
private val songPendingLoudnessDb = mutableMapOf<String, Float?>()
@@ -113,10 +108,12 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
override fun onCreate() {
super.onCreate()
notificationThumbnailSize = (256 * resources.displayMetrics.density).roundToInt()
lastBitmap = resources.getDrawable(R.drawable.disc_placeholder, null)
?.toBitmap(notificationThumbnailSize, notificationThumbnailSize)
bitmapProvider = BitmapProvider(
bitmapSize = (256 * resources.displayMetrics.density).roundToInt(),
colorProvider = { isSystemInDarkMode ->
if (isSystemInDarkMode) Color.BLACK else Color.WHITE
}
)
createNotificationChannel()
@@ -222,6 +219,13 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
super.onDestroy()
}
override fun onConfigurationChanged(newConfig: Configuration) {
if (bitmapProvider.setDefaultBitmap()) {
notificationManager.notify(NotificationId, notification())
}
super.onConfigurationChanged(newConfig)
}
override fun onPlaybackStatsReady(
eventTime: AnalyticsListener.EventTime,
playbackStats: PlaybackStats
@@ -320,7 +324,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
.setContentTitle(mediaMetadata.title)
.setContentText(mediaMetadata.artist)
.setSubText(player.playerError?.message)
.setLargeIcon(lastBitmap)
.setLargeIcon(bitmapProvider.bitmap)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setShowWhen(false)
@@ -343,31 +347,8 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
)
.addMediaAction(R.drawable.play_skip_forward, "Skip forward", ACTION_SKIP_TO_NEXT)
if (lastArtworkUri != mediaMetadata.artworkUri) {
lastArtworkUri = mediaMetadata.artworkUri
Coil.imageLoader(applicationContext).enqueue(
ImageRequest.Builder(applicationContext)
.data(mediaMetadata.artworkUri.thumbnail(notificationThumbnailSize))
.listener(
onError = { _, _ ->
lastBitmap = resources.getDrawable(R.drawable.disc_placeholder, null)
?.toBitmap(notificationThumbnailSize, notificationThumbnailSize)
notificationManager.notify(
NotificationId,
builder.setLargeIcon(lastBitmap).build()
)
},
onSuccess = { _, result ->
lastBitmap = (result.drawable as BitmapDrawable).bitmap
notificationManager.notify(
NotificationId,
builder.setLargeIcon(lastBitmap).build()
)
}
)
.build()
)
bitmapProvider.load(mediaMetadata.artworkUri) { bitmap ->
notificationManager.notify(NotificationId, builder.setLargeIcon(bitmap).build())
}
return builder.build()
@@ -401,6 +382,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
}
}
private fun createCacheDataSource(): DataSource.Factory {
return CacheDataSource.Factory().setCache(cache).apply {
setUpstreamDataSourceFactory(