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