Merge "Move RenderNodeAnimator to android.graphics.animation package"

This commit is contained in:
Derek Sollenberger
2020-02-14 16:32:50 +00:00
committed by Android (Google) Code Review
27 changed files with 687 additions and 655 deletions

View File

@@ -16,518 +16,52 @@
package android.view;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
import android.os.Handler;
import android.os.Looper;
import android.util.SparseIntArray;
import com.android.internal.util.VirtualRefBasePtr;
import com.android.internal.view.animation.FallbackLUTInterpolator;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import java.util.ArrayList;
/**
* @hide
*/
public class RenderNodeAnimator extends Animator {
// Keep in sync with enum RenderProperty in Animator.h
public static final int TRANSLATION_X = 0;
public static final int TRANSLATION_Y = 1;
public static final int TRANSLATION_Z = 2;
public static final int SCALE_X = 3;
public static final int SCALE_Y = 4;
public static final int ROTATION = 5;
public static final int ROTATION_X = 6;
public static final int ROTATION_Y = 7;
public static final int X = 8;
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;
public class RenderNodeAnimator extends android.graphics.animation.RenderNodeAnimator
implements android.graphics.animation.RenderNodeAnimator.ViewListener {
// Keep in sync with enum PaintFields in Animator.h
public static final int PAINT_STROKE_WIDTH = 0;
/**
* Field for the Paint alpha channel, which should be specified as a value
* between 0 and 255.
*/
public static final int PAINT_ALPHA = 1;
// ViewPropertyAnimator uses a mask for its values, we need to remap them
// to the enum values here. RenderPropertyAnimator can't use the mask values
// directly as internally it uses a lookup table so it needs the values to
// be sequential starting from 0
private static final SparseIntArray sViewPropertyAnimatorMap = new SparseIntArray(15) {{
put(ViewPropertyAnimator.TRANSLATION_X, TRANSLATION_X);
put(ViewPropertyAnimator.TRANSLATION_Y, TRANSLATION_Y);
put(ViewPropertyAnimator.TRANSLATION_Z, TRANSLATION_Z);
put(ViewPropertyAnimator.SCALE_X, SCALE_X);
put(ViewPropertyAnimator.SCALE_Y, SCALE_Y);
put(ViewPropertyAnimator.ROTATION, ROTATION);
put(ViewPropertyAnimator.ROTATION_X, ROTATION_X);
put(ViewPropertyAnimator.ROTATION_Y, ROTATION_Y);
put(ViewPropertyAnimator.X, X);
put(ViewPropertyAnimator.Y, Y);
put(ViewPropertyAnimator.Z, Z);
put(ViewPropertyAnimator.ALPHA, ALPHA);
}};
private VirtualRefBasePtr mNativePtr;
private Handler mHandler;
private RenderNode mTarget;
private View mViewTarget;
private int mRenderProperty = -1;
private float mFinalValue;
private TimeInterpolator mInterpolator;
private static final int STATE_PREPARE = 0;
private static final int STATE_DELAYED = 1;
private static final int STATE_RUNNING = 2;
private static final int STATE_FINISHED = 3;
private int mState = STATE_PREPARE;
private long mUnscaledDuration = 300;
private long mUnscaledStartDelay = 0;
// If this is true, we will run any start delays on the UI thread. This is
// the safe default, and is necessary to ensure start listeners fire at
// the correct time. Animators created by RippleDrawable (the
// CanvasProperty<> ones) do not have this expectation, and as such will
// set this to false so that the renderthread handles the startdelay instead
private final boolean mUiThreadHandlesDelay;
private long mStartDelay = 0;
private long mStartTime;
public static int mapViewPropertyToRenderProperty(int viewProperty) {
return sViewPropertyAnimatorMap.get(viewProperty);
}
public RenderNodeAnimator(int property, float finalValue) {
mRenderProperty = property;
mFinalValue = finalValue;
mUiThreadHandlesDelay = true;
init(nCreateAnimator(property, finalValue));
super(property, finalValue);
}
public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
init(nCreateCanvasPropertyFloatAnimator(
property.getNativeContainer(), finalValue));
mUiThreadHandlesDelay = false;
super(property, finalValue);
}
/**
* Creates a new render node animator for a field on a Paint property.
*
* @param property The paint property to target
* @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
* {@link #PAINT_STROKE_WIDTH}
* @param finalValue The target value for the property
*/
public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
init(nCreateCanvasPropertyPaintAnimator(
property.getNativeContainer(), paintField, finalValue));
mUiThreadHandlesDelay = false;
super(property, paintField, finalValue);
}
public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
init(nCreateRevealAnimator(x, y, startRadius, endRadius));
mUiThreadHandlesDelay = true;
}
private void init(long ptr) {
mNativePtr = new VirtualRefBasePtr(ptr);
}
private void checkMutable() {
if (mState != STATE_PREPARE) {
throw new IllegalStateException("Animator has already started, cannot change it now!");
}
if (mNativePtr == null) {
throw new IllegalStateException("Animator's target has been destroyed "
+ "(trying to modify an animation after activity destroy?)");
}
}
static boolean isNativeInterpolator(TimeInterpolator interpolator) {
return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
}
private void applyInterpolator() {
if (mInterpolator == null || mNativePtr == null) return;
long ni;
if (isNativeInterpolator(mInterpolator)) {
ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
} else {
long duration = nGetDuration(mNativePtr.get());
ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
}
nSetInterpolator(mNativePtr.get(), ni);
super(x, y, startRadius, endRadius);
}
@Override
public void start() {
if (mTarget == null) {
throw new IllegalStateException("Missing target!");
}
if (mState != STATE_PREPARE) {
throw new IllegalStateException("Already started!");
}
mState = STATE_DELAYED;
if (mHandler == null) {
mHandler = new Handler(true);
}
applyInterpolator();
if (mNativePtr == null) {
// It's dead, immediately cancel
cancel();
} else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
nSetStartDelay(mNativePtr.get(), mStartDelay);
doStart();
} else {
getHelper().addDelayedAnimation(this);
}
}
private void doStart() {
public void onAlphaAnimationStart(float finalAlpha) {
// Alpha is a special snowflake that has the canonical value stored
// in mTransformationInfo instead of in RenderNode, so we need to update
// it with the final value here.
if (mRenderProperty == RenderNodeAnimator.ALPHA) {
mViewTarget.ensureTransformationInfo();
mViewTarget.setAlphaInternal(mFinalValue);
}
moveToRunningState();
if (mViewTarget != null) {
// Kick off a frame to start the process
mViewTarget.invalidateViewProperty(true, false);
}
}
private void moveToRunningState() {
mState = STATE_RUNNING;
if (mNativePtr != null) {
nStart(mNativePtr.get());
}
notifyStartListeners();
}
private void notifyStartListeners() {
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationStart(this);
}
mViewTarget.ensureTransformationInfo();
mViewTarget.setAlphaInternal(finalAlpha);
}
@Override
public void cancel() {
if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
if (mState == STATE_DELAYED) {
getHelper().removeDelayedAnimation(this);
moveToRunningState();
}
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationCancel(this);
}
end();
}
}
@Override
public void end() {
if (mState != STATE_FINISHED) {
if (mState < STATE_RUNNING) {
getHelper().removeDelayedAnimation(this);
doStart();
}
if (mNativePtr != null) {
nEnd(mNativePtr.get());
if (mViewTarget != null) {
// Kick off a frame to flush the state change
mViewTarget.invalidateViewProperty(true, false);
}
} else {
// It's already dead, jump to onFinish
onFinished();
}
}
}
@Override
public void pause() {
throw new UnsupportedOperationException();
}
@Override
public void resume() {
throw new UnsupportedOperationException();
public void invalidateParent(boolean forceRedraw) {
mViewTarget.invalidateViewProperty(true, false);
}
/** @hide */
public void setTarget(View view) {
public void setTarget(@NonNull View view) {
mViewTarget = view;
setViewListener(this);
setTarget(mViewTarget.mRenderNode);
}
/** Sets the animation target to the owning view of the RecordingCanvas */
public void setTarget(RecordingCanvas canvas) {
setTarget(canvas.mNode);
}
/** @hide */
public void setTarget(DisplayListCanvas canvas) {
setTarget((RecordingCanvas) canvas);
}
private void setTarget(RenderNode node) {
checkMutable();
if (mTarget != null) {
throw new IllegalStateException("Target already set!");
}
nSetListener(mNativePtr.get(), this);
mTarget = node;
mTarget.addAnimator(this);
}
public void setStartValue(float startValue) {
checkMutable();
nSetStartValue(mNativePtr.get(), startValue);
}
@Override
public void setStartDelay(long startDelay) {
checkMutable();
if (startDelay < 0) {
throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
}
mUnscaledStartDelay = startDelay;
mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
}
@Override
public long getStartDelay() {
return mUnscaledStartDelay;
}
@Override
public RenderNodeAnimator setDuration(long duration) {
checkMutable();
if (duration < 0) {
throw new IllegalArgumentException("duration must be positive; " + duration);
}
mUnscaledDuration = duration;
nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
return this;
}
@Override
public long getDuration() {
return mUnscaledDuration;
}
@Override
public long getTotalDuration() {
return mUnscaledDuration + mUnscaledStartDelay;
}
@Override
public boolean isRunning() {
return mState == STATE_DELAYED || mState == STATE_RUNNING;
}
@Override
public boolean isStarted() {
return mState != STATE_PREPARE;
}
@Override
public void setInterpolator(TimeInterpolator interpolator) {
checkMutable();
mInterpolator = interpolator;
}
@Override
public TimeInterpolator getInterpolator() {
return mInterpolator;
}
protected void onFinished() {
if (mState == STATE_PREPARE) {
// Unlikely but possible, the native side has been destroyed
// before we have started.
releaseNativePtr();
return;
}
if (mState == STATE_DELAYED) {
getHelper().removeDelayedAnimation(this);
notifyStartListeners();
}
mState = STATE_FINISHED;
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationEnd(this);
}
// Release the native object, as it has a global reference to us. This
// breaks the cyclic reference chain, and allows this object to be
// GC'd
releaseNativePtr();
}
private void releaseNativePtr() {
if (mNativePtr != null) {
mNativePtr.release();
mNativePtr = null;
}
}
@SuppressWarnings("unchecked")
private ArrayList<AnimatorListener> cloneListeners() {
ArrayList<AnimatorListener> listeners = getListeners();
if (listeners != null) {
listeners = (ArrayList<AnimatorListener>) listeners.clone();
}
return listeners;
}
public long getNativeAnimator() {
return mNativePtr.get();
}
/**
* @return true if the animator was started, false if still delayed
*/
private boolean processDelayed(long frameTimeMs) {
if (mStartTime == 0) {
mStartTime = frameTimeMs;
} else if ((frameTimeMs - mStartTime) >= mStartDelay) {
doStart();
return true;
}
return false;
}
private static DelayedAnimationHelper getHelper() {
DelayedAnimationHelper helper = sAnimationHelper.get();
if (helper == null) {
helper = new DelayedAnimationHelper();
sAnimationHelper.set(helper);
}
return helper;
}
private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
new ThreadLocal<DelayedAnimationHelper>();
private static class DelayedAnimationHelper implements Runnable {
private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
private final Choreographer mChoreographer;
private boolean mCallbackScheduled;
public DelayedAnimationHelper() {
mChoreographer = Choreographer.getInstance();
}
public void addDelayedAnimation(RenderNodeAnimator animator) {
mDelayedAnims.add(animator);
scheduleCallback();
}
public void removeDelayedAnimation(RenderNodeAnimator animator) {
mDelayedAnims.remove(animator);
}
private void scheduleCallback() {
if (!mCallbackScheduled) {
mCallbackScheduled = true;
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
}
}
@Override
public void run() {
long frameTimeMs = mChoreographer.getFrameTime();
mCallbackScheduled = false;
int end = 0;
for (int i = 0; i < mDelayedAnims.size(); i++) {
RenderNodeAnimator animator = mDelayedAnims.get(i);
if (!animator.processDelayed(frameTimeMs)) {
if (end != i) {
mDelayedAnims.set(end, animator);
}
end++;
}
}
while (mDelayedAnims.size() > end) {
mDelayedAnims.remove(mDelayedAnims.size() - 1);
}
if (mDelayedAnims.size() > 0) {
scheduleCallback();
}
}
}
// Called by native
private static void callOnFinished(RenderNodeAnimator animator) {
if (animator.mHandler != null) {
animator.mHandler.post(animator::onFinished);
} else {
new Handler(Looper.getMainLooper(), null, true).post(animator::onFinished);
}
}
@Override
public Animator clone() {
throw new IllegalStateException("Cannot clone this animator");
}
@Override
public void setAllowRunningAsynchronously(boolean mayRunAsync) {
checkMutable();
nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);
}
private static native long nCreateAnimator(int property, float finalValue);
private static native long nCreateCanvasPropertyFloatAnimator(
long canvasProperty, float finalValue);
private static native long nCreateCanvasPropertyPaintAnimator(
long canvasProperty, int paintField, float finalValue);
private static native long nCreateRevealAnimator(
int x, int y, float startRadius, float endRadius);
private static native void nSetStartValue(long nativePtr, float startValue);
private static native void nSetDuration(long nativePtr, long duration);
private static native long nGetDuration(long nativePtr);
private static native void nSetStartDelay(long nativePtr, long startDelay);
private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
private static native void nStart(long animPtr);
private static native void nEnd(long animPtr);
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright (C) 2016 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.graphics.RecordingCanvas;
import android.graphics.RenderNode;
import com.android.internal.view.animation.FallbackLUTInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* This is a helper class to get access to methods and fields needed for RenderNodeAnimatorSet
* that are internal or package private to android.view package.
*
* @hide
*/
public class RenderNodeAnimatorSetHelper {
/** checkstyle @hide */
public static RenderNode getTarget(RecordingCanvas recordingCanvas) {
return recordingCanvas.mNode;
}
/** checkstyle @hide */
public static long createNativeInterpolator(TimeInterpolator interpolator, long
duration) {
if (interpolator == null) {
// create LinearInterpolator
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
} else if (RenderNodeAnimator.isNativeInterpolator(interpolator)) {
return ((NativeInterpolatorFactory)interpolator).createNativeInterpolator();
} else {
return FallbackLUTInterpolator.createNativeInterpolator(interpolator, duration);
}
}
}

