Merge "Invoke insets animation callbacks when resizing system bars" into sc-v2-dev am: a42a8d6bf3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15327977

Change-Id: I095a5ad863d9d27b855fa586cb920c5139782181
This commit is contained in:
Tiger Huang
2021-09-02 11:23:23 +00:00
committed by Automerger Merge Worker
18 changed files with 455 additions and 58 deletions

View File

@@ -20,7 +20,8 @@ import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
/**
* Provide an interface to let InsetsAnimationControlImpl call back into its owner.
* Provide an interface to let InsetsAnimationControlImpl and InsetsResizeAnimationRunner call back
* into its owner.
* @hide
*/
public interface InsetsAnimationControlCallbacks {
@@ -34,10 +35,9 @@ public interface InsetsAnimationControlCallbacks {
* <li>Dispatch {@link WindowInsetsAnimationControlListener#onReady}</li>
* </ul>
*/
void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation,
Bounds bounds);
<T extends InsetsAnimationControlRunner & WindowInsetsAnimationController>
void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation, Bounds bounds);
/**
* Schedule the apply by posting the animation callback.

View File

@@ -105,7 +105,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
private float mCurrentAlpha = 1.0f;
private float mPendingAlpha = 1.0f;
@VisibleForTesting(visibility = PACKAGE)
public boolean mReadyDispatched;
private boolean mReadyDispatched;
private Boolean mPerceptible;
@VisibleForTesting
@@ -169,6 +169,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
return mHasZeroInsetsIme;
}
@Override
public void setReadyDispatched(boolean dispatched) {
mReadyDispatched = dispatched;
}
@Override
public Insets getHiddenStateInsets() {
return mHiddenInsets;

View File

@@ -54,8 +54,8 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro
@Override
@UiThread
public void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
public <T extends InsetsAnimationControlRunner & WindowInsetsAnimationController>
void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation, Bounds bounds) {
// Animation will be started in constructor already.
}

View File

@@ -205,6 +205,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private static final int ANIMATION_DURATION_FADE_IN_MS = 500;
private static final int ANIMATION_DURATION_FADE_OUT_MS = 1500;
/** Visible for WindowManagerWrapper */
public static final int ANIMATION_DURATION_RESIZE = 300;
private static final int ANIMATION_DELAY_DIM_MS = 500;
private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
@@ -235,6 +238,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
new PathInterpolator(0.4f, 0f, 1f, 1f);
/** Visible for WindowManagerWrapper */
public static final Interpolator RESIZE_INTERPOLATOR = new LinearInterpolator();
/** The amount IME will move up/down when animating in floating mode. */
private static final int FLOATING_IME_BOTTOM_INSET_DP = -80;
@@ -288,9 +294,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public static final int ANIMATION_TYPE_USER = 2;
/** Running animation will resize insets */
@VisibleForTesting
public static final int ANIMATION_TYPE_RESIZE = 3;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE,
ANIMATION_TYPE_USER})
ANIMATION_TYPE_USER, ANIMATION_TYPE_RESIZE})
@interface AnimationType {
}
@@ -320,7 +330,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private final boolean mDisable;
private final int mFloatingImeBottomInset;
private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
new ThreadLocal<AnimationHandler>() {
@Override
protected AnimationHandler initialValue() {
@@ -550,7 +560,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
private final ArraySet<InsetsSourceConsumer> mRequestedVisibilityChanged = new ArraySet<>();
private WindowInsets mLastInsets;
@@ -570,7 +579,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private int mCaptionInsetsHeight = 0;
private boolean mAnimationsDisabled;
private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
private final Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
= new ArrayList<>();
@@ -580,7 +589,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
/** Set of inset types which cannot be controlled by the user animation */
private @InsetsType int mDisabledUserAnimationInsetsTypes;
private Runnable mInvokeControllableInsetsChangedListeners =
private final Runnable mInvokeControllableInsetsChangedListeners =
this::invokeControllableInsetsChangedListeners;
public InsetsController(Host host) {
@@ -608,23 +617,23 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
final List<WindowInsetsAnimation> runningAnimations = new ArrayList<>();
final List<WindowInsetsAnimation> finishedAnimations = new ArrayList<>();
final InsetsState state = new InsetsState(mState, true /* copySources */);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (DEBUG) Log.d(TAG, "Running animation type: " + runningAnimation.type);
InsetsAnimationControlRunner runner = runningAnimation.runner;
if (runner instanceof InsetsAnimationControlImpl) {
InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
final InsetsAnimationControlRunner runner = runningAnimation.runner;
if (runner instanceof WindowInsetsAnimationController) {
// Keep track of running animation to be dispatched. Aggregate it here such that
// if it gets finished within applyChangeInsets we still dispatch it to
// onProgress.
if (runningAnimation.startDispatched) {
runningAnimations.add(control.getAnimation());
runningAnimations.add(runner.getAnimation());
}
if (control.applyChangeInsets(state)) {
mTmpFinishedControls.add(control);
if (((WindowInsetsAnimationController) runner).applyChangeInsets(state)) {
finishedAnimations.add(runner.getAnimation());
}
}
}
@@ -642,10 +651,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
}
for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation());
for (int i = finishedAnimations.size() - 1; i >= 0; i--) {
dispatchAnimationEnd(finishedAnimations.get(i));
}
mTmpFinishedControls.clear();
};
}
@@ -691,15 +699,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
true /* excludeInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
startResizingAnimationIfNeeded(lastState);
}
return true;
}
private void updateState(InsetsState newState) {
mState.setDisplayFrame(newState.getDisplayFrame());
mState.setDisplayCutout(newState.getDisplayCutout());
mState.setRoundedCorners(newState.getRoundedCorners());
mState.setPrivacyIndicatorBounds(newState.getPrivacyIndicatorBounds());
mState.set(newState, 0 /* types */);
@InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
@@ -764,6 +770,39 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return false;
}
private void startResizingAnimationIfNeeded(InsetsState fromState) {
if (!fromState.getDisplayFrame().equals(mState.getDisplayFrame())) {
return;
}
@InsetsType int types = 0;
InsetsState toState = null;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(Type.systemBars());
for (int i = internalTypes.size() - 1; i >= 0; i--) {
final @InternalInsetsType int type = internalTypes.valueAt(i);
final InsetsSource fromSource = fromState.peekSource(type);
final InsetsSource toSource = mState.peekSource(type);
if (fromSource != null && toSource != null
&& fromSource.isVisible() && toSource.isVisible()
&& !fromSource.getFrame().equals(toSource.getFrame())
&& (Rect.intersects(mFrame, fromSource.getFrame())
|| Rect.intersects(mFrame, toSource.getFrame()))) {
types |= InsetsState.toPublicType(toSource.getType());
if (toState == null) {
toState = new InsetsState();
}
toState.addSource(new InsetsSource(toSource));
}
}
if (types == 0) {
return;
}
cancelExistingControllers(types);
final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
mFrame, fromState, toState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, types,
this);
mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType()));
}
/**
* @see InsetsState#calculateInsets
*/
@@ -785,7 +824,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
/**
* @see InsetsState#calculateVisibleInsets(Rect, int)
*/
public Rect calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
public Insets calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
return mState.calculateVisibleInsets(mFrame, softInputMode);
}
@@ -1474,12 +1513,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
@Override
public void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
public <T extends InsetsAnimationControlRunner & WindowInsetsAnimationController>
void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation, Bounds bounds) {
mHost.dispatchWindowInsetsAnimationPrepare(animation);
mHost.addOnPreDrawRunnable(() -> {
if (controller.isCancelled()) {
if (runner.isCancelled()) {
if (WARN) Log.w(TAG, "startAnimation canceled before preDraw");
return;
}
@@ -1487,15 +1526,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
"InsetsAnimation: " + WindowInsets.Type.toString(types), types);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (runningAnimation.runner == controller) {
if (runningAnimation.runner == runner) {
runningAnimation.startDispatched = true;
}
}
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
mStartingAnimation = true;
controller.mReadyDispatched = true;
listener.onReady(controller, types);
runner.setReadyDispatched(true);
listener.onReady(runner, types);
mStartingAnimation = false;
});
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA;
import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED;
import static android.view.InsetsAnimationControlImplProto.IS_FINISHED;
import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA;
import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION;
import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS;
import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH;
import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX;
import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.animation.Interpolator;
/**
* Runs a fake animation of resizing insets to produce insets animation callbacks.
* @hide
*/
public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner,
WindowInsetsAnimationController, WindowInsetsAnimationControlListener {
private final InsetsState mFromState;
private final InsetsState mToState;
private final @InsetsType int mTypes;
private final WindowInsetsAnimation mAnimation;
private final InsetsAnimationControlCallbacks mController;
private ValueAnimator mAnimator;
private boolean mCancelled;
private boolean mFinished;
public InsetsResizeAnimationRunner(Rect frame, InsetsState fromState, InsetsState toState,
Interpolator interpolator, long duration, @InsetsType int types,
InsetsAnimationControlCallbacks controller) {
mFromState = fromState;
mToState = toState;
mTypes = types;
mController = controller;
mAnimation = new WindowInsetsAnimation(types, interpolator, duration);
mAnimation.setAlpha(1f);
final Insets fromInsets = fromState.calculateInsets(
frame, types, false /* ignoreVisibility */);
final Insets toInsets = toState.calculateInsets(
frame, types, false /* ignoreVisibility */);
controller.startAnimation(this, this, types, mAnimation,
new Bounds(Insets.min(fromInsets, toInsets), Insets.max(fromInsets, toInsets)));
}
@Override
public int getTypes() {
return mTypes;
}
@Override
public int getControllingTypes() {
return mTypes;
}
@Override
public WindowInsetsAnimation getAnimation() {
return mAnimation;
}
@Override
public int getAnimationType() {
return ANIMATION_TYPE_RESIZE;
}
@Override
public void cancel() {
if (mCancelled || mFinished) {
return;
}
mCancelled = true;
if (mAnimator != null) {
mAnimator.cancel();
}
}
@Override
public boolean isCancelled() {
return mCancelled;
}
@Override
public void onReady(WindowInsetsAnimationController controller, int types) {
if (mCancelled) {
return;
}
mAnimator = ValueAnimator.ofFloat(0f, 1f);
mAnimator.setDuration(mAnimation.getDurationMillis());
mAnimator.addUpdateListener(animation -> {
mAnimation.setFraction(animation.getAnimatedFraction());
mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
});
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFinished = true;
mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
}
});
mAnimator.start();
}
@Override
public boolean applyChangeInsets(InsetsState outState) {
final float fraction = mAnimation.getInterpolatedFraction();
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
final InsetsSource fromSource = mFromState.peekSource(type);
final InsetsSource toSource = mToState.peekSource(type);
if (fromSource == null || toSource == null) {
continue;
}
final Rect fromFrame = fromSource.getFrame();
final Rect toFrame = toSource.getFrame();
final Rect frame = new Rect(
(int) (fromFrame.left + fraction * (toFrame.left - fromFrame.left)),
(int) (fromFrame.top + fraction * (toFrame.top - fromFrame.top)),
(int) (fromFrame.right + fraction * (toFrame.right - fromFrame.right)),
(int) (fromFrame.bottom + fraction * (toFrame.bottom - fromFrame.bottom)));
final InsetsSource source = new InsetsSource(type);
source.setFrame(frame);
source.setVisible(toSource.isVisible());
outState.addSource(source);
}
if (mFinished) {
mController.notifyFinished(this, true /* shown */);
}
return mFinished;
}
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(IS_CANCELLED, mCancelled);
proto.write(IS_FINISHED, mFinished);
proto.write(TMP_MATRIX, "null");
proto.write(PENDING_INSETS, "null");
proto.write(PENDING_FRACTION, mAnimation.getInterpolatedFraction());
proto.write(SHOWN_ON_FINISH, true);
proto.write(CURRENT_ALPHA, 1f);
proto.write(PENDING_ALPHA, 1f);
proto.end(token);
}
@Override
public Insets getHiddenStateInsets() {
return Insets.NONE;
}
@Override
public Insets getShownStateInsets() {
return Insets.NONE;
}
@Override
public Insets getCurrentInsets() {
return Insets.NONE;
}
@Override
public float getCurrentFraction() {
return 0;
}
@Override
public float getCurrentAlpha() {
return 0;
}
@Override
public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
}
@Override
public void finish(boolean shown) {
}
@Override
public boolean isFinished() {
return false;
}
@Override
public void notifyControlRevoked(int types) {
}
@Override
public void updateSurfacePosition(SparseArray<InsetsSourceControl> controls) {
}
@Override
public boolean hasZeroInsetsIme() {
return false;
}
@Override
public void setReadyDispatched(boolean dispatched) {
}
@Override
public void onFinished(WindowInsetsAnimationController controller) {
}
@Override
public void onCancelled(WindowInsetsAnimationController controller) {
}
}

