mirror of
https://github.com/clangen/musikcube.git
synced 2025-04-16 05:42:54 +00:00
More potential fixes for the MediaSession issue. Ugh. Wish there were
reliable repro steps.
This commit is contained in:
parent
9085ee3020
commit
d28a85dc4f
@ -66,8 +66,8 @@ class SystemService : Service() {
|
|||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val channel = NotificationChannel(
|
val channel = NotificationChannel(
|
||||||
NOTIFICATION_CHANNEL,
|
NOTIFICATION_CHANNEL,
|
||||||
NOTIFICATION_CHANNEL,
|
NOTIFICATION_CHANNEL,
|
||||||
NotificationManager.IMPORTANCE_LOW)
|
NotificationManager.IMPORTANCE_LOW)
|
||||||
|
|
||||||
channel.enableVibration(false)
|
channel.enableVibration(false)
|
||||||
@ -122,7 +122,7 @@ class SystemService : Service() {
|
|||||||
|
|
||||||
if (wakeLock == null) {
|
if (wakeLock == null) {
|
||||||
wakeLock = powerManager.newWakeLock(
|
wakeLock = powerManager.newWakeLock(
|
||||||
PowerManager.PARTIAL_WAKE_LOCK, "StreamingPlaybackService:")
|
PowerManager.PARTIAL_WAKE_LOCK, "$SESSION_TAG:")
|
||||||
|
|
||||||
wakeLock?.let {
|
wakeLock?.let {
|
||||||
it.setReferenceCounted(false)
|
it.setReferenceCounted(false)
|
||||||
@ -159,19 +159,24 @@ class SystemService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInitMediaSession() {
|
private fun checkInitMediaSession() {
|
||||||
val receiver = ComponentName(packageName, MediaButtonReceiver::class.java.name)
|
if (mediaSession == null || mediaSession?.isActive != true) {
|
||||||
|
deinitMediaSession()
|
||||||
|
|
||||||
mediaSession = MediaSessionCompat(this, "musikdroid.SystemService", receiver, null)
|
val receiver = ComponentName(
|
||||||
|
packageName, MediaButtonReceiver::class.java.name)
|
||||||
|
|
||||||
mediaSession?.setFlags(
|
mediaSession = MediaSessionCompat(
|
||||||
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
|
this, SESSION_TAG, receiver, null)
|
||||||
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
|
.apply {
|
||||||
|
this.setFlags(
|
||||||
|
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
|
||||||
|
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
|
||||||
|
this.setCallback(mediaSessionCallback)
|
||||||
|
this.isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
mediaSession?.setCallback(mediaSessionCallback)
|
updateMediaSessionPlaybackState()
|
||||||
|
}
|
||||||
updateMediaSessionPlaybackState()
|
|
||||||
|
|
||||||
mediaSession?.isActive = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deinitMediaSession() {
|
private fun deinitMediaSession() {
|
||||||
@ -184,14 +189,13 @@ class SystemService : Service() {
|
|||||||
registerReceiver(headsetUnpluggedReceiver, filter)
|
registerReceiver(headsetUnpluggedReceiver, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unregisterReceivers() {
|
private fun unregisterReceivers() =
|
||||||
try {
|
try {
|
||||||
unregisterReceiver(headsetUnpluggedReceiver)
|
unregisterReceiver(headsetUnpluggedReceiver)
|
||||||
}
|
}
|
||||||
catch (ex: Exception) {
|
catch (ex: Exception) {
|
||||||
Log.e(TAG, "unable to unregister headset (un)plugged BroadcastReceiver")
|
Log.e(TAG, "unable to unregister headset (un)plugged BroadcastReceiver")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateMediaSessionPlaybackState() {
|
private fun updateMediaSessionPlaybackState() {
|
||||||
var mediaSessionState = PlaybackStateCompat.STATE_STOPPED
|
var mediaSessionState = PlaybackStateCompat.STATE_STOPPED
|
||||||
@ -199,31 +203,33 @@ class SystemService : Service() {
|
|||||||
var duration = 0
|
var duration = 0
|
||||||
var playing: ITrack? = null
|
var playing: ITrack? = null
|
||||||
|
|
||||||
if (playback != null) {
|
playback?.let {
|
||||||
when (playback?.state) {
|
when (it.state) {
|
||||||
PlaybackState.Playing -> mediaSessionState = PlaybackStateCompat.STATE_PLAYING
|
PlaybackState.Playing -> mediaSessionState = PlaybackStateCompat.STATE_PLAYING
|
||||||
PlaybackState.Buffering -> mediaSessionState = PlaybackStateCompat.STATE_BUFFERING
|
PlaybackState.Buffering -> mediaSessionState = PlaybackStateCompat.STATE_BUFFERING
|
||||||
PlaybackState.Paused -> mediaSessionState = PlaybackStateCompat.STATE_PAUSED
|
PlaybackState.Paused -> mediaSessionState = PlaybackStateCompat.STATE_PAUSED
|
||||||
else -> { }
|
else -> { }
|
||||||
}
|
}
|
||||||
|
|
||||||
playing = playback!!.playingTrack
|
playing = it.playingTrack
|
||||||
duration = ((playback?.duration ?: 0.0) * 1000).toInt()
|
duration = (it.duration * 1000).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMediaSession(playing, duration)
|
mediaSession?.let {
|
||||||
updateNotification(playing, mediaSessionState)
|
updateMediaSession(playing, duration)
|
||||||
|
updateNotification(playing, mediaSessionState)
|
||||||
|
|
||||||
mediaSession?.setPlaybackState(PlaybackStateCompat.Builder()
|
it.setPlaybackState(PlaybackStateCompat.Builder()
|
||||||
.setState(mediaSessionState, 0, 0f)
|
.setState(mediaSessionState, 0, 0f)
|
||||||
.setActions(MEDIA_SESSION_ACTIONS)
|
.setActions(MEDIA_SESSION_ACTIONS)
|
||||||
.build())
|
.build())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadAlbumArtIfNecessary(track: ITrack, duration: Int) {
|
private fun downloadAlbumArtIfNecessary(track: ITrack, duration: Int) {
|
||||||
if (!albumArt.same(track) || (albumArt.request == null && albumArt.bitmap == null)) {
|
if (!albumArt.same(track) || (albumArt.request == null && albumArt.bitmap == null)) {
|
||||||
if (track.artist.isNotBlank() && track.album.isNotBlank()) {
|
if (track.artist.isNotBlank() && track.album.isNotBlank()) {
|
||||||
Log.d(TAG, "download")
|
Log.d(TAG, "downloading album art")
|
||||||
|
|
||||||
val url = getAlbumArtUrl(track, Size.Mega)
|
val url = getAlbumArtUrl(track, Size.Mega)
|
||||||
|
|
||||||
@ -321,13 +327,11 @@ class SystemService : Service() {
|
|||||||
if (state == PlaybackStateCompat.STATE_PAUSED) {
|
if (state == PlaybackStateCompat.STATE_PAUSED) {
|
||||||
notification.addAction(action(
|
notification.addAction(action(
|
||||||
android.R.drawable.ic_media_play,
|
android.R.drawable.ic_media_play,
|
||||||
getString(R.string.button_play),
|
getString(R.string.button_play), ACTION_NOTIFICATION_PLAY))
|
||||||
ACTION_NOTIFICATION_PLAY))
|
|
||||||
|
|
||||||
notification.addAction(action(
|
notification.addAction(action(
|
||||||
android.R.drawable.ic_menu_close_clear_cancel,
|
android.R.drawable.ic_menu_close_clear_cancel,
|
||||||
getString(R.string.button_close),
|
getString(R.string.button_close), ACTION_NOTIFICATION_STOP))
|
||||||
ACTION_NOTIFICATION_STOP))
|
|
||||||
|
|
||||||
notification.setStyle(MediaStyle()
|
notification.setStyle(MediaStyle()
|
||||||
.setShowActionsInCompactView(0, 1)
|
.setShowActionsInCompactView(0, 1)
|
||||||
@ -336,18 +340,15 @@ class SystemService : Service() {
|
|||||||
else {
|
else {
|
||||||
notification.addAction(action(
|
notification.addAction(action(
|
||||||
android.R.drawable.ic_media_previous,
|
android.R.drawable.ic_media_previous,
|
||||||
getString(R.string.button_prev),
|
getString(R.string.button_prev), ACTION_NOTIFICATION_PREV))
|
||||||
ACTION_NOTIFICATION_PREV))
|
|
||||||
|
|
||||||
notification.addAction(action(
|
notification.addAction(action(
|
||||||
android.R.drawable.ic_media_pause,
|
android.R.drawable.ic_media_pause,
|
||||||
getString(R.string.button_pause),
|
getString(R.string.button_pause), ACTION_NOTIFICATION_PAUSE))
|
||||||
ACTION_NOTIFICATION_PAUSE))
|
|
||||||
|
|
||||||
notification.addAction(action(
|
notification.addAction(action(
|
||||||
android.R.drawable.ic_media_next,
|
android.R.drawable.ic_media_next,
|
||||||
getString(R.string.button_next),
|
getString(R.string.button_next), ACTION_NOTIFICATION_NEXT))
|
||||||
ACTION_NOTIFICATION_NEXT))
|
|
||||||
|
|
||||||
notification.setStyle(MediaStyle()
|
notification.setStyle(MediaStyle()
|
||||||
.setShowActionsInCompactView(0, 1, 2)
|
.setShowActionsInCompactView(0, 1, 2)
|
||||||
@ -366,44 +367,49 @@ class SystemService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handlePlaybackAction(action: String?): Boolean {
|
private fun handlePlaybackAction(action: String?): Boolean {
|
||||||
if (this.playback != null && Strings.notEmpty(action)) {
|
this.playback?.let {
|
||||||
when (action) {
|
if (Strings.notEmpty(action)) {
|
||||||
ACTION_NOTIFICATION_NEXT -> {
|
when (action) {
|
||||||
this.playback?.next()
|
ACTION_NOTIFICATION_NEXT -> {
|
||||||
return true
|
it.next()
|
||||||
}
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
ACTION_NOTIFICATION_PAUSE -> {
|
ACTION_NOTIFICATION_PAUSE -> {
|
||||||
this.playback?.pause()
|
it.pause()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_NOTIFICATION_PLAY -> {
|
ACTION_NOTIFICATION_PLAY -> {
|
||||||
this.playback?.resume()
|
it.resume()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_NOTIFICATION_PREV -> {
|
ACTION_NOTIFICATION_PREV -> {
|
||||||
this.playback?.prev()
|
it.prev()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_NOTIFICATION_STOP -> {
|
ACTION_NOTIFICATION_STOP -> {
|
||||||
this.playback?.stop()
|
it.stop()
|
||||||
shutdown()
|
shutdown()
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val headsetHookDebouncer = object : Debouncer<Void>(HEADSET_HOOK_DEBOUNCE_MS) {
|
private val headsetHookDebouncer = object : Debouncer<Void>(HEADSET_HOOK_DEBOUNCE_MS) {
|
||||||
override fun onDebounced(last: Void?) {
|
override fun onDebounced(last: Void?) {
|
||||||
when (headsetHookPressCount) {
|
playback?.let {
|
||||||
1 -> playback?.pauseOrResume()
|
when (headsetHookPressCount) {
|
||||||
2 -> playback?.next()
|
1 -> it.pauseOrResume()
|
||||||
3 -> playback?.prev()
|
2 -> it.next()
|
||||||
|
3 -> it.prev()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
headsetHookPressCount = 0
|
headsetHookPressCount = 0
|
||||||
}
|
}
|
||||||
@ -455,11 +461,11 @@ class SystemService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlay() {
|
override fun onPlay() {
|
||||||
if (playback?.queueCount == 0) {
|
playback?.let {
|
||||||
playback?.playAll()
|
when (it.queueCount == 0) {
|
||||||
}
|
true -> it.playAll()
|
||||||
else {
|
false -> it.resume()
|
||||||
playback?.resume()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,6 +553,7 @@ class SystemService : Service() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "SystemService"
|
private const val TAG = "SystemService"
|
||||||
|
private const val SESSION_TAG = "musikdroid.SystemService"
|
||||||
private const val NOTIFICATION_ID = 0xdeadbeef.toInt()
|
private const val NOTIFICATION_ID = 0xdeadbeef.toInt()
|
||||||
private const val NOTIFICATION_CHANNEL = "musikdroid"
|
private const val NOTIFICATION_CHANNEL = "musikdroid"
|
||||||
private const val HEADSET_HOOK_DEBOUNCE_MS = 500L
|
private const val HEADSET_HOOK_DEBOUNCE_MS = 500L
|
||||||
|
@ -244,22 +244,29 @@ class MainMetadataView : FrameLayout {
|
|||||||
GlideApp.with(context)
|
GlideApp.with(context)
|
||||||
.load(albumArtUrl)
|
.load(albumArtUrl)
|
||||||
.apply(BITMAP_OPTIONS)
|
.apply(BITMAP_OPTIONS)
|
||||||
.listener(object : RequestListener<Drawable> {
|
.listener(object: RequestListener<Drawable> {
|
||||||
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
|
override fun onResourceReady(resource: Drawable?,
|
||||||
if (!paused) {
|
model: Any?,
|
||||||
preloadNextImage()
|
target: Target<Drawable>?,
|
||||||
}
|
dataSource: DataSource?,
|
||||||
|
isFirstResource: Boolean): Boolean {
|
||||||
setMetadataDisplayMode(DisplayMode.Artwork)
|
if (!paused) {
|
||||||
return false
|
preloadNextImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
|
setMetadataDisplayMode(DisplayMode.Artwork)
|
||||||
setMetadataDisplayMode(DisplayMode.NoArtwork)
|
return false
|
||||||
loadedAlbumArtUrl = null
|
}
|
||||||
return false
|
|
||||||
}
|
override fun onLoadFailed(e: GlideException?,
|
||||||
})
|
model: Any?,
|
||||||
|
target: Target<Drawable>?,
|
||||||
|
isFirstResource: Boolean): Boolean {
|
||||||
|
setMetadataDisplayMode(DisplayMode.NoArtwork)
|
||||||
|
loadedAlbumArtUrl = null
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
.into(albumArtImageView)
|
.into(albumArtImageView)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -99,12 +99,12 @@ private fun dejunk(album: String): String {
|
|||||||
object AlbumArtLookup {
|
object AlbumArtLookup {
|
||||||
fun getUrl(album: IAlbum, size: Size = Size.Small): String? {
|
fun getUrl(album: IAlbum, size: Size = Size.Small): String? {
|
||||||
return getThumbnailUrl(album.thumbnailId)
|
return getThumbnailUrl(album.thumbnailId)
|
||||||
?: getUrl(album.albumArtist, album.name, size)
|
?: getUrl(album.albumArtist, album.name, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUrl(track: ITrack, size: Size = Size.Small): String? {
|
fun getUrl(track: ITrack, size: Size = Size.Small): String? {
|
||||||
return getThumbnailUrl(track.thumbnailId)
|
return getThumbnailUrl(track.thumbnailId)
|
||||||
?: getUrl(track.artist, track.album, size)
|
?: getUrl(track.artist, track.album, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUrl(artist: String = "", album: String = "", size: Size = Size.Small): String? {
|
fun getUrl(artist: String = "", album: String = "", size: Size = Size.Small): String? {
|
||||||
@ -121,7 +121,7 @@ object AlbumArtLookup {
|
|||||||
|
|
||||||
fun canIntercept(request: Request): Boolean {
|
fun canIntercept(request: Request): Boolean {
|
||||||
return request.url().host() == "ws.audioscrobbler.com" &&
|
return request.url().host() == "ws.audioscrobbler.com" &&
|
||||||
request.url().queryParameter("method") == "album.getinfo"
|
request.url().queryParameter("method") == "album.getinfo"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun intercept(req: Request): Request? {
|
fun intercept(req: Request): Request? {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user