Merge "Let InsetsController control requested visible types"

This commit is contained in:
Tiger Huang
2022-12-20 12:06:49 +00:00
committed by Android (Google) Code Review
6 changed files with 175 additions and 220 deletions

View File

@@ -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;
/**
@@ -61,6 +60,38 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
super(ITYPE_IME, state, transactionSupplier, controller);
}
@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);
@@ -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) {

View File

@@ -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}.
*/

View File

@@ -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);
}
/**
* 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;
}
@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);
}
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 "
@@ -298,13 +292,6 @@ public class InsetsSourceConsumer {
public void onPerceptible(boolean perceptible) {
}
/**
* 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.
*/
@@ -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;

View File

@@ -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());

View File

@@ -132,17 +132,10 @@ 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());

View File

@@ -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);