Jetpack Compose Tapjacking: Filter touches on obscured UI

Viewed 151

While there is abundant documentation on Tapjacking in tradition XML views in Android to prevent malicious apps from interacting with sensitive information, there appears to be none around the issue for Jetpack Compose.

Is there an equivalent to filterTouchesWhenObscured for @Composables, was this issue solved at a more fundemental level, or does custom logic need to be implemented with gesture/touch modifiers?

2 Answers

There's no way to specify filterTouchesWhenObscured for a specific composable, and according to this maintainer comment it's not currently planned:

We won't likely implement it beyond the ComposeView level in the near future.

But you can do it for ComposableView which is used to draw Compose tree. For example, if you to apply it to the whole screen while some particular view is on the screen, you can do it like this:

val composeView = LocalView.current

DisposableEffect(Unit) {
    composeView.filterTouchesWhenObscured = true
    onDispose {
        composeView.filterTouchesWhenObscured = false
    }
}

Alternatively, if you want to apply it for a particular composable, like to only part of the screen, you can use such wrapper:

@Composable
fun ObscuredView(
    content: @Composable () -> Unit,
) {
    AndroidView(
        factory = {
            ComposeView(it).apply {
                filterTouchesWhenObscured = true
            }
        },
        update = {
            it.setContent(content)
        }
    )
}

Usage:

ObscuredView {
    Text("this text is Obscured")
}

I have a single Activity Compose Application and created this helper function to solve the security issue for this app. Call the function after you set the Compose content via setContent{...} in Activitie's onCreate.

/**
 *  Must and can only be called after the compose content was set via onCreate
 */
fun preventTapJackingSecurityIssue() {
    ((findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0) as? ViewGroup?)?.filterTouchesWhenObscured = false
}
Related