diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 9589c1551778..c2c39edc370b 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -6776,13 +6776,10 @@ public final class com/facebook/react/views/modal/ReactModalHostManager : com/fa public static final field REACT_CLASS Ljava/lang/String; public fun ()V public synthetic fun addEventEmitters (Lcom/facebook/react/uimanager/ThemedReactContext;Landroid/view/View;)V - public fun createShadowNodeInstance ()Lcom/facebook/react/uimanager/LayoutShadowNode; - public synthetic fun createShadowNodeInstance ()Lcom/facebook/react/uimanager/ReactShadowNode; public synthetic fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Landroid/view/View; public fun getDelegate ()Lcom/facebook/react/uimanager/ViewManagerDelegate; public fun getExportedCustomDirectEventTypeConstants ()Ljava/util/Map; public fun getName ()Ljava/lang/String; - public fun getShadowNodeClass ()Ljava/lang/Class; public synthetic fun onAfterUpdateTransaction (Landroid/view/View;)V public synthetic fun onDropViewInstance (Landroid/view/View;)V public fun onDropViewInstance (Lcom/facebook/react/views/modal/ReactModalHostView;)V @@ -6850,11 +6847,9 @@ public final class com/facebook/react/views/modal/ReactModalHostView : android/v public final fun setStatusBarTranslucent (Z)V public final fun setTransparent (Z)V public final fun showOrUpdate ()V - public final fun updateState (II)V } public final class com/facebook/react/views/modal/ReactModalHostView$DialogRootViewGroup : com/facebook/react/views/view/ReactViewGroup, com/facebook/react/uimanager/RootView { - public fun addView (Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V public fun handleException (Ljava/lang/Throwable;)V public fun onChildEndedNativeGesture (Landroid/view/View;Landroid/view/MotionEvent;)V public fun onChildStartedNativeGesture (Landroid/view/View;Landroid/view/MotionEvent;)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.kt index f1698ae9b833..af5dc51a3bc9 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostHelper.kt @@ -13,6 +13,7 @@ import android.graphics.Point import android.view.WindowManager /** Helper class for Modals. */ +@Deprecated("This class is no longer used and will be removed soon.") internal object ModalHostHelper { private val MIN_POINT = Point() private val MAX_POINT = Point() diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.kt index 4c52f3aa3d55..2466caa3b9bf 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.kt @@ -9,7 +9,6 @@ package com.facebook.react.views.modal import com.facebook.react.uimanager.LayoutShadowNode import com.facebook.react.uimanager.ReactShadowNodeImpl -import com.facebook.react.views.modal.ModalHostHelper.getModalHostSize /** * We implement the Modal by using an Android Dialog. That will fill the entire window of the @@ -19,6 +18,7 @@ import com.facebook.react.views.modal.ModalHostHelper.getModalHostSize * to be the window size. This will then cause the children of the Modal to layout as if they can * fill the window. */ +@Deprecated("This class is no longer used and will be removed soon.") internal class ModalHostShadowNode : LayoutShadowNode() { /** * We need to set the styleWidth and styleHeight of the one child (represented by the @@ -27,8 +27,5 @@ internal class ModalHostShadowNode : LayoutShadowNode() { */ override fun addChildAt(child: ReactShadowNodeImpl, i: Int) { super.addChildAt(child, i) - val modalSize = getModalHostSize(themedContext) - child.setStyleWidth(modalSize.x.toFloat()) - child.setStyleHeight(modalSize.y.toFloat()) } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt index 465760968946..f8cadda3ab2d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt @@ -10,7 +10,6 @@ package com.facebook.react.views.modal import android.content.DialogInterface.OnShowListener import com.facebook.react.bridge.ReadableArray import com.facebook.react.module.annotations.ReactModule -import com.facebook.react.uimanager.LayoutShadowNode import com.facebook.react.uimanager.ReactStylesDiffMap import com.facebook.react.uimanager.StateWrapper import com.facebook.react.uimanager.ThemedReactContext @@ -20,7 +19,6 @@ import com.facebook.react.uimanager.ViewManagerDelegate import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.viewmanagers.ModalHostViewManagerDelegate import com.facebook.react.viewmanagers.ModalHostViewManagerInterface -import com.facebook.react.views.modal.ModalHostHelper.getModalHostSize import com.facebook.react.views.modal.ReactModalHostView.OnRequestCloseListener /** View manager for [ReactModalHostView] components. */ @@ -34,11 +32,6 @@ public class ReactModalHostManager : protected override fun createViewInstance(reactContext: ThemedReactContext): ReactModalHostView = ReactModalHostView(reactContext) - public override fun createShadowNodeInstance(): LayoutShadowNode = ModalHostShadowNode() - - public override fun getShadowNodeClass(): Class = - ModalHostShadowNode::class.java - public override fun onDropViewInstance(view: ReactModalHostView) { super.onDropViewInstance(view) view.onDropInstance() @@ -128,8 +121,6 @@ public class ReactModalHostManager : stateWrapper: StateWrapper ): Any? { view.stateWrapper = stateWrapper - val modalSize = getModalHostSize(view.context) - view.updateState(modalSize.x, modalSize.y) return null } 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 64291e332baa..586d934c781e 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 @@ -30,7 +30,6 @@ import com.facebook.react.R import com.facebook.react.bridge.GuardedRunnable import com.facebook.react.bridge.LifecycleEventListener import com.facebook.react.bridge.ReactContext -import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.UiThreadUtil import com.facebook.react.bridge.WritableMap import com.facebook.react.bridge.WritableNativeMap @@ -38,16 +37,16 @@ import com.facebook.react.common.annotations.VisibleForTesting import com.facebook.react.config.ReactFeatureFlags import com.facebook.react.uimanager.JSPointerDispatcher import com.facebook.react.uimanager.JSTouchDispatcher -import com.facebook.react.uimanager.PixelUtil +import com.facebook.react.uimanager.PixelUtil.pxToDp import com.facebook.react.uimanager.RootView import com.facebook.react.uimanager.StateWrapper import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.UIManagerModule import com.facebook.react.uimanager.events.EventDispatcher import com.facebook.react.views.common.ContextUtils +import com.facebook.react.views.view.setStatusBarTranslucency import com.facebook.react.views.view.ReactViewGroup import java.util.Objects -import kotlin.math.abs /** * ReactModalHostView is a view that sits in the view hierarchy representing a Modal view. @@ -91,18 +90,18 @@ public class ReactModalHostView(context: ThemedReactContext) : } public var stateWrapper: StateWrapper? - get() = hostView.stateWrapper + get() = dialogRootViewGroup.stateWrapper public set(stateWrapper) { - hostView.stateWrapper = stateWrapper + dialogRootViewGroup.stateWrapper = stateWrapper } public var eventDispatcher: EventDispatcher? - get() = hostView.eventDispatcher + get() = dialogRootViewGroup.eventDispatcher public set(eventDispatcher) { - hostView.eventDispatcher = eventDispatcher + dialogRootViewGroup.eventDispatcher = eventDispatcher } - private val hostView: DialogRootViewGroup + private val dialogRootViewGroup: DialogRootViewGroup // Set this flag to true if changing a particular property on the view requires a new Dialog to // be created or Dialog was destroyed. For instance, animation does since it affects Dialog @@ -112,11 +111,11 @@ public class ReactModalHostView(context: ThemedReactContext) : init { context.addLifecycleEventListener(this) - hostView = DialogRootViewGroup(context) + dialogRootViewGroup = DialogRootViewGroup(context) } public override fun dispatchProvideStructure(structure: ViewStructure) { - hostView.dispatchProvideStructure(structure) + dialogRootViewGroup.dispatchProvideStructure(structure) } protected override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { @@ -127,7 +126,7 @@ public class ReactModalHostView(context: ThemedReactContext) : super.setId(id) // Forward the ID to our content view, so event dispatching behaves correctly - hostView.id = id + dialogRootViewGroup.id = id } protected override fun onDetachedFromWindow() { @@ -137,25 +136,25 @@ public class ReactModalHostView(context: ThemedReactContext) : public override fun addView(child: View?, index: Int) { UiThreadUtil.assertOnUiThread() - hostView.addView(child, index) + dialogRootViewGroup.addView(child, index) } - public override fun getChildCount(): Int = hostView.childCount + public override fun getChildCount(): Int = dialogRootViewGroup.childCount - public override fun getChildAt(index: Int): View? = hostView.getChildAt(index) + public override fun getChildAt(index: Int): View? = dialogRootViewGroup.getChildAt(index) public override fun removeView(child: View?) { UiThreadUtil.assertOnUiThread() if (child != null) { - hostView.removeView(child) + dialogRootViewGroup.removeView(child) } } public override fun removeViewAt(index: Int) { UiThreadUtil.assertOnUiThread() val child = getChildAt(index) - hostView.removeView(child) + dialogRootViewGroup.removeView(child) } public override fun addChildrenForAccessibility(outChildren: ArrayList) { @@ -188,7 +187,7 @@ public class ReactModalHostView(context: ThemedReactContext) : // We need to remove the mHostView from the parent // It is possible we are dismissing this dialog and reattaching the hostView to another - (hostView.parent as? ViewGroup)?.removeViewAt(0) + (dialogRootViewGroup.parent as? ViewGroup)?.removeViewAt(0) } } @@ -295,16 +294,7 @@ public class ReactModalHostView(context: ThemedReactContext) : * changed. This has the pleasant side-effect of us not having to preface all Modals with "top: * statusBarHeight", since that margin will be included in the FrameLayout. */ - get() { - val frameLayout = FrameLayout(context) - frameLayout.addView(hostView) - if (statusBarTranslucent) { - frameLayout.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - } else { - frameLayout.fitsSystemWindows = true - } - return frameLayout - } + get() = FrameLayout(context).apply { addView(dialogRootViewGroup) } /** * updateProperties will update the properties that do not require us to recreate the dialog @@ -313,10 +303,10 @@ public class ReactModalHostView(context: ThemedReactContext) : */ private fun updateProperties() { val dialog = checkNotNull(dialog) { "dialog must exist when we call updateProperties" } - val currentActivity = getCurrentActivity() - val window = + val dialogWindow = checkNotNull(dialog.window) { "dialog must have window when we call updateProperties" } - if (currentActivity == null || currentActivity.isFinishing || !window.isActive) { + val currentActivity = getCurrentActivity() + if (currentActivity == null || currentActivity.isFinishing) { // If the activity has disappeared, then we shouldn't update the window associated to the // Dialog. return @@ -325,17 +315,19 @@ public class ReactModalHostView(context: ThemedReactContext) : if (activityWindow != null) { val activityWindowFlags = activityWindow.attributes.flags if ((activityWindowFlags and WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) { - window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) + dialogWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) } else { - window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) + dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) } } + dialogWindow.setStatusBarTranslucency(statusBarTranslucent) + if (transparent) { - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) } else { - window.setDimAmount(0.5f) - window.setFlags( + dialogWindow.setDimAmount(0.5f) + dialogWindow.setFlags( WindowManager.LayoutParams.FLAG_DIM_BEHIND, WindowManager.LayoutParams.FLAG_DIM_BEHIND) } } @@ -343,31 +335,24 @@ public class ReactModalHostView(context: ThemedReactContext) : private fun updateSystemAppearance() { val currentActivity = getCurrentActivity() ?: return val dialog = checkNotNull(dialog) { "dialog must exist when we call updateProperties" } - val window = + val dialogWindow = checkNotNull(dialog.window) { "dialog must have window when we call updateProperties" } + val activityWindow = currentActivity.window // Modeled after the version check in StatusBarModule.setStyle if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { - val currentActivityWindow = currentActivity.window - val insetsController: WindowInsetsController = - checkNotNull(currentActivityWindow.insetsController) + val insetsController: WindowInsetsController = checkNotNull(activityWindow.insetsController) val activityAppearance: Int = insetsController.systemBarsAppearance val activityLightStatusBars = activityAppearance and WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS - window.insetsController?.setSystemBarsAppearance( + dialogWindow.insetsController?.setSystemBarsAppearance( activityLightStatusBars, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS) } else { - val currentActivityWindow = checkNotNull(currentActivity.window) - val decorView = currentActivityWindow.decorView - decorView.setSystemUiVisibility(decorView.systemUiVisibility) + dialogWindow.decorView.systemUiVisibility = activityWindow.decorView.systemUiVisibility } } - public fun updateState(width: Int, height: Int) { - hostView.updateState(width, height) - } - // This listener is called when the user presses KeyEvent.KEYCODE_BACK // An event is then passed to JS which can either close or not close the Modal by setting the // visible property @@ -395,7 +380,6 @@ public class ReactModalHostView(context: ThemedReactContext) : internal var stateWrapper: StateWrapper? = null internal var eventDispatcher: EventDispatcher? = null - private var hasAdjustedSize = false private var viewWidth = 0 private var viewHeight = 0 private val jSTouchDispatcher: JSTouchDispatcher = JSTouchDispatcher(this) @@ -414,75 +398,33 @@ public class ReactModalHostView(context: ThemedReactContext) : super.onSizeChanged(w, h, oldw, oldh) viewWidth = w viewHeight = h - updateFirstChildView() - } - private fun updateFirstChildView() { - if (childCount > 0) { - hasAdjustedSize = false - val viewTag: Int = getChildAt(0).id - if (stateWrapper != null) { - // This will only be called under Fabric - updateState(viewWidth, viewHeight) - } else { - // TODO: T44725185 remove after full migration to Fabric - val reactContext: ReactContext = reactContext - reactContext.runOnNativeModulesQueueThread( - object : GuardedRunnable(reactContext) { - override fun runGuarded() { - this@DialogRootViewGroup.reactContext.reactApplicationContext - .getNativeModule(UIManagerModule::class.java) - ?.updateNodeSize(viewTag, viewWidth, viewHeight) - } - }) - } - } else { - hasAdjustedSize = true - } + updateState(viewWidth, viewHeight) } @UiThread public fun updateState(width: Int, height: Int) { - val realWidth: Float = PixelUtil.toDIPFromPixel(width.toFloat()) - val realHeight: Float = PixelUtil.toDIPFromPixel(height.toFloat()) - - // Check incoming state values. If they're already the correct value, return early to prevent - // infinite UpdateState/SetState loop. - val currentState: ReadableMap? = stateWrapper?.getStateData() - if (currentState != null) { - val delta = 0.9f - val stateScreenHeight = - if (currentState.hasKey("screenHeight")) { - currentState.getDouble("screenHeight").toFloat() - } else { - 0f - } - val stateScreenWidth = - if (currentState.hasKey("screenWidth")) { - currentState.getDouble("screenWidth").toFloat() - } else { - 0f - } - - if (abs((stateScreenWidth - realWidth).toDouble()) < delta && - abs((stateScreenHeight - realHeight).toDouble()) < delta) { - return - } - } + val realWidth: Float = width.toFloat().pxToDp() + val realHeight: Float = height.toFloat().pxToDp() stateWrapper?.let { sw -> + // new architecture val newStateData: WritableMap = WritableNativeMap() newStateData.putDouble("screenWidth", realWidth.toDouble()) newStateData.putDouble("screenHeight", realHeight.toDouble()) sw.updateState(newStateData) - } - } - - override fun addView(child: View, index: Int, params: LayoutParams) { - super.addView(child, index, params) - if (hasAdjustedSize) { - updateFirstChildView() - } + } ?: run { + // old architecture + // TODO: T44725185 remove after full migration to Fabric + reactContext.runOnNativeModulesQueueThread( + object : GuardedRunnable(reactContext) { + override fun runGuarded() { + reactContext.reactApplicationContext + .getNativeModule(UIManagerModule::class.java) + ?.updateNodeSize(id, viewWidth, viewHeight) + } + }) + } } override fun handleException(t: Throwable) {