From 0750c6a91bfef042c29f9397da472208d81a7d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Thu, 2 Jan 2025 20:40:09 -0800 Subject: [PATCH] Modal: `FLAG_SECURE` not respected in modal dialog (#48317) Summary: Fixes https://github.com/facebook/react-native/issues/38537 Setting `WindowManager.LayoutParams.FLAG_SECURE` in the window flags is not respected in the Android Modal component, causing security issues with screenshots or screen recordings as the content in the modal is visible. The flag works correctly in the rest of the components, see the videos in the linked issue. This PR addresses that by checking whether this flag is set in the current activity and then setting it in the dialog when creating a new one in the `ReactModalHostView`. ## Changelog: [ANDROID][FIXED] - `FLAG_SECURE` not respected in Modal dialog Pull Request resolved: https://github.com/facebook/react-native/pull/48317 Test Plan: To test this, you need a physical device as with the emulator the flags don't seem to be respected either. The easiest way to test this in code is by setting the flags in the main activity. You can do so by adding this code snippet:
onCreate in RNTesterApplication.kt ```kt override fun onCreate() { ReactFontManager.getInstance().addCustomFont(this, "Rubik", R.font.rubik) super.onCreate() ... registerActivityLifecycleCallbacks( object : ActivityLifecycleCallbacks { override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { activity.window.setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE ) } override fun onActivityStarted(activity: Activity) {} override fun onActivityResumed(activity: Activity) {} override fun onActivityPaused(activity: Activity) {} override fun onActivityStopped(activity: Activity) {} override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} override fun onActivityDestroyed(activity: Activity) {} } ) } ```
Then, you can render a simple modal component:
RNTesterPlayground.js ```tsx function Playground() { const [modalVisible, setModalVisible] = React.useState(false); return ( <> Hello World!
You can then try to record the screen or take screenshots. You will notice that before opening the modal, you won't be able to see anything in the recording, but when opening the modal, the content is visible. I've tried my best to record the before and after the fix, but as the screen recordings will mostly show a black screen, you have to forward a bit in both videos to see the difference.
Before the fix (notice the blank screen and then content visible) https://github.com/user-attachments/assets/fc5bbe26-d238-425b-90d3-0e43c89ccaac
After the fix (notice all the screen recording is a black screen) https://github.com/user-attachments/assets/0d6991a0-974b-45c5-8f4a-bf4718c284e6
Reviewed By: cipolleschi Differential Revision: D67368741 Pulled By: alanleedev fbshipit-source-id: 9f31063a9208a6df257da424bf3096bf15a5ddcb --- .../react/views/modal/ReactModalHostView.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt index 83d8bc287e3..0894abf74e1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt @@ -220,6 +220,15 @@ public class ReactModalHostView(context: ThemedReactContext) : private fun getCurrentActivity(): Activity? = (context as ThemedReactContext).currentActivity + private fun isFlagSecureSet(activity: Activity?): Boolean { + if (activity == null) { + return false + } + + val flags = activity.window.attributes.flags + return (flags and WindowManager.LayoutParams.FLAG_SECURE) != 0 + } + /** * showOrUpdate will display the Dialog. It is called by the manager once all properties are set * because we need to know all of them before creating the Dialog. It is also smart during updates @@ -293,6 +302,11 @@ public class ReactModalHostView(context: ThemedReactContext) : if (hardwareAccelerated) { newDialog.window?.addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) } + val flagSecureSet = isFlagSecureSet(currentActivity) + if (flagSecureSet) { + newDialog.window?.setFlags( + WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE) + } if (currentActivity?.isFinishing == false) { newDialog.show() updateSystemAppearance()