Skip to content

Commit 922c17d

Browse files
ADFA-40: apply FLAG_SECURE immediately when Instant Hide is toggled
Arming Instant Hide in Settings set the preference but did not re-apply the FLAG_SECURE policy, which otherwise runs only on the next onResume. The Settings window stayed screenshotable and unmasked in Recents until the user navigated away and back -- contrary to the armed-state contract that masking applies the moment the feature is on. The toggle callback now resolves the hosting EdgeToEdgeIDEActivity from the preference's context (unwrapping any ContextWrapper) and re-applies applyScreenSecurity() in place. Turning the feature off clears the flag immediately too. Addresses a CodeRabbit review finding on PR #2133. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VQsMNLYmV7gf2wqLoYRDkm
1 parent 5131c64 commit 922c17d

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

‎app/src/main/java/com/itsaky/androidide/app/EdgeToEdgeIDEActivity.kt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ abstract class EdgeToEdgeIDEActivity : IDEActivity() {
212212
*/
213213
protected open fun isInstantHideGesturesEnabled(): Boolean = true
214214

215+
/**
216+
* Re-applies the FLAG_SECURE policy immediately, for callers that change the armed state while a
217+
* screen is already resumed (arming the toggle in Settings). Without this the new policy would not
218+
* take effect until the next [onResume], leaving the current window screenshotable in between.
219+
*/
220+
internal fun applyInstantHideScreenSecurity() {
221+
securityController.applyScreenSecurity()
222+
}
223+
215224
override fun onResume() {
216225
super.onResume()
217226
securityController.applyScreenSecurity()

‎app/src/main/java/com/itsaky/androidide/preferences/securityPrefExts.kt‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
package com.itsaky.androidide.preferences
1919

2020
import android.content.Context
21+
import android.content.ContextWrapper
2122
import androidx.preference.Preference
23+
import com.itsaky.androidide.app.EdgeToEdgeIDEActivity
2224
import com.itsaky.androidide.resources.R
2325
import com.itsaky.androidide.idetooltips.TooltipTag.PREFS_SECURITY
2426
import com.itsaky.androidide.preferences.internal.SecurityPreferences
@@ -66,6 +68,26 @@ class InstantHide(
6668
override fun onPreferenceChanged(preference: Preference, newValue: Any?): Boolean {
6769
SecurityPreferences.instantHideEnabled =
6870
newValue as Boolean? ?: SecurityPreferences.instantHideEnabled
71+
// Apply the FLAG_SECURE policy to this already-resumed Settings window now: the armed-state
72+
// contract is that screenshots/Recents are masked the moment Instant Hide is on, but
73+
// applyScreenSecurity() otherwise only runs on the next onResume, leaving a gap right after
74+
// arming. Also clears the flag immediately when the user turns it back off.
75+
preference.context.findIDEActivity()?.applyInstantHideScreenSecurity()
6976
return true
7077
}
7178
}
79+
80+
/**
81+
* The hosting [EdgeToEdgeIDEActivity], or null. A preference's context is whatever the host passed
82+
* when the row was built -- today the Activity itself, but unwrapping the [ContextWrapper] chain
83+
* keeps this correct if a themed wrapper is ever interposed, since a missed call would silently
84+
* leave the window screenshotable.
85+
*/
86+
private fun Context.findIDEActivity(): EdgeToEdgeIDEActivity? {
87+
var ctx: Context? = this
88+
while (ctx is ContextWrapper) {
89+
if (ctx is EdgeToEdgeIDEActivity) return ctx
90+
ctx = ctx.baseContext
91+
}
92+
return null
93+
}

0 commit comments

Comments
 (0)