diff options
13 files changed, 570 insertions, 544 deletions
diff --git a/api/current.txt b/api/current.txt index 9ea4b2d4d151..8bf850929c61 100644 --- a/api/current.txt +++ b/api/current.txt @@ -53541,10 +53541,10 @@ package android.view { method public boolean dispatchUnhandledMove(android.view.View, int); method protected void dispatchVisibilityChanged(@NonNull android.view.View, int); method public void dispatchWindowFocusChanged(boolean); - method public void dispatchWindowInsetsAnimationFinish(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation); - method public void dispatchWindowInsetsAnimationPrepare(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation); - method @NonNull public android.view.WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull android.view.WindowInsets); - method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds dispatchWindowInsetsAnimationStart(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds); + method public void dispatchWindowInsetsAnimationEnd(@NonNull android.view.WindowInsetsAnimation); + method public void dispatchWindowInsetsAnimationPrepare(@NonNull android.view.WindowInsetsAnimation); + method @NonNull public android.view.WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull android.view.WindowInsets, @NonNull java.util.List<android.view.WindowInsetsAnimation>); + method @NonNull public android.view.WindowInsetsAnimation.Bounds dispatchWindowInsetsAnimationStart(@NonNull android.view.WindowInsetsAnimation, @NonNull android.view.WindowInsetsAnimation.Bounds); method @Deprecated public void dispatchWindowSystemUiVisiblityChanged(int); method public void dispatchWindowVisibilityChanged(int); method @CallSuper public void draw(android.graphics.Canvas); @@ -54065,7 +54065,7 @@ package android.view { method public void setVisibility(int); method @Deprecated public void setWillNotCacheDrawing(boolean); method public void setWillNotDraw(boolean); - method public void setWindowInsetsAnimationCallback(@Nullable android.view.WindowInsetsAnimationCallback); + method public void setWindowInsetsAnimationCallback(@Nullable android.view.WindowInsetsAnimation.Callback); method public void setX(float); method public void setY(float); method public void setZ(float); @@ -55232,25 +55232,8 @@ package android.view { method public static int tappableElement(); } - public interface WindowInsetsAnimationCallback { - method public int getDispatchMode(); - method public default void onFinish(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation); - method public default void onPrepare(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation); - method @NonNull public android.view.WindowInsets onProgress(@NonNull android.view.WindowInsets); - method @NonNull public default android.view.WindowInsetsAnimationCallback.AnimationBounds onStart(@NonNull android.view.WindowInsetsAnimationCallback.InsetsAnimation, @NonNull android.view.WindowInsetsAnimationCallback.AnimationBounds); - field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1 - field public static final int DISPATCH_MODE_STOP = 0; // 0x0 - } - - public static final class WindowInsetsAnimationCallback.AnimationBounds { - ctor public WindowInsetsAnimationCallback.AnimationBounds(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets); - method @NonNull public android.graphics.Insets getLowerBound(); - method @NonNull public android.graphics.Insets getUpperBound(); - method @NonNull public android.view.WindowInsetsAnimationCallback.AnimationBounds inset(@NonNull android.graphics.Insets); - } - - public static final class WindowInsetsAnimationCallback.InsetsAnimation { - ctor public WindowInsetsAnimationCallback.InsetsAnimation(int, @Nullable android.view.animation.Interpolator, long); + public final class WindowInsetsAnimation { + ctor public WindowInsetsAnimation(int, @Nullable android.view.animation.Interpolator, long); method @FloatRange(from=0.0f, to=1.0f) public float getAlpha(); method public long getDurationMillis(); method @FloatRange(from=0.0f, to=1.0f) public float getFraction(); @@ -55261,6 +55244,24 @@ package android.view { method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float); } + public static final class WindowInsetsAnimation.Bounds { + ctor public WindowInsetsAnimation.Bounds(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets); + method @NonNull public android.graphics.Insets getLowerBound(); + method @NonNull public android.graphics.Insets getUpperBound(); + method @NonNull public android.view.WindowInsetsAnimation.Bounds inset(@NonNull android.graphics.Insets); + } + + public abstract static class WindowInsetsAnimation.Callback { + ctor public WindowInsetsAnimation.Callback(int); + method public final int getDispatchMode(); + method public void onEnd(@NonNull android.view.WindowInsetsAnimation); + method public void onPrepare(@NonNull android.view.WindowInsetsAnimation); + method @NonNull public abstract android.view.WindowInsets onProgress(@NonNull android.view.WindowInsets, @NonNull java.util.List<android.view.WindowInsetsAnimation>); + method @NonNull public android.view.WindowInsetsAnimation.Bounds onStart(@NonNull android.view.WindowInsetsAnimation, @NonNull android.view.WindowInsetsAnimation.Bounds); + field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1 + field public static final int DISPATCH_MODE_STOP = 0; // 0x0 + } + public interface WindowInsetsAnimationControlListener { method public void onCancelled(); method public void onReady(@NonNull android.view.WindowInsetsAnimationController, int); diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java index 0645c98e994a..5d5edecead22 100644 --- a/core/java/android/view/InsetsAnimationControlCallbacks.java +++ b/core/java/android/view/InsetsAnimationControlCallbacks.java @@ -17,8 +17,7 @@ package android.view; import android.view.InsetsController.LayoutInsetsDuringAnimation; -import android.view.WindowInsetsAnimationCallback.AnimationBounds; -import android.view.WindowInsetsAnimationCallback.InsetsAnimation; +import android.view.WindowInsetsAnimation.Bounds; /** * Provide an interface to let InsetsAnimationControlImpl call back into its owner. @@ -29,15 +28,16 @@ public interface InsetsAnimationControlCallbacks { /** * Executes the necessary code to start the animation in the correct order, including: * <ul> - * <li>Dispatch {@link WindowInsetsAnimationCallback#onPrepare}</li> + * <li>Dispatch {@link WindowInsetsAnimation.Callback#onPrepare}</li> * <li>Update insets state and run layout according to {@code layoutDuringAnimation}</li> - * <li>Dispatch {@link WindowInsetsAnimationCallback#onStart}</li> + * <li>Dispatch {@link WindowInsetsAnimation.Callback#onStart}</li> * <li>Dispatch {@link WindowInsetsAnimationControlListener#onReady}</li> * </ul> */ void startAnimation(InsetsAnimationControlImpl controller, - WindowInsetsAnimationControlListener listener, int types, InsetsAnimation animation, - AnimationBounds bounds, @LayoutInsetsDuringAnimation int layoutDuringAnimation); + WindowInsetsAnimationControlListener listener, int types, + WindowInsetsAnimation animation, + Bounds bounds, @LayoutInsetsDuringAnimation int layoutDuringAnimation); /** * Schedule the apply by posting the animation callback. diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 0653b06e4b9d..0e037c24a85b 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -35,8 +35,7 @@ import android.view.InsetsState.InternalInsetsSide; import android.view.InsetsState.InternalInsetsType; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; import android.view.WindowInsets.Type.InsetsType; -import android.view.WindowInsetsAnimationCallback.AnimationBounds; -import android.view.WindowInsetsAnimationCallback.InsetsAnimation; +import android.view.WindowInsetsAnimation.Bounds; import android.view.WindowManager.LayoutParams; import android.view.animation.Interpolator; @@ -67,7 +66,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll private final InsetsState mInitialInsetsState; private final @InsetsType int mTypes; private final InsetsAnimationControlCallbacks mController; - private final WindowInsetsAnimationCallback.InsetsAnimation mAnimation; + private final WindowInsetsAnimation mAnimation; private final Rect mFrame; private final boolean mFade; private Insets mCurrentInsets; @@ -100,11 +99,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll mFrame = new Rect(frame); buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls); - mAnimation = new WindowInsetsAnimationCallback.InsetsAnimation(mTypes, interpolator, + mAnimation = new WindowInsetsAnimation(mTypes, interpolator, durationMs); mAnimation.setAlpha(getCurrentAlpha()); mController.startAnimation(this, listener, types, mAnimation, - new AnimationBounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation); + new Bounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation); } @Override @@ -212,7 +211,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll return mCancelled; } - InsetsAnimation getAnimation() { + WindowInsetsAnimation getAnimation() { return mAnimation; } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 9cd6050efc0b..4a6a5a0312af 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -46,8 +46,7 @@ import android.view.SurfaceControl.Transaction; import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetsType; -import android.view.WindowInsetsAnimationCallback.AnimationBounds; -import android.view.WindowInsetsAnimationCallback.InsetsAnimation; +import android.view.WindowInsetsAnimation.Bounds; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; @@ -58,6 +57,8 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.function.BiFunction; /** @@ -275,6 +276,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>(); + private final ArrayList<WindowInsetsAnimation> mRunningInsetsAnimations = new ArrayList<>(); + private final List<WindowInsetsAnimation> mUnmodifiableRunningInsetsAnimations = + Collections.unmodifiableList(mRunningInsetsAnimations); private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>(); private WindowInsets mLastInsets; @@ -337,10 +341,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mLastInsets.shouldAlwaysConsumeSystemBars(), mLastInsets.getDisplayCutout(), mLastLegacyContentInsets, mLastLegacyStableInsets, mLastLegacySoftInputMode, mLastLegacySystemUiFlags, null /* typeSideMap */); - mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets); + mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, + mUnmodifiableRunningInsetsAnimations); for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) { - dispatchAnimationFinished(mTmpFinishedControls.get(i).getAnimation()); + dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation()); } }; } @@ -579,6 +584,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation frame, mState, listener, typesReady, this, durationMs, interpolator, fade, layoutInsetsDuringAnimation); mRunningAnimations.add(new RunningAnimation(controller, animationType)); + mRunningInsetsAnimations.add(controller.getAnimation()); cancellationSignal.setOnCancelListener(controller::onCancelled); return cancellationSignal; } @@ -729,6 +735,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { if (mRunningAnimations.get(i).control == control) { mRunningAnimations.remove(i); + mRunningInsetsAnimations.remove(i); break; } } @@ -875,8 +882,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting @Override public void startAnimation(InsetsAnimationControlImpl controller, - WindowInsetsAnimationControlListener listener, int types, InsetsAnimation animation, - AnimationBounds bounds, int layoutDuringAnimation) { + WindowInsetsAnimationControlListener listener, int types, + WindowInsetsAnimation animation, Bounds bounds, int layoutDuringAnimation) { if (layoutDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) { showDirectly(types); } else { @@ -904,8 +911,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } @VisibleForTesting - public void dispatchAnimationFinished(InsetsAnimation animation) { - mViewRoot.mView.dispatchWindowInsetsAnimationFinish(animation); + public void dispatchAnimationEnd(WindowInsetsAnimation animation) { + mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation); } @VisibleForTesting diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 13a4ddece814..c7f850a7eeb5 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -112,8 +112,7 @@ import android.view.AccessibilityIterators.WordTextSegmentIterator; import android.view.ContextMenu.ContextMenuInfo; import android.view.Window.OnContentApplyWindowInsetsListener; import android.view.WindowInsets.Type; -import android.view.WindowInsetsAnimationCallback.AnimationBounds; -import android.view.WindowInsetsAnimationCallback.InsetsAnimation; +import android.view.WindowInsetsAnimation.Bounds; import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEventSource; @@ -4672,7 +4671,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; - WindowInsetsAnimationCallback mWindowInsetsAnimationCallback; + WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; /** * This lives here since it's only valid for interactive views. @@ -11200,43 +11199,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Sets a {@link WindowInsetsAnimationCallback} to be notified about animations of windows that + * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that * cause insets. * <p> - * When setting a listener, it's {@link WindowInsetsAnimationCallback#getDispatchMode() dispatch - * mode} will be retrieved and recorded until another listener will be set. + * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() + * dispatch mode} will affect whether animation callbacks are dispatched to the children of + * this view. * </p> - * @param listener The listener to set. + * @param callback The callback to set. */ - public void setWindowInsetsAnimationCallback(@Nullable WindowInsetsAnimationCallback listener) { - getListenerInfo().mWindowInsetsAnimationCallback = listener; + public void setWindowInsetsAnimationCallback( + @Nullable WindowInsetsAnimation.Callback callback) { + getListenerInfo().mWindowInsetsAnimationCallback = callback; } /** - * Dispatches {@link WindowInsetsAnimationCallback#onPrepare(InsetsAnimation)} + * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} * when Window Insets animation is being prepared. * @param animation current animation * - * @see WindowInsetsAnimationCallback#onPrepare(InsetsAnimation) + * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) */ public void dispatchWindowInsetsAnimationPrepare( - @NonNull InsetsAnimation animation) { + @NonNull WindowInsetsAnimation animation) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); } } /** - * Dispatches {@link WindowInsetsAnimationCallback#onStart(InsetsAnimation, AnimationBounds)} + * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} * when Window Insets animation is started. * @param animation current animation - * @param bounds the upper and lower {@link AnimationBounds} that provides range of - * {@link InsetsAnimation}. - * @return the upper and lower {@link AnimationBounds}. + * @param bounds the upper and lower {@link Bounds} that provides range of + * {@link WindowInsetsAnimation}. + * @return the upper and lower {@link Bounds}. */ @NonNull - public AnimationBounds dispatchWindowInsetsAnimationStart( - @NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) { + public Bounds dispatchWindowInsetsAnimationStart( + @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); } @@ -11244,28 +11245,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Dispatches {@link WindowInsetsAnimationCallback#onProgress(WindowInsets)} + * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} * when Window Insets animation makes progress. * @param insets The current {@link WindowInsets}. + * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. * @return current {@link WindowInsets}. */ @NonNull - public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets) { + public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, + @NonNull List<WindowInsetsAnimation> runningAnimations) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { - return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets); + return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, + runningAnimations); } else { return insets; } } /** - * Dispatches {@link WindowInsetsAnimationCallback#onFinish(InsetsAnimation)} - * when Window Insets animation finishes. - * @param animation The current ongoing {@link InsetsAnimation}. + * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} + * when Window Insets animation ends. + * @param animation The current ongoing {@link WindowInsetsAnimation}. */ - public void dispatchWindowInsetsAnimationFinish(@NonNull InsetsAnimation animation) { + public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { - mListenerInfo.mWindowInsetsAnimationCallback.onFinish(animation); + mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d416d420feda..0367536919cf 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -17,8 +17,8 @@ package android.view; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; -import static android.view.WindowInsetsAnimationCallback.DISPATCH_MODE_CONTINUE_ON_SUBTREE; -import static android.view.WindowInsetsAnimationCallback.DISPATCH_MODE_STOP; +import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE; +import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; import android.animation.LayoutTransition; import android.annotation.CallSuper; @@ -48,17 +48,14 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; -import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; import android.util.Pools; import android.util.Pools.SynchronizedPool; import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.view.Window.OnContentApplyWindowInsetsListener; -import android.view.WindowInsetsAnimationCallback.AnimationBounds; -import android.view.WindowInsetsAnimationCallback.DispatchMode; -import android.view.WindowInsetsAnimationCallback.InsetsAnimation; +import android.view.WindowInsetsAnimation.Bounds; +import android.view.WindowInsetsAnimation.Callback.DispatchMode; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -615,7 +612,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Current dispatch mode of animation events * - * @see WindowInsetsAnimationCallback#getDispatchMode() + * @see WindowInsetsAnimation.Callback#getDispatchMode() */ private @DispatchMode int mInsetsAnimationDispatchMode = DISPATCH_MODE_CONTINUE_ON_SUBTREE; @@ -7228,16 +7225,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } @Override - public void setWindowInsetsAnimationCallback(@Nullable WindowInsetsAnimationCallback listener) { - super.setWindowInsetsAnimationCallback(listener); - mInsetsAnimationDispatchMode = listener != null - ? listener.getDispatchMode() + public void setWindowInsetsAnimationCallback( + @Nullable WindowInsetsAnimation.Callback callback) { + super.setWindowInsetsAnimationCallback(callback); + mInsetsAnimationDispatchMode = callback != null + ? callback.getDispatchMode() : DISPATCH_MODE_CONTINUE_ON_SUBTREE; } @Override public void dispatchWindowInsetsAnimationPrepare( - @NonNull InsetsAnimation animation) { + @NonNull WindowInsetsAnimation animation) { super.dispatchWindowInsetsAnimationPrepare(animation); // If we are root-level content view that fits insets, set dispatch mode to stop to imitate @@ -7262,8 +7260,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @Override @NonNull - public AnimationBounds dispatchWindowInsetsAnimationStart( - @NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) { + public Bounds dispatchWindowInsetsAnimationStart( + @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { bounds = super.dispatchWindowInsetsAnimationStart(animation, bounds); if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) { return bounds; @@ -7277,27 +7275,28 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @Override @NonNull - public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets) { - insets = super.dispatchWindowInsetsAnimationProgress(insets); + public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, + @NonNull List<WindowInsetsAnimation> runningAnimations) { + insets = super.dispatchWindowInsetsAnimationProgress(insets, runningAnimations); if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) { return insets; } final int count = getChildCount(); for (int i = 0; i < count; i++) { - getChildAt(i).dispatchWindowInsetsAnimationProgress(insets); + getChildAt(i).dispatchWindowInsetsAnimationProgress(insets, runningAnimations); } return insets; } @Override - public void dispatchWindowInsetsAnimationFinish(@NonNull InsetsAnimation animation) { - super.dispatchWindowInsetsAnimationFinish(animation); + public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { + super.dispatchWindowInsetsAnimationEnd(animation); if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) { return; } final int count = getChildCount(); for (int i = 0; i < count; i++) { - getChildAt(i).dispatchWindowInsetsAnimationFinish(animation); + getChildAt(i).dispatchWindowInsetsAnimationEnd(animation); } } diff --git a/core/java/android/view/WindowInsetsAnimation.java b/core/java/android/view/WindowInsetsAnimation.java new file mode 100644 index 000000000000..396da4acb5bc --- /dev/null +++ b/core/java/android/view/WindowInsetsAnimation.java @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2020 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.annotation.FloatRange; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.graphics.Insets; +import android.view.animation.Interpolator; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + +/** + * Class representing an animation of a set of windows that cause insets. + */ +public final class WindowInsetsAnimation { + + @WindowInsets.Type.InsetsType + private final int mTypeMask; + private float mFraction; + @Nullable + private final Interpolator mInterpolator; + private final long mDurationMillis; + private float mAlpha; + + /** + * Creates a new {@link WindowInsetsAnimation} object. + * <p> + * This should only be used for testing, as usually the system creates this object for the + * application to listen to with {@link Callback}. + * </p> + * @param typeMask The bitmask of {@link WindowInsets.Type}s that are animating. + * @param interpolator The interpolator of the animation. + * @param durationMillis The duration of the animation in + * {@link java.util.concurrent.TimeUnit#MILLISECONDS}. + */ + public WindowInsetsAnimation( + @WindowInsets.Type.InsetsType int typeMask, @Nullable Interpolator interpolator, + long durationMillis) { + mTypeMask = typeMask; + mInterpolator = interpolator; + mDurationMillis = durationMillis; + } + + /** + * @return The bitmask of {@link WindowInsets.Type.InsetsType}s that are animating. + */ + @WindowInsets.Type.InsetsType + public int getTypeMask() { + return mTypeMask; + } + + /** + * Returns the raw fractional progress of this animation between + * start state of the animation and the end state of the animation. Note + * that this progress is the global progress of the animation, whereas + * {@link Callback#onProgress} will only dispatch the insets that may + * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy. + * Progress per insets animation is global for the entire animation. One animation animates + * all things together (in, out, ...). If they don't animate together, we'd have + * multiple animations. + * <p> + * Note: In case the application is controlling the animation, the valued returned here will + * be the same as the application passed into + * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}. + * </p> + * @return The current progress of this animation. + */ + @FloatRange(from = 0f, to = 1f) + public float getFraction() { + return mFraction; + } + + /** + * Returns the interpolated fractional progress of this animation between + * start state of the animation and the end state of the animation. Note + * that this progress is the global progress of the animation, whereas + * {@link Callback#onProgress} will only dispatch the insets that may + * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy. + * Progress per insets animation is global for the entire animation. One animation animates + * all things together (in, out, ...). If they don't animate together, we'd have + * multiple animations. + * <p> + * Note: In case the application is controlling the animation, the valued returned here will + * be the same as the application passed into + * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}, + * interpolated with the interpolator passed into + * {@link WindowInsetsController#controlWindowInsetsAnimation}. + * </p> + * <p> + * Note: For system-initiated animations, this will always return a valid value between 0 + * and 1. + * </p> + * @see #getFraction() for raw fraction. + * @return The current interpolated progress of this animation. -1 if interpolator isn't + * specified. + */ + public float getInterpolatedFraction() { + if (mInterpolator != null) { + return mInterpolator.getInterpolation(mFraction); + } + return -1; + } + + /** + * Retrieves the interpolator used for this animation, or {@code null} if this animation + * doesn't follow an interpolation curved. For system-initiated animations, this will never + * return {@code null}. + * + * @return The interpolator used for this animation. + */ + @Nullable + public Interpolator getInterpolator() { + return mInterpolator; + } + + /** + * @return duration of animation in {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or + * -1 if the animation doesn't have a fixed duration. + */ + public long getDurationMillis() { + return mDurationMillis; + } + + /** + * Set fraction of the progress if {@link WindowInsets.Type.InsetsType} animation is + * controlled by the app. + * <p> + * Note: This should only be used for testing, as the system fills in the fraction for the + * application or the fraction that was passed into + * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being + * used. + * </p> + * @param fraction fractional progress between 0 and 1 where 0 represents hidden and + * zero progress and 1 represent fully shown final state. + * @see #getFraction() + */ + public void setFraction(@FloatRange(from = 0f, to = 1f) float fraction) { + mFraction = fraction; + } + + /** + * Retrieves the translucency of the windows that are animating. + * + * @return Alpha of windows that cause insets of type {@link WindowInsets.Type.InsetsType}. + */ + @FloatRange(from = 0f, to = 1f) + public float getAlpha() { + return mAlpha; + } + + /** + * Sets the translucency of the windows that are animating. + * <p> + * Note: This should only be used for testing, as the system fills in the alpha for the + * application or the alpha that was passed into + * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being + * used. + * </p> + * @param alpha Alpha of windows that cause insets of type + * {@link WindowInsets.Type.InsetsType}. + * @see #getAlpha() + */ + public void setAlpha(@FloatRange(from = 0f, to = 1f) float alpha) { + mAlpha = alpha; + } + + /** + * Class representing the range of an {@link WindowInsetsAnimation} + */ + public static final class Bounds { + + private final Insets mLowerBound; + private final Insets mUpperBound; + + public Bounds(@NonNull Insets lowerBound, @NonNull Insets upperBound) { + mLowerBound = lowerBound; + mUpperBound = upperBound; + } + + /** + * 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 multiple + * animations running at the same time for different inset types. + * + * @see #getUpperBound() + * @see WindowInsetsAnimationController#getHiddenStateInsets + */ + @NonNull + public Insets getLowerBound() { + return mLowerBound; + } + + /** + * Queries the upper 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} + * nd 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 multiple + * animations running at the same time for different inset types. + * + * @see #getLowerBound() + * @see WindowInsetsAnimationController#getShownStateInsets + */ + @NonNull + public Insets getUpperBound() { + return mUpperBound; + } + + /** + * Insets both the lower and upper bound by the specified insets. This is to be used in + * {@link Callback#onStart} to indicate that a part of the insets has + * been used to offset or clip its children, and the children shouldn't worry about that + * part anymore. + * + * @param insets The amount to inset. + * @return A copy of this instance inset in the given directions. + * @see WindowInsets#inset + * @see Callback#onStart + */ + @NonNull + public Bounds inset(@NonNull Insets insets) { + return new Bounds( + // TODO: refactor so that WindowInsets.insetInsets() is in a more appropriate + // place eventually. + WindowInsets.insetInsets( + mLowerBound, insets.left, insets.top, insets.right, insets.bottom), + WindowInsets.insetInsets( + mUpperBound, insets.left, insets.top, insets.right, insets.bottom)); + } + } + + /** + * Interface that allows the application to listen to animation events for windows that cause + * insets. + */ + @SuppressLint("CallbackMethodName") // TODO(b/149430296) Should be on method, not class. + public abstract static class Callback { + + /** + * Return value for {@link #getDispatchMode()}: Dispatching of animation events should + * stop at this level in the view hierarchy, and no animation events should be dispatch to + * the subtree of the view hierarchy. + */ + public static final int DISPATCH_MODE_STOP = 0; + + /** + * Return value for {@link #getDispatchMode()}: Dispatching of animation events should + * continue in the view hierarchy. + */ + public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; + + /** @hide */ + @IntDef(prefix = { "DISPATCH_MODE_" }, value = { + DISPATCH_MODE_STOP, + DISPATCH_MODE_CONTINUE_ON_SUBTREE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DispatchMode {} + + @DispatchMode + private final int mDispatchMode; + + /** + * Creates a new {@link WindowInsetsAnimation} callback with the given + * {@link #getDispatchMode() dispatch mode}. + * + * @param dispatchMode The dispatch mode for this callback. See {@link #getDispatchMode()}. + */ + public Callback(@DispatchMode int dispatchMode) { + mDispatchMode = dispatchMode; + } + + /** + * Retrieves the dispatch mode of this listener. Dispatch of the all animation events is + * hierarchical: It will starts at the root of the view hierarchy and then traverse it and + * invoke the callback of the specific {@link View} that is being traversed. + * The method may return either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that + * animation events should be propagated to the subtree of the view hierarchy, or + * {@link #DISPATCH_MODE_STOP} to stop dispatching. In that case, all animation callbacks + * related to the animation passed in will be stopped from propagating to the subtree of the + * hierarchy. + * <p> + * Also note that {@link #DISPATCH_MODE_STOP} behaves the same way as + * returning {@link WindowInsets#CONSUMED} during the regular insets dispatch in + * {@link View#onApplyWindowInsets}. + * + * @return Either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that dispatching of + * animation events will continue to the subtree of the view hierarchy, or + * {@link #DISPATCH_MODE_STOP} to indicate that animation events will stop + * dispatching. + */ + @DispatchMode + @SuppressLint("CallbackMethodName") // TODO(b/149430296) False positive: not a callback. + public final int getDispatchMode() { + return mDispatchMode; + } + + /** + * Called when an insets animation is about to start and before the views have been laid out + * in the end state of the animation. The ordering of events during an insets animation is + * the following: + * <p> + * <ul> + * <li>Application calls {@link WindowInsetsController#hide(int)}, + * {@link WindowInsetsController#show(int)}, + * {@link WindowInsetsController#controlWindowInsetsAnimation}</li> + * <li>onPrepare is called on the view hierarchy listeners</li> + * <li>{@link View#onApplyWindowInsets} will be called with the end state of the + * animation</li> + * <li>View hierarchy gets laid out according to the changes the application has + * requested due to the new insets being dispatched</li> + * <li>{@link #onStart} is called <em>before</em> the view + * hierarchy gets drawn in the new laid out state</li> + * <li>{@link #onProgress} is called immediately after with the animation start + * state</li> + * <li>The frame gets drawn.</li> + * </ul> + * <p> + * This ordering allows the application to inspect the end state after the animation has + * finished, and then revert to the starting state of the animation in the first + * {@link #onProgress} callback by using post-layout view properties like {@link View#setX} + * and related methods. + * <p> + * Note: If the animation is application controlled by using + * {@link WindowInsetsController#controlWindowInsetsAnimation}, the end state of the + * animation is undefined as the application may decide on the end state only by passing in + * {@code shown} parameter when calling {@link WindowInsetsAnimationController#finish}. In + * this situation, the system will dispatch the insets in the opposite visibility state + * before the animation starts. Example: When controlling the input method with + * {@link WindowInsetsController#controlWindowInsetsAnimation} and the input method is + * currently showing, {@link View#onApplyWindowInsets} will receive a {@link WindowInsets} + * instance for which {@link WindowInsets#isVisible} will return {@code false} for + * {@link WindowInsets.Type#ime}. + * + * @param animation The animation that is about to start. + */ + public void onPrepare(@NonNull WindowInsetsAnimation animation) { + } + + /** + * Called when an insets animation gets started. + * <p> + * Note that, like {@link #onProgress}, dispatch of the animation start event is + * hierarchical: It will starts at the root of the view hierarchy and then traverse it + * and invoke the callback of the specific {@link View} that is being traversed. + * The method may return a modified + * instance of the bounds by calling {@link Bounds#inset} 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. Furthermore, if {@link #getDispatchMode()} returns + * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore. + * + * @param animation The animation that is about to start. + * @param bounds The bounds in which animation happens. + * @return The animation representing the part of the insets that should be dispatched to + * the subtree of the hierarchy. + */ + @NonNull + public Bounds onStart( + @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { + return bounds; + } + + /** + * 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 method 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. Furthermore, if {@link #getDispatchMode()} returns + * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore. + * + * @param insets The current insets. + * @param runningAnimations The currently running animations. + * @return The insets to dispatch to the subtree of the hierarchy. + */ + @NonNull + public abstract WindowInsets onProgress(@NonNull WindowInsets insets, + @NonNull List<WindowInsetsAnimation> runningAnimations); + + /** + * Called when an insets animation has ended. + * + * @param animation The animation that has ended. This will be the same instance + * as passed into {@link #onStart} + */ + public void onEnd(@NonNull WindowInsetsAnimation animation) { + } + + } +} diff --git a/core/java/android/view/WindowInsetsAnimationCallback.java b/core/java/android/view/WindowInsetsAnimationCallback.java deleted file mode 100644 index 4c8463b37df4..000000000000 --- a/core/java/android/view/WindowInsetsAnimationCallback.java +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (C) 2019 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.annotation.FloatRange; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.graphics.Insets; -import android.view.WindowInsets.Type; -import android.view.WindowInsets.Type.InsetsType; -import android.view.animation.Interpolator; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Interface that allows the application to listen to animation events for windows that cause - * insets. - */ -public interface WindowInsetsAnimationCallback { - - /** - * Return value for {@link #getDispatchMode()}: Dispatching of animation events should - * stop at this level in the view hierarchy, and no animation events should be dispatch to the - * subtree of the view hierarchy. - */ - int DISPATCH_MODE_STOP = 0; - - /** - * Return value for {@link #getDispatchMode()}: Dispatching of animation events should - * continue in the view hierarchy. - */ - int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; - - /** @hide */ - @IntDef(prefix = { "DISPATCH_MODE_" }, value = { - DISPATCH_MODE_STOP, - DISPATCH_MODE_CONTINUE_ON_SUBTREE - }) - @Retention(RetentionPolicy.SOURCE) - @interface DispatchMode {} - - /** - * Retrieves the dispatch mode of this listener. Dispatch of the all animation events is - * hierarchical: It will starts at the root of the view hierarchy and then traverse it and - * invoke the callback of the specific {@link View} that is being traversed. - * The method may return either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that - * animation events should be propagated to the subtree of the view hierarchy, or - * {@link #DISPATCH_MODE_STOP} to stop dispatching. In that case, all animation callbacks - * related to the animation passed in will be stopped from propagating to the subtree of the - * hierarchy. - * <p> - * Note that this method will only be invoked once when - * {@link View#setWindowInsetsAnimationCallback setting the listener} and then the framework - * will use the recorded result. - * <p> - * Also note that returning {@link #DISPATCH_MODE_STOP} here behaves the same way as returning - * {@link WindowInsets#CONSUMED} during the regular insets dispatch in - * {@link View#onApplyWindowInsets}. - * - * @return Either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that dispatching of - * animation events will continue to the subtree of the view hierarchy, or - * {@link #DISPATCH_MODE_STOP} to indicate that animation events will stop dispatching. - */ - @DispatchMode - int getDispatchMode(); - - /** - * Called when an insets animation is about to start and before the views have been laid out in - * the end state of the animation. The ordering of events during an insets animation is the - * following: - * <p> - * <ul> - * <li>Application calls {@link WindowInsetsController#hide(int)}, - * {@link WindowInsetsController#show(int)}, - * {@link WindowInsetsController#controlWindowInsetsAnimation}</li> - * <li>onPrepare is called on the view hierarchy listeners</li> - * <li>{@link View#onApplyWindowInsets} will be called with the end state of the - * animation</li> - * <li>View hierarchy gets laid out according to the changes the application has requested - * due to the new insets being dispatched</li> - * <li>{@link #onStart} is called <em>before</em> the view - * hierarchy gets drawn in the new laid out state</li> - * <li>{@link #onProgress} is called immediately after with the animation start state</li> - * <li>The frame gets drawn.</li> - * </ul> - * <p> - * This ordering allows the application to inspect the end state after the animation has - * finished, and then revert to the starting state of the animation in the first - * {@link #onProgress} callback by using post-layout view properties like {@link View#setX} and - * related methods. - * <p> - * Note: If the animation is application controlled by using - * {@link WindowInsetsController#controlWindowInsetsAnimation}, the end state of the animation - * is undefined as the application may decide on the end state only by passing in the - * {@code shown} parameter when calling {@link WindowInsetsAnimationController#finish}. In this - * situation, the system will dispatch the insets in the opposite visibility state before the - * animation starts. Example: When controlling the input method with - * {@link WindowInsetsController#controlWindowInsetsAnimation} and the input method is currently - * showing, {@link View#onApplyWindowInsets} will receive a {@link WindowInsets} instance for - * which {@link WindowInsets#isVisible} will return {@code false} for {@link Type#ime}. - * - * @param animation The animation that is about to start. - */ - default void onPrepare(@NonNull InsetsAnimation animation) { - } - - /** - * Called when an insets animation gets started. - * <p> - * Note that, like {@link #onProgress}, dispatch of the animation start event is hierarchical: - * It will starts at the root of the view hierarchy and then traverse it and invoke the callback - * of the specific {@link View} that is being traversed. The method may return a modified - * instance of the bounds by calling {@link AnimationBounds#inset} 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. Furthermore, if {@link #getDispatchMode()} returns - * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore. - * - * @param animation The animation that is about to start. - * @param bounds The bounds in which animation happens. - * @return The animation representing the part of the insets that should be dispatched to the - * subtree of the hierarchy. - */ - @NonNull - default AnimationBounds onStart( - @NonNull InsetsAnimation animation, @NonNull AnimationBounds bounds) { - return bounds; - } - - /** - * 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 method 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. Furthermore, if {@link #getDispatchMode()} returns - * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore. - * - * TODO: Introduce a way to map (type -> InsetAnimation) so app developer can query animation - * for a given type e.g. callback.getAnimation(type) OR controller.getAnimation(type). - * Or on the controller directly? - * @param insets The current insets. - * @return The insets to dispatch to the subtree of the hierarchy. - */ - @NonNull - WindowInsets onProgress(@NonNull WindowInsets insets); - - /** - * Called when an insets animation has finished. - * - * @param animation The animation that has finished running. This will be the same instance as - * passed into {@link #onStart} - */ - default void onFinish(@NonNull InsetsAnimation animation) { - } - - /** - * Class representing an animation of a set of windows that cause insets. - */ - final class InsetsAnimation { - - private final @InsetsType int mTypeMask; - private float mFraction; - @Nullable private final Interpolator mInterpolator; - private final long mDurationMillis; - private float mAlpha; - - /** - * Creates a new {@link InsetsAnimation} object. - * <p> - * This should only be used for testing, as usually the system creates this object for the - * application to listen to with {@link WindowInsetsAnimationCallback}. - * </p> - * @param typeMask The bitmask of {@link WindowInsets.Type}s that are animating. - * @param interpolator The interpolator of the animation. - * @param durationMillis The duration of the animation in - * {@link java.util.concurrent.TimeUnit#MILLISECONDS}. - */ - public InsetsAnimation( - @InsetsType int typeMask, @Nullable Interpolator interpolator, - long durationMillis) { - mTypeMask = typeMask; - mInterpolator = interpolator; - mDurationMillis = durationMillis; - } - - /** - * @return The bitmask of {@link WindowInsets.Type.InsetsType}s that are animating. - */ - public @InsetsType int getTypeMask() { - return mTypeMask; - } - - /** - * Returns the raw fractional progress of this animation between - * start state of the animation and the end state of the animation. Note - * that this progress is the global progress of the animation, whereas - * {@link WindowInsetsAnimationCallback#onProgress} will only dispatch the insets that may - * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy. - * Progress per insets animation is global for the entire animation. One animation animates - * all things together (in, out, ...). If they don't animate together, we'd have - * multiple animations. - * <p> - * Note: In case the application is controlling the animation, the valued returned here will - * be the same as the application passed into - * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}. - * </p> - * @return The current progress of this animation. - */ - @FloatRange(from = 0f, to = 1f) - public float getFraction() { - return mFraction; - } - - /** - * Returns the interpolated fractional progress of this animation between - * start state of the animation and the end state of the animation. Note - * that this progress is the global progress of the animation, whereas - * {@link WindowInsetsAnimationCallback#onProgress} will only dispatch the insets that may - * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy. - * Progress per insets animation is global for the entire animation. One animation animates - * all things together (in, out, ...). If they don't animate together, we'd have - * multiple animations. - * <p> - * Note: In case the application is controlling the animation, the valued returned here will - * be the same as the application passed into - * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}, - * interpolated with the interpolator passed into - * {@link WindowInsetsController#controlWindowInsetsAnimation}. - * </p> - * <p> - * Note: For system-initiated animations, this will always return a valid value between 0 - * and 1. - * </p> - * @see #getFraction() for raw fraction. - * @return The current interpolated progress of this animation. -1 if interpolator isn't - * specified. - */ - public float getInterpolatedFraction() { - if (mInterpolator != null) { - return mInterpolator.getInterpolation(mFraction); - } - return -1; - } - - /** - * Retrieves the interpolator used for this animation, or {@code null} if this animation - * doesn't follow an interpolation curved. For system-initiated animations, this will never - * return {@code null}. - * - * @return The interpolator used for this animation. - */ - @Nullable - public Interpolator getInterpolator() { - return mInterpolator; - } - - /** - * @return duration of animation in {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or - * -1 if the animation doesn't have a fixed duration. - */ - public long getDurationMillis() { - return mDurationMillis; - } - - /** - * Set fraction of the progress if {@link WindowInsets.Type.InsetsType} animation is - * controlled by the app. - * <p> - * Note: This should only be used for testing, as the system fills in the fraction for the - * application or the fraction that was passed into - * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being - * used. - * </p> - * @param fraction fractional progress between 0 and 1 where 0 represents hidden and - * zero progress and 1 represent fully shown final state. - * @see #getFraction() - */ - public void setFraction(@FloatRange(from = 0f, to = 1f) float fraction) { - mFraction = fraction; - } - - /** - * Retrieves the translucency of the windows that are animating. - * - * @return Alpha of windows that cause insets of type {@link WindowInsets.Type.InsetsType}. - */ - @FloatRange(from = 0f, to = 1f) - public float getAlpha() { - return mAlpha; - } - - /** - * Sets the translucency of the windows that are animating. - * <p> - * Note: This should only be used for testing, as the system fills in the alpha for the - * application or the alpha that was passed into - * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being - * used. - * </p> - * @param alpha Alpha of windows that cause insets of type - * {@link WindowInsets.Type.InsetsType}. - * @see #getAlpha() - */ - public void setAlpha(@FloatRange(from = 0f, to = 1f) float alpha) { - mAlpha = alpha; - } - } - - /** - * Class representing the range of an {@link InsetsAnimation} - */ - final class AnimationBounds { - - private final Insets mLowerBound; - private final Insets mUpperBound; - - public AnimationBounds(@NonNull Insets lowerBound, @NonNull Insets upperBound) { - mLowerBound = lowerBound; - mUpperBound = upperBound; - } - - /** - * 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 multiple - * animations running at the same time for different inset types. - * - * @see #getUpperBound() - * @see WindowInsetsAnimationController#getHiddenStateInsets - */ - @NonNull - public Insets getLowerBound() { - return mLowerBound; - } - - /** - * Queries the upper 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} - * nd 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 multiple - * animations running at the same time for different inset types. - * - * @see #getLowerBound() - * @see WindowInsetsAnimationController#getShownStateInsets - */ - @NonNull - public Insets getUpperBound() { - return mUpperBound; - } - - /** - * Insets both the lower and upper bound by the specified insets. This is to be used in - * {@link WindowInsetsAnimationCallback#onStart} to indicate that a part of the insets has - * been used to offset or clip its children, and the children shouldn't worry about that - * part anymore. - * - * @param insets The amount to inset. - * @return A copy of this instance inset in the given directions. - * @see WindowInsets#inset - * @see WindowInsetsAnimationCallback#onStart - */ - @NonNull - public AnimationBounds inset(@NonNull Insets insets) { - return new AnimationBounds( - // TODO: refactor so that WindowInsets.insetInsets() is in a more appropriate - // place eventually. - WindowInsets.insetInsets( - mLowerBound, insets.left, insets.top, insets.right, insets.bottom), - WindowInsets.insetInsets( - mUpperBound, insets.left, insets.top, insets.right, insets.bottom)); - } - } -} diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java index 4a864be64f64..2c7880b09785 100644 --- a/core/java/android/view/WindowInsetsAnimationController.java +++ b/core/java/android/view/WindowInsetsAnimationController.java @@ -22,8 +22,7 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.graphics.Insets; import android.view.WindowInsets.Type.InsetsType; -import android.view.WindowInsetsAnimationCallback.AnimationBounds; -import android.view.animation.Interpolator; +import android.view.WindowInsetsAnimation.Bounds; /** * Controller for app-driven animation of system windows. @@ -35,7 +34,7 @@ import android.view.animation.Interpolator; * <p> * Control is obtained through {@link WindowInsetsController#controlWindowInsetsAnimation}. */ -@SuppressLint("NotClosable") +@SuppressLint("NotCloseable") public interface WindowInsetsAnimationController { /** @@ -45,12 +44,12 @@ public interface WindowInsetsAnimationController { * to {@link View#getRootView} * <p> * If there are any animation listeners registered, this value is the same as - * {@link AnimationBounds#getLowerBound()} that is being be passed into the root view of the + * {@link Bounds#getLowerBound()} that is being be passed into the root view of the * hierarchy. * * @return Insets when the windows this animation is controlling are fully hidden. * - * @see AnimationBounds#getLowerBound() + * @see Bounds#getLowerBound() */ @NonNull Insets getHiddenStateInsets(); @@ -61,11 +60,11 @@ public interface WindowInsetsAnimationController { * to {@link View#getRootView} * <p> * If there are any animation listeners registered, this value is the same as - * {@link AnimationBounds#getUpperBound()} that is being passed into the root view of hierarchy. + * {@link Bounds#getUpperBound()} that is being passed into the root view of hierarchy. * * @return Insets when the windows this animation is controlling are fully shown. * - * @see AnimationBounds#getUpperBound() + * @see Bounds#getUpperBound() */ @NonNull Insets getShownStateInsets(); @@ -114,9 +113,9 @@ public interface WindowInsetsAnimationController { * Also 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, register a - * {@link WindowInsetsAnimationCallback} by calling - * {@link View#setWindowInsetsAnimationCallback(WindowInsetsAnimationCallback)} that will be - * notified about any insets change via {@link WindowInsetsAnimationCallback#onProgress} during + * {@link WindowInsetsAnimation.Callback} by calling + * {@link View#setWindowInsetsAnimationCallback(WindowInsetsAnimation.Callback)} that will be + * notified about any insets change via {@link WindowInsetsAnimation.Callback#onProgress} during * the animation. * <p> * {@link View#dispatchApplyWindowInsets} will instead be called once the animation has @@ -131,10 +130,10 @@ public interface WindowInsetsAnimationController { * If you intend on changing alpha only, pass null or {@link #getCurrentInsets()}. * @param alpha The new alpha to apply to the inset side. * @param fraction instantaneous animation progress. This value is dispatched to - * {@link WindowInsetsAnimationCallback}. + * {@link WindowInsetsAnimation.Callback}. * - * @see WindowInsetsAnimationCallback - * @see View#setWindowInsetsAnimationCallback(WindowInsetsAnimationCallback) + * @see WindowInsetsAnimation.Callback + * @see View#setWindowInsetsAnimationCallback(WindowInsetsAnimation.Callback) */ void setInsetsAndAlpha(@Nullable Insets insets, @FloatRange(from = 0f, to = 1f) float alpha, @FloatRange(from = 0f, to = 1f) float fraction); diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index 27e92e559b09..b7ca03798bbe 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.graphics.Insets; import android.os.CancellationSignal; import android.view.WindowInsets.Type.InsetsType; -import android.view.WindowInsetsAnimationCallback.InsetsAnimation; import android.view.animation.Interpolator; import java.lang.annotation.Retention; @@ -148,19 +147,19 @@ public interface WindowInsetsController { * @param durationMillis Duration of animation in * {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the * animation doesn't have a predetermined duration. This value will be - * passed to {@link InsetsAnimation#getDurationMillis()} + * passed to {@link WindowInsetsAnimation#getDurationMillis()} * @param interpolator The interpolator used for this animation, or {@code null} if this * animation doesn't follow an interpolation curve. This value will be - * passed to {@link InsetsAnimation#getInterpolator()} and used to calculate - * {@link InsetsAnimation#getInterpolatedFraction()}. + * passed to {@link WindowInsetsAnimation#getInterpolator()} and used to + * calculate {@link WindowInsetsAnimation#getInterpolatedFraction()}. * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the * windows are ready to be controlled, among other callbacks. * @return A cancellation signal that the caller can use to cancel the request to obtain * control, or once they have control, to cancel the control. - * @see InsetsAnimation#getFraction() - * @see InsetsAnimation#getInterpolatedFraction() - * @see InsetsAnimation#getInterpolator() - * @see InsetsAnimation#getDurationMillis() + * @see WindowInsetsAnimation#getFraction() + * @see WindowInsetsAnimation#getInterpolatedFraction() + * @see WindowInsetsAnimation#getInterpolator() + * @see WindowInsetsAnimation#getDurationMillis() */ @NonNull CancellationSignal controlWindowInsetsAnimation(@InsetsType int types, long durationMillis, diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index bdb802195d8b..aa5101ee4141 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package android.view; @@ -23,7 +23,6 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.WindowInsets.Type.systemBars; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 51b9916159fe..b663336bb7ba 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -41,7 +41,7 @@ import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl; import android.view.SyncRtSurfaceTransactionApplier; import android.view.ViewRootImpl; -import android.view.WindowInsetsAnimationCallback; +import android.view.WindowInsetsAnimation; import android.view.WindowInsetsAnimationControlListener; import com.android.internal.annotations.VisibleForTesting; @@ -403,8 +403,8 @@ class InsetsPolicy { @Override public void startAnimation(InsetsAnimationControlImpl controller, WindowInsetsAnimationControlListener listener, int types, - WindowInsetsAnimationCallback.InsetsAnimation animation, - WindowInsetsAnimationCallback.AnimationBounds bounds, + WindowInsetsAnimation animation, + WindowInsetsAnimation.Bounds bounds, int layoutDuringAnimation) { } } diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java index 01e212d01574..b9f5ac0270b2 100644 --- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java @@ -16,24 +16,26 @@ package com.google.android.test.windowinsetstests; +import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; + import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.app.Activity; import android.graphics.Insets; import android.os.Bundle; -import android.util.Log; import android.util.Property; import android.view.View; import android.view.WindowInsets; import android.view.WindowInsets.Type; -import android.view.WindowInsetsAnimationCallback; -import android.view.WindowInsetsAnimationCallback.InsetsAnimation; +import android.view.WindowInsetsAnimation; import android.view.WindowInsetsAnimationControlListener; import android.view.WindowInsetsAnimationController; import com.google.android.test.windowinsetstests.R; +import java.util.List; + public class WindowInsetsActivity extends Activity { private View mRoot; @@ -70,7 +72,7 @@ public class WindowInsetsActivity extends Activity { float startY; float endY; - InsetsAnimation imeAnim; + WindowInsetsAnimation imeAnim; @Override protected void onCreate(Bundle savedInstanceState) { @@ -85,15 +87,11 @@ public class WindowInsetsActivity extends Activity { v.getWindowInsetsController().hide(Type.ime()); } }); - mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimationCallback() { - - @Override - public int getDispatchMode() { - return DISPATCH_MODE_STOP; - } + mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimation.Callback( + DISPATCH_MODE_STOP) { @Override - public void onPrepare(InsetsAnimation animation) { + public void onPrepare(WindowInsetsAnimation animation) { if ((animation.getTypeMask() & Type.ime()) != 0) { imeAnim = animation; } @@ -101,20 +99,21 @@ public class WindowInsetsActivity extends Activity { } @Override - public WindowInsets onProgress(WindowInsets insets) { + public WindowInsets onProgress(WindowInsets insets, + List<WindowInsetsAnimation> runningAnimations) { mButton.setY(startY + (endY - startY) * imeAnim.getInterpolatedFraction()); return insets; } @Override - public AnimationBounds onStart(InsetsAnimation animation, - AnimationBounds bounds) { + public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation, + WindowInsetsAnimation.Bounds bounds) { endY = mButton.getTop(); return bounds; } @Override - public void onFinish(InsetsAnimation animation) { + public void onEnd(WindowInsetsAnimation animation) { imeAnim = null; } }); |