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]

Reviewed By: tdn120

Differential Revision: D61834841

fbshipit-source-id: a40f6b95ab7569bbe7680b5ca314eb0844114d1d
This commit is contained in:
Alan Lee
2024-08-29 01:53:56 -07:00
committed by Facebook GitHub Bot
parent 6fa54f9b5d
commit 768415dd62
3 changed files with 72 additions and 39 deletions
@@ -8336,3 +8336,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
}
@@ -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")
@@ -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)
}