Home | History | Annotate | Download | only in view
      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 
     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      */
     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 
     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 
     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 
     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 
    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