Merge "Add CanvasProperty for drawCircle"

This commit is contained in:
John Reck
2014-05-02 20:48:26 +00:00
committed by Android (Google) Code Review
27 changed files with 810 additions and 265 deletions

View File

@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.DrawFilter;
import android.graphics.Matrix;
import android.graphics.NinePatch;
@@ -888,6 +889,16 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nDrawCircle(long renderer, float cx, float cy,
float radius, long paint);
@Override
public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
nDrawCircle(mRenderer, cx.getNativeContainer(), cy.getNativeContainer(),
radius.getNativeContainer(), paint.getNativeContainer());
}
private static native void nDrawCircle(long renderer, long propCx,
long propCy, long propRadius, long propPaint);
@Override
public void drawColor(int color) {
drawColor(color, PorterDuff.Mode.SRC_OVER);

View File

@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -189,4 +190,7 @@ public abstract class HardwareCanvas extends Canvas {
* @hide
*/
abstract void clearLayerUpdates();
public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint);
}

View File

@@ -16,6 +16,8 @@
package android.view;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.util.SparseIntArray;
import java.lang.ref.WeakReference;
@@ -26,18 +28,22 @@ import java.lang.ref.WeakReference;
public final class RenderNodeAnimator {
// Keep in sync with enum RenderProperty in Animator.h
private static final int TRANSLATION_X = 0;
private static final int TRANSLATION_Y = 1;
private static final int TRANSLATION_Z = 2;
private static final int SCALE_X = 3;
private static final int SCALE_Y = 4;
private static final int ROTATION = 5;
private static final int ROTATION_X = 6;
private static final int ROTATION_Y = 7;
private static final int X = 8;
private static final int Y = 9;
private static final int Z = 10;
private static final int ALPHA = 11;
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;
// Keep in sync with enum PaintFields in Animator.h
public static final int PAINT_STROKE_WIDTH = 0;
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
@@ -59,8 +65,8 @@ public final class RenderNodeAnimator {
}};
// Keep in sync DeltaValueType in Animator.h
private static final int DELTA_TYPE_ABSOLUTE = 0;
private static final int DELTA_TYPE_DELTA = 1;
public static final int DELTA_TYPE_ABSOLUTE = 0;
public static final int DELTA_TYPE_DELTA = 1;
private RenderNode mTarget;
private long mNativePtr;
@@ -74,6 +80,19 @@ public final class RenderNodeAnimator {
property, deltaType, deltaValue);
}
public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) {
mNativePtr = nCreateCanvasPropertyFloatAnimator(
new WeakReference<RenderNodeAnimator>(this),
property.getNativeContainer(), deltaType, deltaValue);
}
public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField,
int deltaType, float deltaValue) {
mNativePtr = nCreateCanvasPropertyPaintAnimator(
new WeakReference<RenderNodeAnimator>(this),
property.getNativeContainer(), paintField, deltaType, deltaValue);
}
public void start(View target) {
mTarget = target.mRenderNode;
mTarget.addAnimator(this);
@@ -117,6 +136,10 @@ public final class RenderNodeAnimator {
private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
int property, int deltaValueType, float deltaValue);
private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
long canvasProperty, int deltaValueType, float deltaValue);
private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
long canvasProperty, int paintField, int deltaValueType, float deltaValue);
private static native void nSetDuration(long nativePtr, int duration);
private static native void nUnref(long nativePtr);
}

View File

@@ -92,6 +92,7 @@ LOCAL_SRC_FILES:= \
android/graphics/BitmapFactory.cpp \
android/graphics/Camera.cpp \
android/graphics/Canvas.cpp \
android/graphics/CanvasProperty.cpp \
android/graphics/ColorFilter.cpp \
android/graphics/DrawFilter.cpp \
android/graphics/CreateJavaOutputStreamAdaptor.cpp \

View File

@@ -105,6 +105,7 @@ extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
extern int register_android_emoji_EmojiFactory(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
extern int register_android_graphics_CanvasProperty(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
extern int register_android_graphics_DrawFilter(JNIEnv* env);
extern int register_android_graphics_Matrix(JNIEnv* env);
@@ -1221,6 +1222,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Camera),
REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
REG_JNI(register_android_graphics_Canvas),
REG_JNI(register_android_graphics_CanvasProperty),
REG_JNI(register_android_graphics_ColorFilter),
REG_JNI(register_android_graphics_DrawFilter),
REG_JNI(register_android_graphics_Interpolator),

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 20014 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.
*/
#include "jni.h"
#include "GraphicsJNI.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/VirtualLightRefBase.h>
#include <CanvasProperty.h>
namespace android {
using namespace uirenderer;
#ifdef USE_OPENGL_RENDERER
static jlong incRef(VirtualLightRefBase* ptr) {
ptr->incStrong(0);
return reinterpret_cast<jlong>(ptr);
}
static jlong createFloat(JNIEnv* env, jobject clazz, jfloat initialValue) {
return incRef(new CanvasPropertyPrimitive(initialValue));
}
static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) {
const SkPaint* paint = reinterpret_cast<const SkPaint*>(paintPtr);
return incRef(new CanvasPropertyPaint(*paint));
}
static void unref(JNIEnv* env, jobject clazz, jlong containerPtr) {
reinterpret_cast<VirtualLightRefBase*>(containerPtr)->decStrong(0);
}
#endif
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
const char* const kClassPathName = "android/graphics/CanvasProperty";
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
{ "nCreateFloat", "(F)J", (void*) createFloat },
{ "nCreatePaint", "(J)J", (void*) createPaint },
{ "nUnref", "(J)V", (void*) unref },
#endif
};
int register_android_graphics_CanvasProperty(JNIEnv* env) {
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
}; // namespace android

