/* * Copyright (C) 2014 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.animation.TimeInterpolator; import android.view.ViewPropertyAnimator.NameValuesHolder; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import com.android.internal.view.animation.FallbackLUTInterpolator; import java.util.ArrayList; /** * This is a RenderThread driven backend for ViewPropertyAnimator. */ class ViewPropertyAnimatorRT { private static final Interpolator sLinearInterpolator = new LinearInterpolator(); private final View mView; private RenderNodeAnimator mAnimators[] = new RenderNodeAnimator[RenderNodeAnimator.LAST_VALUE + 1]; ViewPropertyAnimatorRT(View view) { mView = view; } /** * @return true if ViewPropertyAnimatorRT handled the animation, * false if ViewPropertyAnimator needs to handle it */ public boolean startAnimation(ViewPropertyAnimator parent) { cancelAnimators(parent.mPendingAnimations); if (!canHandleAnimator(parent)) { return false; } doStartAnimation(parent); return true; } public void cancelAll() { for (int i = 0; i < mAnimators.length; i++) { if (mAnimators[i] != null) { mAnimators[i].cancel(); mAnimators[i] = null; } } } private void doStartAnimation(ViewPropertyAnimator parent) { int size = parent.mPendingAnimations.size(); long startDelay = parent.getStartDelay(); long duration = parent.getDuration(); TimeInterpolator interpolator = parent.getInterpolator(); if (interpolator == null) { // Documented to be LinearInterpolator in ValueAnimator.setInterpolator interpolator = sLinearInterpolator; } if (!RenderNodeAnimator.isNativeInterpolator(interpolator)) { interpolator = new FallbackLUTInterpolator(interpolator, duration); } for (int i = 0; i < size; i++) { NameValuesHolder holder = parent.mPendingAnimations.get(i); int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant); final float finalValue = holder.mFromValue + holder.mDeltaValue; RenderNodeAnimator animator = new RenderNodeAnimator(property, finalValue); animator.setStartDelay(startDelay); animator.setDuration(duration); animator.setInterpolator(interpolator); animator.setTarget(mView); animator.start(); mAnimators[property] = animator; } parent.mPendingAnimations.clear(); } private boolean canHandleAnimator(ViewPropertyAnimator parent) { // TODO: Can we eliminate this entirely? // If RenderNode.animatorProperties() can be toggled to point at staging // instead then RNA can be used as the animators for software as well // as the updateListener fallback paths. If this can be toggled // at the top level somehow, combined with requiresUiRedraw, we could // ensure that RT does not self-animate, allowing for safe driving of // the animators from the UI thread using the same mechanisms // ViewPropertyAnimator does, just with everything sitting on a single // animator subsystem instead of multiple. if (parent.getUpdateListener() != null) { return false; } if (parent.getListener() != null) { // TODO support return false; } if (!mView.isHardwareAccelerated()) { // TODO handle this maybe? return false; } if (parent.hasActions()) { return false; } // Here goes nothing... return true; } private void cancelAnimators(ArrayList<NameValuesHolder> mPendingAnimations) { int size = mPendingAnimations.size(); for (int i = 0; i < size; i++) { NameValuesHolder holder = mPendingAnimations.get(i); int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant); if (mAnimators[property] != null) { mAnimators[property].cancel(); mAnimators[property] = null; } } } }