View File

@@ -17,19 +17,18 @@
package android.view.animation;
import android.content.Context;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the rate of change starts and ends slowly but
* accelerates through the middle.
*/
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
implements NativeInterpolator {
public AccelerateDecelerateInterpolator() {
}
@@ -44,6 +43,6 @@ public class AccelerateDecelerateInterpolator extends BaseInterpolator
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
return NativeInterpolatorFactory.createAccelerateDecelerateInterpolator();
}
}

View File

@@ -20,12 +20,12 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the rate of change starts out slowly and
@@ -33,7 +33,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
*
*/
@HasNativeInterpolator
public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolator {
private final float mFactor;
private final double mDoubleFactor;
@@ -85,6 +85,6 @@ public class AccelerateInterpolator extends BaseInterpolator implements NativeIn
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor);
return NativeInterpolatorFactory.createAccelerateInterpolator(mFactor);
}
}

View File

@@ -20,18 +20,18 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the change starts backward then flings forward.
*/
@HasNativeInterpolator
public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolator {
private final float mTension;
public AnticipateInterpolator() {
@@ -73,6 +73,6 @@ public class AnticipateInterpolator extends BaseInterpolator implements NativeIn
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAnticipateInterpolator(mTension);
return NativeInterpolatorFactory.createAnticipateInterpolator(mTension);
}
}

