Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compute correct Keyboard Height with Notch #30919

Closed
wants to merge 11 commits into from
18 changes: 17 additions & 1 deletion ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
fabOnReact marked this conversation as resolved.
Show resolved Hide resolved
DisplayCutout displayCutout = getRootView().getRootWindowInsets().getDisplayCutout();
if (displayCutout != null) {
notchHeight = displayCutout.getSafeInsetTop();
}
}
final int heightDiff =
fabOnReact marked this conversation as resolved.
Show resolved Hide resolved
DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom;
fabOnReact marked this conversation as resolved.
Show resolved Hide resolved
fabOnReact marked this conversation as resolved.
Show resolved Hide resolved
DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels
fabOnReact marked this conversation as resolved.
Show resolved Hide resolved
- mVisibleViewArea.bottom
+ notchHeight;

boolean isKeyboardShowingOrKeyboardHeightChanged =
mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected;
Expand Down
43 changes: 43 additions & 0 deletions ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
}
};

fabOnReact marked this conversation as resolved.
Show resolved Hide resolved
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);
}
}