feat:fix screen wake up when timer ends

This commit is contained in:
Fandroid745
2025-10-21 18:47:53 +05:30
parent 174a1627c3
commit 75d3029250
4 changed files with 78 additions and 2 deletions

View File

@@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.POST_PROMOTED_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_PROMOTED_NOTIFICATIONS" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application <application
android:name=".TomatoApplication" android:name=".TomatoApplication"

View File

@@ -20,7 +20,7 @@ import org.nsh07.pomodoro.utils.toColor
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private val timerViewModel: TimerViewModel by viewModels(factoryProducer = { TimerViewModel.Factory }) private val timerViewModel: TimerViewModel by viewModels(factoryProducer = { TimerViewModel.Factory })
private val settingsViewModel: SettingsViewModel by viewModels(factoryProducer = { SettingsViewModel.Factory }) private val settingsViewModel: SettingsViewModel by viewModels(factoryProducer = { SettingsViewModel.Factory })
private val appContainer by lazy { private val appContainer by lazy {
@@ -59,6 +59,7 @@ class MainActivity : ComponentActivity() {
} }
} }
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
// Reduce the timer loop frequency when not visible to save battery power // Reduce the timer loop frequency when not visible to save battery power

View File

@@ -2,11 +2,13 @@ package org.nsh07.pomodoro.service
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Service import android.app.Service
import android.content.Context
import android.content.Intent import android.content.Intent
import android.media.AudioAttributes import android.media.AudioAttributes
import android.media.MediaPlayer import android.media.MediaPlayer
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager
import android.os.SystemClock import android.os.SystemClock
import android.os.VibrationEffect import android.os.VibrationEffect
import android.os.Vibrator import android.os.Vibrator
@@ -22,6 +24,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.nsh07.pomodoro.MainActivity
import org.nsh07.pomodoro.R import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.TomatoApplication import org.nsh07.pomodoro.TomatoApplication
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode
@@ -59,6 +62,9 @@ class TimerService : Service() {
private var alarm: MediaPlayer? = null private var alarm: MediaPlayer? = null
private var wakeLock: PowerManager.WakeLock? = null
private val vibrator by lazy { private val vibrator by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val vibratorManager = getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager val vibratorManager = getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
@@ -89,6 +95,7 @@ class TimerService : Service() {
saveTimeToDb() saveTimeToDb()
notificationManager.cancel(1) notificationManager.cancel(1)
alarm?.release() alarm?.release()
wakeLock?.release()
} }
super.onDestroy() super.onDestroy()
} }
@@ -117,6 +124,7 @@ class TimerService : Service() {
return super.onStartCommand(intent, flags, startId) return super.onStartCommand(intent, flags, startId)
} }
@Suppress("DEPRECATION")
private fun toggleTimer() { private fun toggleTimer() {
updateProgressSegments() updateProgressSegments()
@@ -157,6 +165,20 @@ class TimerService : Service() {
if (iterations == 0) showTimerNotification(time.toInt()) if (iterations == 0) showTimerNotification(time.toInt())
if (time < 0) { if (time < 0) {
val powerManager = this@TimerService.getSystemService(POWER_SERVICE) as PowerManager
wakeLock = powerManager.newWakeLock(
PowerManager.FULL_WAKE_LOCK or
PowerManager.ACQUIRE_CAUSES_WAKEUP or
PowerManager.ON_AFTER_RELEASE,
"PomodoroApp:AlarmWakeLock"
)
wakeLock?.acquire(2 * 60 * 1000L)
val intent = Intent(this@TimerService, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
startActivity(intent)
skipTimer() skipTimer()
_timerState.update { currentState -> _timerState.update { currentState ->
currentState.copy(timerRunning = false) currentState.copy(timerRunning = false)
@@ -176,7 +198,7 @@ class TimerService : Service() {
} }
} }
@SuppressLint("MissingPermission") // We check for the permission when pressing the Play button in the UI @SuppressLint("MissingPermission", "StringFormatInvalid") // We check for the permission when pressing the Play button in the UI
fun showTimerNotification( fun showTimerNotification(
remainingTime: Int, paused: Boolean = false, complete: Boolean = false remainingTime: Int, paused: Boolean = false, complete: Boolean = false
) { ) {
@@ -372,6 +394,9 @@ class TimerService : Service() {
vibrator.cancel() vibrator.cancel()
} }
wakeLock?.release()
wakeLock = null
_timerState.update { currentState -> _timerState.update { currentState ->
currentState.copy(alarmRinging = false) currentState.copy(alarmRinging = false)
} }

View File

@@ -7,6 +7,11 @@
package org.nsh07.pomodoro.ui.timerScreen package org.nsh07.pomodoro.ui.timerScreen
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.os.Build
import android.view.WindowManager
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -24,8 +29,10 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -37,6 +44,38 @@ fun AlarmDialog(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
stopAlarm: () -> Unit stopAlarm: () -> Unit
) { ) {
val context = LocalContext.current
val activity = context.findActivity()
// Set lockscreen flags when dialog appears, remove when it disappears
DisposableEffect(Unit) {
// Show over lockscreen
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
activity?.setShowWhenLocked(true)
activity?.setTurnScreenOn(true)
} else {
@Suppress("DEPRECATION")
activity?.window?.addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
}
onDispose {
// Remove lockscreen flags when dialog is dismissed
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
activity?.setShowWhenLocked(false)
activity?.setTurnScreenOn(false)
} else {
@Suppress("DEPRECATION")
activity?.window?.clearFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
}
}
}
BasicAlertDialog( BasicAlertDialog(
onDismissRequest = stopAlarm, onDismissRequest = stopAlarm,
modifier = modifier modifier = modifier
@@ -75,4 +114,14 @@ fun AlarmDialog(
} }
} }
} }
}
// Add this helper function at the file level (outside the composable)
fun Context.findActivity(): Activity? {
var context = this
while (context is ContextWrapper) {
if (context is Activity) return context
context = context.baseContext
}
return null
} }