SecureWindowPolicy.kt

2.0 KB · raw

1package com.peachpasswords.ui.components23import android.view.Window4import android.view.WindowManager5import java.util.WeakHashMap67/**8 * The only owner of [WindowManager.LayoutParams.FLAG_SECURE] transitions.9 *10 * Release activities install a permanent policy and therefore no later11 * composable can accidentally clear the activity-wide protection. Debug-only12 * secret screens take reference-counted leases so nested effects cannot clear13 * the flag while another secret screen is still composed. Window instances are14 * weakly keyed because their lifecycle owns the actual resources.15 */16internal object SecureWindowPolicy {17    private data class State(18        var leases: Int = 0,19        var releaseOwned: Boolean = false,20    )2122    private val states = WeakHashMap<Window, State>()2324    /** Install a release-wide owner that is never cleared for this window. */25    fun installRelease(window: Window) {26        synchronized(states) {27            val state = states.getOrPut(window) { State() }28            state.releaseOwned = true29            window.setFlags(30                WindowManager.LayoutParams.FLAG_SECURE,31                WindowManager.LayoutParams.FLAG_SECURE,32            )33        }34    }3536    /** Acquire one debug/composable lease for a window. */37    fun acquire(window: Window) {38        synchronized(states) {39            val state = states.getOrPut(window) { State() }40            state.leases++41            window.setFlags(42                WindowManager.LayoutParams.FLAG_SECURE,43                WindowManager.LayoutParams.FLAG_SECURE,44            )45        }46    }4748    /** Release one lease; release-owned windows remain protected forever. */49    fun release(window: Window) {50        synchronized(states) {51            val state = states[window] ?: return52            if (state.leases > 0) state.leases--53            if (state.leases == 0 && !state.releaseOwned) {54                window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)55                states.remove(window)56            }57        }58    }59}