View File

@@ -24,11 +24,11 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the change starts backward then flings forward and overshoots
@@ -36,7 +36,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
*/
@HasNativeInterpolator
public class AnticipateOvershootInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
implements NativeInterpolator {
private final float mTension;
public AnticipateOvershootInterpolator() {
@@ -103,6 +103,6 @@ public class AnticipateOvershootInterpolator extends BaseInterpolator
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAnticipateOvershootInterpolator(mTension);
return NativeInterpolatorFactory.createAnticipateOvershootInterpolator(mTension);
}
}

View File

@@ -17,17 +17,16 @@
package android.view.animation;
import android.content.Context;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the change bounces at the end.
*/
@HasNativeInterpolator
public class BounceInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class BounceInterpolator extends BaseInterpolator implements NativeInterpolator {
public BounceInterpolator() {
}
@@ -56,6 +55,6 @@ public class BounceInterpolator extends BaseInterpolator implements NativeInterp
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createBounceInterpolator();
return NativeInterpolatorFactory.createBounceInterpolator();
}
}

View File

@@ -20,12 +20,12 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* Repeats the animation for a specified number of cycles. The
@@ -33,7 +33,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
*
*/
@HasNativeInterpolator
public class CycleInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class CycleInterpolator extends BaseInterpolator implements NativeInterpolator {
public CycleInterpolator(float cycles) {
mCycles = cycles;
}
@@ -65,6 +65,6 @@ public class CycleInterpolator extends BaseInterpolator implements NativeInterpo
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createCycleInterpolator(mCycles);
return NativeInterpolatorFactory.createCycleInterpolator(mCycles);
}
}

