• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package com.android.launcher3.anim;
17 
18 import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
19 import static com.android.launcher3.anim.AnimatorPlaybackController.addAnimationHoldersRecur;
20 
21 import android.animation.Animator;
22 import android.animation.Animator.AnimatorListener;
23 import android.animation.AnimatorSet;
24 import android.animation.ObjectAnimator;
25 import android.animation.TimeInterpolator;
26 import android.animation.ValueAnimator;
27 import android.graphics.drawable.ColorDrawable;
28 import android.util.FloatProperty;
29 import android.util.IntProperty;
30 import android.view.View;
31 
32 import com.android.launcher3.anim.AnimatorPlaybackController.Holder;
33 
34 import java.util.ArrayList;
35 import java.util.function.Consumer;
36 
37 /**
38  * Utility class to keep track of a running animation.
39  *
40  * This class allows attaching end callbacks to an animation is intended to be used with
41  * {@link com.android.launcher3.anim.AnimatorPlaybackController}, since in that case
42  * AnimationListeners are not properly dispatched.
43  *
44  * TODO: Find a better name
45  */
46 public class PendingAnimation implements PropertySetter {
47 
48     private final ArrayList<Holder> mAnimHolders = new ArrayList<>();
49     private final AnimatorSet mAnim;
50     private final long mDuration;
51 
52     private ValueAnimator mProgressAnimator;
53 
PendingAnimation(long duration)54     public PendingAnimation(long  duration) {
55         mDuration = duration;
56         mAnim = new AnimatorSet();
57     }
58 
59     /**
60      * Utility method to sent an interpolator on an animation and add it to the list
61      */
add(Animator anim, TimeInterpolator interpolator, SpringProperty springProperty)62     public void add(Animator anim, TimeInterpolator interpolator, SpringProperty springProperty) {
63         anim.setInterpolator(interpolator);
64         add(anim, springProperty);
65     }
66 
add(Animator anim)67     public void add(Animator anim) {
68         add(anim, SpringProperty.DEFAULT);
69     }
70 
add(Animator a, SpringProperty springProperty)71     public void add(Animator a, SpringProperty springProperty) {
72         mAnim.play(a.setDuration(mDuration));
73         addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders);
74     }
75 
76     @Override
setViewAlpha(View view, float alpha, TimeInterpolator interpolator)77     public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
78         if (view == null || view.getAlpha() == alpha) {
79             return;
80         }
81         ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
82         anim.addListener(new AlphaUpdateListener(view));
83         anim.setInterpolator(interpolator);
84         add(anim);
85     }
86 
87     @Override
setViewBackgroundColor(View view, int color, TimeInterpolator interpolator)88     public void setViewBackgroundColor(View view, int color, TimeInterpolator interpolator) {
89         if (view == null || (view.getBackground() instanceof ColorDrawable
90                 && ((ColorDrawable) view.getBackground()).getColor() == color)) {
91             return;
92         }
93         ObjectAnimator anim = ObjectAnimator.ofArgb(view, VIEW_BACKGROUND_COLOR, color);
94         anim.setInterpolator(interpolator);
95         add(anim);
96     }
97 
98     @Override
setFloat(T target, FloatProperty<T> property, float value, TimeInterpolator interpolator)99     public <T> void setFloat(T target, FloatProperty<T> property, float value,
100             TimeInterpolator interpolator) {
101         if (property.get(target) == value) {
102             return;
103         }
104         Animator anim = ObjectAnimator.ofFloat(target, property, value);
105         anim.setDuration(mDuration).setInterpolator(interpolator);
106         add(anim);
107     }
108 
addFloat(T target, FloatProperty<T> property, float from, float to, TimeInterpolator interpolator)109     public <T> void addFloat(T target, FloatProperty<T> property, float from, float to,
110             TimeInterpolator interpolator) {
111         Animator anim = ObjectAnimator.ofFloat(target, property, from, to);
112         anim.setInterpolator(interpolator);
113         add(anim);
114     }
115 
116     @Override
setInt(T target, IntProperty<T> property, int value, TimeInterpolator interpolator)117     public <T> void setInt(T target, IntProperty<T> property, int value,
118             TimeInterpolator interpolator) {
119         if (property.get(target) == value) {
120             return;
121         }
122         Animator anim = ObjectAnimator.ofInt(target, property, value);
123         anim.setInterpolator(interpolator);
124         add(anim);
125     }
126 
127     /**
128      * Adds a callback to be run on every frame of the animation
129      */
addOnFrameCallback(Runnable runnable)130     public void addOnFrameCallback(Runnable runnable) {
131         addOnFrameListener(anim -> runnable.run());
132     }
133 
134     /**
135      * Adds a listener to be run on every frame of the animation
136      */
addOnFrameListener(ValueAnimator.AnimatorUpdateListener listener)137     public void addOnFrameListener(ValueAnimator.AnimatorUpdateListener listener) {
138         if (mProgressAnimator == null) {
139             mProgressAnimator = ValueAnimator.ofFloat(0, 1);
140         }
141 
142         mProgressAnimator.addUpdateListener(listener);
143     }
144 
145     /**
146      * @see AnimatorSet#addListener(AnimatorListener)
147      */
addListener(Animator.AnimatorListener listener)148     public void addListener(Animator.AnimatorListener listener) {
149         mAnim.addListener(listener);
150     }
151 
152     /**
153      * Creates and returns the underlying AnimatorSet
154      */
buildAnim()155     public AnimatorSet buildAnim() {
156         // Add progress animation to the end, so that frame callback is called after all the other
157         // animation update.
158         if (mProgressAnimator != null) {
159             add(mProgressAnimator);
160             mProgressAnimator = null;
161         }
162         if (mAnimHolders.isEmpty()) {
163             // Add a placeholder animation to that the duration is respected
164             add(ValueAnimator.ofFloat(0, 1).setDuration(mDuration));
165         }
166         return mAnim;
167     }
168 
169     /**
170      * Creates a controller for this animation
171      */
createPlaybackController()172     public AnimatorPlaybackController createPlaybackController() {
173         return new AnimatorPlaybackController(buildAnim(), mDuration, mAnimHolders);
174     }
175 
176     /**
177      * Add a listener of receiving the success/failure callback in the end.
178      */
addEndListener(Consumer<Boolean> listener)179     public void addEndListener(Consumer<Boolean> listener) {
180         if (mProgressAnimator == null) {
181             mProgressAnimator = ValueAnimator.ofFloat(0, 1);
182         }
183         mProgressAnimator.addListener(AnimatorListeners.forEndCallback(listener));
184     }
185 }
186