Skip to content

Commit

Permalink
compute correct Keyboard Height with Notch (#30919)
Browse files Browse the repository at this point in the history
Summary:
fixes #27089 fixes #30191 fixes #26296 fixes #24353
Related #30052 #28004 #26536

The keyboard height of event keyboardDidShow is computed as the difference of two variables:

- The screen height excluding the Android Notch
DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels returns the screen height excluding the Android Notch
- The Visible Area excluding the Keyboard, but including the Android Notch
getWindowVisibleDisplayFrame() which returns the visible area including the Android Notch

The computation of the keyboard height is wrong when the device has an Android Notch.
This pr adds the Android Notch computation for API levels 28+

More info at #27089 (comment)

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Fixed] - Compute Android Notch in keyboardDidShow height calculation API 28+

Pull Request resolved: #30919

Test Plan:
adding a ReactRootViewTest for keyboardDidShow verifying correct functionality on API < 28

**<details><summary>TEST CASE - BEFORE FIX</summary>**
<p>

**WITHOUT NOTCH**
- The black view on the bottom is visible
- The keyboard height is 282

| **Full Screen** | **Keyboard Did Show** |
|:-------------------------:|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/107212700-a1fd9d00-6a07-11eb-9248-26f9c4d92ae3.png" width="300" height="" /> | <img src="https://user-images.githubusercontent.com/24992535/107212590-7975a300-6a07-11eb-89f4-891a37a7c406.png"  width="300" height="" /> |

**WITH NOTCH**
- The black view on the bottom is **not** visible. The black view is not visible because keyboardDidHide is sending the wrong keyboard height value.
- The keyboard height changes to 234. The keyboard height is the same from the previous test, but the value sent from keyboardDidHide changed for the Notch.

| **Full Screen** | **Keyboard Did Show** |
|:-------------------------:|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/107212619-81cdde00-6a07-11eb-9630-7e7c8c34d798.png" width="300" height="" /> | <img src="https://user-images.githubusercontent.com/24992535/107212707-a4f88d80-6a07-11eb-9134-f077059c83a6.png"  width="300" height="" /> |

</p>
</details>

**<details><summary>TEST CASE - AFTER FIX</summary>**
<p>

**WITH NOTCH**
- The black view on the bottom is visible
- The keyboard height is 282

| **Full Screen** | **Keyboard Did Show** |
|:-------------------------:|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/107212619-81cdde00-6a07-11eb-9630-7e7c8c34d798.png" width="300" height="" /> | <img src="https://user-images.githubusercontent.com/24992535/107349053-0d0ea880-6ac8-11eb-9695-33128080b6b8.png"  width="300" height="" /> |

</p>
</details>

Reviewed By: ShikaSD

Differential Revision: D31207989

Pulled By: cortinico

fbshipit-source-id: 0955a3884201122166c5c0ae2aca988a0ed4af53
  • Loading branch information
fabOnReact authored and facebook-github-bot committed Sep 28, 2021
1 parent ea3e244 commit 8bef3b1
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
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) {
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;
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;
}
}
};

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);
}
}

0 comments on commit 8bef3b1

Please sign in to comment.