View File

@@ -20,12 +20,12 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the rate of change starts out quickly and
@@ -33,7 +33,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
*
*/
@HasNativeInterpolator
public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolator {
public DecelerateInterpolator() {
}
@@ -81,6 +81,6 @@ public class DecelerateInterpolator extends BaseInterpolator implements NativeIn
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createDecelerateInterpolator(mFactor);
return NativeInterpolatorFactory.createDecelerateInterpolator(mFactor);
}
}

View File

@@ -17,17 +17,16 @@
package android.view.animation;
import android.content.Context;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the rate of change is constant
*/
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolator {
public LinearInterpolator() {
}
@@ -42,6 +41,6 @@ public class LinearInterpolator extends BaseInterpolator implements NativeInterp
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
return NativeInterpolatorFactory.createLinearInterpolator();
}
}

View File

@@ -20,19 +20,19 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator where the change flings forward and overshoots the last value
* then comes back.
*/
@HasNativeInterpolator
public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolator {
private final float mTension;
public OvershootInterpolator() {
@@ -76,6 +76,6 @@ public class OvershootInterpolator extends BaseInterpolator implements NativeInt
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createOvershootInterpolator(mTension);
return NativeInterpolatorFactory.createOvershootInterpolator(mTension);
}
}

View File

@@ -20,14 +20,14 @@ import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Path;
import android.graphics.animation.HasNativeInterpolator;
import android.graphics.animation.NativeInterpolator;
import android.graphics.animation.NativeInterpolatorFactory;
import android.util.AttributeSet;
import android.util.PathParser;
import android.view.InflateException;
import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator that can traverse a Path that extends from <code>Point</code>
@@ -46,7 +46,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
* </pre></blockquote></p>
*/
@HasNativeInterpolator
public class PathInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public class PathInterpolator extends BaseInterpolator implements NativeInterpolator {
// This governs how accurate the approximation of the Path is.
private static final float PRECISION = 0.002f;
@@ -237,7 +237,7 @@ public class PathInterpolator extends BaseInterpolator implements NativeInterpol
/** @hide **/
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createPathInterpolator(mX, mY);
return NativeInterpolatorFactory.createPathInterpolator(mX, mY);
}
}

View File

@@ -1,37 +0,0 @@
/*
* 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 com.android.internal.view.animation;
/**
* Static utility class for constructing native interpolators to keep the
* JNI simpler
*/
public final class NativeInterpolatorFactoryHelper {
private NativeInterpolatorFactoryHelper() {}
public static native long createAccelerateDecelerateInterpolator();
public static native long createAccelerateInterpolator(float factor);
public static native long createAnticipateInterpolator(float tension);
public static native long createAnticipateOvershootInterpolator(float tension);
public static native long createBounceInterpolator();
public static native long createCycleInterpolator(float cycles);
public static native long createDecelerateInterpolator(float factor);
public static native long createLinearInterpolator();
public static native long createOvershootInterpolator(float tension);
public static native long createPathInterpolator(float[] x, float[] y);
public static native long createLutInterpolator(float[] values);
}

View File

@@ -42,9 +42,7 @@ cc_library_shared {
"android_util_StringBlock.cpp",
"android_util_XmlBlock.cpp",
"android_util_jar_StrictJarFile.cpp",
"android_view_RenderNodeAnimator.cpp",
"com_android_internal_util_VirtualRefBasePtr.cpp",
"com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp",
],
include_dirs: [
@@ -351,6 +349,8 @@ cc_library_static {
"android/graphics/apex/android_paint.cpp",
"android/graphics/apex/android_region.cpp",
"android_graphics_animation_NativeInterpolatorFactory.cpp",
"android_graphics_animation_RenderNodeAnimator.cpp",
"android_graphics_Canvas.cpp",
"android_graphics_ColorSpace.cpp",
"android_graphics_drawable_AnimatedVectorDrawable.cpp",

View File

@@ -119,13 +119,11 @@ extern int register_android_graphics_BLASTBufferQueue(JNIEnv* env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_InputApplicationHandle(JNIEnv* env);
extern int register_android_view_InputWindowHandle(JNIEnv* env);
extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env);
extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
extern int register_android_database_CursorWindow(JNIEnv* env);
extern int register_android_database_SQLiteConnection(JNIEnv* env);
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
@@ -1461,7 +1459,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_VintfRuntimeInfo),
REG_JNI(register_android_service_DataLoaderService),
REG_JNI(register_android_view_DisplayEventReceiver),
REG_JNI(register_android_view_RenderNodeAnimator),
REG_JNI(register_android_view_InputApplicationHandle),
REG_JNI(register_android_view_InputWindowHandle),
REG_JNI(register_android_view_Surface),
@@ -1469,7 +1466,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_CompositionSamplingListener),
REG_JNI(register_android_view_TextureView),
REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
REG_JNI(register_android_opengl_jni_EGL14),

View File

