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_PROMOTED_NOTIFICATIONS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name=".TomatoApplication"

View File

@@ -20,7 +20,7 @@ import org.nsh07.pomodoro.utils.toColor
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 appContainer by lazy {
@@ -59,6 +59,7 @@ class MainActivity : ComponentActivity() {
}
}
override fun onStop() {
super.onStop()
// 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.app.Service
import android.content.Context
import android.content.Intent
import android.media.AudioAttributes
import android.media.MediaPlayer
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
import android.os.SystemClock
import android.os.VibrationEffect
import android.os.Vibrator
@@ -22,6 +24,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.nsh07.pomodoro.MainActivity
import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.TomatoApplication
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode
@@ -59,6 +62,9 @@ class TimerService : Service() {
private var alarm: MediaPlayer? = null
private var wakeLock: PowerManager.WakeLock? = null
private val vibrator by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val vibratorManager = getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
@@ -89,6 +95,7 @@ class TimerService : Service() {
saveTimeToDb()
notificationManager.cancel(1)
alarm?.release()
wakeLock?.release()
}
super.onDestroy()
}
@@ -117,6 +124,7 @@ class TimerService : Service() {
return super.onStartCommand(intent, flags, startId)
}
@Suppress("DEPRECATION")
private fun toggleTimer() {
updateProgressSegments()
@@ -157,6 +165,20 @@ class TimerService : Service() {
if (iterations == 0) showTimerNotification(time.toInt())
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()
_timerState.update { currentState ->
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(
remainingTime: Int, paused: Boolean = false, complete: Boolean = false
) {
@@ -372,6 +394,9 @@ class TimerService : Service() {
vibrator.cancel()
}
wakeLock?.release()
wakeLock = null
_timerState.update { currentState ->
currentState.copy(alarmRinging = false)
}

View File

@@ -7,6 +7,11 @@
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.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -24,8 +29,10 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@@ -37,6 +44,38 @@ fun AlarmDialog(
modifier: Modifier = Modifier,
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(
onDismissRequest = stopAlarm,
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
}