Add BitmapProvider class
This commit is contained in:
@@ -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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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(
|
||||||
Reference in New Issue
Block a user