This commit is contained in:
Derek Schmidt 2020-06-21 00:00:28 +00:00 committed by GitHub
commit 19843bf351
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 7 deletions

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.apognu.otter"> xmlns:tools="http://schemas.android.com/tools"
package="com.github.apognu.otter">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
@ -17,6 +18,13 @@
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<meta-data
android:name="com.google.android.gms.car.notification.SmallIcon"
android:resource="@drawable/ottershape" />
<meta-data android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
<!-- <meta-data <!-- <meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME" android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider"/> --> android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider"/> -->
@ -45,7 +53,14 @@
<activity android:name="com.github.apognu.otter.activities.SettingsActivity" /> <activity android:name="com.github.apognu.otter.activities.SettingsActivity" />
<activity android:name="com.github.apognu.otter.activities.LicencesActivity" /> <activity android:name="com.github.apognu.otter.activities.LicencesActivity" />
<service android:name="com.github.apognu.otter.playback.PlayerService" /> <service
android:name="com.github.apognu.otter.playback.PlayerService"
android:exported="true"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<service <service
android:name=".playback.PinService" android:name=".playback.PinService"

View File

@ -1,18 +1,21 @@
package com.github.apognu.otter.playback package com.github.apognu.otter.playback
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.media.AudioAttributes import android.media.AudioAttributes
import android.media.AudioFocusRequest import android.media.AudioFocusRequest
import android.media.AudioManager import android.media.AudioManager
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.Bundle
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
import android.view.KeyEvent import android.view.KeyEvent
import com.github.apognu.otter.Otter import com.github.apognu.otter.Otter
import androidx.media.MediaBrowserServiceCompat
import com.github.apognu.otter.R import com.github.apognu.otter.R
import com.github.apognu.otter.utils.* import com.github.apognu.otter.utils.*
import com.google.android.exoplayer2.C import com.google.android.exoplayer2.C
@ -20,6 +23,7 @@ import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector 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.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.TrackSelectionArray import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
@ -30,7 +34,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class PlayerService : Service() { class PlayerService : MediaBrowserServiceCompat() {
private lateinit var queue: QueueManager private lateinit var queue: QueueManager
private val jobs = mutableListOf<Job>() private val jobs = mutableListOf<Job>()
@ -84,8 +88,21 @@ class PlayerService : Service() {
isActive = true isActive = true
} }
sessionToken = mediaSession.sessionToken
mediaControlsManager = MediaControlsManager(this, mediaSession) 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 { player = SimpleExoPlayer.Builder(this).build().apply {
playWhenReady = false playWhenReady = false
@ -95,6 +112,7 @@ class PlayerService : Service() {
MediaSessionConnector(mediaSession).also { MediaSessionConnector(mediaSession).also {
it.setPlayer(this) it.setPlayer(this)
it.setQueueNavigator(queueNavigator)
it.setMediaButtonEventHandler { player, _, mediaButtonEvent -> it.setMediaButtonEventHandler { player, _, mediaButtonEvent ->
mediaButtonEvent.extras?.getParcelable<KeyEvent>(Intent.EXTRA_KEY_EVENT)?.let { key -> mediaButtonEvent.extras?.getParcelable<KeyEvent>(Intent.EXTRA_KEY_EVENT)?.let { key ->
if (key.action == KeyEvent.ACTION_UP) { if (key.action == KeyEvent.ACTION_UP) {
@ -219,8 +237,6 @@ class PlayerService : Service() {
}) })
} }
override fun onBind(intent: Intent?): IBinder? = null
@SuppressLint("NewApi") @SuppressLint("NewApi")
override fun onDestroy() { override fun onDestroy() {
jobs.forEach { it.cancel() } jobs.forEach { it.cancel() }
@ -430,4 +446,20 @@ class PlayerService : Service() {
} }
} }
} }
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle?
): BrowserRoot? {
return BrowserRoot("/", null)
}
override fun onLoadChildren(
parentId: String,
result: Result<List<MediaBrowserCompat.MediaItem>>
) {
val list = mutableListOf<MediaBrowserCompat.MediaItem>()
result.sendResult(list)
}
} }

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<automotiveApp>
<uses name="media"/>
</automotiveApp>