@@ -65,6 +65,8 @@ extern int register_android_graphics_Path(JNIEnv* env);
extern int register_android_graphics_PathMeasure(JNIEnv* env);
extern int register_android_graphics_Picture(JNIEnv* env);
extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env);
extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env);
extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
extern int register_android_graphics_fonts_Font(JNIEnv* env);
@@ -82,10 +84,8 @@ extern int register_android_util_Log(JNIEnv* env);
extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_util_jar_StrictJarFile(JNIEnv* env);
extern int register_android_view_RenderNode(JNIEnv* env);
extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
extern int register_android_view_DisplayListCanvas(JNIEnv* env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
#define REG_JNI(name) { name }
struct RegJNIRec {
@@ -130,6 +130,10 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.graphics.Region", REG_JNI(register_android_graphics_Region)},
{"android.graphics.Shader", REG_JNI(register_android_graphics_Shader)},
{"android.graphics.Typeface", REG_JNI(register_android_graphics_Typeface)},
{"android.graphics.animation.NativeInterpolatorFactory",
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory)},
{"android.graphics.animation.RenderNodeAnimator",
REG_JNI(register_android_graphics_animation_RenderNodeAnimator)},
{"android.graphics.drawable.AnimatedVectorDrawable",
REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable)},
{"android.graphics.drawable.VectorDrawable",
@@ -151,11 +155,8 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.util.Log", REG_JNI(register_android_util_Log)},
{"android.util.PathParser", REG_JNI(register_android_util_PathParser)},
{"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)},
{"android.view.RenderNodeAnimator", REG_JNI(register_android_view_RenderNodeAnimator)},
{"com.android.internal.util.VirtualRefBasePtr",
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr)},
{"com.android.internal.view.animation.NativeInterpolatorFactoryHelper",
REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper)},
};
// Vector to store the names of classes that need delegates of their native methods
static vector<string> classesToDelegate;

View File

@@ -60,6 +60,8 @@ extern int register_android_graphics_PathMeasure(JNIEnv* env);
extern int register_android_graphics_Picture(JNIEnv*);
extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env);
extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env);
extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
extern int register_android_graphics_fonts_Font(JNIEnv* env);
@@ -123,6 +125,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_SurfaceTexture),
REG_JNI(register_android_graphics_Typeface),
REG_JNI(register_android_graphics_YuvImage),
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory),
REG_JNI(register_android_graphics_animation_RenderNodeAnimator),
REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
REG_JNI(register_android_graphics_drawable_VectorDrawable),
REG_JNI(register_android_graphics_fonts_Font),

View File

