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