mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 04:52:32 +00:00
Notification improvements for Android 13 using the udpated MediaCompat SDK
This commit is contained in:
parent
f1c45b2746
commit
e7574c286b
@ -6,9 +6,6 @@ import android.content.*
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import android.support.v4.media.MediaMetadataCompat
|
||||
import android.support.v4.media.session.MediaSessionCompat
|
||||
import android.support.v4.media.session.PlaybackStateCompat
|
||||
@ -39,9 +36,15 @@ import io.casey.musikcube.remote.util.Debouncer
|
||||
import androidx.core.app.NotificationCompat.Action as NotifAction
|
||||
import io.casey.musikcube.remote.ui.shared.util.AlbumArtLookup.getUrl as getAlbumArtUrl
|
||||
import android.app.NotificationManager
|
||||
import android.os.*
|
||||
|
||||
private fun log(format: String, vararg params: Any?) =
|
||||
const val ENABLE_LOGGING = false
|
||||
|
||||
private fun log(format: String, vararg params: Any?) {
|
||||
if (ENABLE_LOGGING) {
|
||||
Log.d("musikdroid.Service", String.format(format, *params))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a service used to interact with all of the system media-related components -- notifications,
|
||||
@ -66,6 +69,7 @@ class SystemService : Service() {
|
||||
private lateinit var powerManager: PowerManager
|
||||
private lateinit var prefs: SharedPreferences
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val albumArt = AlbumArt()
|
||||
private val sessionData = SessionMetadata()
|
||||
|
||||
@ -285,7 +289,7 @@ class SystemService : Service() {
|
||||
currentImage = albumArt.bitmap
|
||||
}
|
||||
|
||||
if (!sessionData.matches(track, currentImage)) {
|
||||
if (!sessionData.matches(track, currentImage, duration)) {
|
||||
log("updateMediaSession: stale data detected, updating")
|
||||
sessionData.update(track, currentImage, duration)
|
||||
|
||||
@ -311,34 +315,56 @@ class SystemService : Service() {
|
||||
mediaSession?.let { session ->
|
||||
var mediaSessionState = PlaybackStateCompat.STATE_STOPPED
|
||||
var duration = 0
|
||||
var position = 0L
|
||||
var bufferPosition = 0L
|
||||
var playing: ITrack? = null
|
||||
|
||||
playback?.let { pb ->
|
||||
mediaSessionState = when (pb.state) {
|
||||
PlaybackState.Playing -> PlaybackStateCompat.STATE_PLAYING
|
||||
PlaybackState.Buffering -> PlaybackStateCompat.STATE_BUFFERING
|
||||
/* HACK: if we return STATE_PAUSED, the playback controls will disappear
|
||||
from the lock screen! wtf? we don't want that, so we return
|
||||
STATE_BUFFERING instead, which seems to keep the play controls visible,
|
||||
and also display the "PLAY" button like the user expects. sigh */
|
||||
PlaybackState.Paused -> PlaybackStateCompat.STATE_BUFFERING
|
||||
PlaybackState.Paused -> PlaybackStateCompat.STATE_PAUSED
|
||||
PlaybackState.Stopped -> PlaybackStateCompat.STATE_STOPPED
|
||||
}
|
||||
playing = pb.playingTrack
|
||||
duration = (pb.duration * 1000).toInt()
|
||||
position = (pb.currentTime * 1000).toLong()
|
||||
bufferPosition = (pb.bufferedTime * 1000).toLong()
|
||||
}
|
||||
|
||||
updateMediaSession(playing, duration)
|
||||
updateNotification(playing, playback?.state ?: PlaybackState.Stopped)
|
||||
|
||||
session.setPlaybackState(PlaybackStateCompat.Builder()
|
||||
.setState(mediaSessionState, 0, 0f)
|
||||
.setState(mediaSessionState, position, 1f)
|
||||
.setBufferedPosition(bufferPosition)
|
||||
.setActions(MEDIA_SESSION_ACTIONS)
|
||||
.build())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleNotificationTimeUpdate() {
|
||||
handler.removeCallbacks(updateTimeRunnable)
|
||||
handler.postDelayed(updateTimeRunnable, NOTIFICATION_PLAYHEAD_SYNC_MS)
|
||||
}
|
||||
|
||||
private val updateTimeRunnable = object: Runnable {
|
||||
override fun run() {
|
||||
playback?.let { pb ->
|
||||
when (pb.state) {
|
||||
PlaybackState.Playing,
|
||||
PlaybackState.Buffering,
|
||||
PlaybackState.Paused -> {
|
||||
updateNotificationAndSessionDebouncer.call()
|
||||
scheduleNotificationTimeUpdate()
|
||||
}
|
||||
PlaybackState.Stopped -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UnspecifiedImmutableFlag")
|
||||
private fun getPendingActivityIntentCompat(intent: Intent) =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
@ -570,6 +596,7 @@ class SystemService : Service() {
|
||||
if (playback?.state == PlaybackState.Playing) {
|
||||
headsetDoublePauseHack = false
|
||||
}
|
||||
scheduleNotificationTimeUpdate()
|
||||
updateNotificationAndSessionDebouncer.call()
|
||||
}
|
||||
|
||||
@ -624,17 +651,20 @@ class SystemService : Service() {
|
||||
duration = otherDuration
|
||||
}
|
||||
|
||||
fun matches(otherTrack: ITrack?, otherBitmap: Bitmap?): Boolean {
|
||||
fun matches(otherTrack: ITrack?, otherBitmap: Bitmap?, otherDuration: Int): Boolean {
|
||||
log("updateMediaSession.matches(): " +
|
||||
"track=$track, " +
|
||||
"otherTrack=$otherTrack " +
|
||||
"otherTrack.externalId=${otherTrack?.externalId} " +
|
||||
"track.externalId=${track?.externalId} " +
|
||||
"otherBitmap=$otherBitmap " +
|
||||
"bitmap=$bitmap")
|
||||
"bitmap=$bitmap" +
|
||||
"otherDuration=$otherDuration " +
|
||||
"duration=$duration")
|
||||
val result = (track != null && otherTrack != null) &&
|
||||
otherTrack.externalId == track?.externalId &&
|
||||
bitmap === otherBitmap
|
||||
bitmap === otherBitmap &&
|
||||
duration == otherDuration
|
||||
log("updateMediaSession.matches(): result=$result")
|
||||
return result
|
||||
}
|
||||
@ -647,6 +677,7 @@ class SystemService : Service() {
|
||||
private const val HEADSET_HOOK_DEBOUNCE_MS = 500L
|
||||
private const val HEADSET_DOUBLE_PAUSE_HACK_DEBOUNCE_MS = 3500L
|
||||
private const val NOTIFICATION_DEBOUNCE_MS = 750L
|
||||
private const val NOTIFICATION_PLAYHEAD_SYNC_MS = 10000L
|
||||
private const val ACTION_NOTIFICATION_PLAY = "io.casey.musikcube.remote.NOTIFICATION_PLAY"
|
||||
private const val ACTION_NOTIFICATION_PAUSE = "io.casey.musikcube.remote.NOTIFICATION_PAUSE"
|
||||
private const val ACTION_NOTIFICATION_NEXT = "io.casey.musikcube.remote.NOTIFICATION_NEXT"
|
||||
@ -677,8 +708,7 @@ class SystemService : Service() {
|
||||
PlaybackStateCompat.ACTION_PLAY_PAUSE or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
|
||||
PlaybackStateCompat.ACTION_FAST_FORWARD or
|
||||
PlaybackStateCompat.ACTION_REWIND
|
||||
PlaybackStateCompat.ACTION_STOP
|
||||
|
||||
private var wakeLockAcquireTime = -1L
|
||||
private var totalWakeLockTime = 0L
|
||||
|
Loading…
Reference in New Issue
Block a user