### Implement Screenshot Protection with DisposableEffect Source: https://context7.com/lsposed/skipscreenshottest/llms.txt This snippet shows how to combine FLAG_SECURE and setSkipScreenshot within a DisposableEffect. It applies protections on resume and clears them on dispose. Ensure the necessary lifecycleOwner, view, and skipScreenshot state are available. ```kotlin DisposableEffect(lifecycleOwner, view, skipScreenshot) { // 1. FLAG_SECURE: prevents system screenshot gesture & shows black in recents if (skipScreenshot) { window?.addFlags(WindowManager.LayoutParams.FLAG_SECURE) } else { window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) } var isApplied = false // 2. setSkipScreenshot: applied on the first draw after resume val onDrawListener = ViewTreeObserver.OnDrawListener { if (isApplied) return@OnDrawListener try { val sc = HiddenApiBridge.View_getViewRootImpl(view)?.surfaceControl if (sc?.isValid == true) { SurfaceControl.Transaction().use { tx -> HiddenApiBridge.SurfaceControl_setSkipScreenshot(tx, sc, skipScreenshot).apply() isApplied = true Log.v(App.TAG, "Applying skip-screenshot: $skipScreenshot") } } } catch (e: Exception) { Log.e(App.TAG, "Failed to apply skip-screenshot", e) } } // 3. Lifecycle observer: register/unregister the draw listener on resume/pause val observer = LifecycleEventObserver { _, event -> when (event) { Lifecycle.Event.ON_RESUME -> { isApplied = false view.viewTreeObserver.addOnDrawListener(onDrawListener) } Lifecycle.Event.ON_PAUSE -> { view.viewTreeObserver.removeOnDrawListener(onDrawListener) } else -> {} } } lifecycleOwner.lifecycle.addObserver(observer) // 4. Cleanup: remove observer, remove draw listener, clear both protections onDispose { lifecycleOwner.lifecycle.removeObserver(observer) view.viewTreeObserver.removeOnDrawListener(onDrawListener) window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) try { val sc = HiddenApiBridge.View_getViewRootImpl(view)?.surfaceControl if (sc?.isValid == true) { SurfaceControl.Transaction().use { tx -> HiddenApiBridge.SurfaceControl_setSkipScreenshot(tx, sc, false).apply() } } } catch (e: Exception) { Log.e(App.TAG, "Failed to clear skip-screenshot", e) } } } ``` -------------------------------- ### Mark Surface Layer to Skip Screen Capture with SurfaceControl_setSkipScreenshot Source: https://context7.com/lsposed/skipscreenshottest/llms.txt Wraps the hidden `SurfaceControl.Transaction.setSkipScreenshot()` method to exclude a surface layer from screen capture or recording. This protection is independent of `FLAG_SECURE`. The change must be committed by calling `.apply()` on the transaction. ```java // hiddenapi/bridge/src/main/java/hidden/HiddenApiBridge.java public class HiddenApiBridge { /** * @param transaction An open SurfaceControl.Transaction (use try-with-resources). * @param sc The SurfaceControl obtained from ViewRootImpl. * @param skipScreenshot true = exclude surface from capture; false = allow capture. * @return The same transaction for chaining. */ public static SurfaceControl.Transaction SurfaceControl_setSkipScreenshot( SurfaceControl.Transaction transaction, SurfaceControl sc, boolean skipScreenshot) { return transaction.setSkipScreenshot(sc, skipScreenshot); } } ``` ```kotlin // Usage in Kotlin — apply inside an OnDrawListener so the SurfaceControl is valid: val sc = HiddenApiBridge.View_getViewRootImpl(view)?.surfaceControl if (sc?.isValid == true) { SurfaceControl.Transaction().use { tx -> HiddenApiBridge.SurfaceControl_setSkipScreenshot(tx, sc, true).apply() // Surface layer is now excluded from screenshots and screen recordings } } ``` -------------------------------- ### Retrieve ViewRootImpl from a View using HiddenApiBridge Source: https://context7.com/lsposed/skipscreenshottest/llms.txt Wraps the hidden `View.getViewRootImpl()` method to access the `ViewRootImpl` associated with a view. This is necessary to obtain the root `SurfaceControl` for the window. The bridge module compiles against private stubs, and the LSPass exemption enables runtime execution. ```java // hiddenapi/bridge/src/main/java/hidden/HiddenApiBridge.java public class HiddenApiBridge { /** * @param view Any view attached to a window. * @return The ViewRootImpl, or null if the view is not yet attached. */ public static ViewRootImpl View_getViewRootImpl(View view) { return view.getViewRootImpl(); // hidden API — accessible via LSPass exemption } } ``` ```kotlin // Usage in Kotlin (MainActivity.kt): val viewRootImpl = HiddenApiBridge.View_getViewRootImpl(view) val surfaceControl = viewRootImpl?.surfaceControl // SurfaceControl for the window surface ``` -------------------------------- ### VerticalBeforeAfterSlider Composable for Image Comparison Source: https://context7.com/lsposed/skipscreenshottest/llms.txt A full-screen composable that overlays two images, allowing the top image to be clipped by a vertically draggable boundary. It reports the normalized progress of the drag via `onProgressChange`. Handles intrinsic image scaling internally. ```kotlin import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.GenericShape import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import kotlin.math.min @Composable fun VerticalBeforeAfterSlider( topImage: Painter, bottomImage: Painter, modifier: Modifier = Modifier, onProgressChange: (Float) -> Unit = {} // 0.0 = top, 1.0 = bottom ) { var offsetY by remember { mutableFloatStateOf(1.0f) } BoxWithConstraints(modifier = modifier.fillMaxSize()) { // Compute actual rendered image bounds (accounting for Fit scaling) val scale = minOf( constraints.maxWidth / topImage.intrinsicSize.width, constraints.maxHeight / topImage.intrinsicSize.height ) val imageRect = Rect( left = 0f, top = (constraints.maxHeight - topImage.intrinsicSize.height * scale) / 2f, right = topImage.intrinsicSize.width * scale, bottom = (constraints.maxHeight + topImage.intrinsicSize.height * scale) / 2f ) // Bottom (reference) image — always fully visible Image(painter = bottomImage, contentDescription = "Bottom Image", modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Fit) // Top (overlay) image — clipped to offsetY fraction of image height Image( painter = topImage, contentDescription = "Top Image", modifier = Modifier.fillMaxSize().graphicsLayer { clip = true shape = GenericShape { size, _ -> addRect(Rect(0f, 0f, size.width, imageRect.top + imageRect.height * offsetY)) } }, contentScale = ContentScale.Fit ) // Drag handle — full-width touch target, visually a rounded pill Box( modifier = Modifier .fillMaxWidth() .height(48.dp) .align(Alignment.TopCenter) .offset(y = with(LocalDensity.current) { (imageRect.top + imageRect.height * offsetY).toDp() - 24.dp }) .pointerInput(imageRect) { detectDragGestures { change, dragAmount -> change.consume() val newOffset = (offsetY + dragAmount.y / imageRect.height).coerceIn(0f, 1f) if (newOffset != offsetY) { offsetY = newOffset onProgressChange(offsetY) } } }, contentAlignment = Alignment.Center ) { Box(Modifier.width(60.dp).height(5.dp) .background(Color.White.copy(alpha = 0.7f), RoundedCornerShape(100))) } } } ``` ```kotlin // Typical usage in a Scaffold: VerticalBeforeAfterSlider( topImage = painterResource(R.drawable.before_image), bottomImage = painterResource(R.drawable.after_image), modifier = Modifier.padding(innerPadding), onProgressChange = { progress -> // progress == 1.0 → top image fully visible (screenshot allowed) // progress <= 0.75 → trigger screenshot protection screenshotProtectionEnabled = (progress * 100).toInt() <= 75 } ) ``` -------------------------------- ### Status Composable for Screenshot Protection Indicator Source: https://context7.com/lsposed/skipscreenshottest/llms.txt A minimal composable that displays the screenshot protection status as a human-readable string based on the slider's progress. Useful for debugging and understanding the protection state. ```kotlin @Composable fun Status(progress: Float, modifier: Modifier = Modifier) { // Protection is active when the top image covers <= 75% of its height val skipScreenshot = (progress * 100).toInt() <= 75 Text( text = "skipScreenshot=$skipScreenshot", modifier = modifier ) } // Typical output: // Slider at 100% (fully down) → "skipScreenshot=false" // Slider at 75% → "skipScreenshot=true" // Slider at 0% (fully up) → "skipScreenshot=true" ``` -------------------------------- ### HiddenApiBridge.View_getViewRootImpl Source: https://context7.com/lsposed/skipscreenshottest/llms.txt Retrieves the ViewRootImpl associated with a given View. This is a wrapper for the hidden `View.getViewRootImpl()` method, enabling access to the window's root SurfaceControl. ```APIDOC ## `HiddenApiBridge.View_getViewRootImpl` — Retrieve ViewRootImpl from a View ### Description Wraps the hidden `View.getViewRootImpl()` method. Because the bridge module is compiled against private stubs (`hiddenapi/stubs-priv`), the call compiles normally; at runtime the HiddenApiBypass exemption makes it execute without a `NoSuchMethodError`. Returns the `ViewRootImpl` associated with the given view, which exposes the root `SurfaceControl` for the window. ### Method Signature ```java public static ViewRootImpl View_getViewRootImpl(View view) ``` ### Parameters * **view** (View) - Any view attached to a window. ### Returns * **ViewRootImpl** - The `ViewRootImpl` associated with the view, or null if the view is not yet attached. ### Usage Example ```kotlin // Usage in Kotlin (MainActivity.kt): val viewRootImpl = HiddenApiBridge.View_getViewRootImpl(view) val surfaceControl = viewRootImpl?.surfaceControl // SurfaceControl for the window surface ``` ``` -------------------------------- ### Bypass Hidden API Restrictions with LSPass.addHiddenApiExemptions Source: https://context7.com/lsposed/skipscreenshottest/llms.txt Exempts all hidden Android APIs from restriction checks globally. This must be called as early as possible in the application's static initializer, before any Activity or Service accesses a hidden member. ```kotlin import android.app.Application import org.lsposed.hiddenapibypass.LSPass class App : Application() { companion object { init { // Exempt ALL hidden APIs — call as early as possible, // before any Activity or Service accesses a hidden member. LSPass.addHiddenApiExemptions("") } const val TAG: String = "SkipScreenShotTest" } } ``` ```xml // AndroidManifest.xml — register the custom Application subclass // ``` -------------------------------- ### HiddenApiBridge.SurfaceControl_setSkipScreenshot Source: https://context7.com/lsposed/skipscreenshottest/llms.txt Marks a Surface Layer to skip screen capture. This method wraps the hidden `SurfaceControl.Transaction.setSkipScreenshot()` method, allowing control over whether a surface is included in screen captures or recordings. ```APIDOC ## `HiddenApiBridge.SurfaceControl_setSkipScreenshot` — Mark a Surface Layer to Skip Screen Capture ### Description Wraps the hidden `SurfaceControl.Transaction.setSkipScreenshot()` method. When `skipScreenshot = true`, the compositor excludes that surface layer from any screen-capture or recording operation—independent of `FLAG_SECURE`. The method returns the same `Transaction` for chaining, so `.apply()` must be called to commit the change. ### Method Signature ```java public static SurfaceControl.Transaction SurfaceControl_setSkipScreenshot(SurfaceControl.Transaction transaction, SurfaceControl sc, boolean skipScreenshot) ``` ### Parameters * **transaction** (SurfaceControl.Transaction) - An open `SurfaceControl.Transaction` (use try-with-resources). * **sc** (SurfaceControl) - The `SurfaceControl` obtained from `ViewRootImpl`. * **skipScreenshot** (boolean) - `true` to exclude the surface from capture; `false` to allow capture. ### Returns * **SurfaceControl.Transaction** - The same transaction object for chaining. ### Usage Example ```kotlin // Usage in Kotlin — apply inside an OnDrawListener so the SurfaceControl is valid: val sc = HiddenApiBridge.View_getViewRootImpl(view)?.surfaceControl if (sc?.isValid == true) { SurfaceControl.Transaction().use { HiddenApiBridge.SurfaceControl_setSkipScreenshot(it, sc, true).apply() // Surface layer is now excluded from screenshots and screen recordings } } ``` ``` -------------------------------- ### LSPass.addHiddenApiExemptions Source: https://context7.com/lsposed/skipscreenshottest/llms.txt Exempts all hidden Android APIs from restriction checks. This method should be called once in the Application class's static initializer, before any Activity or Service accesses a hidden member. Passing an empty string exempts all hidden members globally. ```APIDOC ## `LSPass.addHiddenApiExemptions` — Bypass Hidden API Restrictions ### Description Called once in the `Application` class static initializer, this exempts all hidden Android APIs from restriction checks before any activity is created. Passing an empty string `""` exempts every hidden member globally. This must run before any hidden API call elsewhere in the app. ### Method Signature ```kotlin public fun addHiddenApiExemptions(vararg memberNames: String) ``` ### Parameters * **memberNames** (String) - A list of hidden API member names to exempt. An empty string `""` exempts all members. ### Request Example ```kotlin // App.kt import android.app.Application import org.lsposed.hiddenapibypass.LSPass class App : Application() { companion object { init { // Exempt ALL hidden APIs — call as early as possible, // before any Activity or Service accesses a hidden member. LSPass.addHiddenApiExemptions("") } const val TAG: String = "SkipScreenShotTest" } } ``` ### Usage Notes Ensure the custom `Application` subclass is registered in `AndroidManifest.xml`: ```xml ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.