From e60564215dad37e03d05df069e4fe85575d63868 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Thu, 27 Aug 2020 19:56:53 -0700 Subject: [PATCH] ReactModalHostView: Prevent infinite SetState/UpdateState loop Summary: Make sure to check incoming state values before calling SetState, or we call back and forth forever. Changelog: [internal] Reviewed By: mdvacca Differential Revision: D23389355 fbshipit-source-id: 9cf6110cf654fe93f555a6fbfd9b20f112214e0a --- .../uimanager/FabricViewStateManager.java | 5 ++++ .../react/views/modal/ReactModalHostView.java | 26 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/FabricViewStateManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/FabricViewStateManager.java index f78eedad134..073b91122f0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/FabricViewStateManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/FabricViewStateManager.java @@ -9,6 +9,7 @@ package com.facebook.react.uimanager; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.config.ReactFeatureFlags; @@ -91,4 +92,8 @@ public class FabricViewStateManager { public void setState(final StateUpdateCallback stateUpdateCallback) { setState(mStateWrapper, stateUpdateCallback, 0); } + + public @Nullable ReadableMap getState() { + return mStateWrapper != null ? mStateWrapper.getState() : null; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 24d324fe709..d1bdd2f6faa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -28,6 +28,7 @@ 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; @@ -441,13 +442,34 @@ public class ReactModalHostView extends ViewGroup @UiThread public void updateState(final int width, final int height) { + final float realWidth = PixelUtil.toDIPFromPixel(width); + final float realHeight = PixelUtil.toDIPFromPixel(height); + + // Check incoming state values. If they're already the correct value, return early to prevent + // infinite UpdateState/SetState loop. + ReadableMap currentState = getFabricViewStateManager().getState(); + if (currentState != null) { + float delta = (float) 0.9; + float stateScreenHeight = + currentState.hasKey("screenHeight") + ? (float) currentState.getDouble("screenHeight") + : 0; + float stateScreenWidth = + currentState.hasKey("screenWidth") ? (float) currentState.getDouble("screenWidth") : 0; + + if (Math.abs(stateScreenWidth - realWidth) < delta + && Math.abs(stateScreenHeight - realHeight) < delta) { + return; + } + } + mFabricViewStateManager.setState( new FabricViewStateManager.StateUpdateCallback() { @Override public WritableMap getStateUpdate() { WritableMap map = new WritableNativeMap(); - map.putDouble("screenWidth", PixelUtil.toDIPFromPixel(width)); - map.putDouble("screenHeight", PixelUtil.toDIPFromPixel(height)); + map.putDouble("screenWidth", realWidth); + map.putDouble("screenHeight", realHeight); return map; } });