From cbd2adeb98d2e3a88acb8769df2a5a9071f6ad5e Mon Sep 17 00:00:00 2001 From: Chad Date: Mon, 24 Aug 2026 19:26:51 +0000 Subject: [PATCH 1/3] Stop overriding Adaptive Brightness on every screen wake applyBrightness() unconditionally forced Settings.System.SCREEN_BRIGHTNESS_MODE to MANUAL every time it ran -- including from reapplyBrightness(), which fires on every ACTION_SCREEN_ON broadcast and every accessibility-service reconnect, and from loadSavedBrightness(), which fires whenever the touch-strip service (re)starts. Neither of those is the user touching a brightness control; both are KompaktX passively restoring its last-known brightness. The net effect: once KompaktX had ever set a brightness (which happens the first time its overlay brightness control is used, and persists across restarts), turning Adaptive Brightness back on in system settings never stuck -- the very next screen wake silently flipped it back to manual. Add a forceManualMode parameter to applyBrightness(), defaulting to true so every direct user gesture (slider drag, sun-icon tap, front-light toggle) keeps forcing manual mode, matching stock Android's own behavior when you drag its brightness slider. The two passive-restore call sites now pass false, so they reapply the physical brightness (still correct) without silently overriding a system setting the user didn't just touch. Scope note: buildBrightnessSection() and buildBrightnessSubPanel() still force manual mode once each, at the top of the function, whenever KompaktX's own brightness UI is displayed (not only when it's touched). That's a smaller, separate quirk left out of this patch to keep it narrowly scoped to the dominant bug -- the continuous every-wake override -- rather than touching every place brightness mode is set. --- .../restore/overlay/OverlayPanelManager.kt | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt b/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt index 282c108..7656e29 100644 --- a/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt +++ b/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt @@ -856,9 +856,10 @@ object OverlayPanelManager { val sp = context.getSharedPreferences("kompaktx_brightness", Context.MODE_PRIVATE) lastManualBrightness = sp.getInt("last_manual_brightness", 128) currentBrightnessTarget = sp.getInt("current_brightness_target", -1) - // If we have a saved target, apply it immediately + // If we have a saved target, apply it immediately — passively, without forcing manual + // brightness mode, since this isn't a user gesture (see applyBrightness's kdoc). if (currentBrightnessTarget >= 0) { - applyBrightness(context.contentResolver, currentBrightnessTarget) + applyBrightness(context.contentResolver, currentBrightnessTarget, forceManualMode = false) } } @@ -2295,11 +2296,25 @@ object OverlayPanelManager { // ─── Helpers ──────────────────────────────────────────────────── - private fun applyBrightness(resolver: android.content.ContentResolver, brightness: Int) { + /** + * @param forceManualMode Whether to also flip the system into manual brightness mode. + * True for a direct user gesture (slider drag, sun-icon tap, front-light toggle) — matching + * stock Android's own "dragging the brightness slider disables Adaptive Brightness" behavior. + * False for a passive reapplication of an already-saved target (screen wake, service + * restart) — those aren't the user touching a brightness control, so they must not silently + * override an Adaptive Brightness setting the user may have turned back on since. + */ + private fun applyBrightness( + resolver: android.content.ContentResolver, + brightness: Int, + forceManualMode: Boolean = true + ) { currentBrightnessTarget = brightness try { - Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) + if (forceManualMode) { + Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) + } Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS, brightness) } catch (_: Exception) {} val screenVal = if (brightness <= 0) 0.001f else brightness / 255f @@ -2324,7 +2339,11 @@ object OverlayPanelManager { val ctx = stripContext ?: return val target = currentBrightnessTarget if (target < 0) return - handler.post { applyBrightness(ctx.contentResolver, target) } + // Fires on every screen wake and accessibility-service reconnect — not a user gesture, + // so don't force manual brightness mode here (see applyBrightness's kdoc). This was + // previously the main reason Adaptive Brightness appeared broken while KompaktX was + // installed: every wake silently flipped the system back to manual. + handler.post { applyBrightness(ctx.contentResolver, target, forceManualMode = false) } } /** Update the live brightness slider/icon UI if the panel is currently open. */ From e1cabb2cdcc9245657d0e22e91d0d13720142c82 Mon Sep 17 00:00:00 2001 From: Chad Date: Mon, 24 Aug 2026 18:15:30 -0500 Subject: [PATCH 2/3] Release the brightness overlay's override when Adaptive Brightness is on Adaptive Brightness now stays on as a setting (fix/preserve-adaptive-brightness), but the physical backlight never actually became adaptive: brightnessOverlay's WindowManager.LayoutParams.screenBrightness permanently pins the real screen to a static value the moment it's first applied, and nothing ever released it back to 'no override' in response to SCREEN_BRIGHTNESS_MODE. - Add a ContentObserver on SCREEN_BRIGHTNESS_MODE so flipping Adaptive Brightness on releases the overlay, the panel window, and the lockscreen accessibility overlay immediately. - applyBrightness(forceManualMode = false) - the passive reapply path used on screen wake and service restart - now checks current mode first and skips all Settings.System writes and overlay pinning entirely when Adaptive Brightness is already on, instead of re-clamping the screen to a stale target every time. Built on fix/preserve-adaptive-brightness: without that branch's change, reapplyBrightness()/loadSavedBrightness() would keep forcing manual mode on every wake, undoing this the moment the screen slept and woke again. --- .../restore/overlay/OverlayPanelManager.kt | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt b/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt index 7656e29..a824c10 100644 --- a/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt +++ b/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt @@ -64,6 +64,7 @@ object OverlayPanelManager { private var touchStripView: View? = null private var brightnessOverlay: View? = null // Persistent full-screen overlay just for screenBrightness private var brightnessObserver: ContentObserver? = null // Watches system brightness changes + private var brightnessModeObserver: ContentObserver? = null // Watches SCREEN_BRIGHTNESS_MODE private var panelView: View? = null // The root FrameLayout attached to WindowManager private var panelContentView: ViewGroup? = null // The inner LinearLayout we swap content in private var headsUpView: View? = null @@ -149,6 +150,24 @@ object OverlayPanelManager { false, brightnessObserver!! ) + // Watch for Adaptive Brightness being turned on and release our static override so the + // physical screen actually goes back to responding to the ambient sensor, instead of + // staying clamped to whatever brightnessOverlay was last pinned to. Without this, the + // Adaptive Brightness *setting* can stay on (per the reapplyBrightness()/ + // loadSavedBrightness() fix above) while the real backlight never becomes adaptive again, + // because nothing else ever releases the overlay's screenBrightness override. + brightnessModeObserver = object : ContentObserver(handler) { + override fun onChange(selfChange: Boolean) { + if (isAdaptiveBrightnessOn(context.contentResolver)) { + releaseBrightnessOverride() + } + } + } + context.contentResolver.registerContentObserver( + Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), + false, brightnessModeObserver!! + ) + windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val dp = context.resources.displayMetrics.density @@ -236,6 +255,10 @@ object OverlayPanelManager { try { stripContext?.contentResolver?.unregisterContentObserver(obs) } catch (_: Exception) {} } brightnessObserver = null + brightnessModeObserver?.let { obs -> + try { stripContext?.contentResolver?.unregisterContentObserver(obs) } catch (_: Exception) {} + } + brightnessModeObserver = null } fun recreateTouchStrip() { @@ -2302,7 +2325,10 @@ object OverlayPanelManager { * stock Android's own "dragging the brightness slider disables Adaptive Brightness" behavior. * False for a passive reapplication of an already-saved target (screen wake, service * restart) — those aren't the user touching a brightness control, so they must not silently - * override an Adaptive Brightness setting the user may have turned back on since. + * override an Adaptive Brightness setting the user may have turned back on since. When false + * and Adaptive Brightness currently reads as on, this also skips writing Settings.System and + * pinning the overlay entirely — see releaseBrightnessOverride() — so a passive reapply never + * re-clamps the physical screen to a stale value while the OS is meant to be driving it. */ private fun applyBrightness( resolver: android.content.ContentResolver, @@ -2310,6 +2336,15 @@ object OverlayPanelManager { forceManualMode: Boolean = true ) { currentBrightnessTarget = brightness + if (!forceManualMode && isAdaptiveBrightnessOn(resolver)) { + // Remember the target (in memory and in SharedPreferences) so the next real user + // gesture picks up where things left off, but leave Settings.System and the overlay + // alone — the OS's own auto-brightness curve should be the one driving the physical + // screen right now, not a stale value from before the user turned Adaptive + // Brightness back on. + saveBrightness(stripContext) + return + } try { if (forceManualMode) { Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE, @@ -2334,6 +2369,26 @@ object OverlayPanelManager { } catch (_: Exception) {} } + /** True when the system's own Adaptive Brightness is currently on. */ + private fun isAdaptiveBrightnessOn(resolver: android.content.ContentResolver): Boolean { + return try { + Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE) == + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC + } catch (_: Exception) { false } + } + + /** + * Release every KompaktX-held brightness override (the persistent overlay, the panel window + * if it happens to be open, and the lockscreen accessibility overlay) so the physical screen + * goes back to being driven by the OS's own Adaptive Brightness. currentBrightnessTarget is + * left untouched — it's what a real user gesture resumes from later. + */ + private fun releaseBrightnessOverride() { + applyScreenBrightnessToView(panelView, -1f) + applyScreenBrightnessToView(brightnessOverlay, -1f) + com.noti.restore.service.RecentsButtonService.clearAccessibilityBrightness() + } + /** Re-apply our brightness target after screen wake. Forces both Settings.System and overlay. */ fun reapplyBrightness() { val ctx = stripContext ?: return From 2ca8d6d7dc730c6ccd31f2334c86a08338093d5d Mon Sep 17 00:00:00 2001 From: Chad Date: Mon, 24 Aug 2026 18:45:09 -0500 Subject: [PATCH 3/3] Also guard the SCREEN_BRIGHTNESS observer against re-pinning while adaptive. --- .../java/com/noti/restore/overlay/OverlayPanelManager.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt b/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt index a824c10..c991c25 100644 --- a/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt +++ b/app/src/main/java/com/noti/restore/overlay/OverlayPanelManager.kt @@ -136,6 +136,13 @@ object OverlayPanelManager { val target = currentBrightnessTarget if (target < 0) return try { + // Don't fight Adaptive Brightness: an external write to SCREEN_BRIGHTNESS + // while the system is in automatic mode (e.g. Settings' own Display screen + // mirroring its live auto-brightness value into this setting) is not KompaktX + // being asked to restore anything — reverting it and re-pinning the overlay + // here would silently undo releaseBrightnessOverride() the moment any such + // write happens, defeating the whole point of that release. + if (isAdaptiveBrightnessOn(context.contentResolver)) return val sys = Settings.System.getInt(context.contentResolver, Settings.System.SCREEN_BRIGHTNESS) if (sys != target) { Settings.System.putInt(context.contentResolver, Settings.System.SCREEN_BRIGHTNESS, target)