View File

@@ -301,7 +301,7 @@ public class InsetsState implements Parcelable {
return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
}
public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
public Insets calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources[type];
@@ -314,10 +314,10 @@ public class InsetsState implements Parcelable {
}
insets = Insets.max(source.calculateInsets(frame, ignoreVisibility), insets);
}
return insets.toRect();
return insets;
}
public Rect calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
public Insets calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources[type];
@@ -332,7 +332,7 @@ public class InsetsState implements Parcelable {
}
insets = Insets.max(source.calculateVisibleInsets(frame), insets);
}
return insets.toRect();
return insets;
}
/**

View File

@@ -2467,7 +2467,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
mWindowAttributes.softInputMode));
mWindowAttributes.softInputMode).toRect());
}
return mLastWindowInsets;
}

View File

@@ -188,4 +188,20 @@ public interface WindowInsetsAnimationController {
* fullscreen or non-overlapping).
*/
boolean hasZeroInsetsIme();
/**
* Flags whether {@link WindowInsetsAnimationControlListener#onReady(
* WindowInsetsAnimationController, int)} has been invoked.
* @hide
*/
void setReadyDispatched(boolean dispatched);
/**
* Returns the {@link InsetsState} based on the current animation progress.
*
* @param outState the insets state which matches the current animation progress.
* @return {@code true} if the animation has been finished; {@code false} otherwise.
* @hide
*/
boolean applyChangeInsets(InsetsState outState);
}