View File

@@ -49,6 +49,7 @@
#include <Stencil.h>
#include <Rect.h>
#include <RenderNode.h>
#include <CanvasProperty.h>
#include <TextLayout.h>
#include <TextLayoutCache.h>
@@ -544,6 +545,16 @@ static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject clazz,
renderer->drawCircle(x, y, radius, paint);
}
static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz,
jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
}
static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject clazz,
jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
jlong paintPtr) {
@@ -1041,6 +1052,7 @@ static JNINativeMethod gMethods[] = {
{ "nDrawRects", "(J[FIJ)V", (void*) android_view_GLES20Canvas_drawRects },
{ "nDrawRoundRect", "(JFFFFFFJ)V", (void*) android_view_GLES20Canvas_drawRoundRect },
{ "nDrawCircle", "(JFFFJ)V", (void*) android_view_GLES20Canvas_drawCircle },
{ "nDrawCircle", "(JJJJJ)V", (void*) android_view_GLES20Canvas_drawCircleProps },
{ "nDrawOval", "(JFFFFJ)V", (void*) android_view_GLES20Canvas_drawOval },
{ "nDrawArc", "(JFFFFFFZJ)V", (void*) android_view_GLES20Canvas_drawArc },
{ "nDrawPoints", "(J[FIIJ)V", (void*) android_view_GLES20Canvas_drawPoints },

View File

@@ -16,8 +16,6 @@
#define LOG_TAG "OpenGLRenderer"
#include "android_view_RenderNodeAnimator.h"
#include "jni.h"
#include "GraphicsJNI.h"
#include <nativehelper/JNIHelp.h>
@@ -47,46 +45,93 @@ static JNIEnv* getEnv(JavaVM* vm) {
return env;
}
RenderNodeAnimator::RenderNodeAnimator(JNIEnv* env, jobject weakThis,
RenderProperty property, DeltaValueType deltaType, float delta)
: RenderPropertyAnimator(property, deltaType, delta) {
mWeakThis = env->NewGlobalRef(weakThis);
env->GetJavaVM(&mJvm);
}
class AnimationListenerBridge : public AnimationListener {
public:
// This holds a strong reference to a Java WeakReference<T> object. This avoids
// cyclic-references-of-doom. If you think "I know, just use NewWeakGlobalRef!"
// then you end up with basically a PhantomReference, which is totally not
// what we want.
AnimationListenerBridge(JNIEnv* env, jobject weakThis) {
mWeakThis = env->NewGlobalRef(weakThis);
env->GetJavaVM(&mJvm);
}
RenderNodeAnimator::~RenderNodeAnimator() {
JNIEnv* env = getEnv(mJvm);
env->DeleteGlobalRef(mWeakThis);
mWeakThis = NULL;
}
virtual ~AnimationListenerBridge() {
JNIEnv* env = getEnv(mJvm);
env->DeleteGlobalRef(mWeakThis);
mWeakThis = NULL;
}
void RenderNodeAnimator::callOnFinished() {
JNIEnv* env = getEnv(mJvm);
env->CallStaticVoidMethod(
gRenderNodeAnimatorClassInfo.clazz,
gRenderNodeAnimatorClassInfo.callOnFinished,
mWeakThis);
}
virtual void onAnimationFinished(BaseAnimator*) {
JNIEnv* env = getEnv(mJvm);
env->CallStaticVoidMethod(
gRenderNodeAnimatorClassInfo.clazz,
gRenderNodeAnimatorClassInfo.callOnFinished,
mWeakThis);
}
static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
jint property, jint deltaType, jfloat deltaValue) {
LOG_ALWAYS_FATAL_IF(property < 0 || property > RenderNodeAnimator::ALPHA,
private:
JavaVM* mJvm;
jobject mWeakThis;
};
static inline RenderPropertyAnimator::RenderProperty toRenderProperty(jint property) {
LOG_ALWAYS_FATAL_IF(property < 0 || property > RenderPropertyAnimator::ALPHA,
"Invalid property %d", property);
return static_cast<RenderPropertyAnimator::RenderProperty>(property);
}
static inline RenderPropertyAnimator::DeltaValueType toDeltaType(jint deltaType) {
LOG_ALWAYS_FATAL_IF(deltaType != RenderPropertyAnimator::DELTA
&& deltaType != RenderPropertyAnimator::ABSOLUTE,
"Invalid delta type %d", deltaType);
return static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType);
}
RenderNodeAnimator* animator = new RenderNodeAnimator(env, weakThis,
static_cast<RenderPropertyAnimator::RenderProperty>(property),
static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType),
deltaValue);
static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) {
LOG_ALWAYS_FATAL_IF(field < 0
|| field > CanvasPropertyPaintAnimator::ALPHA,
"Invalid paint field %d", field);
return static_cast<CanvasPropertyPaintAnimator::PaintField>(field);
}
static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
jint propertyRaw, jint deltaTypeRaw, jfloat deltaValue) {
RenderPropertyAnimator::RenderProperty property = toRenderProperty(propertyRaw);
RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue);
animator->incStrong(0);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static jlong createCanvasPropertyFloatAnimator(JNIEnv* env, jobject clazz,
jobject weakThis, jlong canvasPropertyPtr, jint deltaTypeRaw, jfloat deltaValue) {
RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr);
BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue);
animator->incStrong(0);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static jlong createCanvasPropertyPaintAnimator(JNIEnv* env, jobject clazz,
jobject weakThis, jlong canvasPropertyPtr, jint paintFieldRaw,
jint deltaTypeRaw, jfloat deltaValue) {
RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
CanvasPropertyPaint* canvasProperty = reinterpret_cast<CanvasPropertyPaint*>(canvasPropertyPtr);
CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw);
BaseAnimator* animator = new CanvasPropertyPaintAnimator(
canvasProperty, paintField, deltaType, deltaValue);
animator->incStrong(0);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
RenderNodeAnimator* animator = reinterpret_cast<RenderNodeAnimator*>(animatorPtr);
BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
animator->setDuration(duration);
}
@@ -106,6 +151,8 @@ const char* const kClassPathName = "android/view/RenderNodeAnimator";
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
{ "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IIF)J", (void*) createAnimator },
{ "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyFloatAnimator },
{ "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIIF)J", (void*) createCanvasPropertyPaintAnimator },
{ "nSetDuration", "(JI)V", (void*) setDuration },
{ "nUnref", "(J)V", (void*) unref },
#endif

View File

@@ -26,7 +26,7 @@
#include <android_runtime/android_view_Surface.h>
#include <system/window.h>
#include "android_view_RenderNodeAnimator.h"
#include <Animator.h>
#include <RenderNode.h>
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderTask.h>
@@ -67,26 +67,34 @@ private:
jobject mRunnable;
};
class OnFinishedEvent {
public:
OnFinishedEvent(BaseAnimator* animator, AnimationListener* listener)
: animator(animator), listener(listener) {}
sp<BaseAnimator> animator;
sp<AnimationListener> listener;
};
class InvokeAnimationListeners : public MessageHandler {
public:
InvokeAnimationListeners(std::vector< sp<RenderNodeAnimator> >& animators) {
mAnimators.swap(animators);
InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
mOnFinishedEvents.swap(events);
}
static void callOnFinished(const sp<RenderNodeAnimator>& animator) {
animator->callOnFinished();
static void callOnFinished(OnFinishedEvent& event) {
event.listener->onAnimationFinished(event.animator.get());
}
virtual void handleMessage(const Message& message) {
std::for_each(mAnimators.begin(), mAnimators.end(), callOnFinished);
mAnimators.clear();
std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
mOnFinishedEvents.clear();
}
private:
std::vector< sp<RenderNodeAnimator> > mAnimators;
std::vector<OnFinishedEvent> mOnFinishedEvents;
};
class RootRenderNode : public RenderNode, public AnimationListener {
class RootRenderNode : public RenderNode, public AnimationHook {
public:
RootRenderNode() : RenderNode() {
mLooper = Looper::getForThread();
@@ -96,27 +104,27 @@ public:
virtual ~RootRenderNode() {}
void onAnimationFinished(const sp<RenderPropertyAnimator>& animator) {
mFinishedAnimators.push_back(
reinterpret_cast<RenderNodeAnimator*>(animator.get()));
virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) {
OnFinishedEvent event(animator, listener);
mOnFinishedEvents.push_back(event);
}
virtual void prepareTree(TreeInfo& info) {
info.animationListener = this;
info.animationHook = this;
RenderNode::prepareTree(info);
info.animationListener = NULL;
info.animationHook = NULL;
// post all the finished stuff
if (mFinishedAnimators.size()) {
if (mOnFinishedEvents.size()) {
sp<InvokeAnimationListeners> message
= new InvokeAnimationListeners(mFinishedAnimators);
= new InvokeAnimationListeners(mOnFinishedEvents);
mLooper->sendMessage(message, 0);
}
}
private:
sp<Looper> mLooper;
std::vector< sp<RenderNodeAnimator> > mFinishedAnimators;
std::vector<OnFinishedEvent> mOnFinishedEvents;
};
static void android_view_ThreadedRenderer_postToRenderThread(JNIEnv* env, jobject clazz,

View File

@@ -0,0 +1,56 @@
/*
* 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;
/**
* TODO: Make public?
* @hide
*/
public final class CanvasProperty<T> {
private long mNativeContainer;
public static CanvasProperty<Float> createFloat(float initialValue) {
return new CanvasProperty<Float>(nCreateFloat(initialValue));
}
public static CanvasProperty<Paint> createPaint(Paint initialValue) {
return new CanvasProperty<Paint>(nCreatePaint(initialValue.mNativePaint));
}
private CanvasProperty(long nativeContainer) {
mNativeContainer = nativeContainer;
}
/** @hide */
public long getNativeContainer() {
return mNativeContainer;
}
@Override
protected void finalize() throws Throwable {
try {
nUnref(mNativeContainer);
mNativeContainer = 0;
} finally {
super.finalize();
}
}
private static native long nCreateFloat(float initialValue);
private static native long nCreatePaint(long initialValuePaintPtr);
private static native void nUnref(long ptr);
}

View File

@@ -20,129 +20,12 @@
#include <set>
#include "RenderNode.h"
#include "RenderProperties.h"
namespace android {
namespace uirenderer {
/************************************************************
* Private header
************************************************************/
typedef void (RenderProperties::*SetFloatProperty)(float value);
typedef float (RenderProperties::*GetFloatProperty)() const;
struct PropertyAccessors {
GetFloatProperty getter;
SetFloatProperty setter;
};
// Maps RenderProperty enum to accessors
static const PropertyAccessors PROPERTY_ACCESSOR_LUT[] = {
{&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
{&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
{&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
{&RenderProperties::getScaleX, &RenderProperties::setScaleX },
{&RenderProperties::getScaleY, &RenderProperties::setScaleY },
{&RenderProperties::getRotation, &RenderProperties::setRotation },
{&RenderProperties::getRotationX, &RenderProperties::setRotationX },
{&RenderProperties::getRotationY, &RenderProperties::setRotationY },
{&RenderProperties::getX, &RenderProperties::setX },
{&RenderProperties::getY, &RenderProperties::setY },
{&RenderProperties::getZ, &RenderProperties::setZ },
{&RenderProperties::getAlpha, &RenderProperties::setAlpha },
};
// Helper class to contain generic animator helpers
class BaseAnimator {
public:
BaseAnimator();
virtual ~BaseAnimator();
void setInterpolator(Interpolator* interpolator);
void setDuration(nsecs_t durationInMs);
bool isFinished() { return mPlayState == FINISHED; }
protected:
// This is the main animation entrypoint that subclasses should call
// to generate the onAnimation* lifecycle events
// Returns true if the animation has finished, false otherwise
bool animateFrame(nsecs_t frameTime);
// Called when PlayState switches from PENDING to RUNNING
virtual void onAnimationStarted() {}
virtual void onAnimationUpdated(float fraction) = 0;
virtual void onAnimationFinished() {}
private:
enum PlayState {
PENDING,
RUNNING,
FINISHED,
};
Interpolator* mInterpolator;
PlayState mPlayState;
long mStartTime;
long mDuration;
};
// Hide the base classes & private bits from the exported RenderPropertyAnimator
// in this Impl class so that subclasses of RenderPropertyAnimator don't require
// knowledge of the inner guts but only the public virtual methods.
// Animates a single property
class RenderPropertyAnimatorImpl : public BaseAnimator {
public:
RenderPropertyAnimatorImpl(GetFloatProperty getter, SetFloatProperty setter,
RenderPropertyAnimator::DeltaValueType deltaType, float delta);
~RenderPropertyAnimatorImpl();
bool animate(RenderProperties* target, TreeInfo& info);
protected:
virtual void onAnimationStarted();
virtual void onAnimationUpdated(float fraction);
private:
// mTarget is only valid inside animate()
RenderProperties* mTarget;
GetFloatProperty mGetter;
SetFloatProperty mSetter;
RenderPropertyAnimator::DeltaValueType mDeltaValueType;
float mDeltaValue;
float mFromValue;
};
RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
DeltaValueType deltaType, float deltaValue) {
PropertyAccessors pa = PROPERTY_ACCESSOR_LUT[property];
mImpl = new RenderPropertyAnimatorImpl(pa.getter, pa.setter, deltaType, deltaValue);
}
RenderPropertyAnimator::~RenderPropertyAnimator() {
delete mImpl;
mImpl = NULL;
}
void RenderPropertyAnimator::setInterpolator(Interpolator* interpolator) {
mImpl->setInterpolator(interpolator);
}
void RenderPropertyAnimator::setDuration(nsecs_t durationInMs) {
mImpl->setDuration(durationInMs);
}
bool RenderPropertyAnimator::isFinished() {
return mImpl->isFinished();
}
bool RenderPropertyAnimator::animate(RenderProperties* target, TreeInfo& info) {
return mImpl->animate(target, info);
}
/************************************************************
* Base animator
************************************************************/
@@ -168,10 +51,10 @@ void BaseAnimator::setDuration(nsecs_t duration) {
mDuration = duration;
}
bool BaseAnimator::animateFrame(nsecs_t frameTime) {
bool BaseAnimator::animateFrame(TreeInfo& info) {
if (mPlayState == PENDING) {
mPlayState = RUNNING;
mStartTime = frameTime;
mStartTime = info.frameTimeMs;
// No interpolator was set, use the default
if (!mInterpolator) {
setInterpolator(Interpolator::createDefaultInterpolator());
@@ -181,7 +64,7 @@ bool BaseAnimator::animateFrame(nsecs_t frameTime) {
float fraction = 1.0f;
if (mPlayState == RUNNING) {
fraction = mDuration > 0 ? (float)(frameTime - mStartTime) / mDuration : 1.0f;
fraction = mDuration > 0 ? (float)(info.frameTimeMs - mStartTime) / mDuration : 1.0f;
if (fraction >= 1.0f) {
fraction = 1.0f;
mPlayState = FINISHED;
@@ -192,48 +75,140 @@ bool BaseAnimator::animateFrame(nsecs_t frameTime) {
if (mPlayState == FINISHED) {
onAnimationFinished();
callOnFinishedListener(info);
return true;
}
return false;
}
void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
if (mListener.get()) {
if (!info.animationHook) {
mListener->onAnimationFinished(this);
} else {
info.animationHook->callOnFinished(this, mListener.get());
}
}
}
/************************************************************
* BaseRenderNodeAnimator
************************************************************/
BaseRenderNodeAnimator::BaseRenderNodeAnimator(
BaseRenderNodeAnimator::DeltaValueType deltaType, float delta)
: mTarget(0)
, mDeltaValueType(deltaType)
, mDeltaValue(delta)
, mFromValue(-1) {
}
bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
mTarget = target;
bool finished = animateFrame(info);
mTarget = NULL;
return finished;
}
void BaseRenderNodeAnimator::onAnimationStarted() {
mFromValue = getValue();
if (mDeltaValueType == BaseRenderNodeAnimator::ABSOLUTE) {
mDeltaValue = (mDeltaValue - mFromValue);
mDeltaValueType = BaseRenderNodeAnimator::DELTA;
}
}
void BaseRenderNodeAnimator::onAnimationUpdated(float fraction) {
float value = mFromValue + (mDeltaValue * fraction);
setValue(value);
}
/************************************************************
* RenderPropertyAnimator
************************************************************/
RenderPropertyAnimatorImpl::RenderPropertyAnimatorImpl(
GetFloatProperty getter, SetFloatProperty setter,
RenderPropertyAnimator::DeltaValueType deltaType, float delta)
: mTarget(0)
, mGetter(getter)
, mSetter(setter)
, mDeltaValueType(deltaType)
, mDeltaValue(delta)
, mFromValue(-1) {
// Maps RenderProperty enum to accessors
const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
{&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
{&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
{&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
{&RenderProperties::getScaleX, &RenderProperties::setScaleX },
{&RenderProperties::getScaleY, &RenderProperties::setScaleY },
{&RenderProperties::getRotation, &RenderProperties::setRotation },
{&RenderProperties::getRotationX, &RenderProperties::setRotationX },
{&RenderProperties::getRotationY, &RenderProperties::setRotationY },
{&RenderProperties::getX, &RenderProperties::setX },
{&RenderProperties::getY, &RenderProperties::setY },
{&RenderProperties::getZ, &RenderProperties::setZ },
{&RenderProperties::getAlpha, &RenderProperties::setAlpha },
};
RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
DeltaValueType deltaType, float deltaValue)
: BaseRenderNodeAnimator(deltaType, deltaValue)
, mPropertyAccess(PROPERTY_ACCESSOR_LUT[property]) {
}
RenderPropertyAnimatorImpl::~RenderPropertyAnimatorImpl() {
float RenderPropertyAnimator::getValue() const {
return (target()->animatorProperties().*mPropertyAccess.getter)();
}
bool RenderPropertyAnimatorImpl::animate(RenderProperties* target, TreeInfo& info) {
mTarget = target;
bool finished = animateFrame(info.frameTimeMs);
mTarget = NULL;
return finished;
void RenderPropertyAnimator::setValue(float value) {
(target()->animatorProperties().*mPropertyAccess.setter)(value);
}
void RenderPropertyAnimatorImpl::onAnimationStarted() {
mFromValue = (mTarget->*mGetter)();
/************************************************************
* CanvasPropertyPrimitiveAnimator
************************************************************/
if (mDeltaValueType == RenderPropertyAnimator::ABSOLUTE) {
mDeltaValue = (mDeltaValue - mFromValue);
mDeltaValueType = RenderPropertyAnimator::DELTA;
CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
CanvasPropertyPrimitive* property, DeltaValueType deltaType, float deltaValue)
: BaseRenderNodeAnimator(deltaType, deltaValue)
, mProperty(property) {
}
float CanvasPropertyPrimitiveAnimator::getValue() const {
return mProperty->value;
}
void CanvasPropertyPrimitiveAnimator::setValue(float value) {
mProperty->value = value;
}
/************************************************************
* CanvasPropertySkPaintAnimator
************************************************************/
CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
CanvasPropertyPaint* property, PaintField field,
DeltaValueType deltaType, float deltaValue)
: BaseRenderNodeAnimator(deltaType, deltaValue)
, mProperty(property)
, mField(field) {
}
float CanvasPropertyPaintAnimator::getValue() const {
switch (mField) {
case STROKE_WIDTH:
return mProperty->value.getStrokeWidth();
case ALPHA:
return mProperty->value.getAlpha();
}
LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
return -1;
}
void RenderPropertyAnimatorImpl::onAnimationUpdated(float fraction) {
float value = mFromValue + (mDeltaValue * fraction);
(mTarget->*mSetter)(value);
void CanvasPropertyPaintAnimator::setValue(float value) {
switch (mField) {
case STROKE_WIDTH:
mProperty->value.setStrokeWidth(value);
return;
case ALPHA:
mProperty->value.setAlpha(value);
return;
}
LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
}
} /* namespace uirenderer */

View File

@@ -17,18 +17,72 @@
#define ANIMATOR_H
#include <cutils/compiler.h>
#include <utils/StrongPointer.h>
#include "CanvasProperty.h"
#include "Interpolator.h"
#include "TreeInfo.h"
#include "utils/Macros.h"
#include "utils/VirtualLightRefBase.h"
namespace android {
namespace uirenderer {
class RenderNode;
class RenderProperties;
class RenderPropertyAnimatorImpl;
class RenderPropertyAnimator : public VirtualLightRefBase {
class AnimationListener : public VirtualLightRefBase {
public:
ANDROID_API virtual void onAnimationFinished(BaseAnimator*) = 0;
protected:
ANDROID_API virtual ~AnimationListener() {}
};
// Helper class to contain generic animator helpers
class BaseAnimator : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(BaseAnimator);
public:
ANDROID_API void setInterpolator(Interpolator* interpolator);
ANDROID_API void setDuration(nsecs_t durationInMs);
ANDROID_API void setListener(AnimationListener* listener) {
mListener = listener;
}
bool isFinished() { return mPlayState == FINISHED; }
protected:
BaseAnimator();
virtual ~BaseAnimator();
// This is the main animation entrypoint that subclasses should call
// to generate the onAnimation* lifecycle events
// Returns true if the animation has finished, false otherwise
bool animateFrame(TreeInfo& info);
// Called when PlayState switches from PENDING to RUNNING
virtual void onAnimationStarted() {}
virtual void onAnimationUpdated(float fraction) = 0;
virtual void onAnimationFinished() {}
private:
void callOnFinishedListener(TreeInfo& info);
enum PlayState {
PENDING,
RUNNING,
FINISHED,
};
Interpolator* mInterpolator;
PlayState mPlayState;
long mStartTime;
long mDuration;
sp<AnimationListener> mListener;
};
class BaseRenderNodeAnimator : public BaseAnimator {
public:
// Since the UI thread doesn't necessarily know what the current values
// actually are and thus can't do the calculations, this is used to inform
@@ -43,6 +97,29 @@ public:
DELTA,
};
bool animate(RenderNode* target, TreeInfo& info);
protected:
BaseRenderNodeAnimator(DeltaValueType deltaType, float deltaValue);
RenderNode* target() const { return mTarget; }
virtual float getValue() const = 0;
virtual void setValue(float value) = 0;
private:
virtual void onAnimationStarted();
virtual void onAnimationUpdated(float fraction);
// mTarget is only valid inside animate()
RenderNode* mTarget;
BaseRenderNodeAnimator::DeltaValueType mDeltaValueType;
float mDeltaValue;
float mFromValue;
};
class RenderPropertyAnimator : public BaseRenderNodeAnimator {
public:
enum RenderProperty {
TRANSLATION_X = 0,
TRANSLATION_Y,
@@ -58,19 +135,53 @@ public:
ALPHA,
};
ANDROID_API void setInterpolator(Interpolator* interpolator);
ANDROID_API void setDuration(nsecs_t durationInMs);
ANDROID_API bool isFinished();
bool animate(RenderProperties* target, TreeInfo& info);
ANDROID_API RenderPropertyAnimator(RenderProperty property,
DeltaValueType deltaType, float deltaValue);
protected:
ANDROID_API RenderPropertyAnimator(RenderProperty property, DeltaValueType deltaType,
float deltaValue);
ANDROID_API virtual ~RenderPropertyAnimator();
ANDROID_API virtual float getValue() const;
ANDROID_API virtual void setValue(float value);
private:
RenderPropertyAnimatorImpl* mImpl;
typedef void (RenderProperties::*SetFloatProperty)(float value);
typedef float (RenderProperties::*GetFloatProperty)() const;
struct PropertyAccessors {
GetFloatProperty getter;
SetFloatProperty setter;
};
PropertyAccessors mPropertyAccess;
static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
};
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
public:
ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
DeltaValueType deltaType, float deltaValue);
protected:
ANDROID_API virtual float getValue() const;
ANDROID_API virtual void setValue(float value);
private:
sp<CanvasPropertyPrimitive> mProperty;
};
class CanvasPropertyPaintAnimator : public BaseRenderNodeAnimator {
public:
enum PaintField {
STROKE_WIDTH = 0,
ALPHA,
};
ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
PaintField field, DeltaValueType deltaType, float deltaValue);
protected:
ANDROID_API virtual float getValue() const;
ANDROID_API virtual void setValue(float value);
private:
sp<CanvasPropertyPaint> mProperty;
PaintField mField;
};
} /* namespace uirenderer */

View File

@@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef CANVASPROPERTY_H
#define CANVASPROPERTY_H
#include "utils/Macros.h"
#include "utils/VirtualLightRefBase.h"
#include <SkPaint.h>
namespace android {
namespace uirenderer {
class CanvasPropertyPrimitive : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPrimitive);
public:
CanvasPropertyPrimitive(float initialValue) : value(initialValue) {}
float value;
};
class CanvasPropertyPaint : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPaint);
public:
CanvasPropertyPaint(const SkPaint& initialValue) : value(initialValue) {}
SkPaint value;
};
} /* namespace uirenderer */
} /* namespace android */
#endif /* CANVASPROPERTY_H */

View File

@@ -140,6 +140,14 @@ public:
void addChild(DrawDisplayListOp* childOp);
const Vector<DrawDisplayListOp*>& children() { return mChildren; }
void refProperty(CanvasPropertyPrimitive* prop) {
mReferenceHolders.push(prop);
}
void refProperty(CanvasPropertyPaint* prop) {
mReferenceHolders.push(prop);
}
private:
Vector< sp<VirtualLightRefBase> > mReferenceHolders;

View File

@@ -1198,6 +1198,27 @@ private:
float mRadius;
};
class DrawCirclePropsOp : public DrawOp {
public:
DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint)
: DrawOp(paint), mX(x), mY(y), mRadius(radius) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawCircle(*mX, *mY, *mRadius, getPaint(renderer));
}
virtual void output(int level, uint32_t logFlags) const {
OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius);
}
virtual const char* name() { return "DrawCircleProps"; }
private:
float* mX;
float* mY;
float* mRadius;
};
class DrawOvalOp : public DrawStrokableOp {
public:
DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)

View File

@@ -299,6 +299,17 @@ status_t DisplayListRenderer::drawCircle(float x, float y, float radius, const S
return DrawGlInfo::kStatusDone;
}
status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
mDisplayListData->refProperty(x);
mDisplayListData->refProperty(y);
mDisplayListData->refProperty(radius);
mDisplayListData->refProperty(paint);
addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
&radius->value, &paint->value));
return DrawGlInfo::kStatusDone;
}
status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
const SkPaint* paint) {
paint = refPaint(paint);

View File

@@ -135,6 +135,8 @@ public:
virtual status_t drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint* paint);
virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
virtual status_t drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint);
virtual status_t drawOval(float left, float top, float right, float bottom,
const SkPaint* paint);
virtual status_t drawArc(float left, float top, float right, float bottom,

View File

@@ -49,6 +49,7 @@
#include "UvMapper.h"
#include "Vertex.h"
#include "Caches.h"
#include "CanvasProperty.h"
namespace android {
namespace uirenderer {
@@ -200,6 +201,12 @@ public:
virtual status_t drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint* paint);
virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
virtual status_t drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
// TODO: Remove once android_view_GLES20Canvas uses DisplayListRenderer
// directly
return drawCircle(x->value, y->value, radius->value, &paint->value);
}
virtual status_t drawOval(float left, float top, float right, float bottom,
const SkPaint* paint);
virtual status_t drawArc(float left, float top, float right, float bottom,

View File

@@ -109,7 +109,7 @@ void RenderNode::prepareTreeImpl(TreeInfo& info) {
prepareSubTree(info, mDisplayListData);
}
static bool is_finished(const sp<RenderPropertyAnimator>& animator) {
static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) {
return animator->isFinished();
}
@@ -120,7 +120,7 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
}
if (mNeedsAnimatorsSync) {
mAnimators.resize(mStagingAnimators.size());
std::vector< sp<RenderPropertyAnimator> >::iterator it;
std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
// hint: this means copy_if_not()
it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
mAnimators.begin(), is_finished);
@@ -141,26 +141,22 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
class AnimateFunctor {
public:
AnimateFunctor(RenderProperties* target, TreeInfo& info)
AnimateFunctor(RenderNode* target, TreeInfo& info)
: mTarget(target), mInfo(info) {}
bool operator() (sp<RenderPropertyAnimator>& animator) {
bool finished = animator->animate(mTarget, mInfo);
if (finished && mInfo.animationListener) {
mInfo.animationListener->onAnimationFinished(animator);
}
return finished;
bool operator() (sp<BaseRenderNodeAnimator>& animator) {
return animator->animate(mTarget, mInfo);
}
private:
RenderProperties* mTarget;
RenderNode* mTarget;
TreeInfo& mInfo;
};
void RenderNode::evaluateAnimations(TreeInfo& info) {
if (!mAnimators.size()) return;
AnimateFunctor functor(&mProperties, info);
std::vector< sp<RenderPropertyAnimator> >::iterator newEnd;
AnimateFunctor functor(this, info);
std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
mAnimators.erase(newEnd, mAnimators.end());
mProperties.updateMatrix();

View File

@@ -128,6 +128,10 @@ public:
return mProperties;
}
RenderProperties& animatorProperties() {
return mProperties;
}
const RenderProperties& stagingProperties() {
return mStagingProperties;
}
@@ -148,13 +152,13 @@ public:
ANDROID_API virtual void prepareTree(TreeInfo& info);
// UI thread only!
ANDROID_API void addAnimator(const sp<RenderPropertyAnimator>& animator) {
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mStagingAnimators.insert(animator);
mNeedsAnimatorsSync = true;
}
// UI thread only!
ANDROID_API void removeAnimator(const sp<RenderPropertyAnimator>& animator) {
ANDROID_API void removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mStagingAnimators.erase(animator);
mNeedsAnimatorsSync = true;
}
@@ -233,8 +237,8 @@ private:
DisplayListData* mStagingDisplayListData;
bool mNeedsAnimatorsSync;
std::set< sp<RenderPropertyAnimator> > mStagingAnimators;
std::vector< sp<RenderPropertyAnimator> > mAnimators;
std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
/**
* Draw time state - these properties are only set and used during rendering

View File

@@ -16,20 +16,19 @@
#ifndef TREEINFO_H
#define TREEINFO_H
#include <cutils/compiler.h>
#include <utils/Timers.h>
#include <utils/StrongPointer.h>
namespace android {
namespace uirenderer {
class RenderPropertyAnimator;
class BaseAnimator;
class AnimationListener;
class AnimationListener {
class AnimationHook {
public:
ANDROID_API virtual void onAnimationFinished(const sp<RenderPropertyAnimator>&) = 0;
virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0;
protected:
ANDROID_API virtual ~AnimationListener() {}
~AnimationHook() {}
};
struct TreeInfo {
@@ -41,7 +40,7 @@ struct TreeInfo {
, frameTimeMs(0)
, evaluateAnimations(false)
, hasAnimations(false)
, animationListener(0)
, animationHook(0)
{}
bool hasFunctors;
@@ -53,7 +52,7 @@ struct TreeInfo {
bool evaluateAnimations;
// This is only updated if evaluateAnimations is true
bool hasAnimations;
AnimationListener* animationListener;
AnimationHook* animationHook;
// TODO: Damage calculations
};

View File

@@ -112,6 +112,10 @@ bool DrawFrameTask::syncFrameState() {
initTreeInfo(info);
mContext->processLayerUpdates(&mLayers, info);
mContext->prepareTree(info);
if (info.hasAnimations) {
// TODO: dirty calculations, for now just do a full-screen inval
mDirty.setEmpty();
}
// If prepareTextures is false, we ran out of texture cache space
return !info.hasFunctors && info.prepareTextures;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2012 The Android Open Source Project
* 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.
@@ -13,28 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MACROS_H
#define MACROS_H
#include "jni.h"
#define PREVENT_COPY_AND_ASSIGN(Type) \
private: \
Type(const Type&); \
void operator=(const Type&)
#ifdef USE_OPENGL_RENDERER
#include <Animator.h>
namespace android {
class RenderNodeAnimator : public uirenderer::RenderPropertyAnimator {
public:
RenderNodeAnimator(JNIEnv* env, jobject callbackObject,
RenderProperty property, DeltaValueType deltaType, float delta);
virtual ~RenderNodeAnimator();
void callOnFinished();
private:
JavaVM* mJvm;
jobject mWeakThis;
};
}
#endif
#endif /* MACROS_H */

View File

@@ -287,6 +287,15 @@
</intent-filter>
</activity>
<activity
android:name="CirclePropActivity"
android:label="Draw/Circle Props">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.hwui.TEST" />
</intent-filter>
</activity>
<activity
android:name="ClearActivity"
android:label="Window/Clear">

View File

@@ -0,0 +1,137 @@
/*
* 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.test.hwui;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Bundle;
import android.os.Trace;
import android.view.HardwareCanvas;
import android.view.RenderNodeAnimator;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
import java.util.ArrayList;
public class CirclePropActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
layout.addView(spinner, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
layout.addView(new CircleView(this),
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
setContentView(layout);
}
static class CircleView extends View {
static final int DURATION = 500;
private boolean mToggle = false;
ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
CanvasProperty<Float> mX;
CanvasProperty<Float> mY;
CanvasProperty<Float> mRadius;
CanvasProperty<Paint> mPaint;
CircleView(Context c) {
super(c);
setClickable(true);
mX = CanvasProperty.createFloat(200.0f);
mY = CanvasProperty.createFloat(200.0f);
mRadius = CanvasProperty.createFloat(150.0f);
Paint p = new Paint();
p.setAntiAlias(true);
p.setColor(0xFFFF0000);
p.setStyle(Style.STROKE);
p.setStrokeWidth(60.0f);
mPaint = CanvasProperty.createPaint(p);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (canvas.isHardwareAccelerated()) {
HardwareCanvas hwcanvas = (HardwareCanvas) canvas;
hwcanvas.drawCircle(mX, mY, mRadius, mPaint);
}
}
@Override
public boolean performClick() {
for (int i = 0; i < mRunningAnimations.size(); i++) {
mRunningAnimations.get(i).cancel();
}
mRunningAnimations.clear();
mToggle = !mToggle;
mRunningAnimations.add(new RenderNodeAnimator(
mX, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 400.0f : 200.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mY, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 600.0f : 200.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mRadius, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 250.0f : 150.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_ALPHA,
RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 64.0f : 255.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_STROKE_WIDTH,
RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 5.0f : 60.0f));
for (int i = 0; i < mRunningAnimations.size(); i++) {
mRunningAnimations.get(i).start(this);
}
if (mToggle) {
post(new Runnable() {
@Override
public void run() {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy");
try {
Thread.sleep(DURATION);
} catch (InterruptedException e) {
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
});
}
return true;
}
}
}

View File

@@ -57,7 +57,7 @@ public class SmallCircleActivity extends Activity {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xffffffff);
mPaint.setColor(0xff00ffff);
}
@Override

View File

@@ -19,8 +19,6 @@ import java.util.Map;
public class MainActivity extends Activity implements OnItemClickListener {
static final int TRANSLATION_Y = 1;
static final int DELTA_TYPE_DELTA = 1;
static final int DURATION = 400;
static final String KEY_NAME = "name";
@@ -75,7 +73,7 @@ public class MainActivity extends Activity implements OnItemClickListener {
float delta = (pos - clickedPosition) * 1.1f;
if (delta == 0) delta = -1;
RenderNodeAnimator animator = new RenderNodeAnimator(
TRANSLATION_Y, DELTA_TYPE_DELTA, dy * delta);
RenderNodeAnimator.TRANSLATION_Y, RenderNodeAnimator.DELTA_TYPE_DELTA, dy * delta);
animator.setDuration(DURATION);
animator.start(child);
}