SecureFlagEffect.kt
1package com.peachpasswords.ui.components23import android.view.WindowManager4import androidx.compose.runtime.Composable5import androidx.compose.runtime.DisposableEffect6import androidx.compose.ui.platform.LocalContext7import androidx.fragment.app.FragmentActivity8import com.peachpasswords.BuildConfig910/**11 * Sets WindowManager.FLAG_SECURE while this composable is in the composition and12 * clears it on dispose — blocking screenshots, screen recording, and the recents13 * thumbnail of screens that display secrets (MN-3: recovery words, export blob,14 * codex generation). Mirrors the inline effect EntryDetailScreen / NotesModeScreen15 * already use.16 *17 * Skipped only when BuildConfig.DEBUG is true AND [QaFlags.disableSecureCaptureForQa]18 * was explicitly opted into (see that file) — automated visual QA needs to capture19 * these screens too. Always enforced in release builds regardless of the flag.20 */21@Composable22fun SecureFlagEffect() {23 val context = LocalContext.current24 DisposableEffect(Unit) {25 if (BuildConfig.DEBUG && QaFlags.disableSecureCaptureForQa) {26 return@DisposableEffect onDispose { }27 }28 val window = (context as? FragmentActivity)?.window29 if (BuildConfig.DEBUG) {30 // Debug: MainActivity does not set the flag, so the effect owns it31 // for the lifetime of the secret-bearing composable.32 window?.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)33 }34 // Release: MainActivity already set FLAG_SECURE release-wide. The effect35 // must not clear it on dispose — H-05 found that clearing stripped the36 // activity-wide protection from every screen visited afterward.37 onDispose {38 if (BuildConfig.DEBUG) window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)39 }40 }41}