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 27 namespace android { 28 namespace uirenderer { 29 30 /************************************************************ 31 * BaseRenderNodeAnimator 32 ************************************************************/ 33 34 BaseRenderNodeAnimator::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 50 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() { 51 } 52 53 void 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 59 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) { 60 checkMutable(); 61 mInterpolator.reset(interpolator); 62 } 63 64 void BaseRenderNodeAnimator::setStartValue(float value) { 65 checkMutable(); 66 doSetStartValue(value); 67 } 68 69 void BaseRenderNodeAnimator::doSetStartValue(float value) { 70 mFromValue = value; 71 mDeltaValue = (mFinalValue - mFromValue); 72 mHasStartValue = true; 73 } 74 75 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) { 76 checkMutable(); 77 mDuration = duration; 78 } 79 80 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) { 81 checkMutable(); 82 mStartDelay = startDelay; 83 } 84 85 void BaseRenderNodeAnimator::attach(RenderNode* target) { 86 mStagingTarget = target; 87 onAttached(); 88 } 89 90 void BaseRenderNodeAnimator::start() { 91 mStagingPlayState = PlayState::Running; 92 mStagingRequests.push_back(Request::Start); 93 onStagingPlayStateChanged(); 94 } 95 96 void BaseRenderNodeAnimator::cancel() { 97 mStagingPlayState = PlayState::Finished; 98 mStagingRequests.push_back(Request::Cancel); 99 onStagingPlayStateChanged(); 100 } 101 102 void BaseRenderNodeAnimator::reset() { 103 mStagingPlayState = PlayState::Finished; 104 mStagingRequests.push_back(Request::Reset); 105 onStagingPlayStateChanged(); 106 } 107 108 void BaseRenderNodeAnimator::reverse() { 109 mStagingPlayState = PlayState::Reversing; 110 mStagingRequests.push_back(Request::Reverse); 111 onStagingPlayStateChanged(); 112 } 113 114 void BaseRenderNodeAnimator::end() { 115 mStagingPlayState = PlayState::Finished; 116 mStagingRequests.push_back(Request::End); 117 onStagingPlayStateChanged(); 118 } 119 120 void 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 153 void 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 218 void 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 237 bool 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 265 bool 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 289 nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() { 290 return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime; 291 } 292 293 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) { 294 if (mPlayState < PlayState::Finished) { 295 mPlayState = PlayState::Finished; 296 callOnFinishedListener(context); 297 } 298 } 299 300 void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) { 301 if (mListener.get()) { 302 context.callOnFinished(this, mListener.get()); 303 } 304 } 305 306 /************************************************************ 307 * RenderPropertyAnimator 308 ************************************************************/ 309 310 struct RenderPropertyAnimator::PropertyAccessors { 311 RenderNode::DirtyPropertyMask dirtyMask; 312 GetFloatProperty getter; 313 SetFloatProperty setter; 314 }; 315 316 // Maps RenderProperty enum to accessors 317 const 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 332 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue) 333 : BaseRenderNodeAnimator(finalValue) 334 , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) { 335 } 336 337 void RenderPropertyAnimator::onAttached() { 338 if (!mHasStartValue 339 && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) { 340 setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)()); 341 } 342 } 343 344 void 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 360 void 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 372 uint32_t RenderPropertyAnimator::dirtyMask() { 373 return mPropertyAccess->dirtyMask; 374 } 375 376 float RenderPropertyAnimator::getValue(RenderNode* target) const { 377 return (target->properties().*mPropertyAccess->getter)(); 378 } 379 380 void RenderPropertyAnimator::setValue(RenderNode* target, float value) { 381 (target->animatorProperties().*mPropertyAccess->setter)(value); 382 } 383 384 /************************************************************ 385 * CanvasPropertyPrimitiveAnimator 386 ************************************************************/ 387 388 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator( 389 CanvasPropertyPrimitive* property, float finalValue) 390 : BaseRenderNodeAnimator(finalValue) 391 , mProperty(property) { 392 } 393 394 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const { 395 return mProperty->value; 396 } 397 398 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) { 399 mProperty->value = value; 400 } 401 402 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() { 403 return RenderNode::DISPLAY_LIST; 404 } 405 406 /************************************************************ 407 * CanvasPropertySkPaintAnimator 408 ************************************************************/ 409 410 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator( 411 CanvasPropertyPaint* property, PaintField field, float finalValue) 412 : BaseRenderNodeAnimator(finalValue) 413 , mProperty(property) 414 , mField(field) { 415 } 416 417 float 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 428 static 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 433 void 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 445 uint32_t CanvasPropertyPaintAnimator::dirtyMask() { 446 return RenderNode::DISPLAY_LIST; 447 } 448 449 RevealAnimator::RevealAnimator(int centerX, int centerY, 450 float startValue, float finalValue) 451 : BaseRenderNodeAnimator(finalValue) 452 , mCenterX(centerX) 453 , mCenterY(centerY) { 454 setStartValue(startValue); 455 } 456 457 float RevealAnimator::getValue(RenderNode* target) const { 458 return target->properties().getRevealClip().getRadius(); 459 } 460 461 void RevealAnimator::setValue(RenderNode* target, float value) { 462 target->animatorProperties().mutableRevealClip().set(true, 463 mCenterX, mCenterY, value); 464 } 465 466 uint32_t RevealAnimator::dirtyMask() { 467 return RenderNode::GENERIC; 468 } 469 470 } /* namespace uirenderer */ 471 } /* namespace android */ 472