1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "Animator.h" 18 19#include <inttypes.h> 20#include <set> 21 22#include "AnimationContext.h" 23#include "Interpolator.h" 24#include "RenderNode.h" 25#include "RenderProperties.h" 26 27namespace android { 28namespace uirenderer { 29 30/************************************************************ 31 * BaseRenderNodeAnimator 32 ************************************************************/ 33 34BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue) 35 : mTarget(nullptr) 36 , mFinalValue(finalValue) 37 , mDeltaValue(0) 38 , mFromValue(0) 39 , mStagingPlayState(NOT_STARTED) 40 , mPlayState(NOT_STARTED) 41 , mHasStartValue(false) 42 , mStartTime(0) 43 , mDuration(300) 44 , mStartDelay(0) 45 , mMayRunAsync(true) { 46} 47 48BaseRenderNodeAnimator::~BaseRenderNodeAnimator() { 49} 50 51void BaseRenderNodeAnimator::checkMutable() { 52 // Should be impossible to hit as the Java-side also has guards for this 53 LOG_ALWAYS_FATAL_IF(mStagingPlayState != NOT_STARTED, 54 "Animator has already been started!"); 55} 56 57void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) { 58 checkMutable(); 59 mInterpolator.reset(interpolator); 60} 61 62void BaseRenderNodeAnimator::setStartValue(float value) { 63 checkMutable(); 64 doSetStartValue(value); 65} 66 67void BaseRenderNodeAnimator::doSetStartValue(float value) { 68 mFromValue = value; 69 mDeltaValue = (mFinalValue - mFromValue); 70 mHasStartValue = true; 71} 72 73void BaseRenderNodeAnimator::setDuration(nsecs_t duration) { 74 checkMutable(); 75 mDuration = duration; 76} 77 78void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) { 79 checkMutable(); 80 mStartDelay = startDelay; 81} 82 83void BaseRenderNodeAnimator::attach(RenderNode* target) { 84 mTarget = target; 85 onAttached(); 86} 87 88void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) { 89 if (!mHasStartValue) { 90 doSetStartValue(getValue(mTarget)); 91 } 92 if (mStagingPlayState > mPlayState) { 93 mPlayState = mStagingPlayState; 94 // Oh boy, we're starting! Man the battle stations! 95 if (mPlayState == RUNNING) { 96 transitionToRunning(context); 97 } else if (mPlayState == FINISHED) { 98 callOnFinishedListener(context); 99 } 100 } 101} 102 103void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) { 104 nsecs_t frameTimeMs = context.frameTimeMs(); 105 LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs); 106 if (mStartDelay < 0 || mStartDelay > 50000) { 107 ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay); 108 } 109 mStartTime = frameTimeMs + mStartDelay; 110 if (mStartTime < 0) { 111 ALOGW("Ended up with a really weird start time of %" PRId64 112 " with frame time %" PRId64 " and start delay %" PRId64, 113 mStartTime, frameTimeMs, mStartDelay); 114 // Set to 0 so that the animate() basically instantly finishes 115 mStartTime = 0; 116 } 117 // No interpolator was set, use the default 118 if (!mInterpolator) { 119 mInterpolator.reset(Interpolator::createDefaultInterpolator()); 120 } 121 if (mDuration < 0 || mDuration > 50000) { 122 ALOGW("Your duration is strange and confusing: %" PRId64, mDuration); 123 } 124} 125 126bool BaseRenderNodeAnimator::animate(AnimationContext& context) { 127 if (mPlayState < RUNNING) { 128 return false; 129 } 130 if (mPlayState == FINISHED) { 131 return true; 132 } 133 134 // If BaseRenderNodeAnimator is handling the delay (not typical), then 135 // because the staging properties reflect the final value, we always need 136 // to call setValue even if the animation isn't yet running or is still 137 // being delayed as we need to override the staging value 138 if (mStartTime > context.frameTimeMs()) { 139 setValue(mTarget, mFromValue); 140 return false; 141 } 142 143 float fraction = 1.0f; 144 if (mPlayState == RUNNING && mDuration > 0) { 145 fraction = (float)(context.frameTimeMs() - mStartTime) / mDuration; 146 } 147 if (fraction >= 1.0f) { 148 fraction = 1.0f; 149 mPlayState = FINISHED; 150 } 151 152 fraction = mInterpolator->interpolate(fraction); 153 setValue(mTarget, mFromValue + (mDeltaValue * fraction)); 154 155 if (mPlayState == FINISHED) { 156 callOnFinishedListener(context); 157 return true; 158 } 159 160 return false; 161} 162 163void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) { 164 if (mPlayState < FINISHED) { 165 mPlayState = FINISHED; 166 callOnFinishedListener(context); 167 } 168} 169 170void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) { 171 if (mListener.get()) { 172 context.callOnFinished(this, mListener.get()); 173 } 174} 175 176/************************************************************ 177 * RenderPropertyAnimator 178 ************************************************************/ 179 180struct RenderPropertyAnimator::PropertyAccessors { 181 RenderNode::DirtyPropertyMask dirtyMask; 182 GetFloatProperty getter; 183 SetFloatProperty setter; 184}; 185 186// Maps RenderProperty enum to accessors 187const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = { 188 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX }, 189 {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY }, 190 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ }, 191 {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX }, 192 {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY }, 193 {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation }, 194 {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX }, 195 {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY }, 196 {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX }, 197 {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY }, 198 {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ }, 199 {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha }, 200}; 201 202RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue) 203 : BaseRenderNodeAnimator(finalValue) 204 , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) { 205} 206 207void RenderPropertyAnimator::onAttached() { 208 if (!mHasStartValue 209 && mTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) { 210 setStartValue((mTarget->stagingProperties().*mPropertyAccess->getter)()); 211 } 212} 213 214void RenderPropertyAnimator::onStagingPlayStateChanged() { 215 if (mStagingPlayState == RUNNING) { 216 (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue()); 217 } else if (mStagingPlayState == FINISHED) { 218 // We're being canceled, so make sure that whatever values the UI thread 219 // is observing for us is pushed over 220 mTarget->setPropertyFieldsDirty(dirtyMask()); 221 } 222} 223 224uint32_t RenderPropertyAnimator::dirtyMask() { 225 return mPropertyAccess->dirtyMask; 226} 227 228float RenderPropertyAnimator::getValue(RenderNode* target) const { 229 return (target->properties().*mPropertyAccess->getter)(); 230} 231 232void RenderPropertyAnimator::setValue(RenderNode* target, float value) { 233 (target->animatorProperties().*mPropertyAccess->setter)(value); 234} 235 236/************************************************************ 237 * CanvasPropertyPrimitiveAnimator 238 ************************************************************/ 239 240CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator( 241 CanvasPropertyPrimitive* property, float finalValue) 242 : BaseRenderNodeAnimator(finalValue) 243 , mProperty(property) { 244} 245 246float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const { 247 return mProperty->value; 248} 249 250void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) { 251 mProperty->value = value; 252} 253 254uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() { 255 return RenderNode::DISPLAY_LIST; 256} 257 258/************************************************************ 259 * CanvasPropertySkPaintAnimator 260 ************************************************************/ 261 262CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator( 263 CanvasPropertyPaint* property, PaintField field, float finalValue) 264 : BaseRenderNodeAnimator(finalValue) 265 , mProperty(property) 266 , mField(field) { 267} 268 269float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const { 270 switch (mField) { 271 case STROKE_WIDTH: 272 return mProperty->value.getStrokeWidth(); 273 case ALPHA: 274 return mProperty->value.getAlpha(); 275 } 276 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 277 return -1; 278} 279 280static uint8_t to_uint8(float value) { 281 int c = (int) (value + .5f); 282 return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c ); 283} 284 285void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) { 286 switch (mField) { 287 case STROKE_WIDTH: 288 mProperty->value.setStrokeWidth(value); 289 return; 290 case ALPHA: 291 mProperty->value.setAlpha(to_uint8(value)); 292 return; 293 } 294 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 295} 296 297uint32_t CanvasPropertyPaintAnimator::dirtyMask() { 298 return RenderNode::DISPLAY_LIST; 299} 300 301RevealAnimator::RevealAnimator(int centerX, int centerY, 302 float startValue, float finalValue) 303 : BaseRenderNodeAnimator(finalValue) 304 , mCenterX(centerX) 305 , mCenterY(centerY) { 306 setStartValue(startValue); 307} 308 309float RevealAnimator::getValue(RenderNode* target) const { 310 return target->properties().getRevealClip().getRadius(); 311} 312 313void RevealAnimator::setValue(RenderNode* target, float value) { 314 target->animatorProperties().mutableRevealClip().set(true, 315 mCenterX, mCenterY, value); 316} 317 318uint32_t RevealAnimator::dirtyMask() { 319 return RenderNode::GENERIC; 320} 321 322} /* namespace uirenderer */ 323} /* namespace android */ 324