Do not push our own notification when Chromecast session is active. Fixed issue where PlayerService listener would trigger twice on service restart. Implemented basic queue management on Chromecast player.

This commit is contained in:
Antoine POPINEAU 2020-06-24 19:33:00 +02:00
parent 9ed7eab761
commit 080cce00ee
No known key found for this signature in database
GPG Key ID: A78AC64694F84063
5 changed files with 60 additions and 19 deletions

View File

@ -4,10 +4,7 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.view.Menu import android.view.Menu
import com.github.apognu.otter.playback.PlayerService import com.github.apognu.otter.playback.PlayerService
import com.github.apognu.otter.utils.AppContext import com.github.apognu.otter.utils.*
import com.github.apognu.otter.utils.CastInterface
import com.github.apognu.otter.utils.Track
import com.github.apognu.otter.utils.mustNormalizeUrl
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.Timeline import com.google.android.exoplayer2.Timeline
import com.google.android.exoplayer2.ext.cast.CastPlayer import com.google.android.exoplayer2.ext.cast.CastPlayer
@ -58,7 +55,9 @@ class Cast(val context: Context, val switchListener: PlayerService.OnPlayerSwitc
tracks tracks
.map { track -> buildMediaQueueItem(track) } .map { track -> buildMediaQueueItem(track) }
.apply { .apply {
castPlayer.loadItems(this.toTypedArray(), 0, 0, Player.REPEAT_MODE_OFF) castPlayer.loadItems(this.toTypedArray(), 0, 0, Player.REPEAT_MODE_OFF).also { result ->
result?.addStatusListener { debugQueue() }
}
castPlayer.playWhenReady = true castPlayer.playWhenReady = true
} }
} }
@ -69,7 +68,9 @@ class Cast(val context: Context, val switchListener: PlayerService.OnPlayerSwitc
tracks tracks
.map { track -> buildMediaQueueItem(track) } .map { track -> buildMediaQueueItem(track) }
.forEach { .forEach {
castPlayer.addItems(it) castPlayer.addItems(it).also { result ->
result?.addStatusListener { debugQueue() }
}
} }
} }
} }
@ -80,7 +81,9 @@ class Cast(val context: Context, val switchListener: PlayerService.OnPlayerSwitc
player.currentTimeline.getPeriod(current + 1, this) player.currentTimeline.getPeriod(current + 1, this)
} }
castPlayer.addItems(period.id.toString().toInt(), buildMediaQueueItem(track)) castPlayer.addItems(period.id.toString().toInt(), buildMediaQueueItem(track)).also { result ->
result?.addStatusListener { debugQueue() }
}
} }
} }
@ -90,7 +93,9 @@ class Cast(val context: Context, val switchListener: PlayerService.OnPlayerSwitc
player.currentTimeline.getPeriod(index, this) player.currentTimeline.getPeriod(index, this)
} }
castPlayer.removeItem(period.id.toString().toInt()) castPlayer.removeItem(period.id.toString().toInt()).also { result ->
result?.addStatusListener { debugQueue() }
}
} }
} }
@ -100,7 +105,29 @@ class Cast(val context: Context, val switchListener: PlayerService.OnPlayerSwitc
player.currentTimeline.getPeriod(oldPosition, this) player.currentTimeline.getPeriod(oldPosition, this)
} }
castPlayer.moveItem(period.id.toString().toInt(), newPosition) castPlayer.moveItem(period.id.toString().toInt(), newPosition).also { result ->
result?.addStatusListener { debugQueue() }
}
}
}
private fun debugQueue() {
if (BuildConfig.DEBUG) {
player.onCast()?.let { castPlayer ->
"START queue".log()
for (index in 0 until castPlayer.currentTimeline.periodCount) {
val period = Timeline.Period().run {
player.currentTimeline.getPeriod(index, this)
}
castPlayer.getItem(period.id as Int)?.let { item ->
"${item.media.metadata.getString(MediaMetadata.KEY_ARTIST)} - ${item.media.metadata.getString(MediaMetadata.KEY_TITLE)}".log()
}
}
"END queue".log()
}
} }
} }

View File

@ -39,7 +39,6 @@ import com.squareup.picasso.Picasso
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.partial_now_playing.* import kotlinx.android.synthetic.main.partial_now_playing.*
import kotlinx.android.synthetic.main.row_download.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope

View File

