summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2022-08-14 02:05:42 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-08-14 02:05:42 +0000
commit805dcc2d74d3cbe7a44d3036a10f2a8de45bbe4c (patch)
tree99afe0fb74654ffd4d6266f224c8f0537e635106
parent07fad3278c5e3471fd5a4018670e7f203ea1e09e (diff)
parent8945b5bcfceb3060fd6ff954d9ce1d703cf4a093 (diff)
Merge "Fix IME jumpcut when playing user IME animation after IME restarted"
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java4
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java47
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java10
4 files changed, 66 insertions, 10 deletions
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index d63c25a09382..5236fe772a7b 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -176,7 +176,9 @@ public class InsetsSourceConsumer {
// If we have a new leash, make sure visibility is up-to-date, even though we
// didn't want to run an animation above.
- applyRequestedVisibilityToControl();
+ if (mController.getAnimationType(control.getType()) == ANIMATION_TYPE_NONE) {
+ applyRequestedVisibilityToControl();
+ }
// Remove the surface that owned by last control when it lost.
if (!requestedVisible && lastControl == null) {
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 2054b4fe9a35..8cf118c4b79a 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -18,8 +18,10 @@ package android.view;
import static android.view.InsetsController.ANIMATION_TYPE_NONE;
import static android.view.InsetsController.ANIMATION_TYPE_USER;
+import static android.view.InsetsSourceConsumer.ShowResult.SHOW_IMMEDIATELY;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.statusBars;
import static junit.framework.Assert.assertEquals;
@@ -28,6 +30,7 @@ import static junit.framework.TestCase.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -75,6 +78,7 @@ public class InsetsSourceConsumerTest {
private boolean mRemoveSurfaceCalled = false;
private InsetsController mController;
private InsetsState mState;
+ private ViewRootImpl mViewRoot;
@Before
public void setup() {
@@ -86,10 +90,9 @@ public class InsetsSourceConsumerTest {
instrumentation.runOnMainSync(() -> {
final Context context = instrumentation.getTargetContext();
// cannot mock ViewRootImpl since it's final.
- final ViewRootImpl viewRootImpl = new ViewRootImpl(context,
- context.getDisplayNoVerify());
+ mViewRoot = new ViewRootImpl(context, context.getDisplayNoVerify());
try {
- viewRootImpl.setView(new TextView(context), new LayoutParams(), null);
+ mViewRoot.setView(new TextView(context), new LayoutParams(), null);
} catch (BadTokenException e) {
// activity isn't running, lets ignore BadTokenException.
}
@@ -97,7 +100,7 @@ public class InsetsSourceConsumerTest {
mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
mState.addSource(mSpyInsetsSource);
- mController = new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl));
+ mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot));
mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mState,
() -> mMockTransaction, mController) {
@Override
@@ -207,4 +210,40 @@ public class InsetsSourceConsumerTest {
});
}
+
+ @Test
+ public void testWontUpdateImeLeashVisibility_whenAnimation() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ InsetsState state = new InsetsState();
+ ViewRootInsetsControllerHost host = new ViewRootInsetsControllerHost(mViewRoot);
+ InsetsController insetsController = new InsetsController(host, (controller, type) -> {
+ if (type == ITYPE_IME) {
+ return new InsetsSourceConsumer(ITYPE_IME, state,
+ () -> mMockTransaction, controller) {
+ @Override
+ public int requestShow(boolean fromController) {
+ return SHOW_IMMEDIATELY;
+ }
+ };
+ }
+ return new InsetsSourceConsumer(type, controller.getState(), Transaction::new,
+ controller);
+ }, host.getHandler());
+ InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(ITYPE_IME);
+
+ // Initial IME insets source control with its leash.
+ imeConsumer.setControl(new InsetsSourceControl(ITYPE_IME, mLeash,
+ false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
+ reset(mMockTransaction);
+
+ // Verify when the app requests controlling show IME animation, the IME leash
+ // visibility won't be updated when the consumer received the same leash in setControl.
+ insetsController.controlWindowInsetsAnimation(ime(), 0L,
+ null /* interpolator */, null /* cancellationSignal */, null /* listener */);
+ assertTrue(insetsController.getAnimationType(ITYPE_IME) == ANIMATION_TYPE_USER);
+ imeConsumer.setControl(new InsetsSourceControl(ITYPE_IME, mLeash,
+ true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
+ verify(mMockTransaction, never()).show(mLeash);
+ });
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c8692ca81b2e..fccf54d83198 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4416,13 +4416,20 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
@VisibleForTesting
InsetsControlTarget computeImeControlTarget() {
+ if (mImeInputTarget == null) {
+ // A special case that if there is no IME input target while the IME is being killed,
+ // in case seeing unexpected IME surface visibility change when delivering the IME leash
+ // to the remote insets target during the IME restarting, but the focus window is not in
+ // multi-windowing mode, return null target until the next input target updated.
+ return null;
+ }
+
+ final WindowState imeInputTarget = mImeInputTarget.getWindowState();
if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null
- || (mImeInputTarget != null
- && getImeHostOrFallback(mImeInputTarget.getWindowState())
- == mRemoteInsetsControlTarget)) {
+ || getImeHostOrFallback(imeInputTarget) == mRemoteInsetsControlTarget) {
return mRemoteInsetsControlTarget;
} else {
- return mImeInputTarget != null ? mImeInputTarget.getWindowState() : null;
+ return imeInputTarget;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 2cf9c01a4476..28d2aa157e0a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1252,7 +1252,15 @@ public class DisplayContentTests extends WindowTestsBase {
public void testComputeImeControlTarget() throws Exception {
final DisplayContent dc = createNewDisplay();
dc.setRemoteInsetsController(createDisplayWindowInsetsController());
- dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app"));
+ dc.mCurrentFocus = createWindow(null, TYPE_BASE_APPLICATION, "app");
+
+ // Expect returning null IME control target when the focus window has not yet been the
+ // IME input target (e.g. IME is restarting) in fullscreen windowing mode.
+ dc.setImeInputTarget(null);
+ assertFalse(dc.mCurrentFocus.inMultiWindowMode());
+ assertNull(dc.computeImeControlTarget());
+
+ dc.setImeInputTarget(dc.mCurrentFocus);
dc.setImeLayeringTarget(dc.getImeInputTarget().getWindowState());
assertEquals(dc.getImeInputTarget().getWindowState(), dc.computeImeControlTarget());
}