summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java6
-rw-r--r--core/java/android/view/InsetsController.java49
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java8
-rw-r--r--core/java/android/view/InsetsSourceControl.java4
-rw-r--r--core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java28
-rw-r--r--core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java4
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java16
7 files changed, 72 insertions, 43 deletions
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 4f741982081b..880622a1e121 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -221,13 +221,13 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
@Override
public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
- int[] hideTypes, int[] cancelTypes) {
+ int[] hideTypes, int[] cancelTypes, int[] transientTypes) {
if (Flags.refactorInsetsController()) {
- return super.setControl(control, showTypes, hideTypes, cancelTypes);
+ return super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
} else {
ImeTracing.getInstance().triggerClientDump("ImeInsetsSourceConsumer#setControl",
mController.getHost().getInputMethodManager(), null /* icProto */);
- if (!super.setControl(control, showTypes, hideTypes, cancelTypes)) {
+ if (!super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes)) {
return false;
}
if (control == null && !mIsRequestedVisibleAwaitingLeash) {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index b0813f3a98f6..c174fbe0bbcd 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -959,6 +959,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
final @InsetsType int[] showTypes = new int[1];
final @InsetsType int[] hideTypes = new int[1];
final @InsetsType int[] cancelTypes = new int[1];
+ final @InsetsType int[] transientTypes = new int[1];
ImeTracker.Token statsToken = null;
// Ensure to update all existing source consumers
@@ -984,7 +985,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// control may be null, but we still need to update the control to null if it got
// revoked.
- consumer.setControl(control, showTypes, hideTypes, cancelTypes);
+ consumer.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
}
// Ensure to create source consumers if not available yet.
@@ -992,7 +993,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = mTmpControlArray.valueAt(i);
getSourceConsumer(control.getId(), control.getType())
- .setControl(control, showTypes, hideTypes, cancelTypes);
+ .setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
}
}
@@ -1020,10 +1021,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
handlePendingControlRequest(statsToken);
} else {
if (showTypes[0] != 0) {
- applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
+ applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
+ false /* skipsCallbacks */, statsToken);
}
if (hideTypes[0] != 0) {
- applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
+ applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
+ // The animation of hiding transient types shouldn't be detected by the
+ // app. Otherwise, it might be able to react to the callbacks and cause
+ // flickering.
+ (hideTypes[0] & ~transientTypes[0]) == 0 /* skipsCallbacks */,
+ statsToken);
}
}
} else {
@@ -1033,7 +1040,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
ImeTracker.TYPE_SHOW, ImeTracker.ORIGIN_CLIENT,
SoftInputShowHideReason.CONTROLS_CHANGED,
mHost.isHandlingPointerEvent() /* fromUser */);
- applyAnimation(showTypes[0], true /* show */, false /* fromIme */, newStatsToken);
+ applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
+ false /* skipsCallbacks */, newStatsToken);
}
if (hideTypes[0] != 0) {
final var newStatsToken =
@@ -1041,7 +1049,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT,
SoftInputShowHideReason.CONTROLS_CHANGED,
mHost.isHandlingPointerEvent() /* fromUser */);
- applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, newStatsToken);
+ applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
+ // The animation of hiding transient types shouldn't be detected by the app.
+ // Otherwise, it might be able to react to the callbacks and cause
+ // flickering.
+ (hideTypes[0] & ~transientTypes[0]) == 0 /* skipsCallbacks */,
+ newStatsToken);
}
}
@@ -1174,7 +1187,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// TODO(b/353463205) check if this is needed here
ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
}
- applyAnimation(typesReady, true /* show */, fromIme, statsToken);
+ applyAnimation(typesReady, true /* show */, fromIme, false /* skipsCallbacks */,
+ statsToken);
}
/**
@@ -1287,7 +1301,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
handlePendingControlRequest(statsToken);
getImeSourceConsumer().removeSurface();
}
- applyAnimation(typesReady, false /* show */, fromIme, statsToken);
+ applyAnimation(typesReady, false /* show */, fromIme, false /* skipsCallbacks */,
+ statsToken);
}
@Override
@@ -2007,24 +2022,24 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme,
- @Nullable ImeTracker.Token statsToken) {
+ boolean skipsCallbacks, @Nullable ImeTracker.Token statsToken) {
// TODO(b/166736352): We should only skip the animation of specific types, not all types.
- boolean skipAnim = false;
+ boolean skipsAnim = false;
if ((types & ime()) != 0) {
final InsetsSourceControl imeControl = mImeSourceConsumer.getControl();
// Skip showing animation once that made by system for some reason.
// (e.g. starting window with IME snapshot)
if (imeControl != null) {
- skipAnim = imeControl.getAndClearSkipAnimationOnce() && show
+ skipsAnim = imeControl.getAndClearSkipAnimationOnce() && show
&& mImeSourceConsumer.hasViewFocusWhenWindowFocusGain();
}
}
- applyAnimation(types, show, fromIme, skipAnim, statsToken);
+ applyAnimation(types, show, fromIme, skipsAnim, skipsCallbacks, statsToken);
}
@VisibleForTesting
public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme,
- boolean skipAnim, @Nullable ImeTracker.Token statsToken) {
+ boolean skipsAnim, boolean skipsCallbacks, @Nullable ImeTracker.Token statsToken) {
if (types == 0) {
// nothing to animate.
if (DEBUG) Log.d(TAG, "applyAnimation, nothing to animate. Stopping here");
@@ -2040,7 +2055,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
final InternalAnimationControlListener listener = new InternalAnimationControlListener(
show, hasAnimationCallbacks, types, mHost.getSystemBarsBehavior(),
- skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
+ skipsAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
mLoggingListener, mJankContext);
// We are about to playing the default animation (show/hide). Passing a null frame indicates
@@ -2050,7 +2065,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
listener /* insetsAnimationSpec */,
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
- !hasAnimationCallbacks /* useInsetsAnimationThread */, statsToken,
+ !hasAnimationCallbacks || skipsCallbacks /* useInsetsAnimationThread */, statsToken,
false /* fromPredictiveBack */);
}
@@ -2173,12 +2188,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
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], 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], new int[1]);
+ sourceConsumer.setControl(null, new int[1], 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 17f33c1af4ed..e8e66210bca6 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -130,7 +130,10 @@ public class InsetsSourceConsumer {
* @return Whether the control has changed from the server
*/
public boolean setControl(@Nullable InsetsSourceControl control,
- @InsetsType int[] showTypes, @InsetsType int[] hideTypes, int[] cancelTypes) {
+ @InsetsType int[] showTypes,
+ @InsetsType int[] hideTypes,
+ @InsetsType int[] cancelTypes,
+ @InsetsType int[] transientTypes) {
if (Objects.equals(mSourceControl, control)) {
if (mSourceControl != null && mSourceControl != control) {
mSourceControl.release(SurfaceControl::release);
@@ -185,6 +188,9 @@ public class InsetsSourceConsumer {
} else {
hideTypes[0] |= mType;
}
+ if (lastControl != null && lastControl.isFake()) {
+ transientTypes[0] |= mType;
+ }
} else {
// We are gaining control, but don't need to run an animation.
// However make sure that the leash visibility is still up to date.
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index acbd95bf6810..7f2f0e8863df 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -142,6 +142,10 @@ public class InsetsSourceControl implements Parcelable {
return mInsetsHint;
}
+ public boolean isFake() {
+ return mLeash == null && Insets.NONE.equals(mInsetsHint);
+ }
+
public void setSkipAnimationOnce(boolean skipAnimation) {
mSkipAnimationOnce = skipAnimation;
}
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 248db65d7435..4a54f6b12c9d 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -133,7 +133,7 @@ public class ImeInsetsSourceConsumerTest {
// Called once through the show flow.
verify(mController).applyAnimation(
eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
- eq(statsToken));
+ eq(false) /* skipsCallbacks */, eq(statsToken));
// set control and verify visibility is applied.
InsetsSourceControl control = new InsetsSourceControl(ID_IME,
@@ -142,10 +142,10 @@ public class ImeInsetsSourceConsumerTest {
// IME show animation should be triggered when control becomes available.
verify(mController).applyAnimation(
eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
- and(not(eq(statsToken)), notNull()));
+ eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
verify(mController, never()).applyAnimation(
eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
- and(not(eq(statsToken)), notNull()));
+ eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
});
}
@@ -163,7 +163,7 @@ public class ImeInsetsSourceConsumerTest {
// Called once through the show flow.
verify(mController).applyAnimation(
eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
- eq(statsToken));
+ eq(false) /* skipsCallbacks */, eq(statsToken));
// Clear previous invocations to verify this is never called with control without leash.
clearInvocations(mController);
@@ -175,10 +175,10 @@ public class ImeInsetsSourceConsumerTest {
// as we have no leash.
verify(mController, never()).applyAnimation(
eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
- and(not(eq(statsToken)), notNull()));
+ eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
verify(mController, never()).applyAnimation(
eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
- and(not(eq(statsToken)), notNull()));
+ eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
// set control with leash and verify visibility is applied.
InsetsSourceControl controlWithLeash = new InsetsSourceControl(ID_IME,
@@ -187,10 +187,10 @@ public class ImeInsetsSourceConsumerTest {
// IME show animation should be triggered when control with leash becomes available.
verify(mController).applyAnimation(
eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
- and(not(eq(statsToken)), notNull()));
+ eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
verify(mController, never()).applyAnimation(
eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
- and(not(eq(statsToken)), notNull()));
+ eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
});
}
@@ -223,7 +223,8 @@ public class ImeInsetsSourceConsumerTest {
// Called once through the show flow.
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(true) /* fromIme */,
- eq(false) /* skipAnim */, eq(statsToken));
+ eq(false) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+ eq(statsToken));
}
// set control and verify visibility is applied.
@@ -241,7 +242,8 @@ public class ImeInsetsSourceConsumerTest {
// so the statsToken won't match.
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(false) /* fromIme */,
- eq(expectSkipAnim) /* skipAnim */, and(not(eq(statsToken)), notNull()));
+ eq(expectSkipAnim) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+ and(not(eq(statsToken)), notNull()));
}
// If previously hasViewFocus is false, verify when requesting the IME visible next
@@ -252,14 +254,16 @@ public class ImeInsetsSourceConsumerTest {
// Called once through the show flow.
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(true) /* fromIme */,
- eq(false) /* skipAnim */, eq(statsTokenNext));
+ eq(false) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+ eq(statsTokenNext));
mController.onControlsChanged(new InsetsSourceControl[]{ control });
// Verify IME show animation should be triggered when control becomes available and
// the animation will be skipped by getAndClearSkipAnimationOnce invoked.
verify(control).getAndClearSkipAnimationOnce();
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(false) /* fromIme */,
- eq(true) /* skipAnim */, and(not(eq(statsToken)), notNull()));
+ eq(true) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+ and(not(eq(statsToken)), notNull()));
}
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index d7f6a29d7c86..905d897e9ab0 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -100,14 +100,14 @@ public class InsetsAnimationControlImplTest {
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], 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], 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 3a8f7ee3d7c8..45d66e8ee3a9 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -117,7 +117,7 @@ public class InsetsSourceConsumerTest {
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], new int[1], new int[1]);
}
@Test
@@ -129,7 +129,7 @@ public class InsetsSourceConsumerTest {
newControl.setInsetsHint(Insets.of(0, 0, 0, 100));
int[] cancelTypes = {0};
- mConsumer.setControl(newControl, new int[1], new int[1], cancelTypes);
+ mConsumer.setControl(newControl, new int[1], new int[1], cancelTypes, new int[1]);
assertEquals(statusBars(), cancelTypes[0]);
});
@@ -196,7 +196,7 @@ public class InsetsSourceConsumerTest {
@Test
public void testRestore() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- mConsumer.setControl(null, new int[1], new int[1], new int[1]);
+ mConsumer.setControl(null, new int[1], new int[1], new int[1], new int[1]);
mSurfaceParamsApplied = false;
mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
assertFalse(mSurfaceParamsApplied);
@@ -204,7 +204,7 @@ public class InsetsSourceConsumerTest {
mConsumer.setControl(
new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
true /* initialVisible */, new Point(), Insets.NONE),
- new int[1], hideTypes, new int[1]);
+ new int[1], hideTypes, new int[1], new int[1]);
assertEquals(statusBars(), hideTypes[0]);
assertFalse(mRemoveSurfaceCalled);
});
@@ -214,7 +214,7 @@ public class InsetsSourceConsumerTest {
public void testRestore_noAnimation() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
- mConsumer.setControl(null, new int[1], new int[1], new int[1]);
+ mConsumer.setControl(null, new int[1], new int[1], new int[1], new int[1]);
mLeash = new SurfaceControl.Builder(mSession)
.setName("testSurface")
.build();
@@ -223,7 +223,7 @@ public class InsetsSourceConsumerTest {
mConsumer.setControl(
new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
false /* initialVisible */, new Point(), Insets.NONE),
- new int[1], hideTypes, new int[1]);
+ new int[1], hideTypes, new int[1], new int[1]);
assertTrue(mRemoveSurfaceCalled);
assertEquals(0, hideTypes[0]);
});
@@ -252,7 +252,7 @@ public class InsetsSourceConsumerTest {
// 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],
- new int[1]);
+ new int[1], new int[1]);
mSurfaceParamsApplied = false;
// Verify when the app requests controlling show IME animation, the IME leash
@@ -262,7 +262,7 @@ public class InsetsSourceConsumerTest {
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],
- new int[1]);
+ new int[1], new int[1]);
assertFalse(mSurfaceParamsApplied);
});
}