1 /*
2  * Copyright (C) 2014 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.animation.TimeInterpolator;
20 import android.view.ViewPropertyAnimator.NameValuesHolder;
21 import android.view.animation.Interpolator;
22 import android.view.animation.LinearInterpolator;
23 
24 import com.android.internal.view.animation.FallbackLUTInterpolator;
25 
26 import java.util.ArrayList;
27 
28 
29 /**
30  * This is a RenderThread driven backend for ViewPropertyAnimator.
31  */
32 class ViewPropertyAnimatorRT {
33 
34     private static final Interpolator sLinearInterpolator = new LinearInterpolator();
35 
36     private final View mView;
37 
38     private RenderNodeAnimator mAnimators[] = new RenderNodeAnimator[RenderNodeAnimator.LAST_VALUE + 1];
39 
ViewPropertyAnimatorRT(View view)40     ViewPropertyAnimatorRT(View view) {
41         mView = view;
42     }
43 
44     /**
45      * @return true if ViewPropertyAnimatorRT handled the animation,
46      *         false if ViewPropertyAnimator needs to handle it
47      */
startAnimation(ViewPropertyAnimator parent)48     public boolean startAnimation(ViewPropertyAnimator parent) {
49         cancelAnimators(parent.mPendingAnimations);
50         if (!canHandleAnimator(parent)) {
51             return false;
52         }
53         doStartAnimation(parent);
54         return true;
55     }
56 
cancelAll()57     public void cancelAll() {
58         for (int i = 0; i < mAnimators.length; i++) {
59             if (mAnimators[i] != null) {
60                 mAnimators[i].cancel();
61                 mAnimators[i] = null;
62             }
63         }
64     }
65 
doStartAnimation(ViewPropertyAnimator parent)66     private void doStartAnimation(ViewPropertyAnimator parent) {
67         int size = parent.mPendingAnimations.size();
68 
69         long startDelay = parent.getStartDelay();
70         long duration = parent.getDuration();
71         TimeInterpolator interpolator = parent.getInterpolator();
72         if (interpolator == null) {
73             // Documented to be LinearInterpolator in ValueAnimator.setInterpolator
74             interpolator = sLinearInterpolator;
75         }
76         if (!RenderNodeAnimator.isNativeInterpolator(interpolator)) {
77             interpolator = new FallbackLUTInterpolator(interpolator, duration);
78         }
79         for (int i = 0; i < size; i++) {
80             NameValuesHolder holder = parent.mPendingAnimations.get(i);
81             int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);
82 
83             final float finalValue = holder.mFromValue + holder.mDeltaValue;
84             RenderNodeAnimator animator = new RenderNodeAnimator(property, finalValue);
85             animator.setStartDelay(startDelay);
86             animator.setDuration(duration);
87             animator.setInterpolator(interpolator);
88             animator.setTarget(mView);
89             animator.start();
90 
91             mAnimators[property] = animator;
92         }
93 
94         parent.mPendingAnimations.clear();
95     }
96 
canHandleAnimator(ViewPropertyAnimator parent)97     private boolean canHandleAnimator(ViewPropertyAnimator parent) {
98         // TODO: Can we eliminate this entirely?
99         // If RenderNode.animatorProperties() can be toggled to point at staging
100         // instead then RNA can be used as the animators for software as well
101         // as the updateListener fallback paths. If this can be toggled
102         // at the top level somehow, combined with requiresUiRedraw, we could
103         // ensure that RT does not self-animate, allowing for safe driving of
104         // the animators from the UI thread using the same mechanisms
105         // ViewPropertyAnimator does, just with everything sitting on a single
106         // animator subsystem instead of multiple.
107 
108         if (parent.getUpdateListener() != null) {
109             return false;
110         }
111         if (parent.getListener() != null) {
112             // TODO support
113             return false;
114         }
115         if (!mView.isHardwareAccelerated()) {
116             // TODO handle this maybe?
117             return false;
118         }
119         if (parent.hasActions()) {
120             return false;
121         }
122         // Here goes nothing...
123         return true;
124     }
125 
cancelAnimators(ArrayList<NameValuesHolder> mPendingAnimations)126     private void cancelAnimators(ArrayList<NameValuesHolder> mPendingAnimations) {
127         int size = mPendingAnimations.size();
128         for (int i = 0; i < size; i++) {
129             NameValuesHolder holder = mPendingAnimations.get(i);
130             int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);
131             if (mAnimators[property] != null) {
132                 mAnimators[property].cancel();
133                 mAnimators[property] = null;
134             }
135         }
136     }
137 
138 }
139