View File

@@ -111,7 +111,7 @@ public class InsetsAnimationControlImplTest {
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
mMockController, 10 /* durationMs */, new LinearInterpolator(),
0 /* animationType */, 0 /* layoutInsetsDuringAnimation */, null /* translator */);
mController.mReadyDispatched = true;
mController.setReadyDispatched(true);
}
@Test
@@ -197,7 +197,7 @@ public class InsetsAnimationControlImplTest {
@Test
public void testCancelled_beforeReadyDispatched() {
mController.mReadyDispatched = false;
mController.setReadyDispatched(false);
mController.cancel();
assertFalse(mController.isReady());
assertFalse(mController.isFinished());

View File

@@ -19,13 +19,17 @@ package android.view;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
import static android.view.InsetsController.ANIMATION_TYPE_NONE;
import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsSourceConsumer.ShowResult.IME_SHOW_DELAYED;
import static android.view.InsetsSourceConsumer.ShowResult.SHOW_IMMEDIATELY;
import static android.view.InsetsState.FIRST_TYPE;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.LAST_TYPE;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
@@ -661,6 +665,97 @@ public class InsetsControllerTest {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Test
public void testResizeAnimation_insetsTypes() {
for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
final @AnimationType int expectedAnimationType =
(InsetsState.toPublicType(type) & Type.systemBars()) != 0
? ANIMATION_TYPE_RESIZE
: ANIMATION_TYPE_NONE;
doTestResizeAnimation_insetsTypes(type, expectedAnimationType);
}
}
private void doTestResizeAnimation_insetsTypes(@InternalInsetsType int type,
@AnimationType int expectedAnimationType) {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final InsetsState state1 = new InsetsState();
state1.getSource(type).setVisible(true);
state1.getSource(type).setFrame(0, 0, 500, 50);
final InsetsState state2 = new InsetsState(state1, true /* copySources */);
state2.getSource(type).setFrame(0, 0, 500, 60);
final String message = "Animation type of " + InsetsState.typeToString(type) + ":";
// New insets source won't cause the resize animation.
mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
// Changing frame might cause the resize animation. This depends on the insets type.
mController.onStateChanged(state2);
assertEquals(message, expectedAnimationType, mController.getAnimationType(type));
// Cancel the existing animations for the next iteration.
mController.cancelExistingAnimations();
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Test
public void testResizeAnimation_displayFrame() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final @InternalInsetsType int type = ITYPE_STATUS_BAR;
final InsetsState state1 = new InsetsState();
state1.setDisplayFrame(new Rect(0, 0, 500, 1000));
state1.getSource(type).setFrame(0, 0, 500, 50);
final InsetsState state2 = new InsetsState(state1, true /* copySources */);
state2.setDisplayFrame(new Rect(0, 0, 500, 1010));
state2.getSource(type).setFrame(0, 0, 500, 60);
final String message = "There must not be resize animation.";
// New insets source won't cause the resize animation.
mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
// 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));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Test
public void testResizeAnimation_visibility() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final @InternalInsetsType int type = ITYPE_STATUS_BAR;
final InsetsState state1 = new InsetsState();
state1.getSource(type).setVisible(true);
state1.getSource(type).setFrame(0, 0, 500, 50);
final InsetsState state2 = new InsetsState(state1, true /* copySources */);
state2.getSource(type).setVisible(false);
state2.getSource(type).setFrame(0, 0, 500, 60);
final InsetsState state3 = new InsetsState(state2, true /* copySources */);
state3.getSource(type).setVisible(true);
state3.getSource(type).setFrame(0, 0, 500, 70);
final String message = "There must not be resize animation.";
// New insets source won't cause the resize animation.
mController.onStateChanged(state1);
assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
// 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));
// 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));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Test
public void testCaptionInsetsStateAssemble() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {

View File

@@ -216,9 +216,9 @@ public class InsetsStateTest {
mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(0, 0, 100, 300));
mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
Rect visibleInsets = mState.calculateVisibleInsets(
Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 100, 400), SOFT_INPUT_ADJUST_NOTHING);
assertEquals(new Rect(0, 300, 0, 0), visibleInsets);
assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
}
@Test
@@ -226,9 +226,9 @@ public class InsetsStateTest {
mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(0, 0, 100, 300));
mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
Rect visibleInsets = mState.calculateVisibleInsets(
Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 150, 400), SOFT_INPUT_ADJUST_NOTHING);
assertEquals(new Rect(0, 300, 0, 0), visibleInsets);
assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
}
@Test
@@ -413,9 +413,9 @@ public class InsetsStateTest {
// Make sure bottom gestures are ignored
mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
Rect visibleInsets = mState.calculateVisibleInsets(
Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_PAN);
assertEquals(new Rect(0, 100, 0, 100), visibleInsets);
assertEquals(Insets.of(0, 100, 0, 100), visibleInsets);
}
@Test
@@ -428,9 +428,9 @@ public class InsetsStateTest {
// Make sure bottom gestures are ignored
mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
Rect visibleInsets = mState.calculateVisibleInsets(
Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_NOTHING);
assertEquals(new Rect(0, 100, 0, 0), visibleInsets);
assertEquals(Insets.of(0, 100, 0, 0), visibleInsets);
}
@Test