@@ -90,7 +90,7 @@ static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut)
// JNI Glue
// ----------------------------------------------------------------------------
const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper";
const char* const kClassPathName = "android/graphics/animation/NativeInterpolatorFactory";
static const JNINativeMethod gMethods[] = {
{ "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator },
@@ -106,7 +106,7 @@ static const JNINativeMethod gMethods[] = {
{ "createLutInterpolator", "([F)J", (void*) createLutInterpolator },
};
int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv* env) {
int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env) {
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}

View File

@@ -190,7 +190,7 @@ static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) {
// JNI Glue
// ----------------------------------------------------------------------------
const char* const kClassPathName = "android/view/RenderNodeAnimator";
const char* const kClassPathName = "android/graphics/animation/RenderNodeAnimator";
static const JNINativeMethod gMethods[] = {
{ "nCreateAnimator", "(IF)J", (void*) createAnimator },
@@ -203,12 +203,12 @@ static const JNINativeMethod gMethods[] = {
{ "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
{ "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
{ "nSetAllowRunningAsync", "(JZ)V", (void*) setAllowRunningAsync },
{ "nSetListener", "(JLandroid/view/RenderNodeAnimator;)V", (void*) setListener},
{ "nSetListener", "(JLandroid/graphics/animation/RenderNodeAnimator;)V", (void*) setListener},
{ "nStart", "(J)V", (void*) start},
{ "nEnd", "(J)V", (void*) end },
};
int register_android_view_RenderNodeAnimator(JNIEnv* env) {
int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env) {
sLifecycleChecker.incStrong(0);
gRenderNodeAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName);
gRenderNodeAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env,
@@ -216,7 +216,7 @@ int register_android_view_RenderNodeAnimator(JNIEnv* env) {
gRenderNodeAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
env, gRenderNodeAnimatorClassInfo.clazz, "callOnFinished",
"(Landroid/view/RenderNodeAnimator;)V");
"(Landroid/graphics/animation/RenderNodeAnimator;)V");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}

View File

@@ -22,8 +22,8 @@ import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.animation.RenderNodeAnimator;
import android.view.NativeVectorDrawableAnimator;
import android.view.RenderNodeAnimator;
import android.view.Surface;
import android.view.View;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.internal.view.animation;
package android.graphics.animation;
import android.animation.TimeInterpolator;
import android.util.TimeUtils;
@@ -26,14 +26,15 @@ import android.view.Choreographer;
* with {@link HasNativeInterpolator}
*
* This implements TimeInterpolator to allow for easier interop with Animators
* @hide
*/
@HasNativeInterpolator
public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator {
public class FallbackLUTInterpolator implements NativeInterpolator, TimeInterpolator {
// If the duration of an animation is more than 300 frames, we cap the sample size to 300.
private static final int MAX_SAMPLE_POINTS = 300;
private TimeInterpolator mSourceInterpolator;
private final float mLut[];
private final float[] mLut;
/**
* Used to cache the float[] LUT for use across multiple native
@@ -50,7 +51,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeI
// We need 2 frame values as the minimal.
int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
numAnimFrames = Math.min(numAnimFrames, MAX_SAMPLE_POINTS);
float values[] = new float[numAnimFrames];
float[] values = new float[numAnimFrames];
float lastFrame = numAnimFrames - 1;
for (int i = 0; i < numAnimFrames; i++) {
float inValue = i / lastFrame;
@@ -61,7 +62,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeI
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLutInterpolator(mLut);
return NativeInterpolatorFactory.createLutInterpolator(mLut);
}
/**
@@ -69,7 +70,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeI
*/
public static long createNativeInterpolator(TimeInterpolator interpolator, long duration) {
float[] lut = createLUT(interpolator, duration);
return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
return NativeInterpolatorFactory.createLutInterpolator(lut);
}
@Override

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.internal.view.animation;
package android.graphics.animation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -23,10 +23,10 @@ import java.lang.annotation.Target;
/**
* This is a class annotation that signals that it is safe to create
* a native interpolator counterpart via {@link NativeInterpolatorFactory}
* a native interpolator counterpart via {@link NativeInterpolator}
*
* The idea here is to prevent subclasses of interpolators from being treated as a
* NativeInterpolatorFactory, and instead have them fall back to the LUT & LERP
* NativeInterpolator, and instead have them fall back to the LUT & LERP
* method like a custom interpolator.
*
* @hide

View File

@@ -14,8 +14,16 @@
* limitations under the License.
*/
package com.android.internal.view.animation;
package android.graphics.animation;
public interface NativeInterpolatorFactory {
/**
* @hide
*/
public interface NativeInterpolator {
/**
* Generates a native interpolator object that can be used by HardwareRenderer to draw
* RenderNodes.
* @return ptr to native object
*/
long createNativeInterpolator();
}

View File

@@ -0,0 +1,67 @@
/*
* 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.graphics.animation;
import android.animation.TimeInterpolator;
/**
* Static utility class for constructing native interpolators to keep the
* JNI simpler
*
* @hide
*/
public final class NativeInterpolatorFactory {
private NativeInterpolatorFactory() {}
/**
* Create a native interpolator from the provided param generating a LUT variant if a native
* implementation does not exist.
*/
public static long createNativeInterpolator(TimeInterpolator interpolator, long
duration) {
if (interpolator == null) {
return createLinearInterpolator();
} else if (RenderNodeAnimator.isNativeInterpolator(interpolator)) {
return ((NativeInterpolator) interpolator).createNativeInterpolator();
} else {
return FallbackLUTInterpolator.createNativeInterpolator(interpolator, duration);
}
}
/** Creates a specialized native interpolator for Accelerate/Decelerate */
public static native long createAccelerateDecelerateInterpolator();
/** Creates a specialized native interpolator for Accelerate */
public static native long createAccelerateInterpolator(float factor);
/** Creates a specialized native interpolator for Anticipate */
public static native long createAnticipateInterpolator(float tension);
/** Creates a specialized native interpolator for Anticipate with Overshoot */
public static native long createAnticipateOvershootInterpolator(float tension);
/** Creates a specialized native interpolator for Bounce */
public static native long createBounceInterpolator();
/** Creates a specialized native interpolator for Cycle */
public static native long createCycleInterpolator(float cycles);
/** Creates a specialized native interpolator for Decelerate */
public static native long createDecelerateInterpolator(float factor);
/** Creates a specialized native interpolator for Linear interpolation */
public static native long createLinearInterpolator();
/** Creates a specialized native interpolator for Overshoot */
public static native long createOvershootInterpolator(float tension);
/** Creates a specialized native interpolator for along traveling along a Path */
public static native long createPathInterpolator(float[] x, float[] y);
/** Creates a specialized native interpolator for LUT */
public static native long createLutInterpolator(float[] values);
}

View File

@@ -0,0 +1,513 @@
/*
* 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.graphics.animation;
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
import android.os.Handler;
import android.os.Looper;
import android.view.Choreographer;
import com.android.internal.util.VirtualRefBasePtr;
import java.util.ArrayList;
/**
* @hide
*/
public class RenderNodeAnimator extends Animator {
// Keep in sync with enum RenderProperty in Animator.h
public static final int TRANSLATION_X = 0;
public static final int TRANSLATION_Y = 1;
public static final int TRANSLATION_Z = 2;
public static final int SCALE_X = 3;
public static final int SCALE_Y = 4;
public static final int ROTATION = 5;
public static final int ROTATION_X = 6;
public static final int ROTATION_Y = 7;
public static final int X = 8;
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;
/**
* Field for the Paint alpha channel, which should be specified as a value
* between 0 and 255.
*/
public static final int PAINT_ALPHA = 1;
private VirtualRefBasePtr mNativePtr;
private Handler mHandler;
private RenderNode mTarget;
private ViewListener mViewListener;
private int mRenderProperty = -1;
private float mFinalValue;
private TimeInterpolator mInterpolator;
private static final int STATE_PREPARE = 0;
private static final int STATE_DELAYED = 1;
private static final int STATE_RUNNING = 2;
private static final int STATE_FINISHED = 3;
private int mState = STATE_PREPARE;
private long mUnscaledDuration = 300;
private long mUnscaledStartDelay = 0;
// If this is true, we will run any start delays on the UI thread. This is
// the safe default, and is necessary to ensure start listeners fire at
// the correct time. Animators created by RippleDrawable (the
// CanvasProperty<> ones) do not have this expectation, and as such will
// set this to false so that the renderthread handles the startdelay instead
private final boolean mUiThreadHandlesDelay;
private long mStartDelay = 0;
private long mStartTime;
/**
* Interface used by the view system to update the view hierarchy in conjunction
* with this animator.
*/
public interface ViewListener {
/** notify the listener that an alpha animation has begun. */
void onAlphaAnimationStart(float finalAlpha);
/** notify the listener that the animator has mutated a value that requires invalidation */
void invalidateParent(boolean forceRedraw);
}
public RenderNodeAnimator(int property, float finalValue) {
mRenderProperty = property;
mFinalValue = finalValue;
mUiThreadHandlesDelay = true;
init(nCreateAnimator(property, finalValue));
}
public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
init(nCreateCanvasPropertyFloatAnimator(
property.getNativeContainer(), finalValue));
mUiThreadHandlesDelay = false;
}
/**
* Creates a new render node animator for a field on a Paint property.
*
* @param property The paint property to target
* @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
* {@link #PAINT_STROKE_WIDTH}
* @param finalValue The target value for the property
*/
public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
init(nCreateCanvasPropertyPaintAnimator(
property.getNativeContainer(), paintField, finalValue));
mUiThreadHandlesDelay = false;
}
public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
init(nCreateRevealAnimator(x, y, startRadius, endRadius));
mUiThreadHandlesDelay = true;
}
private void init(long ptr) {
mNativePtr = new VirtualRefBasePtr(ptr);
}
private void checkMutable() {
if (mState != STATE_PREPARE) {
throw new IllegalStateException("Animator has already started, cannot change it now!");
}
if (mNativePtr == null) {
throw new IllegalStateException("Animator's target has been destroyed "
+ "(trying to modify an animation after activity destroy?)");
}
}
static boolean isNativeInterpolator(TimeInterpolator interpolator) {
return interpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class);
}
private void applyInterpolator() {
if (mInterpolator == null || mNativePtr == null) return;
long ni;
if (isNativeInterpolator(mInterpolator)) {
ni = ((NativeInterpolator) mInterpolator).createNativeInterpolator();
} else {
long duration = nGetDuration(mNativePtr.get());
ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
}
nSetInterpolator(mNativePtr.get(), ni);
}
@Override
public void start() {
if (mTarget == null) {
throw new IllegalStateException("Missing target!");
}
if (mState != STATE_PREPARE) {
throw new IllegalStateException("Already started!");
}
mState = STATE_DELAYED;
if (mHandler == null) {
mHandler = new Handler(true);
}
applyInterpolator();
if (mNativePtr == null) {
// It's dead, immediately cancel
cancel();
} else if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
nSetStartDelay(mNativePtr.get(), mStartDelay);
doStart();
} else {
getHelper().addDelayedAnimation(this);
}
}
private void doStart() {
// Alpha is a special snowflake that has the canonical value stored
// in mTransformationInfo instead of in RenderNode, so we need to update
// it with the final value here.
if (mRenderProperty == RenderNodeAnimator.ALPHA && mViewListener != null) {
mViewListener.onAlphaAnimationStart(mFinalValue);
}
moveToRunningState();
if (mViewListener != null) {
// Kick off a frame to start the process
mViewListener.invalidateParent(false);
}
}
private void moveToRunningState() {
mState = STATE_RUNNING;
if (mNativePtr != null) {
nStart(mNativePtr.get());
}
notifyStartListeners();
}
private void notifyStartListeners() {
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationStart(this);
}
}
@Override
public void cancel() {
if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
if (mState == STATE_DELAYED) {
getHelper().removeDelayedAnimation(this);
moveToRunningState();
}
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationCancel(this);
}
end();
}
}
@Override
public void end() {
if (mState != STATE_FINISHED) {
if (mState < STATE_RUNNING) {
getHelper().removeDelayedAnimation(this);
doStart();
}
if (mNativePtr != null) {
nEnd(mNativePtr.get());
if (mViewListener != null) {
// Kick off a frame to flush the state change
mViewListener.invalidateParent(false);
}
} else {
// It's already dead, jump to onFinish
onFinished();
}
}
}
@Override
public void pause() {
throw new UnsupportedOperationException();
}
@Override
public void resume() {
throw new UnsupportedOperationException();
}
/** @hide */
public void setViewListener(ViewListener listener) {
mViewListener = listener;
}
/** Sets the animation target to the owning view of the RecordingCanvas */
public final void setTarget(RecordingCanvas canvas) {
setTarget(canvas.mNode);
}
/** Sets the node that is to be the target of this animation */
protected void setTarget(RenderNode node) {
checkMutable();
if (mTarget != null) {
throw new IllegalStateException("Target already set!");
}
nSetListener(mNativePtr.get(), this);
mTarget = node;
mTarget.addAnimator(this);
}
/** Set the start value for the animation */
public void setStartValue(float startValue) {
checkMutable();
nSetStartValue(mNativePtr.get(), startValue);
}
@Override
public void setStartDelay(long startDelay) {
checkMutable();
if (startDelay < 0) {
throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
}
mUnscaledStartDelay = startDelay;
mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
}
@Override
public long getStartDelay() {
return mUnscaledStartDelay;
}
@Override
public RenderNodeAnimator setDuration(long duration) {
checkMutable();
if (duration < 0) {
throw new IllegalArgumentException("duration must be positive; " + duration);
}
mUnscaledDuration = duration;
nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
return this;
}
@Override
public long getDuration() {
return mUnscaledDuration;
}
@Override
public long getTotalDuration() {
return mUnscaledDuration + mUnscaledStartDelay;
}
@Override
public boolean isRunning() {
return mState == STATE_DELAYED || mState == STATE_RUNNING;
}
@Override
public boolean isStarted() {
return mState != STATE_PREPARE;
}
@Override
public void setInterpolator(TimeInterpolator interpolator) {
checkMutable();
mInterpolator = interpolator;
}
@Override
public TimeInterpolator getInterpolator() {
return mInterpolator;
}
protected void onFinished() {
if (mState == STATE_PREPARE) {
// Unlikely but possible, the native side has been destroyed
// before we have started.
releaseNativePtr();
return;
}
if (mState == STATE_DELAYED) {
getHelper().removeDelayedAnimation(this);
notifyStartListeners();
}
mState = STATE_FINISHED;
final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationEnd(this);
}
// Release the native object, as it has a global reference to us. This
// breaks the cyclic reference chain, and allows this object to be
// GC'd
releaseNativePtr();
}
private void releaseNativePtr() {
if (mNativePtr != null) {
mNativePtr.release();
mNativePtr = null;
}
}
@SuppressWarnings("unchecked")
private ArrayList<AnimatorListener> cloneListeners() {
ArrayList<AnimatorListener> listeners = getListeners();
if (listeners != null) {
listeners = (ArrayList<AnimatorListener>) listeners.clone();
}
return listeners;
}
public long getNativeAnimator() {
return mNativePtr.get();
}
/**
* @return true if the animator was started, false if still delayed
*/
private boolean processDelayed(long frameTimeMs) {
if (mStartTime == 0) {
mStartTime = frameTimeMs;
} else if ((frameTimeMs - mStartTime) >= mStartDelay) {
doStart();
return true;
}
return false;
}
private static DelayedAnimationHelper getHelper() {
DelayedAnimationHelper helper = sAnimationHelper.get();
if (helper == null) {
helper = new DelayedAnimationHelper();
sAnimationHelper.set(helper);
}
return helper;
}
private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
new ThreadLocal<DelayedAnimationHelper>();
private static class DelayedAnimationHelper implements Runnable {
private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
private final Choreographer mChoreographer;
private boolean mCallbackScheduled;
DelayedAnimationHelper() {
mChoreographer = Choreographer.getInstance();
}
public void addDelayedAnimation(RenderNodeAnimator animator) {
mDelayedAnims.add(animator);
scheduleCallback();
}
public void removeDelayedAnimation(RenderNodeAnimator animator) {
mDelayedAnims.remove(animator);
}
private void scheduleCallback() {
if (!mCallbackScheduled) {
mCallbackScheduled = true;
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
}
}
@Override
public void run() {
long frameTimeMs = mChoreographer.getFrameTime();
mCallbackScheduled = false;
int end = 0;
for (int i = 0; i < mDelayedAnims.size(); i++) {
RenderNodeAnimator animator = mDelayedAnims.get(i);
if (!animator.processDelayed(frameTimeMs)) {
if (end != i) {
mDelayedAnims.set(end, animator);
}
end++;
}
}
while (mDelayedAnims.size() > end) {
mDelayedAnims.remove(mDelayedAnims.size() - 1);
}
if (mDelayedAnims.size() > 0) {
scheduleCallback();
}
}
}
// Called by native
private static void callOnFinished(RenderNodeAnimator animator) {
if (animator.mHandler != null) {
animator.mHandler.post(animator::onFinished);
} else {
new Handler(Looper.getMainLooper(), null, true).post(animator::onFinished);
}
}
@Override
public Animator clone() {
throw new IllegalStateException("Cannot clone this animator");
}
@Override
public void setAllowRunningAsynchronously(boolean mayRunAsync) {
checkMutable();
nSetAllowRunningAsync(mNativePtr.get(), mayRunAsync);
}
private static native long nCreateAnimator(int property, float finalValue);
private static native long nCreateCanvasPropertyFloatAnimator(
long canvasProperty, float finalValue);
private static native long nCreateCanvasPropertyPaintAnimator(
long canvasProperty, int paintField, float finalValue);
private static native long nCreateRevealAnimator(
int x, int y, float startRadius, float endRadius);
private static native void nSetStartValue(long nativePtr, float startValue);
private static native void nSetDuration(long nativePtr, long duration);
private static native long nGetDuration(long nativePtr);
private static native void nSetStartDelay(long nativePtr, long startDelay);
private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
private static native void nSetAllowRunningAsync(long animPtr, boolean mayRunAsync);
private static native void nSetListener(long animPtr, RenderNodeAnimator listener);
private static native void nStart(long animPtr);
private static native void nEnd(long animPtr);
}

