• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import android.annotation.FloatRange;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SuppressLint;
24 import android.graphics.Insets;
25 import android.view.animation.Interpolator;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 import java.util.List;
30 
31 /**
32  * Class representing an animation of a set of windows that cause insets.
33  */
34 public final class WindowInsetsAnimation {
35 
36     @WindowInsets.Type.InsetsType
37     private final int mTypeMask;
38     private float mFraction;
39     @Nullable
40     private final Interpolator mInterpolator;
41     private final long mDurationMillis;
42     private float mAlpha;
43 
44     /**
45      * Creates a new {@link WindowInsetsAnimation} object.
46      * <p>
47      * This should only be used for testing, as usually the system creates this object for the
48      * application to listen to with {@link Callback}.
49      * </p>
50      * @param typeMask The bitmask of {@link WindowInsets.Type}s that are animating.
51      * @param interpolator The interpolator of the animation.
52      * @param durationMillis The duration of the animation in
53      *                   {@link java.util.concurrent.TimeUnit#MILLISECONDS}.
54      */
WindowInsetsAnimation( @indowInsets.Type.InsetsType int typeMask, @Nullable Interpolator interpolator, long durationMillis)55     public WindowInsetsAnimation(
56             @WindowInsets.Type.InsetsType int typeMask, @Nullable Interpolator interpolator,
57             long durationMillis) {
58         mTypeMask = typeMask;
59         mInterpolator = interpolator;
60         mDurationMillis = durationMillis;
61     }
62 
63     /**
64      * @return The bitmask of {@link WindowInsets.Type}s that are animating.
65      */
66     @WindowInsets.Type.InsetsType
getTypeMask()67     public int getTypeMask() {
68         return mTypeMask;
69     }
70 
71     /**
72      * Returns the raw fractional progress of this animation between
73      * start state of the animation and the end state of the animation. Note
74      * that this progress is the global progress of the animation, whereas
75      * {@link Callback#onProgress} will only dispatch the insets that may
76      * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy.
77      * Progress per insets animation is global for the entire animation. One animation animates
78      * all things together (in, out, ...). If they don't animate together, we'd have
79      * multiple animations.
80      * <p>
81      * Note: In case the application is controlling the animation, the valued returned here will
82      * be the same as the application passed into
83      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)}.
84      * </p>
85      * @return The current progress of this animation.
86      */
87     @FloatRange(from = 0f, to = 1f)
getFraction()88     public float getFraction() {
89         return mFraction;
90     }
91 
92     /**
93      * Returns the interpolated fractional progress of this animation between
94      * start state of the animation and the end state of the animation. Note
95      * that this progress is the global progress of the animation, whereas
96      * {@link Callback#onProgress} will only dispatch the insets that may
97      * be inset with {@link WindowInsets#inset} by parents of views in the hierarchy.
98      * Progress per insets animation is global for the entire animation. One animation animates
99      * all things together (in, out, ...). If they don't animate together, we'd have
100      * multiple animations.
101      * <p>
102      * Note: In case the application is controlling the animation, the valued returned here will
103      * be the same as the application passed into
104      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)},
105      * interpolated with the interpolator passed into
106      * {@link WindowInsetsController#controlWindowInsetsAnimation}.
107      * </p>
108      * <p>
109      * Note: For system-initiated animations, this will always return a valid value between 0
110      * and 1.
111      * </p>
112      * @see #getFraction() for raw fraction.
113      * @return The current interpolated progress of this animation.
114      */
getInterpolatedFraction()115     public float getInterpolatedFraction() {
116         if (mInterpolator != null) {
117             return mInterpolator.getInterpolation(mFraction);
118         }
119         return mFraction;
120     }
121 
122     /**
123      * Retrieves the interpolator used for this animation, or {@code null} if this animation
124      * doesn't follow an interpolation curved. For system-initiated animations, this will never
125      * return {@code null}.
126      *
127      * @return The interpolator used for this animation.
128      */
129     @Nullable
getInterpolator()130     public Interpolator getInterpolator() {
131         return mInterpolator;
132     }
133 
134     /**
135      * @return duration of animation in {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or
136      *         -1 if the animation doesn't have a fixed duration.
137      */
getDurationMillis()138     public long getDurationMillis() {
139         return mDurationMillis;
140     }
141 
142     /**
143      * Set fraction of the progress if {@link WindowInsets.Type} animation is
144      * controlled by the app.
145      * <p>
146      * Note: This should only be used for testing, as the system fills in the fraction for the
147      * application or the fraction that was passed into
148      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being
149      * used.
150      * </p>
151      * @param fraction fractional progress between 0 and 1 where 0 represents hidden and
152      *                zero progress and 1 represent fully shown final state.
153      * @see #getFraction()
154      */
setFraction(@loatRangefrom = 0f, to = 1f) float fraction)155     public void setFraction(@FloatRange(from = 0f, to = 1f) float fraction) {
156         mFraction = fraction;
157     }
158 
159     /**
160      * Retrieves the translucency of the windows that are animating.
161      *
162      * @return Alpha of windows that cause insets of type {@link WindowInsets.Type}.
163      */
164     @FloatRange(from = 0f, to = 1f)
getAlpha()165     public float getAlpha() {
166         return mAlpha;
167     }
168 
169     /**
170      * Sets the translucency of the windows that are animating.
171      * <p>
172      * Note: This should only be used for testing, as the system fills in the alpha for the
173      * application or the alpha that was passed into
174      * {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)} is being
175      * used.
176      * </p>
177      * @param alpha Alpha of windows that cause insets of type {@link WindowInsets.Type}.
178      * @see #getAlpha()
179      */
setAlpha(@loatRangefrom = 0f, to = 1f) float alpha)180     public void setAlpha(@FloatRange(from = 0f, to = 1f) float alpha) {
181         mAlpha = alpha;
182     }
183 
184     /**
185      * Class representing the range of an {@link WindowInsetsAnimation}
186      */
187     public static final class Bounds {
188 
189         private final Insets mLowerBound;
190         private final Insets mUpperBound;
191 
Bounds(@onNull Insets lowerBound, @NonNull Insets upperBound)192         public Bounds(@NonNull Insets lowerBound, @NonNull Insets upperBound) {
193             mLowerBound = lowerBound;
194             mUpperBound = upperBound;
195         }
196 
197         /**
198          * Queries the lower inset bound of the animation. If the animation is about showing or
199          * hiding a window that cause insets, the lower bound is {@link Insets#NONE} and the upper
200          * bound is the same as {@link WindowInsets#getInsets(int)} for the fully shown state. This
201          * is the same as {@link WindowInsetsAnimationController#getHiddenStateInsets} and
202          * {@link WindowInsetsAnimationController#getShownStateInsets} in case the listener gets
203          * invoked because of an animation that originates from
204          * {@link WindowInsetsAnimationController}.
205          * <p>
206          * However, if the size of a window that causes insets is changing, these are the
207          * lower/upper bounds of that size animation.
208          * </p>
209          * There are no overlapping animations for a specific type, but there may be multiple
210          * animations running at the same time for different inset types.
211          *
212          * @see #getUpperBound()
213          * @see WindowInsetsAnimationController#getHiddenStateInsets
214          */
215         @NonNull
getLowerBound()216         public Insets getLowerBound() {
217             return mLowerBound;
218         }
219 
220         /**
221          * Queries the upper inset bound of the animation. If the animation is about showing or
222          * hiding a window that cause insets, the lower bound is {@link Insets#NONE}
223          * nd the upper bound is the same as {@link WindowInsets#getInsets(int)} for the fully
224          * shown state. This is the same as
225          * {@link WindowInsetsAnimationController#getHiddenStateInsets} and
226          * {@link WindowInsetsAnimationController#getShownStateInsets} in case the listener gets
227          * invoked because of an animation that originates from
228          * {@link WindowInsetsAnimationController}.
229          * <p>
230          * However, if the size of a window that causes insets is changing, these are the
231          * lower/upper bounds of that size animation.
232          * <p>
233          * There are no overlapping animations for a specific type, but there may be multiple
234          * animations running at the same time for different inset types.
235          *
236          * @see #getLowerBound()
237          * @see WindowInsetsAnimationController#getShownStateInsets
238          */
239         @NonNull
getUpperBound()240         public Insets getUpperBound() {
241             return mUpperBound;
242         }
243 
244         /**
245          * Insets both the lower and upper bound by the specified insets. This is to be used in
246          * {@link Callback#onStart} to indicate that a part of the insets has
247          * been used to offset or clip its children, and the children shouldn't worry about that
248          * part anymore.
249          *
250          * @param insets The amount to inset.
251          * @return A copy of this instance inset in the given directions.
252          * @see WindowInsets#inset
253          * @see Callback#onStart
254          */
255         @NonNull
inset(@onNull Insets insets)256         public Bounds inset(@NonNull Insets insets) {
257             return new Bounds(
258                     // TODO: refactor so that WindowInsets.insetInsets() is in a more appropriate
259                     //  place eventually.
260                     WindowInsets.insetInsets(
261                             mLowerBound, insets.left, insets.top, insets.right, insets.bottom),
262                     WindowInsets.insetInsets(
263                             mUpperBound, insets.left, insets.top, insets.right, insets.bottom));
264         }
265 
266         @Override
toString()267         public String toString() {
268             return "Bounds{lower=" + mLowerBound + " upper=" + mUpperBound + "}";
269         }
270     }
271 
272     /**
273      * Interface that allows the application to listen to animation events for windows that cause
274      * insets.
275      */
276     @SuppressLint("CallbackMethodName") // TODO(b/149430296) Should be on method, not class.
277     public abstract static class Callback {
278 
279         /**
280          * Return value for {@link #getDispatchMode()}: Dispatching of animation events should
281          * stop at this level in the view hierarchy, and no animation events should be dispatch to
282          * the subtree of the view hierarchy.
283          */
284         public static final int DISPATCH_MODE_STOP = 0;
285 
286         /**
287          * Return value for {@link #getDispatchMode()}: Dispatching of animation events should
288          * continue in the view hierarchy.
289          */
290         public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1;
291 
292         /** @hide */
293         @IntDef(prefix = { "DISPATCH_MODE_" }, value = {
294                 DISPATCH_MODE_STOP,
295                 DISPATCH_MODE_CONTINUE_ON_SUBTREE
296         })
297         @Retention(RetentionPolicy.SOURCE)
298         public @interface DispatchMode {}
299 
300         @DispatchMode
301         private final int mDispatchMode;
302 
303         /**
304          * Creates a new {@link WindowInsetsAnimation} callback with the given
305          * {@link #getDispatchMode() dispatch mode}.
306          *
307          * @param dispatchMode The dispatch mode for this callback. See {@link #getDispatchMode()}.
308          */
Callback(@ispatchMode int dispatchMode)309         public Callback(@DispatchMode int dispatchMode) {
310             mDispatchMode = dispatchMode;
311         }
312 
313         /**
314          * Retrieves the dispatch mode of this listener. Dispatch of the all animation events is
315          * hierarchical: It will starts at the root of the view hierarchy and then traverse it and
316          * invoke the callback of the specific {@link View} that is being traversed.
317          * The method may return either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that
318          * animation events should be propagated to the subtree of the view hierarchy, or
319          * {@link #DISPATCH_MODE_STOP} to stop dispatching. In that case, all animation callbacks
320          * related to the animation passed in will be stopped from propagating to the subtree of the
321          * hierarchy.
322          * <p>
323          * Also note that {@link #DISPATCH_MODE_STOP} behaves the same way as
324          * returning {@link WindowInsets#CONSUMED} during the regular insets dispatch in
325          * {@link View#onApplyWindowInsets}.
326          *
327          * @return Either {@link #DISPATCH_MODE_CONTINUE_ON_SUBTREE} to indicate that dispatching of
328          *         animation events will continue to the subtree of the view hierarchy, or
329          *         {@link #DISPATCH_MODE_STOP} to indicate that animation events will stop
330          *         dispatching.
331          */
332         @DispatchMode
333         @SuppressLint("CallbackMethodName") // TODO(b/149430296) False positive: not a callback.
getDispatchMode()334         public final int getDispatchMode() {
335             return mDispatchMode;
336         }
337 
338         /**
339          * Called when an insets animation is about to start and before the views have been laid out
340          * in the end state of the animation. The ordering of events during an insets animation is
341          * the following:
342          * <p>
343          * <ul>
344          *     <li>Application calls {@link WindowInsetsController#hide(int)},
345          *     {@link WindowInsetsController#show(int)},
346          *     {@link WindowInsetsController#controlWindowInsetsAnimation}</li>
347          *     <li>onPrepare is called on the view hierarchy listeners</li>
348          *     <li>{@link View#onApplyWindowInsets} will be called with the end state of the
349          *     animation</li>
350          *     <li>View hierarchy gets laid out according to the changes the application has
351          *     requested due to the new insets being dispatched</li>
352          *     <li>{@link #onStart} is called <em>before</em> the view
353          *     hierarchy gets drawn in the new laid out state</li>
354          *     <li>{@link #onProgress} is called immediately after with the animation start
355          *     state</li>
356          *     <li>The frame gets drawn.</li>
357          * </ul>
358          * <p>
359          * This ordering allows the application to inspect the end state after the animation has
360          * finished, and then revert to the starting state of the animation in the first
361          * {@link #onProgress} callback by using post-layout view properties like {@link View#setX}
362          * and related methods.
363          *
364          * <p>Note that the animation might be cancelled before {@link #onStart} is dispatched. On
365          * {@link android.os.Build.VERSION_CODES#S S} and later, {@link #onEnd} is immediately
366          * dispatched without an {@link #onStart} in that case.
367          * On {@link android.os.Build.VERSION_CODES#R R}, no callbacks are dispatched after
368          * {@code #onPrepare} for such an animation.
369          *
370          * <p>
371          * Note: If the animation is application controlled by using
372          * {@link WindowInsetsController#controlWindowInsetsAnimation}, the end state of the
373          * animation is undefined as the application may decide on the end state only by passing in
374          * {@code shown} parameter when calling {@link WindowInsetsAnimationController#finish}. In
375          * this situation, the system will dispatch the insets in the opposite visibility state
376          * before the animation starts. Example: When controlling the input method with
377          * {@link WindowInsetsController#controlWindowInsetsAnimation} and the input method is
378          * currently showing, {@link View#onApplyWindowInsets} will receive a {@link WindowInsets}
379          * instance for which {@link WindowInsets#isVisible} will return {@code false} for
380          * {@link WindowInsets.Type#ime}.
381          *
382          * @param animation The animation that is about to start.
383          */
onPrepare(@onNull WindowInsetsAnimation animation)384         public void onPrepare(@NonNull WindowInsetsAnimation animation) {
385         }
386 
387         /**
388          * Called when an insets animation gets started.
389          * <p>
390          * Note that, like {@link #onProgress}, dispatch of the animation start event is
391          * hierarchical: It will starts at the root of the view hierarchy and then traverse it
392          * and invoke the callback of the specific {@link View} that is being traversed.
393          * The method may return a modified
394          * instance of the bounds by calling {@link Bounds#inset} to indicate that a part of
395          * the insets have been used to offset or clip its children, and the children shouldn't
396          * worry about that part anymore. Furthermore, if {@link #getDispatchMode()} returns
397          * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore.
398          *
399          * @param animation The animation that is about to start.
400          * @param bounds The bounds in which animation happens.
401          * @return The animation representing the part of the insets that should be dispatched to
402          *         the subtree of the hierarchy.
403          */
404         @NonNull
onStart( @onNull WindowInsetsAnimation animation, @NonNull Bounds bounds)405         public Bounds onStart(
406                 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) {
407             return bounds;
408         }
409 
410         /**
411          * Called when the insets change as part of running an animation. Note that even if multiple
412          * animations for different types are running, there will only be one progress callback per
413          * frame. The {@code insets} passed as an argument represents the overall state and will
414          * include all types, regardless of whether they are animating or not.
415          * <p>
416          * Note that insets dispatch is hierarchical: It will start at the root of the view
417          * hierarchy, and then traverse it and invoke the callback of the specific {@link View}
418          * being traversed. The method may return a modified instance by calling
419          * {@link WindowInsets#inset(int, int, int, int)} to indicate that a part of the insets have
420          * been used to offset or clip its children, and the children shouldn't worry about that
421          * part anymore. Furthermore, if {@link #getDispatchMode()} returns
422          * {@link #DISPATCH_MODE_STOP}, children of this view will not receive the callback anymore.
423          *
424          * @param insets The current insets.
425          * @param runningAnimations The currently running animations.
426          * @return The insets to dispatch to the subtree of the hierarchy.
427          */
428         @NonNull
onProgress(@onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)429         public abstract WindowInsets onProgress(@NonNull WindowInsets insets,
430                 @NonNull List<WindowInsetsAnimation> runningAnimations);
431 
432         /**
433          * Called when an insets animation has ended.
434          *
435          * @param animation The animation that has ended. This will be the same instance
436          *                  as passed into {@link #onStart}
437          */
onEnd(@onNull WindowInsetsAnimation animation)438         public void onEnd(@NonNull WindowInsetsAnimation animation) {
439         }
440 
441     }
442 }
443