summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Roos <roosa@google.com>2020-02-12 15:05:27 -0800
committerJorim Jaggi <jjaggi@google.com>2020-02-17 14:30:25 +0100
commitdb5b0c232140c7e9481e0b5648592cdaf03e169e (patch)
treeeedafab624e0da435104f8983cd1e747935189f0
parente96570e2915247f85c43925acbdb75dbe502cd16 (diff)
WindowInsetsAnimation: Clean up API
Fixes issues the app developers have raised with the WindowInsetsAnimation API: - it really makes more sense to have the Animation as the outer class, and the Callback nested within - it was not obvious previously that multiple animations could be running at the same time. A new argument to onProgress now makes this abundantly clear by passing in the list of running animations. - The dispatch mode really fits better as a final property on the callback, rather than it being queried once from a getter. Also fixes lint warnings. Fixes: 143556682 Test: make checkapi; atest WindowInsetsControllerTests Change-Id: I8cd8faac70dd5a15d779d2c983f0a0ea5d6bbd8e
-rw-r--r--api/current.txt49
-rw-r--r--core/java/android/view/InsetsAnimationControlCallbacks.java12
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java11
-rw-r--r--core/java/android/view/InsetsController.java23
-rw-r--r--core/java/android/view/View.java56
-rw-r--r--core/java/android/view/ViewGroup.java41
-rw-r--r--core/java/android/view/WindowInsetsAnimation.java432
-rw-r--r--core/java/android/view/WindowInsetsAnimationCallback.java412
-rw-r--r--core/java/android/view/WindowInsetsAnimationController.java25
-rw-r--r--core/java/android/view/WindowInsetsController.java15
-rw-r--r--core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java3
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java6
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java29
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;
}
});