Skip to content

Commit

Permalink
Migrate to ExoPlayer 2.11.5. Fixes android#359
Browse files Browse the repository at this point in the history
  • Loading branch information
dturner committed Jun 22, 2020
1 parent c39ce40 commit 93b342d
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ class AutomotiveMusicService : MusicService() {
private inner class AutomotiveCommandReceiver : CommandReceiver {
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
override fun onCommand(
player: Player?,
controlDispatcher: ControlDispatcher?,
command: String?,
player: Player,
controlDispatcher: ControlDispatcher,
command: String,
extras: Bundle?,
callback: ResultReceiver?
): Boolean =
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ buildscript {
arch_lifecycle_version = '2.0.0'
constraint_layout_version = '1.1.3'
espresso_version = '3.1.1'
exoplayer_version = '2.10.0'
exoplayer_version = '2.11.5'
glide_version = '4.11.0'
gms_strict_version_matcher_version = '1.0.3'
gradle_version = '3.1.4'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,12 @@ package com.example.android.uamp.media

import android.app.Notification
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioManager
import android.net.Uri
import android.os.Bundle
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaBrowserCompat.MediaItem
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.session.MediaControllerCompat
import android.support.v4.media.session.MediaSessionCompat
import androidx.core.content.ContextCompat
import androidx.media.MediaBrowserServiceCompat
Expand All @@ -41,8 +36,8 @@ import com.example.android.uamp.media.library.UAMP_BROWSABLE_ROOT
import com.example.android.uamp.media.library.UAMP_EMPTY_ROOT
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.ExoPlayerFactory
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.Timeline
import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
Expand All @@ -68,7 +63,7 @@ import kotlinx.coroutines.launch
* visit [https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowserservice.html](https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowserservice.html).
*/
open class MusicService : MediaBrowserServiceCompat() {
private lateinit var becomingNoisyReceiver: BecomingNoisyReceiver

private lateinit var notificationManager: UampNotificationManager
private lateinit var mediaSource: MusicSource
private lateinit var packageValidator: PackageValidator
Expand Down Expand Up @@ -105,8 +100,9 @@ open class MusicService : MediaBrowserServiceCompat() {
* See [Player.AudioComponent.setAudioAttributes] for details.
*/
private val exoPlayer: ExoPlayer by lazy {
ExoPlayerFactory.newSimpleInstance(this).apply {
SimpleExoPlayer.Builder(this).build().apply {
setAudioAttributes(uAmpAudioAttributes, true)
setHandleAudioBecomingNoisy(true)
addListener(playerListener)
}
}
Expand Down Expand Up @@ -152,9 +148,6 @@ open class MusicService : MediaBrowserServiceCompat() {
PlayerNotificationListener()
)

becomingNoisyReceiver =
BecomingNoisyReceiver(context = this, sessionToken = mediaSession.sessionToken)

// The media library is built from a remote JSON file. We'll create the source here,
// and then use a suspend function to perform the download off the main thread.
mediaSource = JsonSource(context = this, source = remoteJsonSource)
Expand Down Expand Up @@ -324,7 +317,7 @@ open class MusicService : MediaBrowserServiceCompat() {
PlayerNotificationManager.NotificationListener {
override fun onNotificationPosted(
notificationId: Int,
notification: Notification?,
notification: Notification,
ongoing: Boolean
) {
if (ongoing && !isForegroundService) {
Expand Down Expand Up @@ -354,7 +347,6 @@ open class MusicService : MediaBrowserServiceCompat() {
Player.STATE_BUFFERING,
Player.STATE_READY -> {
notificationManager.showNotification()
becomingNoisyReceiver.register()

// If playback is paused we remove the foreground state which allows the
// notification to be dismissed. An alternative would be to provide a "close"
Expand All @@ -365,7 +357,6 @@ open class MusicService : MediaBrowserServiceCompat() {
}
else -> {
notificationManager.hideNotification()
becomingNoisyReceiver.unregister()
}
}
}
Expand All @@ -382,42 +373,7 @@ private class UampQueueNavigator(
private val window = Timeline.Window()
override fun getMediaDescription(player: Player, windowIndex: Int): MediaDescriptionCompat =
player.currentTimeline
.getWindow(windowIndex, window, true).tag as MediaDescriptionCompat
}

/**
* Helper class for listening for when headphones are unplugged (or the audio
* will otherwise cause playback to become "noisy").
*/
private class BecomingNoisyReceiver(
private val context: Context,
sessionToken: MediaSessionCompat.Token
) : BroadcastReceiver() {

private val noisyIntentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
private val controller = MediaControllerCompat(context, sessionToken)

private var registered = false

fun register() {
if (!registered) {
context.registerReceiver(this, noisyIntentFilter)
registered = true
}
}

fun unregister() {
if (registered) {
context.unregisterReceiver(this)
registered = false
}
}

override fun onReceive(context: Context, intent: Intent) {
if (intent.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY) {
controller.transportControls.pause()
}
}
.getWindow(windowIndex, window).tag as MediaDescriptionCompat
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,14 @@

package com.example.android.uamp.media

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.support.v4.media.session.MediaControllerCompat
import android.support.v4.media.session.MediaSessionCompat
import androidx.annotation.RequiresApi
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.ui.PlayerNotificationManager
Expand All @@ -36,8 +33,8 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

const val NOW_PLAYING_CHANNEL = "com.example.android.uamp.media.NOW_PLAYING"
const val NOW_PLAYING_NOTIFICATION = 0xb339 // Arbitrary number used to identify our notification
const val NOW_PLAYING_CHANNEL_ID = "com.example.android.uamp.media.NOW_PLAYING"
const val NOW_PLAYING_NOTIFICATION_ID = 0xb339 // Arbitrary number used to identify our notification

/**
* A wrapper class for ExoPlayer's PlayerNotificationManager. It sets up the notification shown to
Expand All @@ -61,9 +58,10 @@ class UampNotificationManager(

notificationManager = PlayerNotificationManager.createWithNotificationChannel(
context,
NOW_PLAYING_CHANNEL,
NOW_PLAYING_CHANNEL_ID,
R.string.notification_channel,
NOW_PLAYING_NOTIFICATION,
R.string.notification_channel_description,
NOW_PLAYING_NOTIFICATION_ID,
DescriptionAdapter(mediaController),
notificationListener
).apply {
Expand Down Expand Up @@ -91,18 +89,18 @@ class UampNotificationManager(
var currentIconUri: Uri? = null
var currentBitmap: Bitmap? = null

override fun createCurrentContentIntent(player: Player?): PendingIntent? =
override fun createCurrentContentIntent(player: Player): PendingIntent? =
controller.sessionActivity

override fun getCurrentContentText(player: Player?) =
override fun getCurrentContentText(player: Player) =
controller.metadata.description.subtitle.toString()

override fun getCurrentContentTitle(player: Player?) =
override fun getCurrentContentTitle(player: Player) =
controller.metadata.description.title.toString()

override fun getCurrentLargeIcon(
player: Player?,
callback: PlayerNotificationManager.BitmapCallback?
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
val iconUri = controller.metadata.description.iconUri
return if (currentIconUri != iconUri || currentBitmap == null) {
Expand All @@ -114,7 +112,7 @@ class UampNotificationManager(
currentBitmap = iconUri?.let {
resolveUriAsBitmap(it)
}
callback?.onBitmap(currentBitmap)
currentBitmap?.let { callback.onBitmap(it) }
}
null
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,9 @@ class UampPlaybackPreparer(
PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH or
PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH

override fun onPrepare() = Unit
override fun onPrepare(playWhenReady: Boolean) = Unit

/**
* Handles callbacks to both [MediaSessionCompat.Callback.onPrepareFromMediaId]
* *AND* [MediaSessionCompat.Callback.onPlayFromMediaId] when using [MediaSessionConnector].
* This is done with the expectation that "play" is just "prepare" + "play".
*
* If your app needs to do something special for either 'prepare' or 'play', it's possible
* to check [ExoPlayer.getPlayWhenReady]. If this returns `true`, then it's
* [MediaSessionCompat.Callback.onPlayFromMediaId], otherwise it's
* [MediaSessionCompat.Callback.onPrepareFromMediaId].
*/
override fun onPrepareFromMediaId(mediaId: String?, extras: Bundle?) {
override fun onPrepareFromMediaId(mediaId: String, playWhenReady: Boolean, extras: Bundle?) {
musicSource.whenReady {
val itemToPlay: MediaMetadataCompat? = musicSource.find { item ->
item.id == mediaId
Expand All @@ -88,38 +78,36 @@ class UampPlaybackPreparer(

exoPlayer.prepare(mediaSource)
exoPlayer.seekTo(initialWindowIndex, 0)
exoPlayer.playWhenReady = playWhenReady
}
}
}

/**
* Handles callbacks to both [MediaSessionCompat.Callback.onPrepareFromSearch]
* *AND* [MediaSessionCompat.Callback.onPlayFromSearch] when using [MediaSessionConnector].
* (See above for details.)
*
* This method is used by the Google Assistant to respond to requests such as:
* - Play Geisha from Wake Up on UAMP
* - Play electronic music on UAMP
* - Play music on UAMP
*
* For details on how search is handled, see [AbstractMusicSource.search].
*/
override fun onPrepareFromSearch(query: String?, extras: Bundle?) {
override fun onPrepareFromSearch(query: String, playWhenReady: Boolean, extras: Bundle?) {
musicSource.whenReady {
val metadataList = musicSource.search(query ?: "", extras ?: Bundle.EMPTY)
val metadataList = musicSource.search(query, extras ?: Bundle.EMPTY)
if (metadataList.isNotEmpty()) {
val mediaSource = metadataList.toMediaSource(dataSourceFactory)
exoPlayer.prepare(mediaSource)
exoPlayer.playWhenReady = playWhenReady
}
}
}

override fun onPrepareFromUri(uri: Uri?, extras: Bundle?) = Unit
override fun onPrepareFromUri(uri: Uri, playWhenReady: Boolean, extras: Bundle?) = Unit

override fun onCommand(
player: Player?,
controlDispatcher: ControlDispatcher?,
command: String?,
player: Player,
controlDispatcher: ControlDispatcher,
command: String,
extras: Bundle?,
cb: ResultReceiver?
) = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import android.support.v4.media.MediaBrowserCompat.MediaItem
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DataSource

Expand Down

0 comments on commit 93b342d

Please sign in to comment.