Make PlaybackService perpetually foreground

Make PlaybackService never leave the foreground unless forced to, will add an option to close the service later.
This commit is contained in:
OxygenCobalt 2020-10-31 20:02:47 -06:00
parent afa50ad531
commit 09971afb42
6 changed files with 37 additions and 13 deletions

View file

@ -27,6 +27,9 @@
<service
android:name=".playback.PlaybackService"
android:icon="@drawable/ic_launcher_foreground"
android:foregroundServiceType="mediaPlayback"
android:exported="false"
android:enabled="true"
android:description="@string/label_service_playback"
android:stopWithTask="false" />
</application>

View file

@ -23,7 +23,7 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
super.onStart()
Intent(this, PlaybackService::class.java).also {
this.startService(it)
startService(it)
}
}
}

View file

@ -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

View file

@ -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)
}
}

View file

@ -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) }

View file

@ -27,9 +27,8 @@
<string name="label_play">Play</string>
<string name="label_queue">Queue</string>
<string name="label_queue_add">Add to queue</string>
<string name="label_notif_playback">Music Playback</string>
<string name="label_notification_playback">Music Playback</string>
<string name="label_service_playback">The music playback service for Auxio.</string>
<string name="label_is_playing">Auxio is playing music</string>
<!-- Hint Namespace | EditText Hints -->
<string name="hint_search_library">Search Library…</string>
@ -50,7 +49,7 @@
<string name="description_skip_prev">Skip to last song</string>
<string name="description_shuffle_on">Turn shuffle on</string>
<string name="description_shuffle_off">Turn shuffle off</string>
<string name="description_loop">Change Loop Mode</string>
<string name="description_loop">Loop</string>
<!-- Placeholder Namespace | Placeholder values -->
<string name="placeholder_genre">Unknown Genre</string>