Merge "Describe requested visibilities in public types (5/n: consumer)"

This commit is contained in:
Tiger Huang
2022-11-07 07:15:02 +00:00
committed by Android (Google) Code Review
9 changed files with 160 additions and 201 deletions

View File

@@ -65,7 +65,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
public void onWindowFocusGained(boolean hasViewFocus) {
super.onWindowFocusGained(hasViewFocus);
getImm().registerImeConsumer(this);
if (isRequestedVisible() && getControl() == null) {
if ((mController.getRequestedVisibleTypes() & getType()) != 0 && getControl() == null) {
mIsRequestedVisibleAwaitingControl = true;
}
}
@@ -125,7 +125,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
// If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
// this code here means that we now got control, so we can start the animation immediately.
// If client window is trying to control IME and IME is already visible, it is immediate.
if (fromIme || mState.getSource(getType()).isVisible() && getControl() != null) {
if (fromIme || (mState.getSource(getInternalType()).isVisible() && getControl() != null)) {
return ShowResult.SHOW_IMMEDIATELY;
}
@@ -169,7 +169,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
@Override
protected boolean isRequestedVisibleAwaitingControl() {
return mIsRequestedVisibleAwaitingControl || isRequestedVisible();
return super.isRequestedVisibleAwaitingControl() || mIsRequestedVisibleAwaitingControl;
}
@Override

View File

@@ -128,7 +128,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
null /* typeSideMap */);
mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
typeSideMap);
mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsInternalType(ITYPE_IME);
mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsType(WindowInsets.Type.ime());
if (mHasZeroInsetsIme) {
// IME has shownInsets of ZERO, and can't map to a side by default.
// Map zero insets IME to bottom, making it a special case of bottom insets.
@@ -141,7 +141,7 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
mCurrentInsets = calculateInsets(mInitialInsetsState, controls, true /* shown */);
mHiddenInsets = calculateInsets(null, controls, false /* shown */);
mShownInsets = calculateInsets(null, controls, true /* shown */);
mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsInternalType(ITYPE_IME);
mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsType(WindowInsets.Type.ime());
buildSideControlsMap(mSideControlsMap, controls);
}
mPendingInsets = mCurrentInsets;

View File