View File

@@ -42,6 +42,7 @@ import android.graphics.PixelFormat;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
import android.graphics.animation.NativeInterpolatorFactory;
import android.os.Build;
import android.os.Handler;
import android.util.ArrayMap;
@@ -54,7 +55,6 @@ import android.util.Property;
import android.util.TimeUtils;
import android.view.Choreographer;
import android.view.NativeVectorDrawableAnimator;
import android.view.RenderNodeAnimatorSetHelper;
import android.view.View;
import com.android.internal.R;
@@ -1532,7 +1532,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
long startDelay = extraDelay + animator.getStartDelay();
TimeInterpolator interpolator = animator.getInterpolator();
long nativeInterpolator =
RenderNodeAnimatorSetHelper.createNativeInterpolator(interpolator, duration);
NativeInterpolatorFactory.createNativeInterpolator(interpolator, duration);
startDelay *= ValueAnimator.getDurationScale();
duration *= ValueAnimator.getDurationScale();
@@ -1548,7 +1548,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
* to the last seen RenderNode target and start right away.
*/
protected void recordLastSeenTarget(RecordingCanvas canvas) {
final RenderNode node = RenderNodeAnimatorSetHelper.getTarget(canvas);
final RenderNode node = canvas.mNode;
mLastSeenTarget = new WeakReference<RenderNode>(node);
// Add the animator to the list of animators on every draw
if (mInitialized || mPendingAnimationActions.size() > 0) {

View File

@@ -25,9 +25,9 @@ import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.animation.RenderNodeAnimator;
import android.util.FloatProperty;
import android.util.MathUtils;
import android.view.RenderNodeAnimator;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;