package com.peachpasswords.ui.components import android.view.Window import android.view.WindowManager import java.util.WeakHashMap /** * The only owner of [WindowManager.LayoutParams.FLAG_SECURE] transitions. * * Release activities install a permanent policy and therefore no later * composable can accidentally clear the activity-wide protection. Debug-only * secret screens take reference-counted leases so nested effects cannot clear * the flag while another secret screen is still composed. Window instances are * weakly keyed because their lifecycle owns the actual resources. */ internal object SecureWindowPolicy { private data class State( var leases: Int = 0, var userSecure: Boolean = true, var userChoiceApplied: Boolean = false, ) private val states = WeakHashMap() private fun evaluate(window: Window, state: State) { if (state.userSecure || (!state.userChoiceApplied && state.leases > 0)) { window.setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE, ) } else { window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) } } /** Set the user's screenshot preference for this window. */ fun setUserSecure(window: Window, secure: Boolean) { synchronized(states) { val state = states.getOrPut(window) { State() } state.userSecure = secure state.userChoiceApplied = true evaluate(window, state) } } /** Acquire one debug/composable lease for a window. */ fun acquire(window: Window) { synchronized(states) { val state = states.getOrPut(window) { State() } state.leases++ evaluate(window, state) } } /** Release one lease; re-evaluates the flag. */ fun release(window: Window) { synchronized(states) { val state = states[window] ?: return if (state.leases > 0) state.leases-- evaluate(window, state) } } }