From 38a164b301152ec629922dc5ce10fb9d921ebaf4 Mon Sep 17 00:00:00 2001 From: Ward Abbass Date: Sat, 12 Feb 2022 23:31:21 +0200 Subject: [PATCH] Android < 30 Keyboard insets adjustNothing & adjustPan Fix (#7453) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Issue: Window insets does not apply when keyboard got closed in case of adjustPan, and in case of adjustNothing it will just ignore it and treat it like adjustResize. The difference between Pan and Resize as pointed [here](https://www.techrepublic.com/article/pro-tip-make-sense-of-pan-vs-resize-in-the-android-manifest/): adjustResize: The activity’s main window is always resized to make room for the soft keyboard on screen. adjustPan: The activity’s main window is not resized to make room for the soft keyboard. Rather, the contents of the window are automatically panned so that the current focus is never obscured by the keyboard and users can always see what they are typing. **This is generally less desirable than resizing, because the user may need to close the soft keyboard to get at and interact with obscured parts of the window.** # Fix: - Due to the nature of adjustPan, we need to wait for the layout to be updated after the keyboard closed, and then apply insets to determine the final state. - Take adjustNothing into consideration and don't adjust the insets. Adjust Nothing: https://user-images.githubusercontent.com/7227793/153453913-7af3fcb7-87f6-4cfa-aaf8-e2f32b023c61.mov Adjust Pan: https://user-images.githubusercontent.com/7227793/153453981-73ccf0c9-e42e-41e3-bede-8f561f9ba53a.mov AdjustPan old Androids (the white space fixed in master, which is not included in the recorded demo) https://user-images.githubusercontent.com/7227793/153454164-300c115b-9e7a-407c-b612-c0ca8ac158ea.mov **NOTE: As checked, if flags are set to adjustResize, then there is no issue at all across all versions.** Closes: #7433. Closes: #7427. Closes: #7428. Closes: #7402. Co-authored-by: Yogev Ben David --- .../component/ComponentViewController.java | 16 ++++++++++++---- .../sidemenu/SideMenuControllerTest.java | 10 +--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java index 75e500c4199..765fe784e26 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java @@ -4,6 +4,7 @@ import android.content.res.Configuration; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import com.reactnativenavigation.options.OverlayAttachOptions; import com.reactnativenavigation.viewcontrollers.viewcontroller.ScrollEventListener; @@ -21,10 +22,13 @@ import androidx.annotation.Nullable; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; +import androidx.core.view.ViewKt; import androidx.core.view.WindowInsetsCompat; import static com.reactnativenavigation.utils.ObjectUtils.perform; +import kotlin.Unit; + public class ComponentViewController extends ChildController { private final String componentName; private final ComponentPresenter presenter; @@ -156,8 +160,10 @@ protected WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat i ViewController viewController = findController(view); if (viewController == null || viewController.getView() == null || ignoreInsets) return insets; final Options currentOptions = resolveCurrentOptions(presenter.defaultOptions); - - final int keyboardBottomInset = currentOptions.layout.adjustResize.get(true) ? insets.getInsets(WindowInsetsCompat.Type.ime()).bottom : 0; + int mode = getActivity().getWindow().getAttributes().softInputMode; + boolean adjustNothing = (mode & WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) ==WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING ; + final int keyboardBottomInset = currentOptions.layout.adjustResize.get(true) &&!adjustNothing ? + insets.getInsets(WindowInsetsCompat.Type.ime()).bottom : 0; final Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); final int visibleNavBar = currentOptions.navigationBar.isVisible.isTrueOrUndefined() ? 1 : 0; final int controllerBottomInset = currentOptions.bottomTabsOptions.isHiddenOrDrawBehind() ? 0 : getBottomInset(); @@ -167,8 +173,10 @@ protected WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat i systemBarsInsets.right, Math.max(0, Math.max(visibleNavBar * systemBarsInsets.bottom, keyboardBottomInset) - controllerBottomInset)) ).build(); - - ViewCompat.onApplyWindowInsets(viewController.getView(), finalInsets); + ViewKt.doOnLayout(viewController.getView(), (v) -> { + ViewCompat.onApplyWindowInsets(viewController.getView(), finalInsets); + return Unit.INSTANCE; + }); return insets; } diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuControllerTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuControllerTest.java index 540c304fe90..250e0dd4747 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuControllerTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuControllerTest.java @@ -58,7 +58,7 @@ public class SideMenuControllerTest extends BaseTest { @Override public void beforeEach() { super.beforeEach(); - activity = createActivity(); + activity = newActivity(); childRegistry = new ChildControllersRegistry(); presenter = spy(new SideMenuPresenter()); @@ -430,14 +430,6 @@ private void closeRightMenu() { uut.onDrawerSlide(right.getView(), 0); } - private Activity createActivity() { - Activity activity = spy(newActivity()); - Window window = mock(Window.class); - when(window.getDecorView()).thenReturn(mock(View.class)); - when(activity.getWindow()).thenReturn(window); - return activity; - } - private void setLeftRight(ViewController left, ViewController right) { uut.setLeftController(left); uut.setRightController(right);