Merge "Fix IME jumpcut when playing user IME animation after IME restarted"
This commit is contained in:
committed by
Android (Google) Code Review
commit
805dcc2d74
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user