Skip to content
Open
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 @@ -7,6 +7,7 @@ data class UserSettings(
val softScreenOff: Boolean = false,
val turnOffWifi: Boolean = false,
val turnOffBluetooth: Boolean = false,
val returnToHome: Boolean = false,
val hapticFeedbackEnabled: Boolean = true,
val theme: ThemeId = ThemeId.Default,
val starsEnabled: Boolean = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface SettingsRepository {
suspend fun updateSoftScreenOff(enabled: Boolean)
suspend fun updateTurnOffWifi(enabled: Boolean)
suspend fun updateTurnOffBluetooth(enabled: Boolean)
suspend fun updateReturnToHome(enabled: Boolean)
suspend fun updateHapticFeedback(enabled: Boolean)
suspend fun updateTheme(theme: ThemeId)
suspend fun updateStarsEnabled(enabled: Boolean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class SettingsRepositoryImpl @Inject constructor(
val SOFT_SCREEN_OFF = booleanPreferencesKey("soft_screen_off")
val TURN_OFF_WIFI = booleanPreferencesKey("turn_off_wifi")
val TURN_OFF_BLUETOOTH = booleanPreferencesKey("turn_off_bluetooth")
val RETURN_TO_HOME = booleanPreferencesKey("return_to_home")
val HAPTIC_FEEDBACK = booleanPreferencesKey("haptic_feedback")
val THEME = stringPreferencesKey("theme")
val STARS_ENABLED = booleanPreferencesKey("stars_enabled")
Expand Down Expand Up @@ -92,6 +93,7 @@ class SettingsRepositoryImpl @Inject constructor(
softScreenOff = prefs[SOFT_SCREEN_OFF] ?: d.softScreenOff,
turnOffWifi = prefs[TURN_OFF_WIFI] ?: d.turnOffWifi,
turnOffBluetooth = prefs[TURN_OFF_BLUETOOTH] ?: d.turnOffBluetooth,
returnToHome = prefs[RETURN_TO_HOME] ?: d.returnToHome,
hapticFeedbackEnabled = prefs[HAPTIC_FEEDBACK] ?: d.hapticFeedbackEnabled,
theme = ThemeId.fromStorage(prefs[THEME]),
starsEnabled = prefs[STARS_ENABLED] ?: d.starsEnabled,
Expand Down Expand Up @@ -128,6 +130,10 @@ class SettingsRepositoryImpl @Inject constructor(
dataStore.edit { it[TURN_OFF_BLUETOOTH] = enabled }
}

override suspend fun updateReturnToHome(enabled: Boolean) {
dataStore.edit { it[RETURN_TO_HOME] = enabled }
}

override suspend fun updateHapticFeedback(enabled: Boolean) {
dataStore.edit { it[HAPTIC_FEEDBACK] = enabled }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import dev.xitee.sleeptimer.core.service.media.MediaVolumeController
import dev.xitee.sleeptimer.core.service.notification.TimerNotificationManager
import dev.xitee.sleeptimer.core.service.screen.ScreenLockHelper
import dev.xitee.sleeptimer.core.service.shizuku.ShizukuBluetoothController
import dev.xitee.sleeptimer.core.service.shizuku.ShizukuHomeController
import dev.xitee.sleeptimer.core.service.shizuku.ShizukuManager
import dev.xitee.sleeptimer.core.service.shizuku.ShizukuScreenOffHelper
import dev.xitee.sleeptimer.core.service.shizuku.ShizukuWifiController
Expand Down Expand Up @@ -49,6 +50,7 @@ class SleepTimerService : Service() {
@Inject lateinit var shizukuScreenOffHelper: ShizukuScreenOffHelper
@Inject lateinit var shizukuWifiController: ShizukuWifiController
@Inject lateinit var shizukuBluetoothController: ShizukuBluetoothController
@Inject lateinit var shizukuHomeController: ShizukuHomeController

private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private var countdownJob: Job? = null
Expand Down Expand Up @@ -303,6 +305,15 @@ class SleepTimerService : Service() {
shizukuBluetoothController.disableBluetooth()
}

if (settings.returnToHome && shizukuManager.isReady()) {
// KEYCODE_HOME wakes a sleeping device, so only send it while the
// screen is still on. Runs before the screen-off step so the launcher
// — not the media app — is what greets the user at the next unlock.
if (powerManager.isInteractive) {
shizukuHomeController.goHome()
}
}

if (settings.screenOff) {
if (settings.softScreenOff && shizukuManager.isReady()) {
// KEYCODE_POWER is a toggle: only send it while the screen is on,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dev.xitee.sleeptimer.core.service.shizuku

import javax.inject.Inject
import javax.inject.Singleton

/**
* Returns to the home screen via a simulated home key press (KEYCODE_HOME = 3).
* Goes through Shizuku because Android 10+ blocks background activity launches,
* so a plain ACTION_MAIN/CATEGORY_HOME startActivity from the service would be
* silently dropped while another app is in the foreground.
*/
@Singleton
class ShizukuHomeController @Inject constructor(
private val shell: ShizukuShell,
) {
suspend fun goHome(): Boolean = shell.exec("input", "keyevent", "3")
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material.icons.filled.Bluetooth
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.MusicOff
import androidx.compose.material.icons.filled.PhoneAndroid
Expand Down Expand Up @@ -106,6 +107,7 @@ private fun SettingsContent(
stringResource(R.string.shizuku_feature_soft_screen_off)
val shizukuWifiExplanation = stringResource(R.string.shizuku_feature_wifi)
val shizukuBluetoothExplanation = stringResource(R.string.shizuku_feature_bluetooth)
val shizukuReturnHomeExplanation = stringResource(R.string.shizuku_feature_return_home)

val deviceAdminLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.StartActivityForResult(),
Expand Down Expand Up @@ -323,6 +325,22 @@ private fun SettingsContent(
},
)

SettingsToggleRow(
icon = Icons.Default.Home,
title = stringResource(R.string.return_home_title),
description = stringResource(R.string.return_home_description),
checked = uiState.settings.returnToHome,
onCheckedChange = { enabled ->
if (enabled) {
requestWithShizuku(shizukuReturnHomeExplanation) {
viewModel.updateReturnToHome(true)
}
} else {
viewModel.updateReturnToHome(false)
}
},
)

SectionHeader(stringResource(R.string.category_haptic))
SettingsToggleRow(
icon = Icons.Default.Vibration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ class SettingsViewModel @Inject constructor(
viewModelScope.launch { settingsRepository.updateTurnOffBluetooth(enabled) }
}

fun updateReturnToHome(enabled: Boolean) {
viewModelScope.launch { settingsRepository.updateReturnToHome(enabled) }
}

fun updateHapticFeedback(enabled: Boolean) {
viewModelScope.launch { settingsRepository.updateHapticFeedback(enabled) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ private fun TimerContent(
ShizukuFeature.SCREEN_OFF -> stringResource(R.string.shizuku_feature_label_display)
ShizukuFeature.WIFI -> stringResource(R.string.shizuku_feature_label_wifi)
ShizukuFeature.BLUETOOTH -> stringResource(R.string.shizuku_feature_label_bluetooth)
ShizukuFeature.RETURN_HOME -> stringResource(R.string.shizuku_feature_label_return_home)
}
}
ShizukuRequiredDialog(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class TimerViewModel @Inject constructor(
if (s.screenOff && s.softScreenOff && !shizukuReady) add(ShizukuFeature.SCREEN_OFF)
if (s.turnOffWifi && !shizukuReady) add(ShizukuFeature.WIFI)
if (s.turnOffBluetooth && !shizukuReady) add(ShizukuFeature.BLUETOOTH)
if (s.returnToHome && !shizukuReady) add(ShizukuFeature.RETURN_HOME)
}
return StartupPermissionCheck(adminMissing, shizukuFeatures)
}
Expand Down Expand Up @@ -178,4 +179,4 @@ data class StartupPermissionCheck(
val shizukuMissingFeatures: List<ShizukuFeature>,
)

enum class ShizukuFeature { SCREEN_OFF, WIFI, BLUETOOTH }
enum class ShizukuFeature { SCREEN_OFF, WIFI, BLUETOOTH, RETURN_HOME }
4 changes: 4 additions & 0 deletions feature/timer/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@
<string name="shizuku_feature_soft_screen_off">Sanftes Bildschirmabschalten simuliert einen Druck der Power-Taste via Shizuku, sodass die biometrische Entsperrung weiterhin funktioniert.</string>
<string name="shizuku_feature_wifi">WLAN nach Timer-Ende auszuschalten erfordert Shizuku, da moderne Android-Versionen Apps das direkte Umschalten von WLAN verbieten.</string>
<string name="shizuku_feature_bluetooth">Bluetooth nach Timer-Ende auszuschalten erfordert Shizuku, da moderne Android-Versionen Apps das direkte Umschalten von Bluetooth verbieten.</string>
<string name="shizuku_feature_return_home">Nach Timer-Ende zum Startbildschirm zurückzukehren erfordert Shizuku, da moderne Android-Versionen Apps den Wechsel zu einem anderen Bildschirm aus dem Hintergrund verbieten.</string>

<!-- Kurzbezeichnungen für die Bullet-Liste im Startup-Dialog -->
<string name="shizuku_feature_label_display">Display ausschalten</string>
<string name="shizuku_feature_label_wifi">WLAN ausschalten</string>
<string name="shizuku_feature_label_bluetooth">Bluetooth ausschalten</string>
<string name="shizuku_feature_label_return_home">Zum Startbildschirm zurückkehren</string>
<string name="shizuku_startup_intro">Die Shizuku-Berechtigung fehlt für folgende aktivierte Funktionen:</string>

<!-- Geräteadministrator-Dialog (beim Start) -->
Expand All @@ -88,6 +90,8 @@
<string name="wifi_off_description">WLAN deaktivieren (Shizuku benötigt)</string>
<string name="bluetooth_off_title">Bluetooth ausschalten</string>
<string name="bluetooth_off_description">Bluetooth deaktivieren (Shizuku benötigt)</string>
<string name="return_home_title">Zum Startbildschirm zurückkehren</string>
<string name="return_home_description">Nach Timer-Ende zum Startbildschirm wechseln (Shizuku benötigt)</string>

<!-- Sperrmethoden-Dialog -->
<string name="screen_method_dialog_title">Sperrmethode wählen</string>
Expand Down
4 changes: 4 additions & 0 deletions feature/timer/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@
<string name="shizuku_feature_soft_screen_off">Soft screen-off simulates a power-button press via Shizuku, so biometric unlock keeps working.</string>
<string name="shizuku_feature_wifi">Turning off Wi-Fi after the timer ends requires Shizuku because modern Android versions block apps from toggling Wi-Fi directly.</string>
<string name="shizuku_feature_bluetooth">Turning off Bluetooth after the timer ends requires Shizuku because modern Android versions block apps from toggling Bluetooth directly.</string>
<string name="shizuku_feature_return_home">Returning to the home screen after the timer ends requires Shizuku because modern Android versions block apps from switching to another screen from the background.</string>

<!-- Short feature labels used in the startup permission dialog's bullet list -->
<string name="shizuku_feature_label_display">Turn off display</string>
<string name="shizuku_feature_label_wifi">Turn off Wi-Fi</string>
<string name="shizuku_feature_label_bluetooth">Turn off Bluetooth</string>
<string name="shizuku_feature_label_return_home">Return to home screen</string>
<string name="shizuku_startup_intro">Shizuku permission is missing for the following enabled features:</string>

<!-- Device admin required dialog (startup) -->
Expand All @@ -88,6 +90,8 @@
<string name="wifi_off_description">Disable Wi-Fi when timer ends (requires Shizuku)</string>
<string name="bluetooth_off_title">Turn off Bluetooth</string>
<string name="bluetooth_off_description">Disable Bluetooth when timer ends (requires Shizuku)</string>
<string name="return_home_title">Return to home screen</string>
<string name="return_home_description">Go to the home screen when timer ends (requires Shizuku)</string>

<!-- Screen-lock method dialog -->
<string name="screen_method_dialog_title">Choose lock method</string>
Expand Down
Loading