From 09971afb427805813f826cf3ae7ec65f3e7e1aa0 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sat, 31 Oct 2020 20:02:47 -0600 Subject: [PATCH] Make PlaybackService perpetually foreground Make PlaybackService never leave the foreground unless forced to, will add an option to close the service later. --- app/src/main/AndroidManifest.xml | 3 ++ .../java/org/oxycblt/auxio/MainActivity.kt | 2 +- .../playback/PlaybackNotificationHolder.kt | 31 +++++++++++++++++-- .../oxycblt/auxio/playback/PlaybackService.kt | 7 ++--- .../playback/state/PlaybackStateManager.kt | 2 +- app/src/main/res/values/strings.xml | 5 ++- 6 files changed, 37 insertions(+), 13 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 76cfd4990..d858553c4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,6 +27,9 @@ diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index c8f446111..5d0ec4d90 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -23,7 +23,7 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) { super.onStart() Intent(this, PlaybackService::class.java).also { - this.startService(it) + startService(it) } } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackNotificationHolder.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackNotificationHolder.kt index 4658bed8d..a0e5c86e2 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackNotificationHolder.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackNotificationHolder.kt @@ -4,6 +4,7 @@ import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context +import android.content.pm.ServiceInfo import android.os.Build import android.support.v4.media.session.MediaSessionCompat import androidx.core.app.NotificationCompat @@ -12,12 +13,16 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.coil.getBitmap +// Manager for the playback notification +// TODO: Implement some ability internal class PlaybackNotificationHolder { private lateinit var mNotification: Notification private lateinit var notificationManager: NotificationManager private lateinit var baseNotification: NotificationCompat.Builder + private var isForeground = false + fun init(context: Context, session: MediaSessionCompat) { // Never run if the notification has already been created if (!::mNotification.isInitialized) { @@ -28,7 +33,7 @@ internal class PlaybackNotificationHolder { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( CHANNEL_ID, - context.getString(R.string.label_notif_playback), + context.getString(R.string.label_notification_playback), NotificationManager.IMPORTANCE_DEFAULT ) notificationManager.createNotificationChannel(channel) @@ -37,6 +42,7 @@ internal class PlaybackNotificationHolder { baseNotification = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_song) .setStyle(MediaStyle().setMediaSession(session.sessionToken)) + .setCategory(NotificationCompat.CATEGORY_SERVICE) .setChannelId(CHANNEL_ID) .setShowWhen(false) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) @@ -48,7 +54,7 @@ internal class PlaybackNotificationHolder { fun setMetadata(song: Song, playbackService: PlaybackService) { // Set the basic metadata since MediaStyle wont do it yourself. // Fun Fact: The documentation still says that MediaStyle will handle metadata changes - // from MediaSession, even though it doesn't. After 6 years. + // from MediaSession, even though it doesn't. Its been 6 years. Fun. baseNotification .setContentTitle(song.name) .setContentText( @@ -62,10 +68,29 @@ internal class PlaybackNotificationHolder { getBitmap(song, playbackService) { baseNotification.setLargeIcon(it) mNotification = baseNotification.build() - playbackService.startForeground(NOTIFICATION_ID, mNotification) + + if (!isForeground) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + playbackService.startForeground( + NOTIFICATION_ID, mNotification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK + ) + } else { + playbackService.startForeground(NOTIFICATION_ID, mNotification) + } + } else { + notificationManager.notify(NOTIFICATION_ID, mNotification) + } } } + fun stop(playbackService: PlaybackService) { + playbackService.stopForeground(true) + notificationManager.cancel(NOTIFICATION_ID) + + isForeground = false + } + companion object { const val CHANNEL_ID = "CHANNEL_AUXIO_PLAYBACK" const val NOTIFICATION_ID = 0xA0A0 diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt index 28631e0e4..ef3d3b554 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt @@ -129,7 +129,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback { override fun onDestroy() { super.onDestroy() - stopForeground(true) + notificationHolder.stop(this) unregisterReceiver(systemReceiver) // Release everything that could cause a memory leak if left around @@ -202,7 +202,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback { // Stop playing/the notification if there's nothing to play. player.stop() - stopForeground(true) + notificationHolder.stop(this) } override fun onPlayingUpdate(isPlaying: Boolean) { @@ -214,9 +214,6 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback { startPollingPosition() } else { player.pause() - - // Be a polite service and stop being foreground if nothing is playing. - stopForeground(false) } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index f98934000..faf83fcea 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -23,7 +23,7 @@ internal class PlaybackStateManager { field = value callbacks.forEach { it.onSongUpdate(value) } } - private var mPosition: Long = 0 // TODO: Consider using millis instead of seconds? + private var mPosition: Long = 0 set(value) { field = value callbacks.forEach { it.onPositionUpdate(value) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 92c5e091f..5c1d512f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,9 +27,8 @@ Play Queue Add to queue - Music Playback + Music Playback The music playback service for Auxio. - Auxio is playing music Search Library… @@ -50,7 +49,7 @@ Skip to last song Turn shuffle on Turn shuffle off - Change Loop Mode + Loop Unknown Genre