Only give DisplayInsetsController control over IME in split-screen
There is additional jank risk as well as animation curves aren't fully aligned with InsetsController, we should limit the scope where we use that controller for now. Once we have better alignment with InsetsController, we can expand it's usage again. Test: DisplayContentTests Test: Open IME in Bubbles Bug: 152197007 Change-Id: Ic8e925842b28c08fc6ea9ba58c7c05627b5a4eaa
This commit is contained in:
@@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||
@@ -141,6 +142,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ActivityInfo.ScreenOrientation;
|
||||
@@ -3370,34 +3372,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isImeControlledByApp() {
|
||||
return mInputMethodTarget != null && !WindowConfiguration.isSplitScreenWindowingMode(
|
||||
mInputMethodTarget.getWindowingMode());
|
||||
}
|
||||
|
||||
boolean isImeAttachedToApp() {
|
||||
return (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null
|
||||
return isImeControlledByApp()
|
||||
&& mInputMethodTarget.mActivityRecord != null
|
||||
&& mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
|
||||
// An activity with override bounds should be letterboxed inside its parent bounds,
|
||||
// so it doesn't fill the screen.
|
||||
&& mInputMethodTarget.mActivityRecord.matchParentBounds());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IME target that should host IME when this display that is reparented to another
|
||||
* WindowState.
|
||||
* IME is never displayed in a child display.
|
||||
* Use {@link WindowState#getImeControlTarget()} when IME target window
|
||||
* which originally called
|
||||
* {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is known.
|
||||
*
|
||||
* @return {@link WindowState} of host that controls IME.
|
||||
* {@code null} when {@param dc} is not a virtual display.
|
||||
* @see DisplayContent#reparent
|
||||
*/
|
||||
@Nullable
|
||||
WindowState getImeControlTarget() {
|
||||
WindowState imeTarget = mInputMethodTarget;
|
||||
if (imeTarget != null) {
|
||||
return imeTarget.getImeControlTarget();
|
||||
}
|
||||
|
||||
return getInsetsStateController().getImeSourceProvider().getControlTarget().getWindow();
|
||||
&& mInputMethodTarget.mActivityRecord.matchParentBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3407,7 +3393,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
*
|
||||
* @param target current IME target.
|
||||
* @return {@link WindowState} that can host IME.
|
||||
* @see DisplayContent#getImeControlTarget()
|
||||
*/
|
||||
WindowState getImeHostOrFallback(WindowState target) {
|
||||
if (target != null && target.getDisplayContent().canShowIme()) {
|
||||
@@ -3448,8 +3433,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
/**
|
||||
* The IME input target is the window which receives input from IME. It is also a candidate
|
||||
* which controls the visibility and animation of the input method window.
|
||||
*
|
||||
* @param target the window that receives input from IME.
|
||||
*/
|
||||
void setInputMethodInputTarget(WindowState target) {
|
||||
if (mInputMethodInputTarget != target) {
|
||||
@@ -3459,12 +3442,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
|
||||
private void updateImeControlTarget() {
|
||||
if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) {
|
||||
mInputMethodControlTarget = mRemoteInsetsControlTarget;
|
||||
} else {
|
||||
// Otherwise, we just use the ime input target
|
||||
mInputMethodControlTarget = mInputMethodInputTarget;
|
||||
}
|
||||
mInputMethodControlTarget = computeImeControlTarget();
|
||||
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
|
||||
}
|
||||
|
||||
@@ -3476,6 +3454,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the window where we hand IME control to.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
InsetsControlTarget computeImeControlTarget() {
|
||||
if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
|
||||
return mRemoteInsetsControlTarget;
|
||||
} else {
|
||||
// Otherwise, we just use the ime target as received from IME.
|
||||
return mInputMethodInputTarget;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the window the IME should be attached to.
|
||||
*/
|
||||
|
||||
@@ -65,6 +65,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@@ -84,10 +85,13 @@ import android.platform.test.annotations.Presubmit;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.Gravity;
|
||||
import android.view.IDisplayWindowInsetsController;
|
||||
import android.view.IDisplayWindowRotationCallback;
|
||||
import android.view.IDisplayWindowRotationController;
|
||||
import android.view.ISystemGestureExclusionListener;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.InsetsSourceControl;
|
||||
import android.view.InsetsState;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
@@ -810,25 +814,19 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testComputeImeParent_app() throws Exception {
|
||||
try (final InsetsModeSession session =
|
||||
new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) {
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
|
||||
assertEquals(dc.mInputMethodTarget.mActivityRecord.getSurfaceControl(),
|
||||
dc.computeImeParent());
|
||||
}
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
|
||||
assertEquals(dc.mInputMethodTarget.mActivityRecord.getSurfaceControl(),
|
||||
dc.computeImeParent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComputeImeParent_app_notFullscreen() throws Exception {
|
||||
try (final InsetsModeSession session =
|
||||
new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) {
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app");
|
||||
dc.mInputMethodTarget.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
|
||||
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
|
||||
}
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app");
|
||||
dc.mInputMethodTarget.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
|
||||
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -843,12 +841,61 @@ public class DisplayContentTests extends WindowTestsBase {
|
||||
|
||||
@Test
|
||||
public void testComputeImeParent_noApp() throws Exception {
|
||||
try (final InsetsModeSession session =
|
||||
new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) {
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar");
|
||||
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
|
||||
}
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar");
|
||||
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComputeImeControlTarget() throws Exception {
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.setRemoteInsetsController(createDisplayWindowInsetsController());
|
||||
dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
|
||||
dc.mInputMethodTarget = dc.mInputMethodInputTarget;
|
||||
assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComputeImeControlTarget_splitscreen() throws Exception {
|
||||
final DisplayContent dc = createNewDisplay();
|
||||
dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
|
||||
dc.mInputMethodInputTarget.setWindowingMode(
|
||||
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
|
||||
dc.mInputMethodTarget = dc.mInputMethodInputTarget;
|
||||
dc.setRemoteInsetsController(createDisplayWindowInsetsController());
|
||||
assertNotEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComputeImeControlTarget_notMatchParentBounds() throws Exception {
|
||||
spyOn(mAppWindow.mActivityRecord);
|
||||
doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds();
|
||||
mDisplayContent.mInputMethodInputTarget = mAppWindow;
|
||||
mDisplayContent.mInputMethodTarget = mDisplayContent.mInputMethodInputTarget;
|
||||
mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController());
|
||||
assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget());
|
||||
}
|
||||
|
||||
private IDisplayWindowInsetsController createDisplayWindowInsetsController() {
|
||||
return new IDisplayWindowInsetsController.Stub() {
|
||||
|
||||
@Override
|
||||
public void insetsChanged(InsetsState insetsState) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insetsControlChanged(InsetsState insetsState,
|
||||
InsetsSourceControl[] insetsSourceControls) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showInsets(int i, boolean b) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideInsets(int i, boolean b) throws RemoteException {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user