diff options
author | John Reck <jreck@google.com> | 2014-05-01 21:27:37 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2014-05-02 13:43:46 -0700 |
commit | 52244fff29042926e21fa897ef5ab11148e35299 (patch) | |
tree | 2cc7b2f6dd47fe7863c6bc2b6a806e275c149ba9 | |
parent | abc975f539b4ea06c05b11ec56b0abe7c6fd95aa (diff) | |
download | frameworks_base-52244fff29042926e21fa897ef5ab11148e35299.zip frameworks_base-52244fff29042926e21fa897ef5ab11148e35299.tar.gz frameworks_base-52244fff29042926e21fa897ef5ab11148e35299.tar.bz2 |
Add CanvasProperty for drawCircle
Change-Id: Icbcc030f5033d2094e567d7c519b9d672f2aac1c
27 files changed, 803 insertions, 258 deletions
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 34b85d9..11948b2 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -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; @@ -889,6 +890,16 @@ class GLES20Canvas extends HardwareCanvas { 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); } diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 233f846..7ec2cc6 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -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); } diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index b70ae3d..b5089b0 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -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); } diff --git a/core/jni/Android.mk b/core/jni/Android.mk index ee59c8a..667bf6c 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -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 \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index f964cd2..66fbb8e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -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), diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp new file mode 100644 index 0000000..70e2db5 --- /dev/null +++ b/core/jni/android/graphics/CanvasProperty.cpp @@ -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 diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index ef5ebd0..3aa179d 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -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 }, diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp index b92c992..3be013b 100644 --- a/core/jni/android_view_RenderNodeAnimator.cpp +++ b/core/jni/android_view_RenderNodeAnimator.cpp @@ -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); +} + +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 ); +} - RenderNodeAnimator* animator = new RenderNodeAnimator(env, weakThis, - static_cast<RenderPropertyAnimator::RenderProperty>(property), - static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType), - deltaValue); +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 diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 58fc1e1..564c9a6 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -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, diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java new file mode 100644 index 0000000..99ea9b1 --- /dev/null +++ b/graphics/java/android/graphics/CanvasProperty.java @@ -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); +} diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp index ee16586..6a3003e 100644 --- a/libs/hwui/Animator.cpp +++ b/libs/hwui/Animator.cpp @@ -20,130 +20,13 @@ #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()); + } + } +} + /************************************************************ - * RenderPropertyAnimator + * BaseRenderNodeAnimator ************************************************************/ -RenderPropertyAnimatorImpl::RenderPropertyAnimatorImpl( - GetFloatProperty getter, SetFloatProperty setter, - RenderPropertyAnimator::DeltaValueType deltaType, float delta) +BaseRenderNodeAnimator::BaseRenderNodeAnimator( + BaseRenderNodeAnimator::DeltaValueType deltaType, float delta) : mTarget(0) - , mGetter(getter) - , mSetter(setter) , mDeltaValueType(deltaType) , mDeltaValue(delta) , mFromValue(-1) { } -RenderPropertyAnimatorImpl::~RenderPropertyAnimatorImpl() { -} - -bool RenderPropertyAnimatorImpl::animate(RenderProperties* target, TreeInfo& info) { +bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) { mTarget = target; - bool finished = animateFrame(info.frameTimeMs); + bool finished = animateFrame(info); mTarget = NULL; return finished; } -void RenderPropertyAnimatorImpl::onAnimationStarted() { - mFromValue = (mTarget->*mGetter)(); +void BaseRenderNodeAnimator::onAnimationStarted() { + mFromValue = getValue(); - if (mDeltaValueType == RenderPropertyAnimator::ABSOLUTE) { + if (mDeltaValueType == BaseRenderNodeAnimator::ABSOLUTE) { mDeltaValue = (mDeltaValue - mFromValue); - mDeltaValueType = RenderPropertyAnimator::DELTA; + mDeltaValueType = BaseRenderNodeAnimator::DELTA; } } -void RenderPropertyAnimatorImpl::onAnimationUpdated(float fraction) { +void BaseRenderNodeAnimator::onAnimationUpdated(float fraction) { float value = mFromValue + (mDeltaValue * fraction); - (mTarget->*mSetter)(value); + setValue(value); +} + +/************************************************************ + * RenderPropertyAnimator + ************************************************************/ + +// 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]) { +} + +float RenderPropertyAnimator::getValue() const { + return (target()->animatorProperties().*mPropertyAccess.getter)(); +} + +void RenderPropertyAnimator::setValue(float value) { + (target()->animatorProperties().*mPropertyAccess.setter)(value); +} + +/************************************************************ + * CanvasPropertyPrimitiveAnimator + ************************************************************/ + +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 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 */ diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index 1c8361b..0b074cc 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -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(); + ANDROID_API RenderPropertyAnimator(RenderProperty property, + DeltaValueType deltaType, float deltaValue); + +protected: + ANDROID_API virtual float getValue() const; + ANDROID_API virtual void setValue(float value); + +private: + typedef void (RenderProperties::*SetFloatProperty)(float value); + typedef float (RenderProperties::*GetFloatProperty)() const; - bool animate(RenderProperties* target, TreeInfo& info); + 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 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: + 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: - RenderPropertyAnimatorImpl* mImpl; + sp<CanvasPropertyPaint> mProperty; + PaintField mField; }; } /* namespace uirenderer */ diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h new file mode 100644 index 0000000..2e1d176 --- /dev/null +++ b/libs/hwui/CanvasProperty.h @@ -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 */ diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index fe70d13..eaeb772 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -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; diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 6dfb918..ce92beb 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -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) diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index e36d975..8afd106 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -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); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 04c5a73..25e78c1 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -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, diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index b49d1e1..7794abc 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -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, diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 7a9c181..2c29985 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -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(); diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 294f436..159903c 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -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 diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index 8957607..a383fbf 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -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 }; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index ff4be71..45f5cb0 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -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; } diff --git a/core/jni/android_view_RenderNodeAnimator.h b/libs/hwui/utils/Macros.h index 760ca91..14a3ec0 100644 --- a/core/jni/android_view_RenderNodeAnimator.h +++ b/libs/hwui/utils/Macros.h @@ -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 */ diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 5c2583b..af0d0ad 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -288,6 +288,15 @@ </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"> <intent-filter> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java new file mode 100644 index 0000000..f060bc8 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java @@ -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; + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java index 8c02539..a3f4ddc 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java @@ -57,7 +57,7 @@ public class SmallCircleActivity extends Activity { mPaint = new Paint(); mPaint.setAntiAlias(true); - mPaint.setColor(0xffffffff); + mPaint.setColor(0xff00ffff); } @Override diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java index 1d209dd..8f9cf58 100644 --- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java +++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java @@ -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); } |