@@ -19,7 +19,6 @@ package android.view;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsController.AnimationType;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
/**
@@ -63,10 +62,10 @@ public interface InsetsAnimationControlRunner {
WindowInsetsAnimation getAnimation();
/**
* @return Whether {@link #getTypes()} maps to a specific {@link InternalInsetsType}.
* @return Whether {@link #getTypes()} contains a specific {@link InsetsType}.
*/
default boolean controlsInternalType(@InternalInsetsType int type) {
return InsetsState.toInternalType(getTypes()).contains(type);
default boolean controlsType(@InsetsType int type) {
return (getTypes() & type) != 0;
}
/**

View File

@@ -24,6 +24,8 @@ 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;
import static android.view.WindowInsets.Type.LAST;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.ime;
@@ -744,8 +746,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
InsetsSource source = newState.peekSource(type);
if (source == null) continue;
@AnimationType int animationType = getAnimationType(type);
@InsetsType int insetsType = toPublicType(type);
@AnimationType int animationType = getAnimationType(insetsType);
if (!source.isUserControllable()) {
// The user animation is not allowed when visible frame is empty.
disabledUserAnimationTypes |= insetsType;
@@ -788,8 +790,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (diff != 0) {
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
if (consumer.getControl() != null
&& (toPublicType(consumer.getType()) & diff) != 0) {
if (consumer.getControl() != null && (consumer.getType() & diff) != 0) {
mHandler.removeCallbacks(mInvokeControllableInsetsChangedListeners);
mHandler.post(mInvokeControllableInsetsChangedListeners);
break;
@@ -897,7 +898,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// Ensure to update all existing source consumers
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
final InsetsSourceControl control = mTmpControlArray.get(consumer.getType());
final InsetsSourceControl control = mTmpControlArray.get(consumer.getInternalType());
// control may be null, but we still need to update the control to null if it got
// revoked.
@@ -985,25 +986,26 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// TODO: Support a ResultReceiver for IME.
// TODO(b/123718661): Make show() work for multi-session IME.
int typesReady = 0;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
@InternalInsetsType int internalType = internalTypes.valueAt(i);
@AnimationType int animationType = getAnimationType(internalType);
InsetsSourceConsumer consumer = getSourceConsumer(internalType);
if (consumer.isRequestedVisible() && animationType == ANIMATION_TYPE_NONE
for (int type = FIRST; type <= LAST; type = type << 1) {
if ((types & type) == 0) {
continue;
}
final @AnimationType int animationType = getAnimationType(type);
final boolean requestedVisible = (type & mRequestedVisibleTypes) != 0;
if (requestedVisible && animationType == ANIMATION_TYPE_NONE
|| animationType == ANIMATION_TYPE_SHOW) {
// no-op: already shown or animating in (because window visibility is
// applied before starting animation).
if (DEBUG) Log.d(TAG, String.format(
"show ignored for type: %d animType: %d requestedVisible: %s",
consumer.getType(), animationType, consumer.isRequestedVisible()));
type, animationType, requestedVisible));
continue;
}
if (fromIme && animationType == ANIMATION_TYPE_USER) {
// App is already controlling the IME, don't cancel it.
continue;
}
typesReady |= InsetsState.toPublicType(consumer.getType());
typesReady |= type;
}
if (DEBUG) Log.d(TAG, "show typesReady: " + typesReady);
applyAnimation(typesReady, true /* show */, fromIme);
@@ -1024,17 +1026,18 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
}
int typesReady = 0;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
@InternalInsetsType int internalType = internalTypes.valueAt(i);
@AnimationType int animationType = getAnimationType(internalType);
InsetsSourceConsumer consumer = getSourceConsumer(internalType);
if (!consumer.isRequestedVisible() && animationType == ANIMATION_TYPE_NONE
for (int type = FIRST; type <= LAST; type = type << 1) {
if ((types & type) == 0) {
continue;
}
final @AnimationType int animationType = getAnimationType(type);
final boolean requestedVisible = (type & mRequestedVisibleTypes) != 0;
if (!requestedVisible && animationType == ANIMATION_TYPE_NONE
|| animationType == ANIMATION_TYPE_HIDE) {
// no-op: already hidden or animating out.
continue;
}
typesReady |= InsetsState.toPublicType(consumer.getType());
typesReady |= type;
}
applyAnimation(typesReady, false /* show */, fromIme /* fromIme */);
}
@@ -1228,13 +1231,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (!canRun) {
if (WARN) Log.w(TAG, String.format(
"collectSourceControls can't continue show for type: %s fromIme: %b",
InsetsState.typeToString(consumer.getType()), fromIme));
InsetsState.typeToString(consumer.getInternalType()), fromIme));
continue;
}
final InsetsSourceControl control = consumer.getControl();
if (control != null && control.getLeash() != null) {
controls.put(consumer.getType(), new InsetsSourceControl(control));
typesReady |= toPublicType(consumer.getType());
controls.put(control.getType(), new InsetsSourceControl(control));
typesReady |= consumer.getType();
} else if (animationType == ANIMATION_TYPE_SHOW) {
if (DEBUG) Log.d(TAG, "collectSourceControls no control for show(). fromIme: "
+ fromIme);
@@ -1260,25 +1263,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode(
@InsetsType int types) {
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
// Generally, we want to layout the opposite of the current state. This is to make animation
// callbacks easy to use: The can capture the layout values and then treat that as end-state
// during the animation.
//
// However, if controlling multiple sources, we want to treat it as shown if any of the
// types is currently hidden.
for (int i = internalTypes.size() - 1; i >= 0; i--) {
InsetsSourceConsumer consumer = mSourceConsumers.get(internalTypes.valueAt(i));
if (consumer == null) {
continue;
}
if (!consumer.isRequestedVisible()) {
return LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
}
}
return LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
return (mRequestedVisibleTypes & types) != types
? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
}
private void cancelExistingControllers(@InsetsType int types) {
@@ -1332,15 +1325,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
void notifyControlRevoked(InsetsSourceConsumer consumer) {
final @InsetsType int types = toPublicType(consumer.getType());
final @InsetsType int type = consumer.getType();
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
control.notifyControlRevoked(types);
control.notifyControlRevoked(type);
if (control.getControllingTypes() == 0) {
cancelAnimation(control, true /* invokeCallback */);
}
}
if (consumer.getType() == ITYPE_IME) {
if (type == ime()) {
abortPendingImeControlRequest();
}
}
@@ -1425,27 +1418,25 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
@VisibleForTesting
public @AnimationType int getAnimationType(@InternalInsetsType int type) {
public @AnimationType int getAnimationType(@InsetsType int type) {
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
if (control.controlsInternalType(type)) {
if (control.controlsType(type)) {
return mRunningAnimations.get(i).type;
}
}
return ANIMATION_TYPE_NONE;
}
@VisibleForTesting
public void onRequestedVisibilityChanged(InsetsSourceConsumer consumer) {
final @InsetsType int type = InsetsState.toPublicType(consumer.getType());
final int requestedVisibleTypes = consumer.isRequestedVisible()
? mRequestedVisibleTypes | type
: mRequestedVisibleTypes & ~type;
void setRequestedVisibleTypes(@InsetsType int visibleTypes, @InsetsType int mask) {
final @InsetsType int requestedVisibleTypes =
(mRequestedVisibleTypes & ~mask) | (visibleTypes & mask);
if (mRequestedVisibleTypes != requestedVisibleTypes) {
mRequestedVisibleTypes = requestedVisibleTypes;
if (WindowInsets.Type.hasCompatSystemBars(type)) {
if (WindowInsets.Type.hasCompatSystemBars(
mRequestedVisibleTypes ^ requestedVisibleTypes)) {
mCompatSysUiVisibilityStaled = true;
}
mRequestedVisibleTypes = requestedVisibleTypes;
}
}
@@ -1664,9 +1655,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@InsetsType int result = 0;
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
InsetsSource source = mState.peekSource(consumer.mType);
InsetsSource source = mState.peekSource(consumer.getInternalType());
if (consumer.getControl() != null && source != null && source.isUserControllable()) {
result |= toPublicType(consumer.mType);
result |= consumer.getType();
}
}
return result & ~mState.calculateUncontrollableInsetsFromFrame(mFrame);
@@ -1707,12 +1698,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
@Override
public void reportPerceptible(int types, boolean perceptible) {
final ArraySet<Integer> internalTypes = toInternalType(types);
public void reportPerceptible(@InsetsType int types, boolean perceptible) {
final int size = mSourceConsumers.size();
for (int i = 0; i < size; i++) {
final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
if (internalTypes.contains(consumer.getType())) {
if ((consumer.getType() & types) != 0) {
consumer.onPerceptible(perceptible);
}
}

View File

@@ -27,7 +27,6 @@ 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 android.view.InsetsState.toPublicType;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
@@ -74,9 +73,9 @@ public class InsetsSourceConsumer {
}
protected final InsetsController mController;
protected boolean mRequestedVisible;
protected final InsetsState mState;
protected final @InternalInsetsType int mType;
private final @InternalInsetsType int mInternalType;
private final @InsetsType int mType;
private static final String TAG = "InsetsSourceConsumer";
private final Supplier<Transaction> mTransactionSupplier;
@@ -99,11 +98,11 @@ public class InsetsSourceConsumer {
*/
public InsetsSourceConsumer(@InternalInsetsType int type, InsetsState state,
Supplier<Transaction> transactionSupplier, InsetsController controller) {
mType = type;
mType = InsetsState.toPublicType(type);
mInternalType = type;
mState = state;
mTransactionSupplier = transactionSupplier;
mController = controller;
mRequestedVisible = getDefaultVisibility(type);
}
/**
@@ -117,7 +116,7 @@ public class InsetsSourceConsumer {
*/
public boolean setControl(@Nullable InsetsSourceControl control,
@InsetsType int[] showTypes, @InsetsType int[] hideTypes) {
if (mType == ITYPE_IME) {
if (mInternalType == ITYPE_IME) {
ImeTracing.getInstance().triggerClientDump("InsetsSourceConsumer#setControl",
mController.getHost().getInputMethodManager(), null /* icProto */);
}
@@ -141,9 +140,10 @@ public class InsetsSourceConsumer {
mController.notifyControlRevoked(this);
// Check if we need to restore server visibility.
final InsetsSource source = mState.getSource(mType);
final InsetsSource source = mState.getSource(mInternalType);
final boolean serverVisibility =
mController.getLastDispatchedState().getSourceOrDefaultVisibility(mType);
mController.getLastDispatchedState().getSourceOrDefaultVisibility(
mInternalType);
if (source.isVisible() != serverVisibility) {
source.setVisible(serverVisibility);
mController.notifyVisibilityChanged();
@@ -159,9 +159,9 @@ public class InsetsSourceConsumer {
if (DEBUG) Log.d(TAG, String.format("Gaining leash in %s, requestedVisible: %b",
mController.getHost().getRootViewTitle(), requestedVisible));
if (requestedVisible) {
showTypes[0] |= toPublicType(getType());
showTypes[0] |= mType;
} else {
hideTypes[0] |= toPublicType(getType());
hideTypes[0] |= mType;
}
} else {
// We are gaining control, but don't need to run an animation.
@@ -172,7 +172,7 @@ 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.
if (mController.getAnimationType(control.getType()) == ANIMATION_TYPE_NONE) {
if (mController.getAnimationType(mType) == ANIMATION_TYPE_NONE) {
applyRequestedVisibilityToControl();
}
@@ -195,29 +195,32 @@ public class InsetsSourceConsumer {
/**
* Determines if the consumer will be shown after control is available.
* Note: for system bars this method is same as {@link #isRequestedVisible()}.
*
* @return {@code true} if consumer has a pending show.
*/
protected boolean isRequestedVisibleAwaitingControl() {
return isRequestedVisible();
return (mController.getRequestedVisibleTypes() & mType) != 0;
}
int getType() {
@InsetsType int getType() {
return mType;
}
@InternalInsetsType int getInternalType() {
return mInternalType;
}
@VisibleForTesting
public void show(boolean fromIme) {
if (DEBUG) Log.d(TAG, String.format("Call show() for type: %s fromIme: %b ",
InsetsState.typeToString(mType), fromIme));
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(mType), mController.getHost().getRootViewTitle()));
InsetsState.typeToString(mInternalType), mController.getHost().getRootViewTitle()));
setRequestedVisible(false);
}
@@ -245,11 +248,13 @@ public class InsetsSourceConsumer {
}
boolean applyLocalVisibilityOverride() {
final InsetsSource source = mState.peekSource(mType);
final boolean isVisible = source != null ? source.isVisible() : getDefaultVisibility(mType);
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 (mType == ITYPE_IME) {
if (mInternalType == ITYPE_IME) {
ImeTracing.getInstance().triggerClientDump(
"InsetsSourceConsumer#applyLocalVisibilityOverride",
mController.getHost().getInputMethodManager(), null /* icProto */);
@@ -259,23 +264,18 @@ public class InsetsSourceConsumer {
if (!hasControl) {
if (DEBUG) Log.d(TAG, "applyLocalVisibilityOverride: No control in "
+ mController.getHost().getRootViewTitle()
+ " requestedVisible " + mRequestedVisible);
+ " requestedVisible=" + requestedVisible);
return false;
}
if (isVisible == mRequestedVisible) {
if (isVisible == requestedVisible) {
return false;
}
if (DEBUG) Log.d(TAG, String.format("applyLocalVisibilityOverride: %s requestedVisible: %b",
mController.getHost().getRootViewTitle(), mRequestedVisible));
mState.getSource(mType).setVisible(mRequestedVisible);
mController.getHost().getRootViewTitle(), requestedVisible));
mState.getSource(mInternalType).setVisible(requestedVisible);
return true;
}
@VisibleForTesting
public boolean isRequestedVisible() {
return mRequestedVisible;
}
/**
* Request to show current window type.
*
@@ -314,7 +314,7 @@ public class InsetsSourceConsumer {
@VisibleForTesting(visibility = PACKAGE)
public void updateSource(InsetsSource newSource, @AnimationType int animationType) {
InsetsSource source = mState.peekSource(mType);
InsetsSource source = mState.peekSource(mInternalType);
if (source == null || animationType == ANIMATION_TYPE_NONE
|| source.getFrame().equals(newSource.getFrame())) {
mPendingFrame = null;
@@ -339,7 +339,7 @@ public class InsetsSourceConsumer {
@VisibleForTesting(visibility = PACKAGE)
public boolean notifyAnimationFinished() {
if (mPendingFrame != null) {
InsetsSource source = mState.getSource(mType);
InsetsSource source = mState.getSource(mInternalType);
source.setFrame(mPendingFrame);
source.setVisibleFrame(mPendingVisibleFrame);
mPendingFrame = null;
@@ -354,11 +354,8 @@ public class InsetsSourceConsumer {
* the moment.
*/
protected void setRequestedVisible(boolean requestedVisible) {
if (mRequestedVisible != requestedVisible) {
mRequestedVisible = requestedVisible;
mController.onRequestedVisibilityChanged(this);
if (DEBUG) Log.d(TAG, "setRequestedVisible: " + requestedVisible);
}
mController.setRequestedVisibleTypes(requestedVisible ? mType : 0, mType);
if (DEBUG) Log.d(TAG, "setRequestedVisible: " + requestedVisible);
if (applyLocalVisibilityOverride()) {
mController.notifyVisibilityChanged();
}
@@ -369,25 +366,26 @@ public class InsetsSourceConsumer {
return;
}
final boolean requestedVisible = (mController.getRequestedVisibleTypes() & mType) != 0;
try (Transaction t = mTransactionSupplier.get()) {
if (DEBUG) Log.d(TAG, "applyRequestedVisibilityToControl: " + mRequestedVisible);
if (mRequestedVisible) {
if (DEBUG) Log.d(TAG, "applyRequestedVisibilityToControl: " + requestedVisible);
if (requestedVisible) {
t.show(mSourceControl.getLeash());
} else {
t.hide(mSourceControl.getLeash());
}
// Ensure the alpha value is aligned with the actual requested visibility.
t.setAlpha(mSourceControl.getLeash(), mRequestedVisible ? 1 : 0);
t.setAlpha(mSourceControl.getLeash(), requestedVisible ? 1 : 0);
t.apply();
}
onPerceptible(mRequestedVisible);
onPerceptible(requestedVisible);
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(INTERNAL_INSETS_TYPE, InsetsState.typeToString(mType));
proto.write(INTERNAL_INSETS_TYPE, InsetsState.typeToString(mInternalType));
proto.write(HAS_WINDOW_FOCUS, mHasWindowFocus);
proto.write(IS_REQUESTED_VISIBLE, mRequestedVisible);
proto.write(IS_REQUESTED_VISIBLE, (mController.getRequestedVisibleTypes() & mType) != 0);
if (mSourceControl != null) {
mSourceControl.dumpDebug(proto, SOURCE_CONTROL);
}

View File

@@ -100,12 +100,12 @@ public class ImeInsetsSourceConsumerTest {
mImeConsumer.onWindowFocusGained(true);
mController.show(WindowInsets.Type.ime(), true /* fromIme */);
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertTrue((mController.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
// test if setVisibility can hide IME
mController.hide(WindowInsets.Type.ime(), true /* fromIme */);
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertFalse((mController.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
});
}

View File

@@ -27,7 +27,6 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -90,7 +89,6 @@ public class InsetsAnimationControlImplTest {
mInsetsState = new InsetsState();
mInsetsState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 500, 100));
mInsetsState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(400, 0, 500, 500));
doNothing().when(mMockController).onRequestedVisibilityChanged(any());
InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mInsetsState,
() -> mMockTransaction, mMockController);
topConsumer.setControl(

View File

@@ -255,10 +255,7 @@ public class InsetsControllerTest {
@Test
public void testAnimationEndState() {
InsetsSourceControl[] controls = prepareControls();
InsetsSourceControl navBar = controls[0];
InsetsSourceControl statusBar = controls[1];
InsetsSourceControl ime = controls[2];
prepareControls();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained(true);
@@ -267,16 +264,13 @@ public class InsetsControllerTest {
mController.show(all());
// quickly jump to final state by cancelling it.
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
final @InsetsType int types = navigationBars() | statusBars() | ime();
assertEquals(types, mController.getRequestedVisibleTypes() & types);
mController.hide(ime(), true /* fromIme */);
mController.hide(all());
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(0, mController.getRequestedVisibleTypes() & types);
mController.getSourceConsumer(ITYPE_IME).onWindowFocusLost();
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -290,10 +284,10 @@ public class InsetsControllerTest {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained(true);
mController.show(ime(), true /* fromIme */);
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertTrue(isRequestedVisible(mController, ime()));
mController.hide(ime(), true /* fromIme */);
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertFalse(isRequestedVisible(mController, ime()));
mController.getSourceConsumer(ITYPE_IME).onWindowFocusLost();
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -307,26 +301,22 @@ public class InsetsControllerTest {
InsetsSourceControl ime = controls[2];
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
int types = navigationBars() | systemBars();
int types = navigationBars() | statusBars();
// test hide select types.
mController.hide(types);
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(navigationBars()));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(statusBars()));
mController.cancelExistingAnimations();
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_STATUS_BAR));
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(navigationBars()));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(statusBars()));
assertEquals(0, mController.getRequestedVisibleTypes() & (types | ime()));
// test hide all
// test show all
mController.show(types);
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(navigationBars()));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(statusBars()));
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(types, mController.getRequestedVisibleTypes() & (types | ime()));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -339,33 +329,27 @@ public class InsetsControllerTest {
InsetsSourceControl ime = controls[2];
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
int types = navigationBars() | systemBars();
int types = navigationBars() | statusBars();
// test show select types.
mController.show(types);
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(types, mController.getRequestedVisibleTypes() & types);
assertEquals(0, mController.getRequestedVisibleTypes() & ime());
// test hide all
mController.hide(all());
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(0, mController.getRequestedVisibleTypes() & (types | ime()));
// test single show
mController.show(navigationBars());
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(navigationBars(),
mController.getRequestedVisibleTypes() & (types | ime()));
// test single hide
mController.hide(navigationBars());
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(0, mController.getRequestedVisibleTypes() & (types | ime()));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -373,49 +357,38 @@ public class InsetsControllerTest {
@Test
public void testShowHideMultiple() {
InsetsSourceControl[] controls = prepareControls();
InsetsSourceControl navBar = controls[0];
InsetsSourceControl statusBar = controls[1];
InsetsSourceControl ime = controls[2];
prepareControls();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
// start two animations and see if previous is cancelled and final state is reached.
mController.hide(navigationBars());
mController.hide(systemBars());
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
int types = navigationBars() | statusBars();
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(navigationBars()));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(statusBars()));
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(0, mController.getRequestedVisibleTypes() & (types | ime()));
mController.show(navigationBars());
mController.show(systemBars());
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(navigationBars()));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(statusBars()));
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(types, mController.getRequestedVisibleTypes() & (types | ime()));
int types = navigationBars() | systemBars();
// show two at a time and hide one by one.
mController.show(types);
mController.hide(navigationBars());
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(navigationBars()));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(statusBars()));
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(statusBars(), mController.getRequestedVisibleTypes() & (types | ime()));
mController.hide(systemBars());
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(ITYPE_NAVIGATION_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_NONE, mController.getAnimationType(navigationBars()));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(statusBars()));
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(0, mController.getRequestedVisibleTypes() & (types | ime()));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -428,20 +401,16 @@ public class InsetsControllerTest {
InsetsSourceControl ime = controls[2];
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
int types = navigationBars() | systemBars();
int types = navigationBars() | statusBars();
// show two at a time and hide one by one.
mController.show(types);
mController.hide(navigationBars());
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertTrue(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(statusBars(), mController.getRequestedVisibleTypes() & (types | ime()));
mController.hide(systemBars());
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(navBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(statusBar.getType()).isRequestedVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isRequestedVisible());
assertEquals(0, mController.getRequestedVisibleTypes() & (types | ime()));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -453,7 +422,7 @@ public class InsetsControllerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.hide(statusBars());
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(isRequestedVisible(mController, statusBars()));
assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
// Loosing control
@@ -461,14 +430,14 @@ public class InsetsControllerTest {
state.setSourceVisible(ITYPE_STATUS_BAR, true);
mController.onStateChanged(state);
mController.onControlsChanged(new InsetsSourceControl[0]);
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(isRequestedVisible(mController, statusBars()));
assertTrue(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
// Gaining control
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(statusBars()));
mController.cancelExistingAnimations();
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(isRequestedVisible(mController, statusBars()));
assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -488,9 +457,9 @@ public class InsetsControllerTest {
// Gaining control shortly after
mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ime()));
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
assertTrue(isRequestedVisible(mController, ime()));
assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -509,9 +478,9 @@ public class InsetsControllerTest {
// Pretend IME is calling
mController.show(ime(), true /* fromIme */);
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ime()));
mController.cancelExistingAnimations();
assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
assertTrue(isRequestedVisible(mController, ime()));
assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -538,7 +507,7 @@ public class InsetsControllerTest {
});
waitUntilNextFrame();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(isRequestedVisible(mController, statusBars()));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -565,7 +534,7 @@ public class InsetsControllerTest {
});
waitUntilNextFrame();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
assertFalse(isRequestedVisible(mController, statusBars()));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -701,6 +670,7 @@ public class InsetsControllerTest {
private void doTestResizeAnimation_insetsTypes(@InternalInsetsType int type,
@AnimationType int expectedAnimationType) {
final @InsetsType int publicType = InsetsState.toPublicType(type);
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final InsetsState state1 = new InsetsState();
state1.getSource(type).setVisible(true);
@@ -711,15 +681,15 @@ public class InsetsControllerTest {
// New insets source won't cause the resize animation.
mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(publicType));
// Changing frame might cause the resize animation. This depends on the insets type.
mController.onStateChanged(state2);
assertEquals(message, expectedAnimationType, mController.getAnimationType(type));
assertEquals(message, expectedAnimationType, mController.getAnimationType(publicType));
// Cancel the existing animations for the next iteration.
mController.cancelExistingAnimations();
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(publicType));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -728,6 +698,7 @@ public class InsetsControllerTest {
public void testResizeAnimation_displayFrame() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final @InternalInsetsType int type = ITYPE_STATUS_BAR;
final @InsetsType int publicType = statusBars();
final InsetsState state1 = new InsetsState();
state1.setDisplayFrame(new Rect(0, 0, 500, 1000));
state1.getSource(type).setFrame(0, 0, 500, 50);
@@ -738,11 +709,11 @@ public class InsetsControllerTest {
// New insets source won't cause the resize animation.
mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(publicType));
// Changing frame won't cause the resize animation if the display frame is also changed.
mController.onStateChanged(state2);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(publicType));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -751,6 +722,7 @@ public class InsetsControllerTest {
public void testResizeAnimation_visibility() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final @InternalInsetsType int type = ITYPE_STATUS_BAR;
final @InsetsType int publicType = statusBars();
final InsetsState state1 = new InsetsState();
state1.getSource(type).setVisible(true);
state1.getSource(type).setFrame(0, 0, 500, 50);
@@ -764,17 +736,17 @@ public class InsetsControllerTest {
// New insets source won't cause the resize animation.
mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(publicType));
// Changing source visibility (visible --> invisible) won't cause the resize animation.
// The previous source and the current one must be both visible.
mController.onStateChanged(state2);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(publicType));
// Changing source visibility (invisible --> visible) won't cause the resize animation.
// The previous source and the current one must be both visible.
mController.onStateChanged(state3);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(publicType));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -940,10 +912,10 @@ public class InsetsControllerTest {
// Verify IME requested visibility should be updated to IME consumer from controller.
mController.show(ime());
assertTrue(imeInsetsConsumer.isRequestedVisible());
assertTrue(isRequestedVisible(mController, ime()));
mController.hide(ime());
assertFalse(imeInsetsConsumer.isRequestedVisible());
assertFalse(isRequestedVisible(mController, ime()));
});
}
@@ -980,6 +952,10 @@ public class InsetsControllerTest {
return controls;
}
private static boolean isRequestedVisible(InsetsController controller, @InsetsType int type) {
return (controller.getRequestedVisibleTypes() & type) != 0;
}
public static class TestHost extends ViewRootInsetsControllerHost {
private @InsetsType int mRequestedVisibleTypes = defaultVisible();

View File

@@ -122,7 +122,6 @@ public class InsetsSourceConsumerTest {
public void testHide() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mConsumer.hide();
assertFalse("Consumer should not be visible", mConsumer.isRequestedVisible());
verify(mSpyInsetsSource).setVisible(eq(false));
});
@@ -134,7 +133,6 @@ public class InsetsSourceConsumerTest {
// Insets source starts out visible
mConsumer.hide();
mConsumer.show(false /* fromIme */);
assertTrue("Consumer should be visible", mConsumer.isRequestedVisible());
verify(mSpyInsetsSource).setVisible(eq(false));
verify(mSpyInsetsSource).setVisible(eq(true));
});
@@ -240,7 +238,7 @@ public class InsetsSourceConsumerTest {
// 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);
assertEquals(ANIMATION_TYPE_USER, insetsController.getAnimationType(ime()));
imeConsumer.setControl(new InsetsSourceControl(ITYPE_IME, mLeash,
true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
verify(mMockTransaction, never()).show(mLeash);