diff options
| -rw-r--r-- | core/java/android/view/Choreographer.java | 25 | ||||
| -rw-r--r-- | core/java/android/view/InsetsAnimationControlImpl.java | 54 | ||||
| -rw-r--r-- | core/java/android/view/InsetsController.java | 42 | ||||
| -rw-r--r-- | core/java/android/view/InsetsState.java | 4 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 34 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 29 | ||||
| -rw-r--r-- | core/java/android/view/WindowInsetsAnimationController.java | 21 | ||||
| -rw-r--r-- | core/java/android/view/WindowInsetsAnimationListener.java | 122 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java | 3 |
9 files changed, 310 insertions, 24 deletions
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 96ef8ba1a241..ccd0fc179f0e 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -22,6 +22,7 @@ import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.graphics.FrameInfo; +import android.graphics.Insets; import android.hardware.display.DisplayManagerGlobal; import android.os.Build; import android.os.Handler; @@ -199,7 +200,7 @@ public final class Choreographer { * @hide */ private static final String[] CALLBACK_TRACE_TITLES = { - "input", "animation", "traversal", "commit" + "input", "animation", "insets_animation", "traversal", "commit" }; /** @@ -209,18 +210,33 @@ public final class Choreographer { public static final int CALLBACK_INPUT = 0; /** - * Callback type: Animation callback. Runs before traversals. + * Callback type: Animation callback. Runs before {@link #CALLBACK_INSETS_ANIMATION}. * @hide */ @TestApi public static final int CALLBACK_ANIMATION = 1; /** + * Callback type: Animation callback to handle inset updates. This is separate from + * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via + * {@link WindowInsetsAnimationController#changeInsets} for multiple ongoing animations but then + * update the whole view system with a single callback to {@link View#dispatchWindowInsetsAnimationProgress} + * that contains all the combined updated insets. + * <p> + * Both input and animation may change insets, so we need to run this after these callbacks, but + * before traversals. + * <p> + * Runs before traversals. + * @hide + */ + public static final int CALLBACK_INSETS_ANIMATION = 2; + + /** * Callback type: Traversal callback. Handles layout and draw. Runs * after all other asynchronous messages have been handled. * @hide */ - public static final int CALLBACK_TRAVERSAL = 2; + public static final int CALLBACK_TRAVERSAL = 3; /** * Callback type: Commit callback. Handles post-draw operations for the frame. @@ -232,7 +248,7 @@ public final class Choreographer { * to the view hierarchy state) actually took effect. * @hide */ - public static final int CALLBACK_COMMIT = 3; + public static final int CALLBACK_COMMIT = 4; private static final int CALLBACK_LAST = CALLBACK_COMMIT; @@ -704,6 +720,7 @@ public final class Choreographer { mFrameInfo.markAnimationsStart(); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); + doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos); mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 7b9f78e70050..ce71b07da805 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -45,7 +45,9 @@ import java.util.function.Supplier; * @hide */ @VisibleForTesting -public class InsetsAnimationControlImpl implements WindowInsetsAnimationController { +public class InsetsAnimationControlImpl implements WindowInsetsAnimationController { + + private final Rect mTmpFrame = new Rect(); private final WindowInsetsAnimationControlListener mListener; private final SparseArray<InsetsSourceConsumer> mConsumers; @@ -61,19 +63,23 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll private final InsetsState mInitialInsetsState; private final @InsetType int mTypes; private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier; - + private final InsetsController mController; + private final WindowInsetsAnimationListener.InsetsAnimation mAnimation; private Insets mCurrentInsets; + private Insets mPendingInsets; @VisibleForTesting public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @InsetType int types, - Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier) { + Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier, + InsetsController controller) { mConsumers = consumers; mListener = listener; mTypes = types; mTransactionApplierSupplier = transactionApplierSupplier; - mInitialInsetsState = new InsetsState(state); + mController = controller; + mInitialInsetsState = new InsetsState(state, true /* copySources */); mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */); mHiddenInsets = calculateInsets(mInitialInsetsState, frame, consumers, false /* shown */, null /* typeSideMap */); @@ -83,6 +89,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll // TODO: Check for controllability first and wait for IME if needed. listener.onReady(this, types); + + mAnimation = new WindowInsetsAnimationListener.InsetsAnimation(mTypes, mHiddenInsets, + mShownInsets); + mController.dispatchAnimationStarted(mAnimation); } @Override @@ -108,29 +118,35 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll @Override public void changeInsets(Insets insets) { - insets = sanitize(insets); - final Insets offset = Insets.subtract(mShownInsets, insets); + mPendingInsets = sanitize(insets); + mController.scheduleApplyChangeInsets(); + } + + void applyChangeInsets(InsetsState state) { + final Insets offset = Insets.subtract(mShownInsets, mPendingInsets); ArrayList<SurfaceParams> params = new ArrayList<>(); if (offset.left != 0) { - updateLeashesForSide(INSET_SIDE_LEFT, offset.left, params); + updateLeashesForSide(INSET_SIDE_LEFT, offset.left, params, state); } if (offset.top != 0) { - updateLeashesForSide(INSET_SIDE_TOP, offset.top, params); + updateLeashesForSide(INSET_SIDE_TOP, offset.top, params, state); } if (offset.right != 0) { - updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, params); + updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, params, state); } if (offset.bottom != 0) { - updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, params); + updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, params, state); } SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get(); applier.scheduleApply(params.toArray(new SurfaceParams[params.size()])); - mCurrentInsets = insets; + mCurrentInsets = mPendingInsets; } @Override public void finish(int shownTypes) { // TODO + + mController.dispatchAnimationFinished(mAnimation); } private Insets calculateInsets(InsetsState state, Rect frame, @@ -146,7 +162,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll @Nullable @InsetSide SparseIntArray typeSideMap) { return state.calculateInsets(frame, false /* isScreenRound */, false /* alwaysConsumerNavBar */, null /* displayCutout */, typeSideMap) - .getSystemWindowInsets(); + .getInsets(mTypes); } private Insets sanitize(Insets insets) { @@ -154,7 +170,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll } private void updateLeashesForSide(@InsetSide int side, int inset, - ArrayList<SurfaceParams> surfaceParams) { + ArrayList<SurfaceParams> surfaceParams, InsetsState state) { ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side); // TODO: Implement behavior when inset spans over multiple types for (int i = items.size() - 1; i >= 0; i--) { @@ -162,24 +178,32 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll final InsetsSource source = mInitialInsetsState.getSource(consumer.getType()); final SurfaceControl leash = consumer.getControl().getLeash(); mTmpMatrix.setTranslate(source.getFrame().left, source.getFrame().top); - addTranslationToMatrix(side, inset, mTmpMatrix); + + mTmpFrame.set(source.getFrame()); + addTranslationToMatrix(side, inset, mTmpMatrix, mTmpFrame); + + state.getSource(source.getType()).setFrame(mTmpFrame); surfaceParams.add(new SurfaceParams(leash, 1f, mTmpMatrix, null, 0, 0f)); } } - private void addTranslationToMatrix(@InsetSide int side, int inset, Matrix m) { + private void addTranslationToMatrix(@InsetSide int side, int inset, Matrix m, Rect frame) { switch (side) { case INSET_SIDE_LEFT: m.postTranslate(-inset, 0); + frame.offset(-inset, 0); break; case INSET_SIDE_TOP: m.postTranslate(0, -inset); + frame.offset(0, -inset); break; case INSET_SIDE_RIGHT: m.postTranslate(inset, 0); + frame.offset(inset, 0); break; case INSET_SIDE_BOTTOM: m.postTranslate(0, inset); + frame.offset(0, inset); break; } } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 01af37e75cb9..c2ade764ca81 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -18,6 +18,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; +import android.graphics.Insets; import android.graphics.Rect; import android.os.RemoteException; import android.util.ArraySet; @@ -49,9 +50,29 @@ public class InsetsController implements WindowInsetsController { private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final ArrayList<InsetsAnimationControlImpl> mAnimationControls = new ArrayList<>(); + private WindowInsets mLastInsets; + + private boolean mAnimCallbackScheduled; + + private final Runnable mAnimCallback; public InsetsController(ViewRootImpl viewRoot) { mViewRoot = viewRoot; + mAnimCallback = () -> { + mAnimCallbackScheduled = false; + if (mAnimationControls.isEmpty()) { + return; + } + + InsetsState state = new InsetsState(mState, true /* copySources */); + for (int i = mAnimationControls.size() - 1; i >= 0; i--) { + mAnimationControls.get(i).applyChangeInsets(state); + } + WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(), + mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(), + null /* typeSideMap */); + mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets); + }; } void onFrameChanged(Rect frame) { @@ -82,8 +103,9 @@ public class InsetsController implements WindowInsetsController { @VisibleForTesting public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeNavBar, DisplayCutout cutout) { - return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout, + mLastInsets = mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout, null /* typeSideMap */); + return mLastInsets; } /** @@ -148,7 +170,7 @@ public class InsetsController implements WindowInsetsController { } final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers, mFrame, mState, listener, types, - () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView)); + () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this); mAnimationControls.add(controller); } @@ -200,4 +222,20 @@ public class InsetsController implements WindowInsetsController { pw.println(prefix); pw.println("InsetsController:"); mState.dump(prefix + " ", pw); } + + void dispatchAnimationStarted(WindowInsetsAnimationListener.InsetsAnimation animation) { + mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation); + } + + void dispatchAnimationFinished(WindowInsetsAnimationListener.InsetsAnimation animation) { + mViewRoot.mView.dispatchWindowInsetsAnimationFinished(animation); + } + + void scheduleApplyChangeInsets() { + if (!mAnimCallbackScheduled) { + mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, + mAnimCallback, null /* token*/); + mAnimCallbackScheduled = true; + } + } } diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 093191499921..cf8c0707828d 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -107,6 +107,10 @@ public class InsetsState implements Parcelable { set(copy); } + public InsetsState(InsetsState copy, boolean copySources) { + set(copy, copySources); + } + /** * Calculates {@link WindowInsets} based on the current source configuration. * diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index cd0e5794a5c7..abefd551331e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -96,6 +96,7 @@ import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; import android.view.AccessibilityIterators.TextSegmentIterator; import android.view.AccessibilityIterators.WordTextSegmentIterator; import android.view.ContextMenu.ContextMenuInfo; +import android.view.WindowInsetsAnimationListener.InsetsAnimation; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEventSource; import android.view.accessibility.AccessibilityManager; @@ -4547,6 +4548,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, OnCapturedPointerListener mOnCapturedPointerListener; private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; + + private WindowInsetsAnimationListener mWindowInsetsAnimationListener; } @UnsupportedAppUsage @@ -10488,6 +10491,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Sets a {@link WindowInsetsAnimationListener} to be notified about animations of windows that + * cause insets. + * + * @param listener The listener to set. + * @hide pending unhide + */ + public void setWindowInsetsAnimationListener(WindowInsetsAnimationListener listener) { + getListenerInfo().mWindowInsetsAnimationListener = listener; + } + + void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) { + if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { + mListenerInfo.mWindowInsetsAnimationListener.onStarted(animation); + } + } + + WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) { + if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { + return mListenerInfo.mWindowInsetsAnimationListener.onProgress(insets); + } else { + return insets; + } + } + + void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) { + if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { + mListenerInfo.mWindowInsetsAnimationListener.onFinished(animation); + } + } + + /** * Compute the view's coordinate within the surface. * * <p>Computes the coordinates of this view in its surface. The argument diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 9d11397498cf..0986cfa454b6 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -51,6 +51,7 @@ import android.util.Pools; import android.util.Pools.SynchronizedPool; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.view.WindowInsetsAnimationListener.InsetsAnimation; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -7139,6 +7140,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return insets; } + @Override + void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) { + super.dispatchWindowInsetsAnimationStarted(animation); + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + getChildAt(i).dispatchWindowInsetsAnimationStarted(animation); + } + } + + @Override + WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) { + insets = super.dispatchWindowInsetsAnimationProgress(insets); + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + getChildAt(i).dispatchWindowInsetsAnimationProgress(insets); + } + return insets; + } + + @Override + void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) { + super.dispatchWindowInsetsAnimationFinished(animation); + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + getChildAt(i).dispatchWindowInsetsAnimationFinished(animation); + } + } + /** * Returns the animation listener to which layout animation events are * sent. diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java index 9de517dac5de..cf4415d2b2ba 100644 --- a/core/java/android/view/WindowInsetsAnimationController.java +++ b/core/java/android/view/WindowInsetsAnimationController.java @@ -19,6 +19,7 @@ package android.view; import android.annotation.NonNull; import android.graphics.Insets; import android.view.WindowInsets.Type.InsetType; +import android.view.WindowInsetsAnimationListener.InsetsAnimation; /** * Interface to control a window inset animation frame-by-frame. @@ -28,8 +29,13 @@ public interface WindowInsetsAnimationController { /** * Retrieves the {@link Insets} when the windows this animation is controlling are fully hidden. + * <p> + * If there are any animation listeners registered, this value is the same as + * {@link InsetsAnimation#getLowerBound()} that will be passed into the callbacks. * * @return Insets when the windows this animation is controlling are fully hidden. + * + * @see InsetsAnimation#getLowerBound() */ @NonNull Insets getHiddenStateInsets(); @@ -38,8 +44,13 @@ public interface WindowInsetsAnimationController { * <p> * In case the size of a window causing insets is changing in the middle of the animation, we * execute that height change after this animation has finished. + * <p> + * If there are any animation listeners registered, this value is the same as + * {@link InsetsAnimation#getUpperBound()} that will be passed into the callbacks. * * @return Insets when the windows this animation is controlling are fully shown. + * + * @see InsetsAnimation#getUpperBound() */ @NonNull Insets getShownStateInsets(); @@ -59,8 +70,11 @@ public interface WindowInsetsAnimationController { * <p> * Note that this will <b>not</b> inform the view system of a full inset change via * {@link View#dispatchApplyWindowInsets} in order to avoid a full layout pass during the - * animation. If you'd like to animate views during a window inset animation, use - * TODO add link to animation listeners. + * animation. If you'd like to animate views during a window inset animation, register a + * {@link WindowInsetsAnimationListener} by calling + * {@link View#setWindowInsetsAnimationListener(WindowInsetsAnimationListener)} that will be + * notified about any insets change via {@link WindowInsetsAnimationListener#onProgress} during + * the animation. * <p> * {@link View#dispatchApplyWindowInsets} will instead be called once the animation has * finished, i.e. once {@link #finish} has been called. @@ -70,6 +84,9 @@ public interface WindowInsetsAnimationController { * the resulting insets of that configuration will match the passed in parameter. * Note that these insets are being clamped to the range from * {@link #getHiddenStateInsets} to {@link #getShownStateInsets} + * + * @see WindowInsetsAnimationListener + * @see View#setWindowInsetsAnimationListener(WindowInsetsAnimationListener) */ void changeInsets(@NonNull Insets insets); diff --git a/core/java/android/view/WindowInsetsAnimationListener.java b/core/java/android/view/WindowInsetsAnimationListener.java new file mode 100644 index 000000000000..682ab5bfb63c --- /dev/null +++ b/core/java/android/view/WindowInsetsAnimationListener.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 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 android.graphics.Insets; + +/** + * Interface that allows the application to listen to animation events for windows that cause + * insets. + * @hide pending unhide + */ +public interface WindowInsetsAnimationListener { + + /** + * Called when an inset animation gets started. + * + * @param animation The animation that is about to start. + */ + void onStarted(InsetsAnimation animation); + + /** + * Called when the insets change as part of running an animation. Note that even if multiple + * animations for different types are running, there will only be one progress callback per + * frame. The {@code insets} passed as an argument represents the overall state and will include + * all types, regardless of whether they are animating or not. + * <p> + * Note that insets dispatch is hierarchical: It will start at the root of the view hierarchy, + * and then traverse it and invoke the callback of the specific {@link View} being traversed. + * The callback may return a modified instance by calling {@link WindowInsets#inset(int, int, int, int)} + * to indicate that a part of the insets have been used to offset or clip its children, and the + * children shouldn't worry about that part anymore. + * + * @param insets The current insets. + * @return The insets to dispatch to the subtree of the hierarchy. + */ + WindowInsets onProgress(WindowInsets insets); + + /** + * Called when an inset animation has finished. + * + * @param animation The animation that has finished running. + */ + void onFinished(InsetsAnimation animation); + + /** + * Class representing an animation of a set of windows that cause insets. + */ + class InsetsAnimation { + + private final @WindowInsets.Type.InsetType int mTypeMask; + private final Insets mLowerBound; + private final Insets mUpperBound; + + /** + * @hide + */ + InsetsAnimation(int typeMask, Insets lowerBound, Insets upperBound) { + mTypeMask = typeMask; + mLowerBound = lowerBound; + mUpperBound = upperBound; + } + + /** + * @return The bitmask of {@link WindowInsets.Type.InsetType}s that are animating. + */ + public @WindowInsets.Type.InsetType int getTypeMask() { + return mTypeMask; + } + + /** + * Queries the lower inset bound of the animation. If the animation is about showing or + * hiding a window that cause insets, the lower bound is {@link Insets#NONE} and the upper + * bound is the same as {@link WindowInsets#getInsets(int)} for the fully shown state. This + * is the same as {@link WindowInsetsAnimationController#getHiddenStateInsets} and + * {@link WindowInsetsAnimationController#getShownStateInsets} in case the listener gets + * invoked because of an animation that originates from + * {@link WindowInsetsAnimationController}. + * <p> + * However, if the size of a window that causes insets is changing, these are the + * lower/upper bounds of that size animation. + * <p> + * There are no overlapping animations for a specific type, but there may be two animations + * running at the same time for different inset types. + * + * @see #getUpperBound() + * @see WindowInsetsAnimationController#getHiddenStateInsets + * TODO: It's a bit weird that these are global per window but onProgress is hierarchical. + * TODO: If multiple types are animating, querying the bound per type isn't possible. Should + * we: + * 1. Offer bounds by type here? + * 2. Restrict one animation to one single type only? + * Returning WindowInsets here isn't feasible in case of overlapping animations: We can't + * fill in the insets for the types from the other animation into the WindowInsets object + * as it's changing as well. + */ + public Insets getLowerBound() { + return mLowerBound; + } + + /** + * @see #getLowerBound() + * @see WindowInsetsAnimationController#getShownStateInsets + */ + public Insets getUpperBound() { + return mUpperBound; + } + } +} diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index d520f151c2fa..81ca9109c643 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -19,6 +19,7 @@ package android.view; import static android.view.InsetsState.TYPE_NAVIGATION_BAR; import static android.view.InsetsState.TYPE_TOP_BAR; import static junit.framework.Assert.assertEquals; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.graphics.Insets; @@ -83,7 +84,7 @@ public class InsetsAnimationControlImplTest { consumers.put(TYPE_NAVIGATION_BAR, navConsumer); mController = new InsetsAnimationControlImpl(consumers, new Rect(0, 0, 500, 500), state, mMockListener, WindowInsets.Type.systemBars(), - () -> mMockTransactionApplier); + () -> mMockTransactionApplier, mock(InsetsController.class)); } @Test |