Loading core/java/android/view/RenderNodeAnimator.java +8 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ public final class RenderNodeAnimator extends Animator { public static final int Y = 9; public static final int Z = 10; public static final int ALPHA = 11; // The last value in the enum, used for array size initialization public static final int LAST_VALUE = ALPHA; // Keep in sync with enum PaintFields in Animator.h public static final int PAINT_STROKE_WIDTH = 0; Loading Loading @@ -86,7 +88,7 @@ public final class RenderNodeAnimator extends Animator { private boolean mStarted = false; private boolean mFinished = false; public int mapViewPropertyToRenderProperty(int viewProperty) { public static int mapViewPropertyToRenderProperty(int viewProperty) { return sViewPropertyAnimatorMap.get(viewProperty); } Loading Loading @@ -125,11 +127,15 @@ public final class RenderNodeAnimator extends Animator { } } static boolean isNativeInterpolator(TimeInterpolator interpolator) { return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class); } private void applyInterpolator() { if (mInterpolator == null) return; long ni; if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) { if (isNativeInterpolator(mInterpolator)) { ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator(); } else { long duration = nGetDuration(mNativePtr.get()); Loading core/java/android/view/ViewPropertyAnimator.java +28 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.view; import android.animation.Animator; import android.animation.ValueAnimator; import android.animation.TimeInterpolator; import android.os.Build; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -108,6 +109,11 @@ public class ViewPropertyAnimator { */ private ValueAnimator mTempValueAnimator; /** * A RenderThread-driven backend that may intercept startAnimation */ private ViewPropertyAnimatorRT mRTBackend; /** * This listener is the mechanism by which the underlying Animator causes changes to the * properties currently being animated, as well as the cleanup after an animation is Loading Loading @@ -227,7 +233,7 @@ public class ViewPropertyAnimator { * values are used to calculate the animated value for a given animation fraction * during the animation. */ private static class NameValuesHolder { static class NameValuesHolder { int mNameConstant; float mFromValue; float mDeltaValue; Loading @@ -247,6 +253,9 @@ public class ViewPropertyAnimator { ViewPropertyAnimator(View view) { mView = view; view.ensureTransformationInfo(); if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) { mRTBackend = new ViewPropertyAnimatorRT(view); } } /** Loading Loading @@ -371,6 +380,10 @@ public class ViewPropertyAnimator { return this; } Animator.AnimatorListener getListener() { return mListener; } /** * Sets a listener for update events in the underlying ValueAnimator that runs * the property animations. Note that the underlying animator is animating between Loading @@ -390,6 +403,10 @@ public class ViewPropertyAnimator { return this; } ValueAnimator.AnimatorUpdateListener getUpdateListener() { return mUpdateListener; } /** * Starts the currently pending property animations immediately. Calling <code>start()</code> * is optional because all animations start automatically at the next opportunity. However, Loading Loading @@ -825,12 +842,22 @@ public class ViewPropertyAnimator { return this; } boolean hasActions() { return mPendingSetupAction != null || mPendingCleanupAction != null || mPendingOnStartAction != null || mPendingOnEndAction != null; } /** * Starts the underlying Animator for a set of properties. We use a single animator that * simply runs from 0 to 1, and then use that fractional value to set each property * value accordingly. */ private void startAnimation() { if (mRTBackend != null && mRTBackend.startAnimation(this)) { return; } mView.setHasTransientState(true); ValueAnimator animator = ValueAnimator.ofFloat(1.0f); ArrayList<NameValuesHolder> nameValueList = Loading core/java/android/view/ViewPropertyAnimatorRT.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * 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 com.android.internal.view.animation.FallbackLUTInterpolator; import java.util.ArrayList; /** * This is a RenderThread driven backend for ViewPropertyAnimator. */ class ViewPropertyAnimatorRT { 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; } private void doStartAnimation(ViewPropertyAnimator parent) { int size = parent.mPendingAnimations.size(); long startDelay = parent.getStartDelay(); long duration = parent.getDuration(); TimeInterpolator interpolator = parent.getInterpolator(); 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); RenderNodeAnimator animator = new RenderNodeAnimator(property, holder.mFromValue + holder.mDeltaValue); animator.setStartDelay(startDelay); animator.setDuration(duration); animator.setInterpolator(interpolator); animator.setTarget(mView); animator.start(); } 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; } } } } core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java +10 −1 Original line number Diff line number Diff line Loading @@ -24,10 +24,13 @@ import android.view.Choreographer; * Interpolator that builds a lookup table to use. This is a fallback for * building a native interpolator from a TimeInterpolator that is not marked * with {@link HasNativeInterpolator} * * This implements TimeInterpolator to allow for easier interop with Animators */ @HasNativeInterpolator public class FallbackLUTInterpolator implements NativeInterpolatorFactory { public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator { private TimeInterpolator mSourceInterpolator; private final float mLut[]; /** Loading @@ -35,6 +38,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory { * interpolator creation */ public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) { mSourceInterpolator = interpolator; mLut = createLUT(interpolator, duration); } Loading Loading @@ -63,4 +67,9 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory { float[] lut = createLUT(interpolator, duration); return NativeInterpolatorFactoryHelper.createLutInterpolator(lut); } @Override public float getInterpolation(float input) { return mSourceInterpolator.getInterpolation(input); } } tests/RenderThreadTest/Android.mk +1 −1 Original line number Diff line number Diff line LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := tests # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) Loading Loading
core/java/android/view/RenderNodeAnimator.java +8 −2 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ public final class RenderNodeAnimator extends Animator { public static final int Y = 9; public static final int Z = 10; public static final int ALPHA = 11; // The last value in the enum, used for array size initialization public static final int LAST_VALUE = ALPHA; // Keep in sync with enum PaintFields in Animator.h public static final int PAINT_STROKE_WIDTH = 0; Loading Loading @@ -86,7 +88,7 @@ public final class RenderNodeAnimator extends Animator { private boolean mStarted = false; private boolean mFinished = false; public int mapViewPropertyToRenderProperty(int viewProperty) { public static int mapViewPropertyToRenderProperty(int viewProperty) { return sViewPropertyAnimatorMap.get(viewProperty); } Loading Loading @@ -125,11 +127,15 @@ public final class RenderNodeAnimator extends Animator { } } static boolean isNativeInterpolator(TimeInterpolator interpolator) { return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class); } private void applyInterpolator() { if (mInterpolator == null) return; long ni; if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) { if (isNativeInterpolator(mInterpolator)) { ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator(); } else { long duration = nGetDuration(mNativePtr.get()); Loading
core/java/android/view/ViewPropertyAnimator.java +28 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.view; import android.animation.Animator; import android.animation.ValueAnimator; import android.animation.TimeInterpolator; import android.os.Build; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -108,6 +109,11 @@ public class ViewPropertyAnimator { */ private ValueAnimator mTempValueAnimator; /** * A RenderThread-driven backend that may intercept startAnimation */ private ViewPropertyAnimatorRT mRTBackend; /** * This listener is the mechanism by which the underlying Animator causes changes to the * properties currently being animated, as well as the cleanup after an animation is Loading Loading @@ -227,7 +233,7 @@ public class ViewPropertyAnimator { * values are used to calculate the animated value for a given animation fraction * during the animation. */ private static class NameValuesHolder { static class NameValuesHolder { int mNameConstant; float mFromValue; float mDeltaValue; Loading @@ -247,6 +253,9 @@ public class ViewPropertyAnimator { ViewPropertyAnimator(View view) { mView = view; view.ensureTransformationInfo(); if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) { mRTBackend = new ViewPropertyAnimatorRT(view); } } /** Loading Loading @@ -371,6 +380,10 @@ public class ViewPropertyAnimator { return this; } Animator.AnimatorListener getListener() { return mListener; } /** * Sets a listener for update events in the underlying ValueAnimator that runs * the property animations. Note that the underlying animator is animating between Loading @@ -390,6 +403,10 @@ public class ViewPropertyAnimator { return this; } ValueAnimator.AnimatorUpdateListener getUpdateListener() { return mUpdateListener; } /** * Starts the currently pending property animations immediately. Calling <code>start()</code> * is optional because all animations start automatically at the next opportunity. However, Loading Loading @@ -825,12 +842,22 @@ public class ViewPropertyAnimator { return this; } boolean hasActions() { return mPendingSetupAction != null || mPendingCleanupAction != null || mPendingOnStartAction != null || mPendingOnEndAction != null; } /** * Starts the underlying Animator for a set of properties. We use a single animator that * simply runs from 0 to 1, and then use that fractional value to set each property * value accordingly. */ private void startAnimation() { if (mRTBackend != null && mRTBackend.startAnimation(this)) { return; } mView.setHasTransientState(true); ValueAnimator animator = ValueAnimator.ofFloat(1.0f); ArrayList<NameValuesHolder> nameValueList = Loading
core/java/android/view/ViewPropertyAnimatorRT.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * 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 com.android.internal.view.animation.FallbackLUTInterpolator; import java.util.ArrayList; /** * This is a RenderThread driven backend for ViewPropertyAnimator. */ class ViewPropertyAnimatorRT { 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; } private void doStartAnimation(ViewPropertyAnimator parent) { int size = parent.mPendingAnimations.size(); long startDelay = parent.getStartDelay(); long duration = parent.getDuration(); TimeInterpolator interpolator = parent.getInterpolator(); 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); RenderNodeAnimator animator = new RenderNodeAnimator(property, holder.mFromValue + holder.mDeltaValue); animator.setStartDelay(startDelay); animator.setDuration(duration); animator.setInterpolator(interpolator); animator.setTarget(mView); animator.start(); } 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; } } } }
core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java +10 −1 Original line number Diff line number Diff line Loading @@ -24,10 +24,13 @@ import android.view.Choreographer; * Interpolator that builds a lookup table to use. This is a fallback for * building a native interpolator from a TimeInterpolator that is not marked * with {@link HasNativeInterpolator} * * This implements TimeInterpolator to allow for easier interop with Animators */ @HasNativeInterpolator public class FallbackLUTInterpolator implements NativeInterpolatorFactory { public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator { private TimeInterpolator mSourceInterpolator; private final float mLut[]; /** Loading @@ -35,6 +38,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory { * interpolator creation */ public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) { mSourceInterpolator = interpolator; mLut = createLUT(interpolator, duration); } Loading Loading @@ -63,4 +67,9 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory { float[] lut = createLUT(interpolator, duration); return NativeInterpolatorFactoryHelper.createLutInterpolator(lut); } @Override public float getInterpolation(float input) { return mSourceInterpolator.getInterpolation(input); } }
tests/RenderThreadTest/Android.mk +1 −1 Original line number Diff line number Diff line LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := tests # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) Loading