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 , mStagingTarget(nullptr) 37 , mFinalValue(finalValue) 38 , mDeltaValue(0) 39 , mFromValue(0) 40 , mStagingPlayState(PlayState::NotStarted) 41 , mPlayState(PlayState::NotStarted) 42 , mHasStartValue(false) 43 , mStartTime(0) 44 , mDuration(300) 45 , mStartDelay(0) 46 , mMayRunAsync(true) 47 , mPlayTime(0) { 48} 49 50BaseRenderNodeAnimator::~BaseRenderNodeAnimator() { 51} 52 53void BaseRenderNodeAnimator::checkMutable() { 54 // Should be impossible to hit as the Java-side also has guards for this 55 LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted, 56 "Animator has already been started!"); 57} 58 59void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) { 60 checkMutable(); 61 mInterpolator.reset(interpolator); 62} 63 64void BaseRenderNodeAnimator::setStartValue(float value) { 65 checkMutable(); 66 doSetStartValue(value); 67} 68 69void BaseRenderNodeAnimator::doSetStartValue(float value) { 70 mFromValue = value; 71 mDeltaValue = (mFinalValue - mFromValue); 72 mHasStartValue = true; 73} 74 75void BaseRenderNodeAnimator::setDuration(nsecs_t duration) { 76 checkMutable(); 77 mDuration = duration; 78} 79 80void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) { 81 checkMutable(); 82 mStartDelay = startDelay; 83} 84 85void BaseRenderNodeAnimator::attach(RenderNode* target) { 86 mStagingTarget = target; 87 onAttached(); 88} 89 90void BaseRenderNodeAnimator::start() { 91 mStagingPlayState = PlayState::Running; 92 mStagingRequests.push_back(Request::Start); 93 onStagingPlayStateChanged(); 94} 95 96void BaseRenderNodeAnimator::cancel() { 97 mStagingPlayState = PlayState::Finished; 98 mStagingRequests.push_back(Request::Cancel); 99 onStagingPlayStateChanged(); 100} 101 102void BaseRenderNodeAnimator::reset() { 103 mStagingPlayState = PlayState::Finished; 104 mStagingRequests.push_back(Request::Reset); 105 onStagingPlayStateChanged(); 106} 107 108void BaseRenderNodeAnimator::reverse() { 109 mStagingPlayState = PlayState::Reversing; 110 mStagingRequests.push_back(Request::Reverse); 111 onStagingPlayStateChanged(); 112} 113 114void BaseRenderNodeAnimator::end() { 115 mStagingPlayState = PlayState::Finished; 116 mStagingRequests.push_back(Request::End); 117 onStagingPlayStateChanged(); 118} 119 120void BaseRenderNodeAnimator::resolveStagingRequest(Request request) { 121 switch (request) { 122 case Request::Start: 123 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ? 124 mPlayTime : 0; 125 mPlayState = PlayState::Running; 126 mPendingActionUponFinish = Action::None; 127 break; 128 case Request::Reverse: 129 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ? 130 mPlayTime : mDuration; 131 mPlayState = PlayState::Reversing; 132 mPendingActionUponFinish = Action::None; 133 break; 134 case Request::Reset: 135 mPlayTime = 0; 136 mPlayState = PlayState::Finished; 137 mPendingActionUponFinish = Action::Reset; 138 break; 139 case Request::Cancel: 140 mPlayState = PlayState::Finished; 141 mPendingActionUponFinish = Action::None; 142 break; 143 case Request::End: 144 mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration; 145 mPlayState = PlayState::Finished; 146 mPendingActionUponFinish = Action::End; 147 break; 148 default: 149 LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request)); 150 }; 151} 152 153void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) { 154 if (mStagingTarget) { 155 RenderNode* oldTarget = mTarget; 156 mTarget = mStagingTarget; 157 mStagingTarget = nullptr; 158 if (oldTarget && oldTarget != mTarget) { 159 oldTarget->onAnimatorTargetChanged(this); 160 } 161 } 162 163 if (!mHasStartValue) { 164 doSetStartValue(getValue(mTarget)); 165 } 166 167 if (!mStagingRequests.empty()) { 168 // No interpolator was set, use the default 169 if (mPlayState == PlayState::NotStarted && !mInterpolator) { 170 mInterpolator.reset(Interpolator::createDefaultInterpolator()); 171 } 172 // Keep track of the play state and play time before they are changed when 173 // staging requests are resolved. 174 nsecs_t currentPlayTime = mPlayTime; 175 PlayState prevFramePlayState = mPlayState; 176 177 // Resolve staging requests one by one. 178 for (Request request : mStagingRequests) { 179 resolveStagingRequest(request); 180 } 181 mStagingRequests.clear(); 182 183 if (mStagingPlayState == PlayState::Finished) { 184 callOnFinishedListener(context); 185 } else if (mStagingPlayState == PlayState::Running 186 || mStagingPlayState == PlayState::Reversing) { 187 bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState; 188 if (prevFramePlayState != mStagingPlayState) { 189 transitionToRunning(context); 190 } 191 if (changed) { 192 // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was 193 // requested from UI thread). It is achieved by modifying mStartTime, such that 194 // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the 195 // case of reversing) 196 nsecs_t currentFrameTime = context.frameTimeMs(); 197 if (mPlayState == PlayState::Reversing) { 198 // Reverse is not supported for animations with a start delay, so here we 199 // assume no start delay. 200 mStartTime = currentFrameTime - (mDuration - mPlayTime); 201 } else { 202 // Animation should play forward 203 if (mPlayTime == 0) { 204 // If the request is to start from the beginning, include start delay. 205 mStartTime = currentFrameTime + mStartDelay; 206 } else { 207 // If the request is to seek to a non-zero play time, then we skip start 208 // delay. 209 mStartTime = currentFrameTime - mPlayTime; 210 } 211 } 212 } 213 } 214 } 215 onPushStaging(); 216} 217 218void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) { 219 nsecs_t frameTimeMs = context.frameTimeMs(); 220 LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs); 221 if (mStartDelay < 0 || mStartDelay > 50000) { 222 ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay); 223 } 224 mStartTime = frameTimeMs + mStartDelay; 225 if (mStartTime < 0) { 226 ALOGW("Ended up with a really weird start time of %" PRId64 227 " with frame time %" PRId64 " and start delay %" PRId64, 228 mStartTime, frameTimeMs, mStartDelay); 229 // Set to 0 so that the animate() basically instantly finishes 230 mStartTime = 0; 231 } 232 if (mDuration < 0) { 233 ALOGW("Your duration is strange and confusing: %" PRId64, mDuration); 234 } 235} 236 237bool BaseRenderNodeAnimator::animate(AnimationContext& context) { 238 if (mPlayState < PlayState::Running) { 239 return false; 240 } 241 if (mPlayState == PlayState::Finished) { 242 if (mPendingActionUponFinish == Action::Reset) { 243 // Skip to start. 244 updatePlayTime(0); 245 } else if (mPendingActionUponFinish == Action::End) { 246 // Skip to end. 247 updatePlayTime(mDuration); 248 } 249 // Reset pending action. 250 mPendingActionUponFinish = Action ::None; 251 return true; 252 } 253 254 // This should be set before setValue() so animators can query this time when setValue 255 // is called. 256 nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime; 257 bool finished = updatePlayTime(currentPlayTime); 258 if (finished && mPlayState != PlayState::Finished) { 259 mPlayState = PlayState::Finished; 260 callOnFinishedListener(context); 261 } 262 return finished; 263} 264 265bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) { 266 mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime; 267 onPlayTimeChanged(mPlayTime); 268 // If BaseRenderNodeAnimator is handling the delay (not typical), then 269 // because the staging properties reflect the final value, we always need 270 // to call setValue even if the animation isn't yet running or is still 271 // being delayed as we need to override the staging value 272 if (playTime < 0) { 273 setValue(mTarget, mFromValue); 274 return false; 275 } 276 277 float fraction = 1.0f; 278 if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) { 279 fraction = mPlayTime / (float) mDuration; 280 } 281 fraction = MathUtils::clamp(fraction, 0.0f, 1.0f); 282 283 fraction = mInterpolator->interpolate(fraction); 284 setValue(mTarget, mFromValue + (mDeltaValue * fraction)); 285 286 return playTime >= mDuration; 287} 288 289nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() { 290 return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime; 291} 292 293void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) { 294 if (mPlayState < PlayState::Finished) { 295 mPlayState = PlayState::Finished; 296 callOnFinishedListener(context); 297 } 298} 299 300void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) { 301 if (mListener.get()) { 302 context.callOnFinished(this, mListener.get()); 303 } 304} 305 306/************************************************************ 307 * RenderPropertyAnimator 308 ************************************************************/ 309 310struct RenderPropertyAnimator::PropertyAccessors { 311 RenderNode::DirtyPropertyMask dirtyMask; 312 GetFloatProperty getter; 313 SetFloatProperty setter; 314}; 315 316// Maps RenderProperty enum to accessors 317const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = { 318 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX }, 319 {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY }, 320 {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ }, 321 {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX }, 322 {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY }, 323 {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation }, 324 {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX }, 325 {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY }, 326 {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX }, 327 {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY }, 328 {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ }, 329 {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha }, 330}; 331 332RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue) 333 : BaseRenderNodeAnimator(finalValue) 334 , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) { 335} 336 337void RenderPropertyAnimator::onAttached() { 338 if (!mHasStartValue 339 && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) { 340 setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)()); 341 } 342} 343 344void RenderPropertyAnimator::onStagingPlayStateChanged() { 345 if (mStagingPlayState == PlayState::Running) { 346 if (mStagingTarget) { 347 (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue()); 348 } else { 349 // In the case of start delay where stagingTarget has been sync'ed over and null'ed 350 // we delay the properties update to push staging. 351 mShouldUpdateStagingProperties = true; 352 } 353 } else if (mStagingPlayState == PlayState::Finished) { 354 // We're being canceled, so make sure that whatever values the UI thread 355 // is observing for us is pushed over 356 mShouldSyncPropertyFields = true; 357 } 358} 359 360void RenderPropertyAnimator::onPushStaging() { 361 if (mShouldUpdateStagingProperties) { 362 (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue()); 363 mShouldUpdateStagingProperties = false; 364 } 365 366 if (mShouldSyncPropertyFields) { 367 mTarget->setPropertyFieldsDirty(dirtyMask()); 368 mShouldSyncPropertyFields = false; 369 } 370} 371 372uint32_t RenderPropertyAnimator::dirtyMask() { 373 return mPropertyAccess->dirtyMask; 374} 375 376float RenderPropertyAnimator::getValue(RenderNode* target) const { 377 return (target->properties().*mPropertyAccess->getter)(); 378} 379 380void RenderPropertyAnimator::setValue(RenderNode* target, float value) { 381 (target->animatorProperties().*mPropertyAccess->setter)(value); 382} 383 384/************************************************************ 385 * CanvasPropertyPrimitiveAnimator 386 ************************************************************/ 387 388CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator( 389 CanvasPropertyPrimitive* property, float finalValue) 390 : BaseRenderNodeAnimator(finalValue) 391 , mProperty(property) { 392} 393 394float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const { 395 return mProperty->value; 396} 397 398void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) { 399 mProperty->value = value; 400} 401 402uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() { 403 return RenderNode::DISPLAY_LIST; 404} 405 406/************************************************************ 407 * CanvasPropertySkPaintAnimator 408 ************************************************************/ 409 410CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator( 411 CanvasPropertyPaint* property, PaintField field, float finalValue) 412 : BaseRenderNodeAnimator(finalValue) 413 , mProperty(property) 414 , mField(field) { 415} 416 417float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const { 418 switch (mField) { 419 case STROKE_WIDTH: 420 return mProperty->value.getStrokeWidth(); 421 case ALPHA: 422 return mProperty->value.getAlpha(); 423 } 424 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 425 return -1; 426} 427 428static uint8_t to_uint8(float value) { 429 int c = (int) (value + .5f); 430 return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c ); 431} 432 433void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) { 434 switch (mField) { 435 case STROKE_WIDTH: 436 mProperty->value.setStrokeWidth(value); 437 return; 438 case ALPHA: 439 mProperty->value.setAlpha(to_uint8(value)); 440 return; 441 } 442 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 443} 444 445uint32_t CanvasPropertyPaintAnimator::dirtyMask() { 446 return RenderNode::DISPLAY_LIST; 447} 448 449RevealAnimator::RevealAnimator(int centerX, int centerY, 450 float startValue, float finalValue) 451 : BaseRenderNodeAnimator(finalValue) 452 , mCenterX(centerX) 453 , mCenterY(centerY) { 454 setStartValue(startValue); 455} 456 457float RevealAnimator::getValue(RenderNode* target) const { 458 return target->properties().getRevealClip().getRadius(); 459} 460 461void RevealAnimator::setValue(RenderNode* target, float value) { 462 target->animatorProperties().mutableRevealClip().set(true, 463 mCenterX, mCenterY, value); 464} 465 466uint32_t RevealAnimator::dirtyMask() { 467 return RenderNode::GENERIC; 468} 469 470} /* namespace uirenderer */ 471} /* namespace android */ 472