diff --git a/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt b/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt index db1679dcb0..0e6cce976b 100644 --- a/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt +++ b/app/src/main/java/com/github/libretube/services/OfflinePlayerService.kt @@ -27,12 +27,11 @@ import com.github.libretube.extensions.updateParameters import com.github.libretube.helpers.PlayerHelper import com.github.libretube.obj.PlayerNotificationData import com.github.libretube.util.NowPlayingNotification +import com.github.libretube.util.PauseableTimer import kotlin.io.path.exists import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.util.Timer -import java.util.TimerTask /** * A service to play downloaded audio in the background @@ -45,7 +44,10 @@ class OfflinePlayerService : LifecycleService() { private lateinit var videoId: String private var downloadsWithItems: List = emptyList() - private var watchPositionTimer: Timer? = null + private val watchPositionTimer = PauseableTimer( + onTick = this::saveWatchPosition, + delayMillis = PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS + ) private val playerListener = object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { @@ -53,14 +55,9 @@ class OfflinePlayerService : LifecycleService() { // Start or pause watch position timer if (isPlaying) { - watchPositionTimer = Timer() - watchPositionTimer!!.scheduleAtFixedRate(object : TimerTask() { - override fun run() { - handler.post(this@OfflinePlayerService::saveWatchPosition) - } - }, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS) + watchPositionTimer.resume() } else { - watchPositionTimer?.cancel() + watchPositionTimer.pause() } } @@ -191,7 +188,7 @@ class OfflinePlayerService : LifecycleService() { player = null nowPlayingNotification = null - watchPositionTimer?.cancel() + watchPositionTimer.destroy() ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE) stopSelf() diff --git a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt index 3c37211286..d95b23d910 100644 --- a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt +++ b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt @@ -39,13 +39,12 @@ import com.github.libretube.helpers.ProxyHelper import com.github.libretube.obj.PlayerNotificationData import com.github.libretube.parcelable.PlayerData import com.github.libretube.util.NowPlayingNotification +import com.github.libretube.util.PauseableTimer import com.github.libretube.util.PlayingQueue import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.serialization.encodeToString -import java.util.Timer -import java.util.TimerTask /** * Loads the selected videos audio in background mode with a notification area. @@ -102,7 +101,10 @@ class OnlinePlayerService : LifecycleService() { var onStateOrPlayingChanged: ((isPlaying: Boolean) -> Unit)? = null var onNewVideo: ((streams: Streams, videoId: String) -> Unit)? = null - private var watchPositionTimer: Timer? = null + private val watchPositionTimer = PauseableTimer( + onTick = this::saveWatchPosition, + delayMillis = PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS + ) private val playerListener = object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { @@ -111,14 +113,9 @@ class OnlinePlayerService : LifecycleService() { // Start or pause watch position timer if (isPlaying) { - watchPositionTimer = Timer() - watchPositionTimer!!.scheduleAtFixedRate(object : TimerTask() { - override fun run() { - handler.post(this@OnlinePlayerService::saveWatchPosition) - } - }, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS) + watchPositionTimer.resume() } else { - watchPositionTimer?.cancel() + watchPositionTimer.pause() } } @@ -394,7 +391,7 @@ class OnlinePlayerService : LifecycleService() { player?.stop() player?.release() - watchPositionTimer?.cancel() + watchPositionTimer.destroy() // called when the user pressed stop in the notification // stop the service from being in the foreground and remove the notification diff --git a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt index 4ebed3c171..c6235b855f 100644 --- a/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt +++ b/app/src/main/java/com/github/libretube/ui/activities/OfflinePlayerActivity.kt @@ -4,8 +4,6 @@ import android.content.pm.ActivityInfo import android.media.session.PlaybackState import android.net.Uri import android.os.Bundle -import android.os.Handler -import android.os.Looper import android.text.format.DateUtils import android.view.KeyEvent import androidx.activity.viewModels @@ -40,17 +38,14 @@ import com.github.libretube.ui.interfaces.TimeFrameReceiver import com.github.libretube.ui.listeners.SeekbarPreviewListener import com.github.libretube.ui.models.PlayerViewModel import com.github.libretube.util.OfflineTimeFrameReceiver +import com.github.libretube.util.PauseableTimer import kotlin.io.path.exists import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.util.Timer -import java.util.TimerTask @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) class OfflinePlayerActivity : BaseActivity() { - private val handler = Handler(Looper.getMainLooper()) - private lateinit var binding: ActivityOfflinePlayerBinding private lateinit var videoId: String private lateinit var player: ExoPlayer @@ -61,7 +56,10 @@ class OfflinePlayerActivity : BaseActivity() { private lateinit var playerBinding: ExoStyledPlayerControlViewBinding private val playerViewModel: PlayerViewModel by viewModels() - private var watchPositionTimer: Timer? = null + private val watchPositionTimer = PauseableTimer( + onTick = this::saveWatchPosition, + delayMillis = PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS + ) private val playerListener = object : Player.Listener { override fun onEvents(player: Player, events: Player.Events) { @@ -77,14 +75,9 @@ class OfflinePlayerActivity : BaseActivity() { // Start or pause watch position timer if (isPlaying) { - watchPositionTimer = Timer() - watchPositionTimer!!.scheduleAtFixedRate(object : TimerTask() { - override fun run() { - handler.post(this@OfflinePlayerActivity::saveWatchPosition) - } - }, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS) + watchPositionTimer.resume() } else { - watchPositionTimer?.cancel() + watchPositionTimer.pause() } } @@ -255,7 +248,7 @@ class OfflinePlayerActivity : BaseActivity() { saveWatchPosition() player.release() - watchPositionTimer?.cancel() + watchPositionTimer.destroy() super.onDestroy() } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 298c2cf804..5c01fef0c3 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -108,6 +108,7 @@ import com.github.libretube.ui.sheets.PlayingQueueSheet import com.github.libretube.ui.sheets.StatsSheet import com.github.libretube.util.NowPlayingNotification import com.github.libretube.util.OnlineTimeFrameReceiver +import com.github.libretube.util.PauseableTimer import com.github.libretube.util.PlayingQueue import com.github.libretube.util.TextUtils import com.github.libretube.util.TextUtils.toTimeInSeconds @@ -236,7 +237,10 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { } // schedule task to save the watch position each second - private var watchPositionTimer: Timer? = null + private val watchPositionTimer = PauseableTimer( + onTick = this::saveWatchPosition, + delayMillis = PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS + ) private var bufferingTimeoutTask: Runnable? = null @@ -267,14 +271,9 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { // Start or pause watch position timer if (isPlaying) { - watchPositionTimer = Timer() - watchPositionTimer!!.scheduleAtFixedRate(object : TimerTask() { - override fun run() { - handler.post(this@PlayerFragment::saveWatchPosition) - } - }, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS, PlayerHelper.WATCH_POSITION_TIMER_DELAY_MS) + watchPositionTimer.resume() } else { - watchPositionTimer?.cancel() + watchPositionTimer.pause() } } @@ -835,7 +834,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { stopVideoPlay() - watchPositionTimer?.cancel() + watchPositionTimer.destroy() } private fun stopVideoPlay() { diff --git a/app/src/main/java/com/github/libretube/util/PauseableTimer.kt b/app/src/main/java/com/github/libretube/util/PauseableTimer.kt new file mode 100644 index 0000000000..e64d5bb323 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/PauseableTimer.kt @@ -0,0 +1,39 @@ +package com.github.libretube.util + +import android.os.Handler +import android.os.Looper +import java.util.Timer +import java.util.TimerTask + +class PauseableTimer( + private val onTick: () -> Unit, + private val delayMillis: Long = 1000L +) { + val handler: Handler = Handler(Looper.getMainLooper()) + + var timer: Timer? = null + + init { + resume() + } + + fun resume() { + if (timer == null) timer = Timer() + + timer?.scheduleAtFixedRate(object : TimerTask() { + override fun run() { + handler.post(onTick) + } + }, delayMillis, delayMillis) + } + + fun pause() { + timer?.cancel() + timer = null + } + + fun destroy() { + timer?.cancel() + timer = null + } +} \ No newline at end of file