summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tiger Huang <tigerhuang@google.com> 2022-12-20 12:06:49 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-12-20 12:06:49 +0000
commit80cb333f059a37c3458eb544ae85257ce72e0783 (patch)
tree4bb9c5dc17c918597dbdad732d02099315de8260
parentcb7dd5c61b051cfae9dcae31645e603f20f7f0ee (diff)
parent5e6f95454c0a028920f759220a3db2c17be99a5d (diff)
Merge "Let InsetsController control requested visible types"
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java89
-rw-r--r--core/java/android/view/InsetsController.java174
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java82
-rw-r--r--core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java3
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java19
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java28
6 files changed, 175 insertions, 220 deletions
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 02e0fccd7d6c..e34aef97a8ab 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -16,21 +16,20 @@
package android.view;
-import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
import static android.view.ImeInsetsSourceConsumerProto.IS_HIDE_ANIMATION_RUNNING;
import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;
import static android.view.ImeInsetsSourceConsumerProto.IS_SHOW_REQUESTED_DURING_HIDE_ANIMATION;
-import static android.view.InsetsController.AnimationType;
import static android.view.InsetsState.ITYPE_IME;
import android.annotation.Nullable;
import android.os.IBinder;
-import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl.Transaction;
import android.view.inputmethod.InputMethodManager;
+import com.android.internal.inputmethod.ImeTracing;
+
import java.util.function.Supplier;
/**
@@ -62,6 +61,38 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
}
@Override
+ public boolean onAnimationStateChanged(boolean running) {
+ if (!running) {
+ ImeTracing.getInstance().triggerClientDump(
+ "ImeInsetsSourceConsumer#onAnimationFinished",
+ mController.getHost().getInputMethodManager(), null /* icProto */);
+ }
+ final boolean insetsChanged = super.onAnimationStateChanged(running);
+ final boolean showRequested = (mController.getRequestedVisibleTypes() & getType()) != 0;
+ if (showRequested) {
+ onShowRequested();
+ } else {
+ mIsRequestedVisibleAwaitingControl = false;
+ if (!running) {
+ // Remove IME surface as IME has finished hide animation, if there is no pending
+ // show request.
+ if (!mIsShowRequestedDuringHideAnimation) {
+ notifyHidden();
+ removeSurface();
+ }
+ }
+ // Here is reached
+ // (1) before the hide animation starts.
+ // (2) after the hide animation ends.
+ // (3) if the IME is not controllable (animationFinished == true in this case).
+ // We should reset mIsShowRequestedDuringHideAnimation in all cases.
+ mIsHideAnimationRunning = running;
+ mIsShowRequestedDuringHideAnimation = false;
+ }
+ return insetsChanged;
+ }
+
+ @Override
public void onWindowFocusGained(boolean hasViewFocus) {
super.onWindowFocusGained(hasViewFocus);
getImm().registerImeConsumer(this);
@@ -78,36 +109,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
}
@Override
- public void show(boolean fromIme) {
- super.show(fromIme);
- onShowRequested();
- }
-
- @Override
- public void hide() {
- super.hide();
- mIsRequestedVisibleAwaitingControl = false;
- }
-
- @Override
- void hide(boolean animationFinished, @AnimationType int animationType) {
- hide();
-
- if (animationFinished) {
- // Remove IME surface as IME has finished hide animation, if there is no pending
- // show request.
- if (!mIsShowRequestedDuringHideAnimation) {
- notifyHidden();
- removeSurface();
- }
- }
- // This method is called
- // (1) before the hide animation starts.
- // (2) after the hide animation ends.
- // (3) if the IME is not controllable (animationFinished == true in this case).
- // We should reset mIsShowRequestedDuringHideAnimation in all cases.
- mIsHideAnimationRunning = !animationFinished;
- mIsShowRequestedDuringHideAnimation = false;
+ public boolean applyLocalVisibilityOverride() {
+ ImeTracing.getInstance().triggerClientDump(
+ "ImeInsetsSourceConsumer#applyLocalVisibilityOverride",
+ mController.getHost().getInputMethodManager(), null /* icProto */);
+ return super.applyLocalVisibilityOverride();
}
/**
@@ -116,6 +122,12 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
*/
@Override
public @ShowResult int requestShow(boolean fromIme) {
+ if (fromIme) {
+ ImeTracing.getInstance().triggerClientDump(
+ "ImeInsetsSourceConsumer#requestShow",
+ mController.getHost().getInputMethodManager(), null /* icProto */);
+ }
+
// TODO: ResultReceiver for IME.
// TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
if (getControl() == null) {
@@ -137,10 +149,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
* Notify {@link com.android.server.inputmethod.InputMethodManagerService} that
* IME insets are hidden.
*/
- @Override
- void notifyHidden() {
+ private void notifyHidden() {
getImm().notifyImeHidden(mController.getHost().getWindowToken());
- Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
}
@Override
@@ -154,11 +164,13 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
@Override
public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
int[] hideTypes) {
+ ImeTracing.getInstance().triggerClientDump("ImeInsetsSourceConsumer#setControl",
+ mController.getHost().getInputMethodManager(), null /* icProto */);
if (!super.setControl(control, showTypes, hideTypes)) {
return false;
}
if (control == null && !mIsRequestedVisibleAwaitingControl) {
- hide();
+ mController.setRequestedVisibleTypes(0 /* visibleTypes */, getType());
removeSurface();
}
if (control != null) {
@@ -192,7 +204,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
}
/**
- * Called when {@link #show} or {@link InputMethodManager#showSoftInput(View, int)} is called.
+ * Called when {@link #onAnimationStateChanged(boolean)} or
+ * {@link InputMethodManager#showSoftInput(View, int)} is called.
*/
public void onShowRequested() {
if (mIsHideAnimationRunning) {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 421efed83852..e1b27ffe035d 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -21,7 +21,6 @@ import static android.view.InsetsControllerProto.CONTROL;
import static android.view.InsetsControllerProto.STATE;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
-import static android.view.InsetsState.toInternalType;
import static android.view.InsetsState.toPublicType;
import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.WindowInsets.Type.FIRST;
@@ -742,6 +741,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private void updateState(InsetsState newState) {
mState.set(newState, 0 /* types */);
+ @InsetsType int existingTypes = 0;
@InsetsType int visibleTypes = 0;
@InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
@@ -760,10 +760,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
}
getSourceConsumer(type).updateSource(source, animationType);
+ existingTypes |= insetsType;
if (source.isVisible()) {
visibleTypes |= insetsType;
}
}
+
+ // If a type doesn't have a source, treat it as visible if it is visible by default.
+ visibleTypes |= WindowInsets.Type.defaultVisible() & ~existingTypes;
+
if (mVisibleTypes != visibleTypes) {
if (WindowInsets.Type.hasCompatSystemBars(mVisibleTypes ^ visibleTypes)) {
mCompatSysUiVisibilityStaled = true;
@@ -1103,6 +1108,29 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@AnimationType int animationType,
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken) {
+ final boolean visible = layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
+
+ // Basically, we accept the requested visibilities from the upstream callers...
+ setRequestedVisibleTypes(visible ? types : 0, types);
+
+ // However, we might reject the request in some cases, such as delaying showing IME or
+ // rejecting showing IME.
+ controlAnimationUncheckedInner(types, cancellationSignal, listener, frame, fromIme,
+ durationMs, interpolator, animationType, layoutInsetsDuringAnimation,
+ useInsetsAnimationThread, statsToken);
+
+ // We are finishing setting the requested visible types. Report them to the server and/or
+ // the app.
+ reportRequestedVisibleTypes();
+ }
+
+ private void controlAnimationUncheckedInner(@InsetsType int types,
+ @Nullable CancellationSignal cancellationSignal,
+ WindowInsetsAnimationControlListener listener, @Nullable Rect frame, boolean fromIme,
+ long durationMs, Interpolator interpolator,
+ @AnimationType int animationType,
+ @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
+ boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken) {
ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
if ((types & mTypesBeingCancelled) != 0) {
throw new IllegalStateException("Cannot start a new insets animation of "
@@ -1119,13 +1147,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
&& !mState.getSource(ITYPE_IME).isVisible()) {
// We've requested IMM to show IME, but the IME is not controllable. We need to
// cancel the request.
- getSourceConsumer(ITYPE_IME).hide(true, animationType);
+ setRequestedVisibleTypes(0 /* visibleTypes */, ime());
+ if (getSourceConsumer(ITYPE_IME).onAnimationStateChanged(false /* running */)) {
+ notifyVisibilityChanged();
+ }
}
}
if (types == 0) {
// nothing to animate.
listener.onCancelled(null);
- reportRequestedVisibleTypes();
if (DEBUG) Log.d(TAG, "no types to animate in controlAnimationUnchecked");
return;
}
@@ -1161,7 +1191,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
});
}
- reportRequestedVisibleTypes();
+
+ // The requested visibilities should be delayed as well. Otherwise, the server will
+ // create already visible leashes for us before we play the show animation.
+ setRequestedVisibleTypes(mReportedRequestedVisibleTypes, types);
+
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0);
return;
}
@@ -1169,7 +1203,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (typesReady == 0) {
if (DEBUG) Log.d(TAG, "No types ready. onCancelled()");
listener.onCancelled(null);
- reportRequestedVisibleTypes();
return;
}
@@ -1198,12 +1231,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
} else {
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
}
- if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
- showDirectly(types, fromIme);
- } else {
- hideDirectly(types, false /* animationFinished */, animationType, fromIme);
+ onAnimationStateChanged(types, true /* running */);
+
+ if (fromIme) {
+ switch (animationType) {
+ case ANIMATION_TYPE_SHOW:
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
+ break;
+ case ANIMATION_TYPE_HIDE:
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
+ break;
+ }
+ } else if (animationType == ANIMATION_TYPE_HIDE) {
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
}
- reportRequestedVisibleTypes();
}
// TODO(b/242962223): Make this setter restrictive.
@@ -1228,11 +1269,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
boolean canRun = true;
if (show) {
// Show request
- if (fromIme) {
- ImeTracing.getInstance().triggerClientDump(
- "ImeInsetsSourceConsumer#requestShow", mHost.getInputMethodManager(),
- null /* icProto */);
- }
switch(consumer.requestShow(fromIme)) {
case ShowResult.SHOW_IMMEDIATELY:
break;
@@ -1246,15 +1282,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// IME cannot be shown (since it didn't have focus), proceed
// with animation of other types.
canRun = false;
+
+ // Reject the show request.
+ setRequestedVisibleTypes(0 /* visibleTypes */, consumer.getType());
break;
}
- } else {
- // Hide request
- // TODO: Move notifyHidden() to beginning of the hide animation
- // (when visibility actually changes using hideDirectly()).
- if (!fromIme) {
- consumer.notifyHidden();
- }
}
if (!canRun) {
if (WARN) Log.w(TAG, String.format(
@@ -1266,24 +1298,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (control != null && control.getLeash() != null) {
controls.put(control.getId(), new InsetsSourceControl(control));
typesReady |= consumer.getType();
- } else if (animationType == ANIMATION_TYPE_SHOW) {
- if (DEBUG) Log.d(TAG, "collectSourceControls no control for show(). fromIme: "
- + fromIme);
- // We don't have a control at the moment. However, we still want to update requested
- // visibility state such that in case we get control, we can apply show animation.
- if (fromIme) {
- ImeTracing.getInstance().triggerClientDump(
- "InsetsSourceConsumer#show", mHost.getInputMethodManager(),
- null /* icProto */);
- }
- consumer.show(fromIme);
- } else if (animationType == ANIMATION_TYPE_HIDE) {
- if (fromIme) {
- ImeTracing.getInstance().triggerClientDump(
- "InsetsSourceConsumer#hide", mHost.getInputMethodManager(),
- null /* icProto */);
- }
- consumer.hide();
}
}
return new Pair<>(typesReady, imeReady);
@@ -1332,6 +1346,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
@Override
public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
+ setRequestedVisibleTypes(shown ? runner.getTypes() : 0, runner.getTypes());
cancelAnimation(runner, false /* invokeCallback */);
if (DEBUG) Log.d(TAG, "notifyFinished. shown: " + shown);
if (runner.getAnimationType() == ANIMATION_TYPE_RESIZE) {
@@ -1343,15 +1358,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (shown) {
ImeTracker.get().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_SHOW);
- showDirectly(runner.getTypes(), true /* fromIme */);
ImeTracker.get().onShown(statsToken);
} else {
ImeTracker.get().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_HIDE);
- hideDirectly(runner.getTypes(), true /* animationFinished */,
- runner.getAnimationType(), true /* fromIme */);
ImeTracker.get().onHidden(statsToken);
}
+ reportRequestedVisibleTypes();
}
@Override
@@ -1388,28 +1401,31 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
"cancelAnimation of types: %d, animType: %d, host: %s",
control.getTypes(), control.getAnimationType(), mHost.getRootViewTitle()));
}
- boolean stateChanged = false;
+ @InsetsType int removedTypes = 0;
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == control) {
mRunningAnimations.remove(i);
- ArraySet<Integer> types = toInternalType(control.getTypes());
- for (int j = types.size() - 1; j >= 0; j--) {
- if (types.valueAt(j) == ITYPE_IME) {
- ImeTracing.getInstance().triggerClientDump(
- "InsetsSourceConsumer#notifyAnimationFinished",
- mHost.getInputMethodManager(), null /* icProto */);
- }
- stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
- }
+ removedTypes = control.getTypes();
if (invokeCallback) {
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
}
break;
}
}
- if (stateChanged) {
- mHost.notifyInsetsChanged();
+ onAnimationStateChanged(removedTypes, false /* running */);
+ }
+
+ private void onAnimationStateChanged(@InsetsType int types, boolean running) {
+ boolean insetsChanged = false;
+ for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
+ final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
+ if ((consumer.getType() & types) != 0) {
+ insetsChanged |= consumer.onAnimationStateChanged(running);
+ }
+ }
+ if (insetsChanged) {
+ notifyVisibilityChanged();
}
}
@@ -1472,27 +1488,28 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return ANIMATION_TYPE_NONE;
}
- void setRequestedVisibleTypes(@InsetsType int visibleTypes, @InsetsType int mask) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setRequestedVisibleTypes(@InsetsType int visibleTypes, @InsetsType int mask) {
final @InsetsType int requestedVisibleTypes =
(mRequestedVisibleTypes & ~mask) | (visibleTypes & mask);
if (mRequestedVisibleTypes != requestedVisibleTypes) {
- if (WindowInsets.Type.hasCompatSystemBars(
- mRequestedVisibleTypes ^ requestedVisibleTypes)) {
- mCompatSysUiVisibilityStaled = true;
- }
mRequestedVisibleTypes = requestedVisibleTypes;
}
}
/**
- * Sends the requested visible types to window manager if any of them is changed.
+ * Called when finishing setting requested visible types or finishing setting controls.
*/
private void reportRequestedVisibleTypes() {
- updateCompatSysUiVisibility();
if (mReportedRequestedVisibleTypes != mRequestedVisibleTypes) {
+ final @InsetsType int diff = mRequestedVisibleTypes ^ mReportedRequestedVisibleTypes;
+ if (WindowInsets.Type.hasCompatSystemBars(diff)) {
+ mCompatSysUiVisibilityStaled = true;
+ }
mReportedRequestedVisibleTypes = mRequestedVisibleTypes;
mHost.updateRequestedVisibleTypes(mReportedRequestedVisibleTypes);
}
+ updateCompatSysUiVisibility();
}
@VisibleForTesting
@@ -1538,39 +1555,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
!hasAnimationCallbacks /* useInsetsAnimationThread */, statsToken);
}
- private void hideDirectly(@InsetsType int types, boolean animationFinished,
- @AnimationType int animationType, boolean fromIme) {
- if ((types & ime()) != 0) {
- ImeTracing.getInstance().triggerClientDump("InsetsController#hideDirectly",
- mHost.getInputMethodManager(), null /* icProto */);
- }
- final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
- for (int i = internalTypes.size() - 1; i >= 0; i--) {
- getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
- }
- reportRequestedVisibleTypes();
-
- if (fromIme) {
- Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
- }
- }
-
- private void showDirectly(@InsetsType int types, boolean fromIme) {
- if ((types & ime()) != 0) {
- ImeTracing.getInstance().triggerClientDump("InsetsController#showDirectly",
- mHost.getInputMethodManager(), null /* icProto */);
- }
- final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
- for (int i = internalTypes.size() - 1; i >= 0; i--) {
- getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
- }
- reportRequestedVisibleTypes();
-
- if (fromIme) {
- Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
- }
- }
-
/**
* Cancel on-going animation to show/hide {@link InsetsType}.
*/
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index b8c4eaa782e7..7aeada8e9def 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -25,7 +25,6 @@ import static android.view.InsetsSourceConsumerProto.IS_REQUESTED_VISIBLE;
import static android.view.InsetsSourceConsumerProto.PENDING_FRAME;
import static android.view.InsetsSourceConsumerProto.PENDING_VISIBLE_FRAME;
import static android.view.InsetsSourceConsumerProto.SOURCE_CONTROL;
-import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.getDefaultVisibility;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
@@ -40,7 +39,6 @@ import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type.InsetsType;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.inputmethod.ImeTracing;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -116,10 +114,6 @@ public class InsetsSourceConsumer {
*/
public boolean setControl(@Nullable InsetsSourceControl control,
@InsetsType int[] showTypes, @InsetsType int[] hideTypes) {
- if (mInternalType == ITYPE_IME) {
- ImeTracing.getInstance().triggerClientDump("InsetsSourceConsumer#setControl",
- mController.getHost().getInputMethodManager(), null /* icProto */);
- }
if (Objects.equals(mSourceControl, control)) {
if (mSourceControl != null && mSourceControl != control) {
mSourceControl.release(SurfaceControl::release);
@@ -210,22 +204,27 @@ public class InsetsSourceConsumer {
return mInternalType;
}
- @VisibleForTesting
- public void show(boolean fromIme) {
- if (DEBUG) Log.d(TAG, String.format("Call show() for type: %s fromIme: %b ",
- InsetsState.typeToString(mInternalType), fromIme));
- setRequestedVisible(true);
- }
-
- @VisibleForTesting
- public void hide() {
- if (DEBUG) Log.d(TAG, String.format("Call hide for %s on %s",
- InsetsState.typeToString(mInternalType), mController.getHost().getRootViewTitle()));
- setRequestedVisible(false);
- }
+ /**
+ * Called right after the animation is started or finished.
+ */
+ @VisibleForTesting(visibility = PACKAGE)
+ public boolean onAnimationStateChanged(boolean running) {
+ boolean insetsChanged = false;
+ if (!running && mPendingFrame != null) {
+ InsetsSource source = mState.getSource(mInternalType);
+ source.setFrame(mPendingFrame);
+ source.setVisibleFrame(mPendingVisibleFrame);
+ mPendingFrame = null;
+ mPendingVisibleFrame = null;
+ insetsChanged = true;
+ }
- void hide(boolean animationFinished, @AnimationType int animationType) {
- hide();
+ // We apply the visibility override after the animation is started. We don't do this before
+ // that because we need to know the initial insets state while creating the animation.
+ // We also need to apply the override after the animation is finished because the requested
+ // visibility can be set when finishing the user animation.
+ insetsChanged |= applyLocalVisibilityOverride();
+ return insetsChanged;
}
/**
@@ -247,19 +246,14 @@ public class InsetsSourceConsumer {
return mHasViewFocusWhenWindowFocusGain;
}
- boolean applyLocalVisibilityOverride() {
+ @VisibleForTesting(visibility = PACKAGE)
+ public boolean applyLocalVisibilityOverride() {
final InsetsSource source = mState.peekSource(mInternalType);
final boolean isVisible = source != null ? source.isVisible() : getDefaultVisibility(
mInternalType);
final boolean hasControl = mSourceControl != null;
final boolean requestedVisible = (mController.getRequestedVisibleTypes() & mType) != 0;
- if (mInternalType == ITYPE_IME) {
- ImeTracing.getInstance().triggerClientDump(
- "InsetsSourceConsumer#applyLocalVisibilityOverride",
- mController.getHost().getInputMethodManager(), null /* icProto */);
- }
-
// If we don't have control, we are not able to change the visibility.
if (!hasControl) {
if (DEBUG) Log.d(TAG, "applyLocalVisibilityOverride: No control in "
@@ -299,13 +293,6 @@ public class InsetsSourceConsumer {
}
/**
- * Notify listeners that window is now hidden.
- */
- void notifyHidden() {
- // no-op for types that always return ShowResult#SHOW_IMMEDIATELY.
- }
-
- /**
* Remove surface on which this consumer type is drawn.
*/
public void removeSurface() {
@@ -336,31 +323,6 @@ public class InsetsSourceConsumer {
if (DEBUG) Log.d(TAG, "updateSource: " + newSource);
}
- @VisibleForTesting(visibility = PACKAGE)
- public boolean notifyAnimationFinished() {
- if (mPendingFrame != null) {
- InsetsSource source = mState.getSource(mInternalType);
- source.setFrame(mPendingFrame);
- source.setVisibleFrame(mPendingVisibleFrame);
- mPendingFrame = null;
- mPendingVisibleFrame = null;
- return true;
- }
- return false;
- }
-
- /**
- * Sets requested visibility from the client, regardless of whether we are able to control it at
- * the moment.
- */
- protected void setRequestedVisible(boolean requestedVisible) {
- mController.setRequestedVisibleTypes(requestedVisible ? mType : 0, mType);
- if (DEBUG) Log.d(TAG, "setRequestedVisible: " + requestedVisible);
- if (applyLocalVisibilityOverride()) {
- mController.notifyVisibilityChanged();
- }
- }
-
private void applyRequestedVisibilityToControl() {
if (mSourceControl == null || mSourceControl.getLeash() == null) {
return;
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 19ff5982f65f..597df0ba4949 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -102,7 +102,8 @@ public class InsetsAnimationControlImplTest {
new InsetsSourceControl(ITYPE_NAVIGATION_BAR, WindowInsets.Type.navigationBars(),
mNavLeash, true, new Point(400, 0), Insets.of(0, 0, 100, 0)),
new int[1], new int[1]);
- navConsumer.hide();
+ mMockController.setRequestedVisibleTypes(0, WindowInsets.Type.navigationBars());
+ navConsumer.applyLocalVisibilityOverride();
SparseArray<InsetsSourceControl> controls = new SparseArray<>();
controls.put(ITYPE_STATUS_BAR, topConsumer.getControl());
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index fad9a5ca057c..88249ad0db4c 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -133,16 +133,9 @@ public class InsetsControllerTest {
private boolean mImeRequestedShow;
@Override
- public void show(boolean fromIme) {
- super.show(fromIme);
- if (fromIme) {
- mImeRequestedShow = true;
- }
- }
-
- @Override
public int requestShow(boolean fromController) {
if (fromController || mImeRequestedShow) {
+ mImeRequestedShow = true;
return SHOW_IMMEDIATELY;
} else {
return IME_SHOW_DELAYED;
@@ -815,10 +808,10 @@ public class InsetsControllerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
prepareControls();
- // Hiding visible system bars should only causes insets change once for each bar.
+ // Calling to hide system bars once should only cause insets change once.
clearInvocations(mTestHost);
mController.hide(statusBars() | navigationBars());
- verify(mTestHost, times(2)).notifyInsetsChanged();
+ verify(mTestHost, times(1)).notifyInsetsChanged();
// Sending the same insets state should not cause insets change.
// This simulates the callback from server after hiding system bars.
@@ -826,10 +819,10 @@ public class InsetsControllerTest {
mController.onStateChanged(mController.getState());
verify(mTestHost, never()).notifyInsetsChanged();
- // Showing invisible system bars should only causes insets change once for each bar.
+ // Calling to show system bars once should only cause insets change once.
clearInvocations(mTestHost);
mController.show(statusBars() | navigationBars());
- verify(mTestHost, times(2)).notifyInsetsChanged();
+ verify(mTestHost, times(1)).notifyInsetsChanged();
// Sending the same insets state should not cause insets change.
// This simulates the callback from server after showing system bars.
@@ -912,7 +905,7 @@ public class InsetsControllerTest {
assertNull(imeInsetsConsumer.getControl());
// Verify IME requested visibility should be updated to IME consumer from controller.
- mController.show(ime());
+ mController.show(ime(), true /* fromIme */, null /* statsToken */);
assertTrue(isRequestedVisible(mController, ime()));
mController.hide(ime());
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 521b65edf2bd..cec3fc5ba2d8 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -29,7 +29,6 @@ import static junit.framework.TestCase.assertFalse;
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;
@@ -119,30 +118,33 @@ public class InsetsSourceConsumerTest {
}
@Test
- public void testHide() {
+ public void testOnAnimationStateChanged_requestedInvisible() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- mConsumer.hide();
+ mController.setRequestedVisibleTypes(0 /* visibleTypes */, mSpyInsetsSource.getType());
+ mConsumer.onAnimationStateChanged(false /* running */);
verify(mSpyInsetsSource).setVisible(eq(false));
});
-
}
@Test
- public void testShow() {
+ public void testOnAnimationStateChanged_requestedVisible() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
// Insets source starts out visible
- mConsumer.hide();
- mConsumer.show(false /* fromIme */);
+ final int type = mSpyInsetsSource.getType();
+ mController.setRequestedVisibleTypes(0 /* visibleTypes */, type);
+ mConsumer.onAnimationStateChanged(false /* running */);
+ mController.setRequestedVisibleTypes(type, type);
+ mConsumer.onAnimationStateChanged(false /* running */);
verify(mSpyInsetsSource).setVisible(eq(false));
verify(mSpyInsetsSource).setVisible(eq(true));
});
-
}
@Test
public void testPendingStates() {
InsetsState state = new InsetsState();
- InsetsController controller = mock(InsetsController.class);
+ InsetsController controller = new InsetsController(new ViewRootInsetsControllerHost(
+ mViewRoot));
InsetsSourceConsumer consumer = new InsetsSourceConsumer(
ITYPE_IME, state, null, controller);
@@ -156,7 +158,7 @@ public class InsetsSourceConsumerTest {
assertEquals(new Rect(0, 1, 2, 3), state.peekSource(ITYPE_IME).getFrame());
// Finish the animation, now the pending frame should be applied
- assertTrue(consumer.notifyAnimationFinished());
+ assertTrue(consumer.onAnimationStateChanged(false /* running */));
assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
// Animating again, updates are delayed
@@ -169,7 +171,7 @@ public class InsetsSourceConsumerTest {
source.setFrame(4, 5, 6, 7);
consumer.updateSource(new InsetsSource(source), ANIMATION_TYPE_USER);
- assertFalse(consumer.notifyAnimationFinished());
+ assertFalse(consumer.onAnimationStateChanged(false /* running */));
assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
}
@@ -178,7 +180,7 @@ public class InsetsSourceConsumerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mConsumer.setControl(null, new int[1], new int[1]);
reset(mMockTransaction);
- mConsumer.hide();
+ mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
verifyZeroInteractions(mMockTransaction);
int[] hideTypes = new int[1];
mConsumer.setControl(
@@ -193,7 +195,7 @@ public class InsetsSourceConsumerTest {
@Test
public void testRestore_noAnimation() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- mConsumer.hide();
+ mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
mConsumer.setControl(null, new int[1], new int[1]);
reset(mMockTransaction);
verifyZeroInteractions(mMockTransaction);