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 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {} 50 51 void BaseRenderNodeAnimator::checkMutable() { 52 // Should be impossible to hit as the Java-side also has guards for this 53 LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted, 54 "Animator has already been started!"); 55 } 56 57 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) { 58 checkMutable(); 59 mInterpolator.reset(interpolator); 60 } 61 62 void BaseRenderNodeAnimator::setStartValue(float value) { 63 checkMutable(); 64 doSetStartValue(value); 65 } 66 67 void BaseRenderNodeAnimator::doSetStartValue(float value) { 68 mFromValue = value; 69 mDeltaValue = (mFinalValue - mFromValue); 70 mHasStartValue = true; 71 } 72 73 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) { 74 checkMutable(); 75 mDuration = duration; 76 } 77 78 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) { 79 checkMutable(); 80 mStartDelay = startDelay; 81 } 82 83 void BaseRenderNodeAnimator::attach(RenderNode* target) { 84 mStagingTarget = target; 85 onAttached(); 86 } 87 88 void BaseRenderNodeAnimator::start() { 89 mStagingPlayState = PlayState::Running; 90 mStagingRequests.push_back(Request::Start); 91 onStagingPlayStateChanged(); 92 } 93 94 void BaseRenderNodeAnimator::cancel() { 95 mStagingPlayState = PlayState::Finished; 96 mStagingRequests.push_back(Request::Cancel); 97 onStagingPlayStateChanged(); 98 } 99 100 void BaseRenderNodeAnimator::reset() { 101 mStagingPlayState = PlayState::Finished; 102 mStagingRequests.push_back(Request::Reset); 103 onStagingPlayStateChanged(); 104 } 105 106 void BaseRenderNodeAnimator::reverse() { 107 mStagingPlayState = PlayState::Reversing; 108 mStagingRequests.push_back(Request::Reverse); 109 onStagingPlayStateChanged(); 110 } 111 112 void BaseRenderNodeAnimator::end() { 113 mStagingPlayState = PlayState::Finished; 114 mStagingRequests.push_back(Request::End); 115 onStagingPlayStateChanged(); 116 } 117 118 void BaseRenderNodeAnimator::resolveStagingRequest(Request request) { 119 switch (request) { 120 case Request::Start: 121 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) 122 ? mPlayTime 123 : 0; 124 mPlayState = PlayState::Running; 125 mPendingActionUponFinish = Action::None; 126 break; 127 case Request::Reverse: 128 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) 129 ? mPlayTime 130 : 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 " with frame time %" PRId64 227 " 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, 319 &RenderProperties::setTranslationX}, 320 {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, 321 &RenderProperties::setTranslationY}, 322 {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ, 323 &RenderProperties::setTranslationZ}, 324 {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX}, 325 {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY}, 326 {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation}, 327 {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX}, 328 {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY}, 329 {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX}, 330 {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY}, 331 {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ}, 332 {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha}, 333 }; 334 335 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue) 336 : BaseRenderNodeAnimator(finalValue), mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {} 337 338 void RenderPropertyAnimator::onAttached() { 339 if (!mHasStartValue && 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(CanvasPropertyPrimitive* property, 389 float finalValue) 390 : BaseRenderNodeAnimator(finalValue), mProperty(property) {} 391 392 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const { 393 return mProperty->value; 394 } 395 396 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) { 397 mProperty->value = value; 398 } 399 400 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() { 401 return RenderNode::DISPLAY_LIST; 402 } 403 404 /************************************************************ 405 * CanvasPropertySkPaintAnimator 406 ************************************************************/ 407 408 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, 409 PaintField field, float finalValue) 410 : BaseRenderNodeAnimator(finalValue), mProperty(property), mField(field) {} 411 412 float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const { 413 switch (mField) { 414 case STROKE_WIDTH: 415 return mProperty->value.getStrokeWidth(); 416 case ALPHA: 417 return mProperty->value.getAlpha(); 418 } 419 LOG_ALWAYS_FATAL("Unknown field %d", (int)mField); 420 return -1; 421 } 422 423 static uint8_t to_uint8(float value) { 424 int c = (int)(value + .5f); 425 return static_cast<uint8_t>(c < 0 ? 0 : c > 255 ? 255 : c); 426 } 427 428 void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) { 429 switch (mField) { 430 case STROKE_WIDTH: 431 mProperty->value.setStrokeWidth(value); 432 return; 433 case ALPHA: 434 mProperty->value.setAlpha(to_uint8(value)); 435 return; 436 } 437 LOG_ALWAYS_FATAL("Unknown field %d", (int)mField); 438 } 439 440 uint32_t CanvasPropertyPaintAnimator::dirtyMask() { 441 return RenderNode::DISPLAY_LIST; 442 } 443 444 RevealAnimator::RevealAnimator(int centerX, int centerY, float startValue, float finalValue) 445 : BaseRenderNodeAnimator(finalValue), mCenterX(centerX), mCenterY(centerY) { 446 setStartValue(startValue); 447 } 448 449 float RevealAnimator::getValue(RenderNode* target) const { 450 return target->properties().getRevealClip().getRadius(); 451 } 452 453 void RevealAnimator::setValue(RenderNode* target, float value) { 454 target->animatorProperties().mutableRevealClip().set(true, mCenterX, mCenterY, value); 455 } 456 457 uint32_t RevealAnimator::dirtyMask() { 458 return RenderNode::GENERIC; 459 } 460 461 } /* namespace uirenderer */ 462 } /* namespace android */ 463