From 5116c35389f6240fb671799f243730198121fa8f Mon Sep 17 00:00:00 2001 From: Alan Lee Date: Wed, 28 Aug 2024 16:54:26 -0700 Subject: [PATCH] Refactoring: extract helper functions from StatusBarModule (#46224) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46224 - Extract functions from StatusBarModule so they can be reused - WindowUtil was created as a container for the extracted Window related helper functions Changelog: [Internal] Differential Revision: D61834841 Reviewed By: tdn120 --- .../ReactAndroid/api/ReactAndroid.api | 5 ++ .../modules/statusbar/StatusBarModule.kt | 43 ++----------- .../facebook/react/views/view/WindowUtil.kt | 63 +++++++++++++++++++ 3 files changed, 72 insertions(+), 39 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 410ebdc0055806..da047724835f00 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -8330,3 +8330,8 @@ public final class com/facebook/react/views/view/ViewGroupClickEvent : com/faceb public fun getEventName ()Ljava/lang/String; } +public final class com/facebook/react/views/view/WindowUtilKt { + public static final fun setStatusBarTranslucency (Landroid/view/Window;Z)V + public static final fun setStatusBarVisibility (Landroid/view/Window;Z)V +} + diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt index 047635b2967759..c5547ca8d3a542 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt @@ -24,6 +24,8 @@ import com.facebook.react.bridge.UiThreadUtil import com.facebook.react.common.ReactConstants import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.PixelUtil +import com.facebook.react.views.view.setStatusBarTranslucency +import com.facebook.react.views.view.setStatusBarVisibility /** [NativeModule] that allows changing the appearance of the status bar. */ @ReactModule(name = NativeStatusBarManagerAndroidSpec.NAME) @@ -97,23 +99,7 @@ public class StatusBarModule(reactContext: ReactApplicationContext?) : UiThreadUtil.runOnUiThread( object : GuardedRunnable(reactApplicationContext) { override fun runGuarded() { - // If the status bar is translucent hook into the window insets calculations - // and consume all the top insets so no padding will be added under the status bar. - val window = activity.window ?: return - val decorView = window.decorView - if (translucent) { - decorView.setOnApplyWindowInsetsListener { v, insets -> - val defaultInsets = v.onApplyWindowInsets(insets) - defaultInsets.replaceSystemWindowInsets( - defaultInsets.systemWindowInsetLeft, - 0, - defaultInsets.systemWindowInsetRight, - defaultInsets.systemWindowInsetBottom) - } - } else { - decorView.setOnApplyWindowInsetsListener(null) - } - ViewCompat.requestApplyInsets(decorView) + activity.window?.setStatusBarTranslucency(translucent) } }) } @@ -127,28 +113,7 @@ public class StatusBarModule(reactContext: ReactApplicationContext?) : "StatusBarModule: Ignored status bar change, current activity is null.") return } - UiThreadUtil.runOnUiThread( - Runnable { - val window = activity.window ?: return@Runnable - if (hidden) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - // Ensure the content extends into the cutout area - window.attributes.layoutInDisplayCutoutMode = - WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES - window.setDecorFitsSystemWindows(false) - } - window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) - window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) - } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - window.attributes.layoutInDisplayCutoutMode = - WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT - window.setDecorFitsSystemWindows(true) - } - window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) - window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) - } - }) + UiThreadUtil.runOnUiThread { activity.window?.setStatusBarVisibility(hidden) } } @Suppress("DEPRECATION") diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt new file mode 100644 index 00000000000000..4795564901c049 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.views.view + +import android.os.Build +import android.view.Window +import android.view.WindowManager +import androidx.core.view.ViewCompat + +@Suppress("DEPRECATION") +public fun Window.setStatusBarTranslucency(isTranslucent: Boolean) { + // If the status bar is translucent hook into the window insets calculations + // and consume all the top insets so no padding will be added under the status bar. + if (isTranslucent) { + decorView.setOnApplyWindowInsetsListener { v, insets -> + val defaultInsets = v.onApplyWindowInsets(insets) + defaultInsets.replaceSystemWindowInsets( + defaultInsets.systemWindowInsetLeft, + 0, + defaultInsets.systemWindowInsetRight, + defaultInsets.systemWindowInsetBottom) + } + } else { + decorView.setOnApplyWindowInsetsListener(null) + } + ViewCompat.requestApplyInsets(decorView) +} + +public fun Window.setStatusBarVisibility(isHidden: Boolean) { + if (isHidden) { + this.statusBarHide() + } else { + this.statusBarShow() + } +} + +@Suppress("DEPRECATION") +private fun Window.statusBarHide() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // Ensure the content extends into the cutout area + attributes.layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES + setDecorFitsSystemWindows(false) + } + addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) + clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) +} + +@Suppress("DEPRECATION") +private fun Window.statusBarShow() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + attributes.layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT + setDecorFitsSystemWindows(true) + } + addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) + clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) +}