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 277void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) { 278 if (mPlayState < PlayState::Finished) { 279 mPlayState = PlayState::Finished; 280 callOnFinishedListener(context); 281 } 282} 283 284void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) { 285 if (mListener.get()) { 286 context.callOnFinished(this, mListener.get()); 287 } 288} 289 290/************************************************************ 291 * RenderPropertyAnimator 292 ************************************************************/ 293 294struct RenderPropertyAnimator::PropertyAccessors { 295 RenderNode::DirtyPropertyMask dirtyMask; 296 GetFloatProperty getter; 297 SetFloatProperty setter; 298}; 299 300// Maps RenderProperty enum to accessors 301const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = { 302 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX }, 303 {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY }, 304 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ }, 305 {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX }, 306 {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY }, 307 {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation }, 308 {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX }, 309 {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY }, 310 {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX }, 311 {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY }, 312 {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ }, 313 {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha }, 314}; 315 316RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue) 317 : BaseRenderNodeAnimator(finalValue) 318 , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) { 319} 320 321void RenderPropertyAnimator::onAttached() { 322 if (!mHasStartValue 323 && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) { 324 setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)()); 325 } 326} 327 328void RenderPropertyAnimator::onStagingPlayStateChanged() { 329 if (mStagingPlayState == PlayState::Running) { 330 if (mStagingTarget) { 331 (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue()); 332 } else { 333 // In the case of start delay where stagingTarget has been sync'ed over and null'ed 334 // we delay the properties update to push staging. 335 mShouldUpdateStagingProperties = true; 336 } 337 } else if (mStagingPlayState == PlayState::Finished) { 338 // We're being canceled, so make sure that whatever values the UI thread 339 // is observing for us is pushed over 340 mShouldSyncPropertyFields = true; 341 } 342} 343 344void RenderPropertyAnimator::onPushStaging() { 345 if (mShouldUpdateStagingProperties) { 346 (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue()); 347 mShouldUpdateStagingProperties = false; 348 } 349 350 if (mShouldSyncPropertyFields) { 351 mTarget->setPropertyFieldsDirty(dirtyMask()); 352 mShouldSyncPropertyFields = false; 353 } 354} 355 356uint32_t RenderPropertyAnimator::dirtyMask() { 357 return mPropertyAccess->dirtyMask; 358} 359 360float RenderPropertyAnimator::getValue(RenderNode* target) const { 361 return (target->properties().*mPropertyAccess->getter)(); 362} 363 364void RenderPropertyAnimator::setValue(RenderNode* target, float value) { 365 (target->animatorProperties().*mPropertyAccess->setter)(value); 366} 367 368/************************************************************ 369 * CanvasPropertyPrimitiveAnimator 370 ************************************************************/ 371 372CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator( 373 CanvasPropertyPrimitive* property, float finalValue) 374 : BaseRenderNodeAnimator(finalValue) 375 , mProperty(property) { 376} 377 378float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const { 379 return mProperty->value; 380} 381 382void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) { 383 mProperty->value = value; 384} 385 386uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() { 387 return RenderNode::DISPLAY_LIST; 388} 389 390/************************************************************ 391 * CanvasPropertySkPaintAnimator 392 ************************************************************/ 393 394CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator( 395 CanvasPropertyPaint* property, PaintField field, float finalValue) 396 : BaseRenderNodeAnimator(finalValue) 397 , mProperty(property) 398 , mField(field) { 399} 400 401float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const { 402 switch (mField) { 403 case STROKE_WIDTH: 404 return mProperty->value.getStrokeWidth(); 405 case ALPHA: 406 return mProperty->value.getAlpha(); 407 } 408 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 409 return -1; 410} 411 412static uint8_t to_uint8(float value) { 413 int c = (int) (value + .5f); 414 return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c ); 415} 416 417void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) { 418 switch (mField) { 419 case STROKE_WIDTH: 420 mProperty->value.setStrokeWidth(value); 421 return; 422 case ALPHA: 423 mProperty->value.setAlpha(to_uint8(value)); 424 return; 425 } 426 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 427} 428 429uint32_t CanvasPropertyPaintAnimator::dirtyMask() { 430 return RenderNode::DISPLAY_LIST; 431} 432 433RevealAnimator::RevealAnimator(int centerX, int centerY, 434 float startValue, float finalValue) 435 : BaseRenderNodeAnimator(finalValue) 436 , mCenterX(centerX) 437 , mCenterY(centerY) { 438 setStartValue(startValue); 439} 440 441float RevealAnimator::getValue(RenderNode* target) const { 442 return target->properties().getRevealClip().getRadius(); 443} 444 445void RevealAnimator::setValue(RenderNode* target, float value) { 446 target->animatorProperties().mutableRevealClip().set(true, 447 mCenterX, mCenterY, value); 448} 449 450uint32_t RevealAnimator::dirtyMask() { 451 return RenderNode::GENERIC; 452} 453 454} /* namespace uirenderer */ 455} /* namespace android */ 456