@ -158,8 +158,6 @@ class TracksAdapter(private val context: Context?, private val favoriteListener:
} }
notifyItemMoved(oldPosition, newPosition) notifyItemMoved(oldPosition, newPosition)
CommandBus.send(Command.MoveFromQueue(oldPosition, newPosition))
} }
inner class ViewHolder(view: View, val context: Context?) : RecyclerView.ViewHolder(view), View.OnClickListener { inner class ViewHolder(view: View, val context: Context?) : RecyclerView.ViewHolder(view), View.OnClickListener {
@ -186,6 +184,9 @@ class TracksAdapter(private val context: Context?, private val favoriteListener:
} }
inner class TouchHelperCallback : ItemTouchHelper.Callback() { inner class TouchHelperCallback : ItemTouchHelper.Callback() {
var from = -1
var to = -1
override fun isLongPressDragEnabled() = false override fun isLongPressDragEnabled() = false
override fun isItemViewSwipeEnabled() = false override fun isItemViewSwipeEnabled() = false
@ -194,7 +195,9 @@ class TracksAdapter(private val context: Context?, private val favoriteListener:
makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0)
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
onItemMove(viewHolder.adapterPosition, target.adapterPosition) to = target.adapterPosition
onItemMove(viewHolder.adapterPosition, to)
return true return true
} }
@ -204,7 +207,10 @@ class TracksAdapter(private val context: Context?, private val favoriteListener:
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) { if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
context?.let { context?.let {
viewHolder?.itemView?.background = ColorDrawable(context.getColor(R.color.colorSelected)) viewHolder?.let {
from = viewHolder.adapterPosition
viewHolder.itemView.background = ColorDrawable(context.getColor(R.color.colorSelected))
}
} }
} }
@ -212,6 +218,13 @@ class TracksAdapter(private val context: Context?, private val favoriteListener:
} }
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
if (from != -1 && to != -1) {
CommandBus.send(Command.MoveFromQueue(from, to))
from = -1
to = -1
}
viewHolder.itemView.background = ColorDrawable(Color.TRANSPARENT) viewHolder.itemView.background = ColorDrawable(Color.TRANSPARENT)
super.clearView(recyclerView, viewHolder) super.clearView(recyclerView, viewHolder)

View File

@ -24,7 +24,6 @@ import com.github.apognu.otter.repositories.AlbumsRepository
import com.github.apognu.otter.repositories.ArtistTracksRepository import com.github.apognu.otter.repositories.ArtistTracksRepository
import com.github.apognu.otter.repositories.Repository import com.github.apognu.otter.repositories.Repository
import com.github.apognu.otter.utils.* import com.github.apognu.otter.utils.*
import com.github.apognu.otter.views.LoadingFlotingActionButton
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
import kotlinx.android.synthetic.main.fragment_albums.* import kotlinx.android.synthetic.main.fragment_albums.*

View File

@ -59,7 +59,7 @@ class PlayerService : Service() {
private lateinit var radioPlayer: RadioPlayer private lateinit var radioPlayer: RadioPlayer
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
watchEventBus() if (jobs.isEmpty()) watchEventBus()
return START_STICKY return START_STICKY
} }
@ -235,7 +235,10 @@ class PlayerService : Service() {
@SuppressLint("NewApi") @SuppressLint("NewApi")
override fun onDestroy() { override fun onDestroy() {
jobs.forEach { it.cancel() } jobs.forEach {
it.cancel()
jobs.remove(it)
}
try { try {
unregisterReceiver(headphonesUnpluggedReceiver) unregisterReceiver(headphonesUnpluggedReceiver)
@ -356,7 +359,7 @@ class PlayerService : Service() {
when (playWhenReady) { when (playWhenReady) {
true -> { true -> {
when (playbackState) { when (playbackState) {
Player.STATE_READY -> mediaControlsManager.updateNotification(queue.current(), true) Player.STATE_READY -> player.onLocal()?.also { mediaControlsManager.updateNotification(queue.current(), true) }
Player.STATE_BUFFERING -> EventBus.send(Event.Buffering(true)) Player.STATE_BUFFERING -> EventBus.send(Event.Buffering(true))
Player.STATE_ENDED -> EventBus.send(Event.PlaybackStopped) Player.STATE_ENDED -> EventBus.send(Event.PlaybackStopped)
} }
@ -379,7 +382,7 @@ class PlayerService : Service() {
super.onTracksChanged(trackGroups, trackSelections) super.onTracksChanged(trackGroups, trackSelections)
queue.current = player.currentWindowIndex queue.current = player.currentWindowIndex
mediaControlsManager.updateNotification(queue.current(), player.playWhenReady) player.onLocal()?.also { mediaControlsManager.updateNotification(queue.current(), player.playWhenReady) }
if (queue.get().isNotEmpty() && queue.current() == queue.get().last() && radioPlayer.isActive()) { if (queue.get().isNotEmpty() && queue.current() == queue.get().last() && radioPlayer.isActive()) {
GlobalScope.launch(IO) { GlobalScope.launch(IO) {