/*
* 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 ANIMATOR_H
#define ANIMATOR_H
#include "CanvasProperty.h"
#include <cutils/compiler.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
#include <memory>
#include "utils/Macros.h"
#include <vector>
namespace android {
namespace uirenderer {
class AnimationContext;
class BaseRenderNodeAnimator;
class Interpolator;
class RenderNode;
class RenderProperties;
class AnimationListener : public VirtualLightRefBase {
public:
ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
protected:
ANDROID_API virtual ~AnimationListener() {}
};
enum class RepeatMode {
// These are the same values as the RESTART and REVERSE in ValueAnimator.java.
Restart = 1,
Reverse = 2
};
class BaseRenderNodeAnimator : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
public:
ANDROID_API void setStartValue(float value);
ANDROID_API void setInterpolator(Interpolator* interpolator);
ANDROID_API void setDuration(nsecs_t durationInMs);
ANDROID_API nsecs_t duration() { return mDuration; }
ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
ANDROID_API nsecs_t startDelay() { return mStartDelay; }
ANDROID_API void setListener(AnimationListener* listener) { mListener = listener; }
AnimationListener* listener() { return mListener.get(); }
ANDROID_API void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; }
bool mayRunAsync() { return mMayRunAsync; }
ANDROID_API void start();
ANDROID_API virtual void reset();
ANDROID_API void reverse();
// Terminates the animation at its current progress.
ANDROID_API void cancel();
// Terminates the animation and skip to the end of the animation.
ANDROID_API virtual void end();
void attach(RenderNode* target);
virtual void onAttached() {}
void detach() { mTarget = nullptr; }
ANDROID_API void pushStaging(AnimationContext& context);
ANDROID_API bool animate(AnimationContext& context);
// Returns the remaining time in ms for the animation. Note this should only be called during
// an animation on RenderThread.
ANDROID_API nsecs_t getRemainingPlayTime();
bool isRunning() {
return mPlayState == PlayState::Running || mPlayState == PlayState::Reversing;
}
bool isFinished() { return mPlayState == PlayState::Finished; }
float finalValue() { return mFinalValue; }
ANDROID_API virtual uint32_t dirtyMask() = 0;
void forceEndNow(AnimationContext& context);
RenderNode* target() { return mTarget; }
RenderNode* stagingTarget() { return mStagingTarget; }
protected:
// PlayState is used by mStagingPlayState and mPlayState to track the state initiated from UI
// thread and Render Thread animation state, respectively.
// From the UI thread, mStagingPlayState transition looks like
// NotStarted -> Running/Reversing -> Finished
// ^ |
// | |
// ----------------------
// Note: For mStagingState, the Finished state (optional) is only set when the animation is
// terminated by user.
//
// On Render Thread, mPlayState transition:
// NotStart -> Running/Reversing-> Finished
// ^ |
// | |
// ------------------
// Note that if the animation is in Running/Reversing state, calling start or reverse again
// would do nothing if the animation has the same play direction as the request; otherwise,
// the animation would start from where it is and change direction (i.e. Reversing <-> Running)
enum class PlayState {
NotStarted,
Running,
Reversing,
Finished,
};
explicit BaseRenderNodeAnimator(float finalValue);
virtual ~BaseRenderNodeAnimator();
virtual float getValue(RenderNode* target) const = 0;
virtual void setValue(RenderNode* target, float value) = 0;
void callOnFinishedListener(AnimationContext& context);
virtual void onStagingPlayStateChanged() {}
virtual void onPlayTimeChanged(nsecs_t playTime) {}
virtual void onPushStaging() {}
RenderNode* mTarget;
RenderNode* mStagingTarget;
float mFinalValue;
float mDeltaValue;
float mFromValue;
std::unique_ptr<Interpolator> mInterpolator;
PlayState mStagingPlayState;
PlayState mPlayState;
bool mHasStartValue;
nsecs_t mStartTime;
nsecs_t mDuration;
nsecs_t mStartDelay;
bool mMayRunAsync;
// Play Time tracks the progress of animation, it should always be [0, mDuration], 0 being
// the beginning of the animation, will reach mDuration at the end of an animation.
nsecs_t mPlayTime;
sp<AnimationListener> mListener;
private:
enum class Request { Start, Reverse, Reset, Cancel, End };
// Defines different actions upon finish.
enum class Action {
// For animations that got canceled or finished normally. no more action needs to be done.
None,
// For animations that get reset, the reset will happen in the next animation pulse.
Reset,
// For animations being ended, in the next animation pulse the animation will skip to end.
End
};
inline void checkMutable();
virtual void transitionToRunning(AnimationContext& context);
void doSetStartValue(float value);
bool updatePlayTime(nsecs_t playTime);
void resolveStagingRequest(Request request);
std::vector<Request> mStagingRequests;
Action mPendingActionUponFinish = Action::None;
};
class RenderPropertyAnimator : public BaseRenderNodeAnimator {
public:
enum RenderProperty {
TRANSLATION_X = 0,
TRANSLATION_Y,
TRANSLATION_Z,
SCALE_X,
SCALE_Y,
ROTATION,
ROTATION_X,
ROTATION_Y,
X,
Y,
Z,
ALPHA,
};
ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
virtual void onAttached() override;
virtual void onStagingPlayStateChanged() override;
virtual void onPushStaging() override;
private:
typedef bool (RenderProperties::*SetFloatProperty)(float value);
typedef float (RenderProperties::*GetFloatProperty)() const;
struct PropertyAccessors;
const PropertyAccessors* mPropertyAccess;
static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
bool mShouldSyncPropertyFields = false;
bool mShouldUpdateStagingProperties = false;
};
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
public:
ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
private:
sp<CanvasPropertyPrimitive> mProperty;
};
class CanvasPropertyPaintAnimator : public BaseRenderNodeAnimator {
public:
enum PaintField {
STROKE_WIDTH = 0,
ALPHA,
};
ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field,
float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
private:
sp<CanvasPropertyPaint> mProperty;
PaintField mField;
};
class RevealAnimator : public BaseRenderNodeAnimator {
public:
ANDROID_API RevealAnimator(int centerX, int centerY, float startValue, float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
private:
int mCenterX, mCenterY;
};
} /* namespace uirenderer */
} /* namespace android */
#endif /* ANIMATOR_H */