View File

@@ -343,7 +343,7 @@ public class TaskSnapshotWindow {
static Rect getSystemBarInsets(Rect frame, InsetsState state) {
return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
false /* ignoreVisibility */);
false /* ignoreVisibility */).toRect();
}
private void drawSnapshot() {

View File

@@ -27,10 +27,12 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.InsetsController;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.animation.Interpolator;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -89,6 +91,9 @@ public class WindowManagerWrapper {
public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT =
InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
public static final int ANIMATION_DURATION_RESIZE = InsetsController.ANIMATION_DURATION_RESIZE;
public static final Interpolator RESIZE_INTERPOLATOR = InsetsController.RESIZE_INTERPOLATOR;
private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
public static WindowManagerWrapper getInstance() {

View File

@@ -6963,7 +6963,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
Rect appRect;
if (win != null) {
insets = win.getInsetsStateWithVisibilityOverride().calculateInsets(
win.getFrame(), Type.systemBars(), false /* ignoreVisibility */);
win.getFrame(), Type.systemBars(), false /* ignoreVisibility */).toRect();
appRect = new Rect(win.getFrame());
appRect.inset(insets);
} else {
@@ -9231,7 +9231,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return null;
}
final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
task.getBounds(), Type.systemBars(), false /* ignoreVisibility */);
task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, getLetterboxInsets());
return new RemoteAnimationTarget(task.mTaskId, record.getMode(),

View File

@@ -48,6 +48,7 @@ import android.view.SyncRtSurfaceTransactionApplier;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
import android.view.WindowManager;
import com.android.internal.R;
@@ -570,8 +571,8 @@ class InsetsPolicy {
}
@Override
public void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
public <T extends InsetsAnimationControlRunner & WindowInsetsAnimationController>
void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation,
Bounds bounds) {
}

