From 6a2609852895be315fbe784f93bea139bebb0543 Mon Sep 17 00:00:00 2001 From: Derek Schmidt Date: Sun, 31 May 2020 14:16:23 -0700 Subject: [PATCH 1/2] Enable android auto support Meet min requirements for Android Auto to connect to our mediasession Still to go: 1. File browsing 2. Additional playback controls --- app/src/main/AndroidManifest.xml | 19 +++++++++++-- .../apognu/otter/playback/PlayerService.kt | 28 +++++++++++++++---- app/src/main/res/xml/automotive_app_desc.xml | 4 +++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 app/src/main/res/xml/automotive_app_desc.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 350d19b..475f59d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.github.apognu.otter"> @@ -16,6 +17,13 @@ android:supportsRtl="true" android:theme="@style/AppTheme"> + + + + @@ -44,7 +52,14 @@ - + + + + + () @@ -84,6 +86,8 @@ class PlayerService : Service() { isActive = true } + sessionToken = mediaSession.sessionToken + mediaControlsManager = MediaControlsManager(this, mediaSession) player = SimpleExoPlayer.Builder(this).build().apply { @@ -224,8 +228,6 @@ class PlayerService : Service() { }) } - override fun onBind(intent: Intent?): IBinder? = null - @SuppressLint("NewApi") override fun onDestroy() { jobs.forEach { it.cancel() } @@ -437,4 +439,20 @@ class PlayerService : Service() { } } } + + override fun onGetRoot( + clientPackageName: String, + clientUid: Int, + rootHints: Bundle? + ): BrowserRoot? { + return BrowserRoot("/", null) + } + + override fun onLoadChildren( + parentId: String, + result: Result> + ) { + val list = mutableListOf() + result.sendResult(list) + } } diff --git a/app/src/main/res/xml/automotive_app_desc.xml b/app/src/main/res/xml/automotive_app_desc.xml new file mode 100644 index 0000000..0a6a3c9 --- /dev/null +++ b/app/src/main/res/xml/automotive_app_desc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 8878cdc7a719f06d7033dafa7fa97b0f8560731b Mon Sep 17 00:00:00 2001 From: Derek Schmidt Date: Fri, 19 Jun 2020 05:36:10 -0700 Subject: [PATCH 2/2] Add queue navigation Automatic next and previous implimentations! ExoPlayer is rad Should also help with metadata confusion when pre-loading the next track for gapless playback --- .../github/apognu/otter/playback/PlayerService.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 ed3b785..94b3281 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 @@ -7,6 +7,7 @@ import android.content.IntentFilter import android.media.AudioAttributes import android.media.AudioFocusRequest import android.media.AudioManager +import android.net.Uri import android.os.Build import android.os.Bundle import android.support.v4.media.MediaBrowserCompat @@ -22,6 +23,7 @@ import com.google.android.exoplayer2.ExoPlaybackException import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.SimpleExoPlayer import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector +import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator import com.google.android.exoplayer2.source.TrackGroupArray import com.google.android.exoplayer2.trackselection.TrackSelectionArray import kotlinx.coroutines.Dispatchers.IO @@ -90,6 +92,17 @@ class PlayerService : MediaBrowserServiceCompat() { mediaControlsManager = MediaControlsManager(this, mediaSession) + val queueNavigator: TimelineQueueNavigator = object : TimelineQueueNavigator(mediaSession) { + override fun getMediaDescription(player: Player, windowIndex: Int): MediaDescriptionCompat { + val track = queue.get(windowIndex) + return MediaDescriptionCompat.Builder().apply { + setTitle(track.title) + setSubtitle(track.subtitle()) + setIconUri(Uri.parse(maybeNormalizeUrl(track.cover()))) + }.build() + } + } + player = SimpleExoPlayer.Builder(this).build().apply { playWhenReady = false @@ -99,6 +112,7 @@ class PlayerService : MediaBrowserServiceCompat() { MediaSessionConnector(mediaSession).also { it.setPlayer(this) + it.setQueueNavigator(queueNavigator) it.setMediaButtonEventHandler { player, _, mediaButtonEvent -> mediaButtonEvent.extras?.getParcelable(Intent.EXTRA_KEY_EVENT)?.let { key -> if (key.action == KeyEvent.ACTION_UP) {