Merge "Cancel existing insets animation if the side is changed" into main
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 229e8ee7..4f74198 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -221,13 +221,13 @@
@Override
public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
- int[] hideTypes) {
+ int[] hideTypes, int[] cancelTypes) {
if (Flags.refactorInsetsController()) {
- return super.setControl(control, showTypes, hideTypes);
+ return super.setControl(control, showTypes, hideTypes, cancelTypes);
} else {
ImeTracing.getInstance().triggerClientDump("ImeInsetsSourceConsumer#setControl",
mController.getHost().getInputMethodManager(), null /* icProto */);
- if (!super.setControl(control, showTypes, hideTypes)) {
+ if (!super.setControl(control, showTypes, hideTypes, cancelTypes)) {
return false;
}
if (control == null && !mIsRequestedVisibleAwaitingLeash) {
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 97facc1..4fead2a 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -371,6 +371,7 @@
mPendingInsets = mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN
? mShownInsets : mHiddenInsets;
mPendingAlpha = 1f;
+ mPendingFraction = 1f;
applyChangeInsets(null);
mCancelled = true;
mListener.onCancelled(mReadyDispatched ? this : null);
@@ -486,6 +487,17 @@
if (controls == null) {
return;
}
+
+ final boolean visible = mPendingFraction == 0
+ // The first frame of ANIMATION_TYPE_SHOW should be invisible since it is
+ // animated from the hidden state.
+ ? mAnimationType != ANIMATION_TYPE_SHOW
+ : mPendingFraction < 1f || (mFinished
+ ? mShownOnFinish
+ // If the animation is cancelled, mFinished and mShownOnFinish are not set.
+ // Here uses mLayoutInsetsDuringAnimation to decide if it should be visible.
+ : mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN);
+
// TODO: Implement behavior when inset spans over multiple types
for (int i = controls.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = controls.valueAt(i);
@@ -498,12 +510,6 @@
}
addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);
- // The first frame of ANIMATION_TYPE_SHOW should be invisible since it is animated from
- // the hidden state.
- final boolean visible = mPendingFraction == 0
- ? mAnimationType != ANIMATION_TYPE_SHOW
- : !mFinished || mShownOnFinish;
-
if (outState != null && source != null) {
outState.addSource(new InsetsSource(source)
.setVisible(visible)
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8ac5532..d08873c 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -957,6 +957,7 @@
int consumedControlCount = 0;
final @InsetsType int[] showTypes = new int[1];
final @InsetsType int[] hideTypes = new int[1];
+ final @InsetsType int[] cancelTypes = new int[1];
ImeTracker.Token statsToken = null;
// Ensure to update all existing source consumers
@@ -982,7 +983,7 @@
// control may be null, but we still need to update the control to null if it got
// revoked.
- consumer.setControl(control, showTypes, hideTypes);
+ consumer.setControl(control, showTypes, hideTypes, cancelTypes);
}
// Ensure to create source consumers if not available yet.
@@ -990,7 +991,7 @@
for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = mTmpControlArray.valueAt(i);
getSourceConsumer(control.getId(), control.getType())
- .setControl(control, showTypes, hideTypes);
+ .setControl(control, showTypes, hideTypes, cancelTypes);
}
}
@@ -1002,6 +1003,10 @@
}
mTmpControlArray.clear();
+ if (cancelTypes[0] != 0) {
+ cancelExistingControllers(cancelTypes[0]);
+ }
+
// Do not override any animations that the app started in the OnControllableInsetsChanged
// listeners.
int animatingTypes = invokeControllableInsetsChangedListeners();
@@ -2154,12 +2159,12 @@
new InsetsSourceControl(ID_IME_CAPTION_BAR, captionBar(),
null /* leash */, false /* initialVisible */,
new Point(), Insets.NONE),
- new int[1], new int[1]);
+ new int[1], new int[1], new int[1]);
} else {
mState.removeSource(ID_IME_CAPTION_BAR);
InsetsSourceConsumer sourceConsumer = mSourceConsumers.get(ID_IME_CAPTION_BAR);
if (sourceConsumer != null) {
- sourceConsumer.setControl(null, new int[1], new int[1]);
+ sourceConsumer.setControl(null, new int[1], new int[1], new int[1]);
}
}
mHost.notifyInsetsChanged();
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index da788a7..17f33c1 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -122,7 +122,7 @@
/**
* Updates the control delivered from the server.
-
+ *
* @param showTypes An integer array with a single entry that determines which types a show
* animation should be run after setting the control.
* @param hideTypes An integer array with a single entry that determines which types a hide
@@ -130,7 +130,7 @@
* @return Whether the control has changed from the server
*/
public boolean setControl(@Nullable InsetsSourceControl control,
- @InsetsType int[] showTypes, @InsetsType int[] hideTypes) {
+ @InsetsType int[] showTypes, @InsetsType int[] hideTypes, int[] cancelTypes) {
if (Objects.equals(mSourceControl, control)) {
if (mSourceControl != null && mSourceControl != control) {
mSourceControl.release(SurfaceControl::release);
@@ -165,6 +165,12 @@
// Reset the applier to the default one which has the most lightweight implementation.
setSurfaceParamsApplier(InsetsAnimationControlRunner.SurfaceParamsApplier.DEFAULT);
} else {
+ if (lastControl != null && InsetsSource.getInsetSide(lastControl.getInsetsHint())
+ != InsetsSource.getInsetSide(control.getInsetsHint())) {
+ // The source has been moved to a different side. The coordinates are stale.
+ // Canceling existing animation if there is any.
+ cancelTypes[0] |= mType;
+ }
final boolean requestedVisible = isRequestedVisibleAwaitingControl();
final SurfaceControl oldLeash = lastControl != null ? lastControl.getLeash() : null;
final SurfaceControl newLeash = control.getLeash();
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index ba6f62c..d7f6a29 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -100,14 +100,14 @@
topConsumer.setControl(
new InsetsSourceControl(ID_STATUS_BAR, WindowInsets.Type.statusBars(),
mStatusLeash, true, new Point(0, 0), Insets.of(0, 100, 0, 0)),
- new int[1], new int[1]);
+ new int[1], new int[1], new int[1]);
InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ID_NAVIGATION_BAR,
WindowInsets.Type.navigationBars(), mInsetsState, mMockController);
navConsumer.setControl(
new InsetsSourceControl(ID_NAVIGATION_BAR, WindowInsets.Type.navigationBars(),
mNavLeash, true, new Point(400, 0), Insets.of(0, 0, 100, 0)),
- new int[1], new int[1]);
+ new int[1], new int[1], new int[1]);
mMockController.setRequestedVisibleTypes(0, WindowInsets.Type.navigationBars());
navConsumer.applyLocalVisibilityOverride();
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index d6d45e8..3a8f7ee 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -117,7 +117,23 @@
mConsumer.setControl(
new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
true /* initialVisible */, new Point(), Insets.NONE),
- new int[1], new int[1]);
+ new int[1], new int[1], new int[1]);
+ }
+
+ @Test
+ public void testSetControl_cancelAnimation() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final InsetsSourceControl newControl = new InsetsSourceControl(mConsumer.getControl());
+
+ // Change the side of the insets hint.
+ newControl.setInsetsHint(Insets.of(0, 0, 0, 100));
+
+ int[] cancelTypes = {0};
+ mConsumer.setControl(newControl, new int[1], new int[1], cancelTypes);
+
+ assertEquals(statusBars(), cancelTypes[0]);
+ });
+
}
@Test
@@ -180,7 +196,7 @@
@Test
public void testRestore() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- mConsumer.setControl(null, new int[1], new int[1]);
+ mConsumer.setControl(null, new int[1], new int[1], new int[1]);
mSurfaceParamsApplied = false;
mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
assertFalse(mSurfaceParamsApplied);
@@ -188,7 +204,7 @@
mConsumer.setControl(
new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
true /* initialVisible */, new Point(), Insets.NONE),
- new int[1], hideTypes);
+ new int[1], hideTypes, new int[1]);
assertEquals(statusBars(), hideTypes[0]);
assertFalse(mRemoveSurfaceCalled);
});
@@ -198,7 +214,7 @@
public void testRestore_noAnimation() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
- mConsumer.setControl(null, new int[1], new int[1]);
+ mConsumer.setControl(null, new int[1], new int[1], new int[1]);
mLeash = new SurfaceControl.Builder(mSession)
.setName("testSurface")
.build();
@@ -207,7 +223,7 @@
mConsumer.setControl(
new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
false /* initialVisible */, new Point(), Insets.NONE),
- new int[1], hideTypes);
+ new int[1], hideTypes, new int[1]);
assertTrue(mRemoveSurfaceCalled);
assertEquals(0, hideTypes[0]);
});
@@ -235,7 +251,8 @@
// Initial IME insets source control with its leash.
imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,
- false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
+ false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1],
+ new int[1]);
mSurfaceParamsApplied = false;
// Verify when the app requests controlling show IME animation, the IME leash
@@ -244,7 +261,8 @@
null /* interpolator */, null /* cancellationSignal */, null /* listener */);
assertEquals(ANIMATION_TYPE_USER, insetsController.getAnimationType(ime()));
imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,
- true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
+ true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1],
+ new int[1]);
assertFalse(mSurfaceParamsApplied);
});
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 8f28f59..6067a99 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -384,16 +384,19 @@
}
final boolean serverVisibleChanged = mServerVisible != isServerVisible;
setServerVisible(isServerVisible);
- final boolean positionChanged = updateInsetsControlPosition(windowState);
- if (mControl != null && !positionChanged
- // The insets hint would be updated if the position is changed. Here updates it for
- // the possible change of the bounds or the server visibility.
- && (updateInsetsHint()
- || serverVisibleChanged
- && android.view.inputmethod.Flags.refactorInsetsController())) {
- // Only call notifyControlChanged here when the position is not changed. Otherwise, it
- // is called or is scheduled to be called during updateInsetsControlPosition.
- mStateController.notifyControlChanged(mControlTarget, this);
+ if (mControl != null) {
+ final boolean positionChanged = updateInsetsControlPosition(windowState);
+ if (!(positionChanged || mHasPendingPosition)
+ // The insets hint would be updated while changing the position. Here updates it
+ // for the possible change of the bounds or the server visibility.
+ && (updateInsetsHint()
+ || (android.view.inputmethod.Flags.refactorInsetsController()))
+ && serverVisibleChanged) {
+ // Only call notifyControlChanged here when the position hasn't been or won't be
+ // changed. Otherwise, it has been called or scheduled to be called during
+ // updateInsetsControlPosition.
+ mStateController.notifyControlChanged(mControlTarget, this);
+ }
}
}
@@ -409,6 +412,7 @@
mPosition.set(position.x, position.y);
if (windowState != null && windowState.getWindowFrames().didFrameSizeChange()
&& windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) {
+ mHasPendingPosition = true;
windowState.applyWithNextDraw(mSetControlPositionConsumer);
} else {
Transaction t = mWindowContainer.getSyncTransaction();