mirror of
https://github.com/antebudimir/tempus.git
synced 2025-12-31 17:43:32 +00:00
fix(widget): resume progress updates during playback
The widget was only updating on play/pause state changes, so the timer did not advance while playback continued. Added a Handler loop in MediaService that updates the widget every second while playback is running and clears it when playback stops, ensuring the progress bar refreshes regularly. Co-Authored-By: Firehawk <firehawk@opayq.net>
This commit is contained in:
parent
e81e1a5356
commit
b79cfa4af0
3 changed files with 111 additions and 0 deletions
|
|
@ -8,6 +8,8 @@ import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import androidx.media3.common.*
|
import androidx.media3.common.*
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.exoplayer.DefaultLoadControl
|
import androidx.media3.exoplayer.DefaultLoadControl
|
||||||
|
|
@ -40,6 +42,18 @@ class MediaService : MediaLibraryService() {
|
||||||
lateinit var equalizerManager: EqualizerManager
|
lateinit var equalizerManager: EqualizerManager
|
||||||
|
|
||||||
private var customLayout = ImmutableList.of<CommandButton>()
|
private var customLayout = ImmutableList.of<CommandButton>()
|
||||||
|
private val widgetUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
|
private var widgetUpdateScheduled = false
|
||||||
|
private val widgetUpdateRunnable = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (!player.isPlaying) {
|
||||||
|
widgetUpdateScheduled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateWidget()
|
||||||
|
widgetUpdateHandler.postDelayed(this, WIDGET_UPDATE_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inner class LocalBinder : Binder() {
|
inner class LocalBinder : Binder() {
|
||||||
fun getEqualizerManager(): EqualizerManager {
|
fun getEqualizerManager(): EqualizerManager {
|
||||||
|
|
@ -81,6 +95,7 @@ class MediaService : MediaLibraryService() {
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
equalizerManager.release()
|
equalizerManager.release()
|
||||||
|
stopWidgetUpdates()
|
||||||
releasePlayer()
|
releasePlayer()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
@ -281,6 +296,11 @@ class MediaService : MediaLibraryService() {
|
||||||
} else {
|
} else {
|
||||||
MediaManager.scrobble(player.currentMediaItem, false)
|
MediaManager.scrobble(player.currentMediaItem, false)
|
||||||
}
|
}
|
||||||
|
if (isPlaying) {
|
||||||
|
scheduleWidgetUpdates()
|
||||||
|
} else {
|
||||||
|
stopWidgetUpdates()
|
||||||
|
}
|
||||||
updateWidget()
|
updateWidget()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,6 +347,9 @@ class MediaService : MediaLibraryService() {
|
||||||
mediaLibrarySession.setCustomLayout(customLayout)
|
mediaLibrarySession.setCustomLayout(customLayout)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (player.isPlaying) {
|
||||||
|
scheduleWidgetUpdates()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setPlayer(player: Player) {
|
private fun setPlayer(player: Player) {
|
||||||
|
|
@ -407,9 +430,23 @@ class MediaService : MediaLibraryService() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun scheduleWidgetUpdates() {
|
||||||
|
if (widgetUpdateScheduled) return
|
||||||
|
widgetUpdateHandler.postDelayed(widgetUpdateRunnable, WIDGET_UPDATE_INTERVAL_MS)
|
||||||
|
widgetUpdateScheduled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopWidgetUpdates() {
|
||||||
|
if (!widgetUpdateScheduled) return
|
||||||
|
widgetUpdateHandler.removeCallbacks(widgetUpdateRunnable)
|
||||||
|
widgetUpdateScheduled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
|
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
|
||||||
|
|
||||||
private fun getMediaSourceFactory() =
|
private fun getMediaSourceFactory() =
|
||||||
DefaultMediaSourceFactory(this).setDataSourceFactory(DownloadUtil.getDataSourceFactory(this))
|
DefaultMediaSourceFactory(this).setDataSourceFactory(DownloadUtil.getDataSourceFactory(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val WIDGET_UPDATE_INTERVAL_MS = 1000L
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import android.app.TaskStackBuilder
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import androidx.media3.cast.CastPlayer
|
import androidx.media3.cast.CastPlayer
|
||||||
import androidx.media3.cast.SessionAvailabilityListener
|
import androidx.media3.cast.SessionAvailabilityListener
|
||||||
import androidx.media3.common.AudioAttributes
|
import androidx.media3.common.AudioAttributes
|
||||||
|
|
@ -50,6 +52,18 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
||||||
}
|
}
|
||||||
|
private val widgetUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
|
private var widgetUpdateScheduled = false
|
||||||
|
private val widgetUpdateRunnable = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (!player.isPlaying) {
|
||||||
|
widgetUpdateScheduled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateWidget()
|
||||||
|
widgetUpdateHandler.postDelayed(this, WIDGET_UPDATE_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
@ -81,6 +95,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
equalizerManager.release()
|
equalizerManager.release()
|
||||||
|
stopWidgetUpdates()
|
||||||
releasePlayer()
|
releasePlayer()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +197,11 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
} else {
|
} else {
|
||||||
MediaManager.scrobble(player.currentMediaItem, false)
|
MediaManager.scrobble(player.currentMediaItem, false)
|
||||||
}
|
}
|
||||||
|
if (isPlaying) {
|
||||||
|
scheduleWidgetUpdates()
|
||||||
|
} else {
|
||||||
|
stopWidgetUpdates()
|
||||||
|
}
|
||||||
updateWidget()
|
updateWidget()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,6 +251,9 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (player.isPlaying) {
|
||||||
|
scheduleWidgetUpdates()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWidget() {
|
private fun updateWidget() {
|
||||||
|
|
@ -254,6 +277,18 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun scheduleWidgetUpdates() {
|
||||||
|
if (widgetUpdateScheduled) return
|
||||||
|
widgetUpdateHandler.postDelayed(widgetUpdateRunnable, WIDGET_UPDATE_INTERVAL_MS)
|
||||||
|
widgetUpdateScheduled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopWidgetUpdates() {
|
||||||
|
if (!widgetUpdateScheduled) return
|
||||||
|
widgetUpdateHandler.removeCallbacks(widgetUpdateRunnable)
|
||||||
|
widgetUpdateScheduled = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun initializeLoadControl(): DefaultLoadControl {
|
private fun initializeLoadControl(): DefaultLoadControl {
|
||||||
return DefaultLoadControl.Builder()
|
return DefaultLoadControl.Builder()
|
||||||
.setBufferDurationsMs(
|
.setBufferDurationsMs(
|
||||||
|
|
@ -316,3 +351,5 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
player.prepare()
|
player.prepare()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val WIDGET_UPDATE_INTERVAL_MS = 1000L
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import android.app.TaskStackBuilder
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import androidx.media3.cast.CastPlayer
|
import androidx.media3.cast.CastPlayer
|
||||||
import androidx.media3.cast.SessionAvailabilityListener
|
import androidx.media3.cast.SessionAvailabilityListener
|
||||||
import androidx.media3.common.AudioAttributes
|
import androidx.media3.common.AudioAttributes
|
||||||
|
|
@ -50,6 +52,18 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
||||||
}
|
}
|
||||||
|
private val widgetUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
|
private var widgetUpdateScheduled = false
|
||||||
|
private val widgetUpdateRunnable = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (!player.isPlaying) {
|
||||||
|
widgetUpdateScheduled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateWidget()
|
||||||
|
widgetUpdateHandler.postDelayed(this, WIDGET_UPDATE_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
@ -81,6 +95,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
equalizerManager.release()
|
equalizerManager.release()
|
||||||
|
stopWidgetUpdates()
|
||||||
releasePlayer()
|
releasePlayer()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +197,11 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
} else {
|
} else {
|
||||||
MediaManager.scrobble(player.currentMediaItem, false)
|
MediaManager.scrobble(player.currentMediaItem, false)
|
||||||
}
|
}
|
||||||
|
if (isPlaying) {
|
||||||
|
scheduleWidgetUpdates()
|
||||||
|
} else {
|
||||||
|
stopWidgetUpdates()
|
||||||
|
}
|
||||||
updateWidget()
|
updateWidget()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,6 +251,9 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (player.isPlaying) {
|
||||||
|
scheduleWidgetUpdates()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWidget() {
|
private fun updateWidget() {
|
||||||
|
|
@ -253,6 +276,18 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun scheduleWidgetUpdates() {
|
||||||
|
if (widgetUpdateScheduled) return
|
||||||
|
widgetUpdateHandler.postDelayed(widgetUpdateRunnable, WIDGET_UPDATE_INTERVAL_MS)
|
||||||
|
widgetUpdateScheduled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopWidgetUpdates() {
|
||||||
|
if (!widgetUpdateScheduled) return
|
||||||
|
widgetUpdateHandler.removeCallbacks(widgetUpdateRunnable)
|
||||||
|
widgetUpdateScheduled = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun initializeLoadControl(): DefaultLoadControl {
|
private fun initializeLoadControl(): DefaultLoadControl {
|
||||||
return DefaultLoadControl.Builder()
|
return DefaultLoadControl.Builder()
|
||||||
.setBufferDurationsMs(
|
.setBufferDurationsMs(
|
||||||
|
|
@ -314,3 +349,5 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
||||||
player.prepare()
|
player.prepare()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val WIDGET_UPDATE_INTERVAL_MS = 1000L
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue