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:
parent
9ed7eab761
commit
080cce00ee
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.*
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue