From e8d622e9d118a7fcf71a14d665b2d2bf33dd0b1f Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Tue, 31 Oct 2023 07:22:26 -0700 Subject: [PATCH] Fix an issue where the status bar colors would not match when opening modals (#40979) Summary: The current ReactModalHostView implementation incorrectly applies system bar appearances by providing the wrong mask to the `setSystemBarsAppearance` method invocation. Per [this issue comment](https://github.com/facebook/react-native/issues/34350#issuecomment-1760339877), jaydonlau correctly identified that when the status bar is set to `light-content` (light icons, dark background), the function is called with both a `0` appearance and `0` mask, which should instead be provided with the `APPEARANCE_LIGHT_STATUS_BARS` mask. The first pass at this PR attempted to pull out the entire appearance from the activity, compare it against the dialog's appearance, and only use a mask of differing bits (see the `appearanceMask` variable). However, if the `android:windowLightStatusBar` attribute is ever set to true, this does not impact the appearance of the status bar but rather the system UI visibility. As a result, the derived mask from system bars appearance would be 0 since both the activity and dialog would have appearances of 0. Rather than try and "future-proof" this implementation for other uses of system bar appearance, this change is directed only at updating the `APPEARANCE_LIGHT_STATUS_BARS` bit in the dialog's system bar appearance. The only other native code that touches status bars is the `StatusBarModule` and that only touches this flag. This is a follow-up to https://github.com/facebook/react-native/issues/34899. ## Changelog: [ANDROID] [FIXED] - Fixed an issue where the status bar colors would not match when opening modals Pull Request resolved: https://github.com/facebook/react-native/pull/40979 Test Plan: First test: - Replace the `RNTesterAppShared` implementation with the implementation from [this Expo snack](https://snack.expo.dev/abbondanzo/status-bar-tester) - Toggle the status bar to show dark icons, open the modal and ensure that dark icons are displayed - Toggle the status bar to show light icons, open the modal and ensure that light icons are displayed Second test: - Set the `android:windowLightStatusBar` attribute to true in the `AppTheme` - Follow the steps from the First test above, guaranteeing that status bar appearance overrides the theme Reviewed By: NickGerleman Differential Revision: D50329714 Pulled By: luluwu2032 fbshipit-source-id: 26ecaca05f8e00a52e13767e468b552ac167fc98 --- .../react/views/modal/ReactModalHostView.java | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 2b3de095d40..2ae3bb9bda3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -19,6 +19,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewStructure; import android.view.Window; +import android.view.WindowInsetsController; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; @@ -328,19 +329,7 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe } if (currentActivity != null && !currentActivity.isFinishing()) { mDialog.show(); - if (context instanceof Activity) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { - int appearance = - ((Activity) context).getWindow().getInsetsController().getSystemBarsAppearance(); - mDialog.getWindow().getInsetsController().setSystemBarsAppearance(appearance, appearance); - } else { - mDialog - .getWindow() - .getDecorView() - .setSystemUiVisibility( - ((Activity) context).getWindow().getDecorView().getSystemUiVisibility()); - } - } + updateSystemAppearance(); mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); } } @@ -394,6 +383,32 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe } } + private void updateSystemAppearance() { + Activity currentActivity = getCurrentActivity(); + if (currentActivity == null) { + return; + } + Assertions.assertNotNull(mDialog, "mDialog must exist when we call updateSystemAppearance"); + // Modeled after the version check in StatusBarModule.setStyle + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { + int activityAppearance = + currentActivity.getWindow().getInsetsController().getSystemBarsAppearance(); + int activityLightStatusBars = + activityAppearance & WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; + mDialog + .getWindow() + .getInsetsController() + .setSystemBarsAppearance( + activityLightStatusBars, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS); + } else { + mDialog + .getWindow() + .getDecorView() + .setSystemUiVisibility( + currentActivity.getWindow().getDecorView().getSystemUiVisibility()); + } + } + @Nullable public StateWrapper getStateWrapper() { return mHostView.getStateWrapper();