diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 602a0c7..b97c382 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -34,15 +34,22 @@
android:name="com.github.apognu.otter.activities.LoginActivity"
android:configChanges="screenSize|orientation"
android:launchMode="singleInstance" />
+
+
+
+
+
-
+
when (command) {
is Command.StartService -> {
- startService(Intent(this@MainActivity, PlayerService::class.java).apply {
- putExtra(PlayerService.INITIAL_COMMAND_KEY, command.command.toString())
- })
+ Build.VERSION_CODES.O.onApi(
+ {
+ startForegroundService(Intent(this@MainActivity, PlayerService::class.java).apply {
+ putExtra(PlayerService.INITIAL_COMMAND_KEY, command.command.toString())
+ })
+ },
+ {
+ startService(Intent(this@MainActivity, PlayerService::class.java).apply {
+ putExtra(PlayerService.INITIAL_COMMAND_KEY, command.command.toString())
+ })
+ }
+ )
}
is Command.RefreshTrack -> refreshCurrentTrack(command.track)
diff --git a/app/src/main/java/com/github/apognu/otter/playback/MediaSession.kt b/app/src/main/java/com/github/apognu/otter/playback/MediaSession.kt
new file mode 100644
index 0000000..a01a30e
--- /dev/null
+++ b/app/src/main/java/com/github/apognu/otter/playback/MediaSession.kt
@@ -0,0 +1,103 @@
+package com.github.apognu.otter.playback
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.ResultReceiver
+import android.support.v4.media.session.MediaSessionCompat
+import android.support.v4.media.session.PlaybackStateCompat
+import android.view.KeyEvent
+import com.github.apognu.otter.Otter
+import com.github.apognu.otter.utils.Command
+import com.github.apognu.otter.utils.CommandBus
+import com.google.android.exoplayer2.ControlDispatcher
+import com.google.android.exoplayer2.Player
+import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
+
+class MediaSession(private val context: Context) {
+ var active: Boolean = false
+
+ private val playbackStateBuilder = PlaybackStateCompat.Builder().apply {
+ setActions(
+ PlaybackStateCompat.ACTION_PLAY_PAUSE or
+ PlaybackStateCompat.ACTION_PLAY or
+ PlaybackStateCompat.ACTION_PAUSE or
+ PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
+ PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
+ PlaybackStateCompat.ACTION_SEEK_TO or
+ PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM
+ )
+ }
+
+ val session: MediaSessionCompat by lazy {
+ active = true
+
+ MediaSessionCompat(context, context.packageName).apply {
+ setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
+ setPlaybackState(playbackStateBuilder.build())
+
+ isActive = true
+ }
+ }
+
+ val connector: MediaSessionConnector by lazy {
+ MediaSessionConnector(Otter.get().mediaSession.session).also {
+ it.setQueueNavigator(OtterQueueNavigator())
+
+ it.setMediaButtonEventHandler { _, _, event ->
+ if (!active) {
+ event.extras?.getParcelable(Intent.EXTRA_KEY_EVENT)?.let { key ->
+ if (key.action == KeyEvent.ACTION_UP) {
+ val command = when (key.keyCode) {
+ KeyEvent.KEYCODE_MEDIA_PLAY -> Command.ToggleState
+ KeyEvent.KEYCODE_MEDIA_PAUSE -> Command.ToggleState
+ KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> Command.ToggleState
+ KeyEvent.KEYCODE_MEDIA_NEXT -> Command.NextTrack
+ KeyEvent.KEYCODE_MEDIA_PREVIOUS -> Command.PreviousTrack
+ else -> null
+ }
+
+ command?.let {
+ CommandBus.send(command)
+ CommandBus.send(Command.StartService(command))
+
+ return@setMediaButtonEventHandler true
+ }
+ }
+ }
+ }
+
+ false
+ }
+ }
+ }
+}
+
+class OtterQueueNavigator : MediaSessionConnector.QueueNavigator {
+ override fun onSkipToQueueItem(player: Player, controlDispatcher: ControlDispatcher, id: Long) {
+ CommandBus.send(Command.PlayTrack(id.toInt()))
+ }
+
+ override fun onCurrentWindowIndexChanged(player: Player) {}
+
+ override fun onCommand(player: Player, controlDispatcher: ControlDispatcher, command: String, extras: Bundle?, cb: ResultReceiver?) = true
+
+ override fun getSupportedQueueNavigatorActions(player: Player): Long {
+ return PlaybackStateCompat.ACTION_PLAY_PAUSE or
+ PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
+ PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
+ PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM
+ }
+
+ override fun onSkipToNext(player: Player, controlDispatcher: ControlDispatcher) {
+ CommandBus.send(Command.NextTrack)
+ }
+
+ override fun getActiveQueueItemId(player: Player?) = 0L
+
+ override fun onSkipToPrevious(player: Player, controlDispatcher: ControlDispatcher) {
+ CommandBus.send(Command.PreviousTrack)
+ }
+
+ override fun onTimelineChanged(player: Player) {}
+}
diff --git a/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt b/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt
index c76e57c..8777857 100644
--- a/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt
+++ b/app/src/main/java/com/github/apognu/otter/playback/PlayerService.kt
@@ -10,17 +10,15 @@ import android.media.AudioFocusRequest
import android.media.AudioManager
import android.media.MediaMetadata
import android.os.Build
-import android.os.Bundle
import android.os.IBinder
-import android.os.ResultReceiver
import android.support.v4.media.MediaMetadataCompat
-import android.support.v4.media.session.PlaybackStateCompat
-import android.view.KeyEvent
import com.github.apognu.otter.Otter
import com.github.apognu.otter.R
import com.github.apognu.otter.utils.*
-import com.google.android.exoplayer2.*
-import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
+import com.google.android.exoplayer2.C
+import com.google.android.exoplayer2.ExoPlaybackException
+import com.google.android.exoplayer2.Player
+import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import com.squareup.picasso.Picasso
@@ -61,6 +59,8 @@ class PlayerService : Service() {
intent?.extras?.getString(INITIAL_COMMAND_KEY)?.let {
when (it) {
+ Command.SetState(true).toString() -> setPlaybackState(true)
+ Command.SetState(false).toString() -> setPlaybackState(false)
Command.ToggleState.toString() -> togglePlayback()
Command.NextTrack.toString() -> skipToNextTrack()
Command.PreviousTrack.toString() -> skipToPreviousTrack()
@@ -97,7 +97,7 @@ class PlayerService : Service() {
}
}
- mediaControlsManager = MediaControlsManager(this, scope, Otter.get().mediaSession)
+ mediaControlsManager = MediaControlsManager(this, scope, Otter.get().mediaSession.session)
player = SimpleExoPlayer.Builder(this).build().apply {
playWhenReady = false
@@ -105,28 +105,13 @@ class PlayerService : Service() {
playerEventListener = PlayerEventListener().also {
addListener(it)
}
+ }
- MediaSessionConnector(Otter.get().mediaSession).also {
- it.setPlayer(this)
- it.setQueueNavigator(OtterQueueNavigator())
- it.setMediaMetadataProvider {
- buildTrackMetadata(queue.current())
- }
+ Otter.get().mediaSession.connector.apply {
+ setPlayer(player)
- it.setMediaButtonEventHandler { player, _, mediaButtonEvent ->
- mediaButtonEvent.extras?.getParcelable(Intent.EXTRA_KEY_EVENT)?.let { key ->
- if (key.action == KeyEvent.ACTION_UP) {
- when (key.keyCode) {
- KeyEvent.KEYCODE_MEDIA_PLAY -> setPlaybackState(true)
- KeyEvent.KEYCODE_MEDIA_PAUSE -> setPlaybackState(false)
- KeyEvent.KEYCODE_MEDIA_NEXT -> player.next()
- KeyEvent.KEYCODE_MEDIA_PREVIOUS -> skipToPreviousTrack()
- }
- }
- }
-
- true
- }
+ setMediaMetadataProvider {
+ buildTrackMetadata(queue.current())
}
}
@@ -250,6 +235,8 @@ class PlayerService : Service() {
audioManager.abandonAudioFocus(audioFocusChangeListener)
})
+ Otter.get().mediaSession.active = false
+
player.removeListener(playerEventListener)
setPlaybackState(false)
player.release()
@@ -470,33 +457,4 @@ class PlayerService : Service() {
}
}
}
-
- inner class OtterQueueNavigator : MediaSessionConnector.QueueNavigator {
- override fun onSkipToQueueItem(player: Player, controlDispatcher: ControlDispatcher, id: Long) {
- CommandBus.send(Command.PlayTrack(id.toInt()))
- }
-
- override fun onCurrentWindowIndexChanged(player: Player) {}
-
- override fun onCommand(player: Player, controlDispatcher: ControlDispatcher, command: String, extras: Bundle?, cb: ResultReceiver?) = true
-
- override fun getSupportedQueueNavigatorActions(player: Player): Long {
- return PlaybackStateCompat.ACTION_PLAY_PAUSE or
- PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
- PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
- PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM
- }
-
- override fun onSkipToNext(player: Player, controlDispatcher: ControlDispatcher) {
- skipToNextTrack()
- }
-
- override fun getActiveQueueItemId(player: Player?) = queue.current.toLong()
-
- override fun onSkipToPrevious(player: Player, controlDispatcher: ControlDispatcher) {
- skipToPreviousTrack()
- }
-
- override fun onTimelineChanged(player: Player) {}
- }
}
\ No newline at end of file