SecureFlagEffect.kt

1.8 KB · raw

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}