diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 13074f8963e445..5bfdf9aafd8398 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -16,8 +16,10 @@ import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; +import android.os.Build; import android.os.Bundle; import android.util.AttributeSet; +import android.view.DisplayCutout; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; @@ -647,6 +649,11 @@ public void runApplication() { mJSTouchDispatcher = new JSTouchDispatcher(this); } + @VisibleForTesting + /* package */ void simulateCheckForKeyboardForTesting() { + getCustomGlobalLayoutListener().checkForKeyboardEvents(); + } + private CustomGlobalLayoutListener getCustomGlobalLayoutListener() { if (mCustomGlobalLayoutListener == null) { mCustomGlobalLayoutListener = new CustomGlobalLayoutListener(); @@ -766,8 +773,17 @@ public void onGlobalLayout() { private void checkForKeyboardEvents() { getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea); + int notchHeight = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + DisplayCutout displayCutout = getRootView().getRootWindowInsets().getDisplayCutout(); + if (displayCutout != null) { + notchHeight = displayCutout.getSafeInsetTop(); + } + } final int heightDiff = - DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom; + DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels + - mVisibleViewArea.bottom + + notchHeight; boolean isKeyboardShowingOrKeyboardHeightChanged = mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected; diff --git a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java index c0a28af8f86fb4..6389c29d7179a9 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java @@ -16,6 +16,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.graphics.Rect; import android.view.MotionEvent; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.CatalystInstance; @@ -25,7 +26,9 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactTestHelper; import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.SystemClock; +import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.events.Event; @@ -37,6 +40,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; @@ -209,4 +213,43 @@ public void testRemountApplication() { rootView.unmountReactApplication(); rootView.startReactApplication(instanceManager, ""); } + + @Test + public void testCheckForKeyboardEvents() { + ReactInstanceManager instanceManager = mock(ReactInstanceManager.class); + RCTDeviceEventEmitter eventEmitterModuleMock = mock(RCTDeviceEventEmitter.class); + + when(instanceManager.getCurrentReactContext()).thenReturn(mReactContext); + when(mReactContext.getJSModule(RCTDeviceEventEmitter.class)).thenReturn(eventEmitterModuleMock); + + ReactRootView rootView = + new ReactRootView(mReactContext) { + @Override + public void getWindowVisibleDisplayFrame(Rect outRect) { + if (outRect.bottom == 0) { + outRect.bottom += 100; + outRect.right += 370; + } else { + outRect.bottom += 370; + } + } + }; + + rootView.startReactApplication(instanceManager, ""); + rootView.simulateCheckForKeyboardForTesting(); + + WritableMap params = Arguments.createMap(); + WritableMap endCoordinates = Arguments.createMap(); + double screenHeight = 470.0; + double keyboardHeight = 100.0; + params.putDouble("duration", 0.0); + endCoordinates.putDouble("width", screenHeight - keyboardHeight); + endCoordinates.putDouble("screenX", 0.0); + endCoordinates.putDouble("height", screenHeight - keyboardHeight); + endCoordinates.putDouble("screenY", keyboardHeight); + params.putMap("endCoordinates", endCoordinates); + params.putString("easing", "keyboard"); + + verify(eventEmitterModuleMock, Mockito.times(1)).emit("keyboardDidShow", params); + } }