diff --git a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt index debe3a5f9..3a012b9a4 100644 --- a/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt +++ b/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt @@ -108,6 +108,7 @@ class SettingsRepository(private val context: Context) { const val KEY_FLASHLIGHT_PULSE_ENABLED = "flashlight_pulse_enabled" const val KEY_FLASHLIGHT_PULSE_FACEDOWN_ONLY = "flashlight_pulse_facedown_only" const val KEY_FLASHLIGHT_PULSE_MAX_INTENSITY = "flashlight_pulse_max_intensity" + const val KEY_FLASHLIGHT_POCKET_TURN_OFF_ENABLED = "flashlight_pocket_turn_off_enabled" const val KEY_SCREEN_LOCKED_SECURITY_ENABLED = "screen_locked_security_enabled" const val KEY_HIDE_SYSTEM_ICONS = "hide_system_icons" diff --git a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt index 47dd20bfd..50c93722e 100644 --- a/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt +++ b/app/src/main/java/com/sameerasw/essentials/domain/registry/FeatureRegistry.kt @@ -707,6 +707,12 @@ object FeatureRegistry { R.string.search_remap_flashlight_desc, "flashlight_toggle", R.array.keywords_flashlight + ), + SearchSetting( + R.string.search_flashlight_pocket_title, + R.string.search_flashlight_pocket_desc, + "flashlight_options", + R.array.keywords_pocket_detection ) ), parentFeatureId = "Input", diff --git a/app/src/main/java/com/sameerasw/essentials/services/tiles/ScreenOffAccessibilityService.kt b/app/src/main/java/com/sameerasw/essentials/services/tiles/ScreenOffAccessibilityService.kt index 0ea641a9a..8873814e0 100644 --- a/app/src/main/java/com/sameerasw/essentials/services/tiles/ScreenOffAccessibilityService.kt +++ b/app/src/main/java/com/sameerasw/essentials/services/tiles/ScreenOffAccessibilityService.kt @@ -62,6 +62,26 @@ class ScreenOffAccessibilityService : AccessibilityService(), SensorEventListene FreezeManager.freezeAll(this) } + // Pocket Detection + private val pocketFlashlightHandler = Handler(Looper.getMainLooper()) + private val pocketFlashlightRunnable = Runnable { + val prefs = getSharedPreferences("essentials_prefs", MODE_PRIVATE) + val pocketTurnOffEnabled = prefs.getBoolean("flashlight_pocket_turn_off_enabled", false) + // Re-check at fire time — guards against external torch-off between scheduling and firing + if (pocketTurnOffEnabled && flashlightHandler.isProximityBlocked && flashlightHandler.isTorchOn) { + flashlightHandler.toggleFlashlight() + } + } + + private fun schedulePocketFlashlightTurnOff() { + pocketFlashlightHandler.removeCallbacks(pocketFlashlightRunnable) + pocketFlashlightHandler.postDelayed(pocketFlashlightRunnable, 1500L) + } + + private fun cancelPocketFlashlightTurnOff() { + pocketFlashlightHandler.removeCallbacks(pocketFlashlightRunnable) + } + private val preferenceChangeListener = android.content.SharedPreferences.OnSharedPreferenceChangeListener { _, key -> if (key == "circle_to_search_gesture_enabled" || @@ -220,6 +240,7 @@ class ScreenOffAccessibilityService : AccessibilityService(), SensorEventListene omniGestureOverlayHandler.removeOverlay() statusBarIconHandler.unregister() stopInputEventListener() + cancelPocketFlashlightTurnOff() serviceScope.cancel() getSharedPreferences("essentials_prefs", MODE_PRIVATE) .unregisterOnSharedPreferenceChangeListener(preferenceChangeListener) @@ -244,6 +265,15 @@ class ScreenOffAccessibilityService : AccessibilityService(), SensorEventListene val isBlocked = distance < maxRange && distance < 5f flashlightHandler.isProximityBlocked = isBlocked + + val prefs = getSharedPreferences("essentials_prefs", MODE_PRIVATE) + val pocketTurnOffEnabled = prefs.getBoolean("flashlight_pocket_turn_off_enabled", false) + + if (pocketTurnOffEnabled && isBlocked && flashlightHandler.isTorchOn) { + schedulePocketFlashlightTurnOff() + } else { + cancelPocketFlashlightTurnOff() + } } } diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/ButtonRemapSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/ButtonRemapSettingsUI.kt index b811fd1a1..ffee9124c 100644 --- a/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/ButtonRemapSettingsUI.kt +++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/configs/ButtonRemapSettingsUI.kt @@ -527,6 +527,16 @@ fun ButtonRemapSettingsUI( ) } ) + + IconToggleItem( + iconRes = R.drawable.rounded_front_hand_24, + title = stringResource(R.string.flashlight_pocket_title), + description = stringResource(R.string.flashlight_pocket_desc), + isChecked = viewModel.isFlashlightPocketTurnOffEnabled.value, + onCheckedChange = { + viewModel.setFlashlightPocketTurnOffEnabled(it, context) + } + ) } Button( diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt index 492ac93af..852eed2bb 100644 --- a/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/MainViewModel.kt @@ -113,6 +113,7 @@ class MainViewModel : ViewModel() { val isFlashlightPulseFacedownOnly = mutableStateOf(true) val isFlashlightPulseUseLightingApps = mutableStateOf(true) val flashlightPulseMaxIntensity = mutableFloatStateOf(0.5f) + val isFlashlightPocketTurnOffEnabled = mutableStateOf(false) val isLocationPermissionGranted = mutableStateOf(false) val isBackgroundLocationPermissionGranted = mutableStateOf(false) val isFullScreenIntentPermissionGranted = mutableStateOf(false) @@ -595,6 +596,10 @@ class MainViewModel : ViewModel() { settingsRepository.getFloat(key, 0.5f) } + SettingsRepository.KEY_FLASHLIGHT_POCKET_TURN_OFF_ENABLED -> { + isFlashlightPocketTurnOffEnabled.value = settingsRepository.getBoolean(key) + } + SettingsRepository.KEY_CIRCLE_TO_SEARCH_GESTURE_ENABLED -> { isCircleToSearchGestureEnabled.value = settingsRepository.getBoolean(key) } @@ -1152,6 +1157,8 @@ class MainViewModel : ViewModel() { SettingsRepository.KEY_FLASHLIGHT_PULSE_MAX_INTENSITY, 0.5f ) + isFlashlightPocketTurnOffEnabled.value = + settingsRepository.getBoolean(SettingsRepository.KEY_FLASHLIGHT_POCKET_TURN_OFF_ENABLED) isPitchBlackThemeEnabled.value = settingsRepository.getBoolean(SettingsRepository.KEY_PITCH_BLACK_THEME_ENABLED) @@ -3313,6 +3320,14 @@ class MainViewModel : ViewModel() { ) } + fun setFlashlightPocketTurnOffEnabled(enabled: Boolean, context: Context) { + isFlashlightPocketTurnOffEnabled.value = enabled + settingsRepository.putBoolean( + SettingsRepository.KEY_FLASHLIGHT_POCKET_TURN_OFF_ENABLED, + enabled + ) + } + fun setFlashlightFadeEnabled(enabled: Boolean, context: Context) { isFlashlightFadeEnabled.value = enabled settingsRepository.putBoolean(SettingsRepository.KEY_FLASHLIGHT_FADE_ENABLED, enabled) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2d79cf8a2..af4e6e66d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -98,6 +98,8 @@ Other Always turn off flashlight Even while display is on + Pocket detection + Turn off flashlight when phone is in your pocket Settings @@ -584,6 +586,8 @@ Vibration feedback when remapped button is pressed Flashlight toggle Toggle flashlight with volume buttons + Flashlight pocket detection + Auto-turn off flashlight when placed in pocket Enable Dynamic Night Light Master switch for dynamic night light Enable app lock @@ -951,6 +955,13 @@ pulse notification + + pocket + proximity + sensor + torch + auto + awake developer