View File

@@ -581,7 +581,7 @@ public class RecentsAnimationController implements DeathRecipient {
contentInsets = targetAppMainWindow
.getInsetsStateWithVisibilityOverride()
.calculateInsets(mTargetActivityRecord.getBounds(), Type.systemBars(),
false /* ignoreVisibility */);
false /* ignoreVisibility */).toRect();
} else {
// If the window for the activity had not yet been created, use the display insets.
mService.getStableInsets(mDisplayId, mTmpRect);
@@ -1209,7 +1209,7 @@ public class RecentsAnimationController implements DeathRecipient {
return null;
}
final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
mBounds, Type.systemBars(), false /* ignoreVisibility */);
mBounds, Type.systemBars(), false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets());
final int mode = topApp.getActivityType() == mTargetActivityType
? MODE_OPENING

View File

@@ -683,7 +683,8 @@ class TaskSnapshotController {
}
static Rect getSystemBarInsets(Rect frame, InsetsState state) {
return state.calculateInsets(frame, Type.systemBars(), false /* ignoreVisibility */);
return state.calculateInsets(
frame, Type.systemBars(), false /* ignoreVisibility */).toRect();
}
void dump(PrintWriter pw, String prefix) {

View File

@@ -5959,9 +5959,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
outSurfaceInsets.set(getAttrs().surfaceInsets);
final InsetsState state = getInsetsStateWithVisibilityOverride();
outInsets.set(state.calculateInsets(outFrame, systemBars(),
false /* ignoreVisibility */));
false /* ignoreVisibility */).toRect());
outStableInsets.set(state.calculateInsets(outFrame, systemBars(),
true /* ignoreVisibility */));
true /* ignoreVisibility */).toRect());
}
void setViewVisibility(int viewVisibility) {