Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #1593: set sleep timer without exact alarm #1599

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@
*/
package code.name.monkey.retromusic.dialogs

import android.app.AlarmManager
import android.app.Dialog
import android.app.PendingIntent
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.os.SystemClock
Expand All @@ -27,18 +24,13 @@ import android.widget.SeekBar
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.getSystemService
import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.DialogSleepTimerBinding
import code.name.monkey.retromusic.extensions.addAccentColor
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_PENDING_QUIT
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_QUIT
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil

Expand Down Expand Up @@ -97,42 +89,26 @@ class SleepTimerDialog : DialogFragment() {
setPositiveButton(android.R.string.ok, null)
setNegativeButton(R.string.action_cancel) { _, _ ->
timerUpdater.cancel()
val previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE)
if (previous != null) {
val am = requireContext().getSystemService<AlarmManager>()
am?.cancel(previous)
previous.cancel()
Toast.makeText(
requireContext(),
requireContext().resources.getString(R.string.sleep_timer_canceled),
Toast.LENGTH_SHORT
).show()
val musicService = MusicPlayerRemote.musicService
if (musicService != null && musicService.pendingQuit) {
musicService.pendingQuit = false
Toast.makeText(
requireContext(),
requireContext().resources.getString(R.string.sleep_timer_canceled),
Toast.LENGTH_SHORT
).show()
}
}

MusicPlayerRemote.musicService?.sleepTimer?.stopTimer()
Toast.makeText(
requireContext(),
requireContext().resources.getString(R.string.sleep_timer_canceled),
Toast.LENGTH_SHORT
).show()
}
} else {
seekBar.isVisible = true
shouldFinishLastSong.isVisible = true
setPositiveButton(R.string.action_set) { _, _ ->
PreferenceUtil.isSleepTimerFinishMusic = shouldFinishLastSong.isChecked
val minutes = seekArcProgress
val pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT)
val nextSleepTimerElapsedTime =
SystemClock.elapsedRealtime() + minutes * 60 * 1000
PreferenceUtil.nextSleepTimerElapsedRealTime = nextSleepTimerElapsedTime.toInt()
val am = requireContext().getSystemService<AlarmManager>()
am?.setExact(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
MusicPlayerRemote.musicService?.sleepTimer?.startTimer(
nextSleepTimerElapsedTime,
pi
shouldFinishLastSong.isChecked
)

Toast.makeText(
Expand All @@ -153,21 +129,6 @@ class SleepTimerDialog : DialogFragment() {
timerDisplay.text = "$seekArcProgress min"
}

private fun makeTimerPendingIntent(flag: Int): PendingIntent? {
return PendingIntent.getService(
requireActivity(), 0, makeTimerIntent(), flag or if (VersionUtils.hasMarshmallow())
PendingIntent.FLAG_IMMUTABLE
else 0
)
}

private fun makeTimerIntent(): Intent {
val intent = Intent(requireActivity(), MusicService::class.java)
return if (shouldFinishLastSong.isChecked) {
intent.setAction(ACTION_PENDING_QUIT)
} else intent.setAction(ACTION_QUIT)
}

override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
timerUpdater.cancel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import code.name.monkey.retromusic.service.notification.PlayingNotificationClass
import code.name.monkey.retromusic.service.notification.PlayingNotificationImpl24
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.service.playback.Playback.PlaybackCallbacks
import code.name.monkey.retromusic.service.playback.PlaybackSleepTimer
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.MusicUtil.toggleFavorite
import code.name.monkey.retromusic.util.PackageValidator
Expand Down Expand Up @@ -107,9 +108,6 @@ class MusicService : MediaBrowserServiceCompat(),
@JvmField
var nextPosition = -1

@JvmField
var pendingQuit = false

private lateinit var playbackManager: PlaybackManager

val playback: Playback? get() = playbackManager.playback
Expand Down Expand Up @@ -271,6 +269,14 @@ class MusicService : MediaBrowserServiceCompat(),
private var wakeLock: WakeLock? = null
private var notificationManager: NotificationManager? = null
private var isForeground = false
val sleepTimer = PlaybackSleepTimer(
pausePlayback = {
notifyChange(PLAY_STATE_CHANGED)
seek(0, false)
quit()
}
)

override fun onCreate() {
super.onCreate()
val powerManager = getSystemService<PowerManager>()
Expand Down Expand Up @@ -685,11 +691,8 @@ class MusicService : MediaBrowserServiceCompat(),
ACTION_REWIND -> back(true)
ACTION_SKIP -> playNextSong(true)
ACTION_STOP, ACTION_QUIT -> {
pendingQuit = false
quit()
}

ACTION_PENDING_QUIT -> pendingQuit = true
TOGGLE_FAVORITE -> toggleFavorite()
}
}
Expand All @@ -700,13 +703,13 @@ class MusicService : MediaBrowserServiceCompat(),
override fun onTrackEnded() {
acquireWakeLock()
// if there is a timer finished, don't continue
val pendingQuit = sleepTimer.onTrackEnded()
if (pendingQuit
|| repeatMode == REPEAT_MODE_NONE && isLastTrack
) {
notifyChange(PLAY_STATE_CHANGED)
seek(0, false)
if (pendingQuit) {
pendingQuit = false
quit()
}
} else {
Expand All @@ -721,12 +724,12 @@ class MusicService : MediaBrowserServiceCompat(),
}

override fun onTrackWentToNext() {
val pendingQuit = sleepTimer.onTrackEnded()
if (pendingQuit || repeatMode == REPEAT_MODE_NONE && isLastTrack) {
playbackManager.setNextDataSource(null)
pause(false)
seek(0, false)
if (pendingQuit) {
pendingQuit = false
quit()
}
} else {
Expand Down Expand Up @@ -1387,7 +1390,6 @@ class MusicService : MediaBrowserServiceCompat(),
const val ACTION_SKIP = "$RETRO_MUSIC_PACKAGE_NAME.skip"
const val ACTION_REWIND = "$RETRO_MUSIC_PACKAGE_NAME.rewind"
const val ACTION_QUIT = "$RETRO_MUSIC_PACKAGE_NAME.quitservice"
const val ACTION_PENDING_QUIT = "$RETRO_MUSIC_PACKAGE_NAME.pendingquitservice"
const val INTENT_EXTRA_PLAYLIST = RETRO_MUSIC_PACKAGE_NAME + "intentextra.playlist"
const val INTENT_EXTRA_SHUFFLE_MODE =
"$RETRO_MUSIC_PACKAGE_NAME.intentextra.shufflemode"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package code.name.monkey.retromusic.service.playback

import android.os.Handler
import android.os.Looper
import android.util.Log
import java.util.Date
import kotlin.math.max

class PlaybackSleepTimer(
private val pausePlayback: () -> Unit
) {
private var handler: Handler? = null
private var playToEnd: Boolean = false
private var startTime: Date? = null
private var delay: Long = 0L

/**
* Start the sleep timer.
*
* @param delayMillis time in milliseconds until the sleep timer should sleep.
* @param playToEnd whether to wait until the current track ends before pausing playback.
*/
fun startTimer(
delayMillis: Long,
playToEnd: Boolean
){
Log.v("PlaybackSleepTimer", "startTimer() called.. Delay: ${delay}ms")

this.startTime = Date()
this.delay = delayMillis
this.playToEnd = playToEnd
handler?.removeCallbacksAndMessages(null)
handler = Handler(Looper.getMainLooper())

handler?.postDelayed({
if (!playToEnd) {
sleep()
}
}, delay)
}

/**
* Cancels the sleep timer
*/
fun stopTimer() {
Log.v("PlaybackSleepTimer","stopTimer() called")

}

/**
* @return the time remaining until sleep, or null if the sleep timer has not been started.
*/
fun timeRemaining(): Long? {
startTime?.let { startTime ->
return max(0L, delay - (Date().time - startTime.time))
}

return null
}

private fun sleep() {
Log.v("PlaybackSleepTimer","sleep() called")
pausePlayback()
stopTimer()
}

/**
* This function should be called in the playback callback for when a track is ended
* so playToEnd parameter can work properly
* @return true if timer stopped playback
*/
fun onTrackEnded(): Boolean {
Log.v("PlaybackSleepTimer","onPlaybackComplete, playToEnd: $playToEnd, timeRemaining: ${timeRemaining()}")
if (playToEnd && timeRemaining() == 0L) {
sleep()
return true
}
return false
}
}