1 /* 2 * Copyright (C) 2017 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 package com.android.server.wm; 18 19 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM; 20 import static com.android.server.wm.SurfaceAnimatorProto.ANIMATION_ADAPTER; 21 import static com.android.server.wm.SurfaceAnimatorProto.ANIMATION_START_DELAYED; 22 import static com.android.server.wm.SurfaceAnimatorProto.LEASH; 23 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 24 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 25 26 import android.annotation.IntDef; 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.util.Slog; 30 import android.util.proto.ProtoOutputStream; 31 import android.view.SurfaceControl; 32 import android.view.SurfaceControl.Transaction; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.internal.protolog.ProtoLogImpl; 36 import com.android.internal.protolog.common.ProtoLog; 37 38 import java.io.PrintWriter; 39 import java.io.StringWriter; 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.util.function.Supplier; 43 44 /** 45 * A class that can run animations on objects that have a set of child surfaces. We do this by 46 * reparenting all child surfaces of an object onto a new surface, called the "Leash". The Leash 47 * gets attached in the surface hierarchy where the the children were attached to. We then hand off 48 * the Leash to the component handling the animation, which is specified by the 49 * {@link AnimationAdapter}. When the animation is done animating, our callback to finish the 50 * animation will be invoked, at which we reparent the children back to the original parent. 51 */ 52 class SurfaceAnimator { 53 54 private static final String TAG = TAG_WITH_CLASS_NAME ? "SurfaceAnimator" : TAG_WM; 55 56 private final WindowManagerService mService; 57 private AnimationAdapter mAnimation; 58 private @AnimationType int mAnimationType; 59 60 @VisibleForTesting 61 SurfaceControl mLeash; 62 @VisibleForTesting 63 SurfaceFreezer.Snapshot mSnapshot; 64 @VisibleForTesting 65 final Animatable mAnimatable; 66 @VisibleForTesting 67 final OnAnimationFinishedCallback mInnerAnimationFinishedCallback; 68 69 /** 70 * Static callback to run on all animations started through this SurfaceAnimator 71 * when an animation on a Surface is finished or cancelled without restart. 72 */ 73 @VisibleForTesting 74 @Nullable 75 final OnAnimationFinishedCallback mStaticAnimationFinishedCallback; 76 77 /** 78 * Callback unique to each animation (i.e. AnimationAdapter). To be run when an animation on a 79 * Surface is finished or cancelled without restart. 80 */ 81 @Nullable 82 private OnAnimationFinishedCallback mSurfaceAnimationFinishedCallback; 83 84 /** 85 * The callback is triggered after the SurfaceAnimator sends a cancel call to the underlying 86 * AnimationAdapter. 87 * NOTE: Must be called wherever we call onAnimationCancelled on mAnimation. 88 */ 89 @Nullable 90 private Runnable mAnimationCancelledCallback; 91 92 private boolean mAnimationStartDelayed; 93 94 private boolean mAnimationFinished; 95 96 /** 97 * @param animatable The object to animate. 98 * @param staticAnimationFinishedCallback Callback to invoke when an animation has finished 99 * running. 100 */ SurfaceAnimator(Animatable animatable, @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback, WindowManagerService service)101 SurfaceAnimator(Animatable animatable, 102 @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback, 103 WindowManagerService service) { 104 mAnimatable = animatable; 105 mService = service; 106 mStaticAnimationFinishedCallback = staticAnimationFinishedCallback; 107 mInnerAnimationFinishedCallback = getFinishedCallback(staticAnimationFinishedCallback); 108 } 109 getFinishedCallback( @ullable OnAnimationFinishedCallback staticAnimationFinishedCallback)110 private OnAnimationFinishedCallback getFinishedCallback( 111 @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback) { 112 return (type, anim) -> { 113 synchronized (mService.mGlobalLock) { 114 final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim); 115 if (target != null) { 116 target.mInnerAnimationFinishedCallback.onAnimationFinished(type, anim); 117 return; 118 } 119 120 if (anim != mAnimation) { 121 return; 122 } 123 final Runnable resetAndInvokeFinish = () -> { 124 // We need to check again if the animation has been replaced with a new 125 // animation because the animatable may defer to finish. 126 if (anim != mAnimation) { 127 return; 128 } 129 final OnAnimationFinishedCallback animationFinishCallback = 130 mSurfaceAnimationFinishedCallback; 131 reset(mAnimatable.getSyncTransaction(), true /* destroyLeash */); 132 if (staticAnimationFinishedCallback != null) { 133 staticAnimationFinishedCallback.onAnimationFinished(type, anim); 134 } 135 if (animationFinishCallback != null) { 136 animationFinishCallback.onAnimationFinished(type, anim); 137 } 138 }; 139 // If both the Animatable and AnimationAdapter requests to be deferred, only the 140 // first one will be called. 141 if (!(mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish) 142 || anim.shouldDeferAnimationFinish(resetAndInvokeFinish))) { 143 resetAndInvokeFinish.run(); 144 } 145 mAnimationFinished = true; 146 } 147 }; 148 } 149 150 /** 151 * Starts an animation. 152 * 153 * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the 154 * component responsible for running the animation. It runs the animation with 155 * {@link AnimationAdapter#startAnimation} once the hierarchy with 156 * the Leash has been set up. 157 * @param hidden Whether the container holding the child surfaces is currently visible or not. 158 * This is important as it will start with the leash hidden or visible before 159 * handing it to the component that is responsible to run the animation. 160 * @param animationFinishedCallback The callback being triggered when the animation finishes. 161 * @param animationCancelledCallback The callback is triggered after the SurfaceAnimator sends a 162 * cancel call to the underlying AnimationAdapter. 163 * @param snapshotAnim The animation to run for the snapshot. {@code null} if there is no 164 * snapshot. 165 */ 166 void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, 167 @AnimationType int type, 168 @Nullable OnAnimationFinishedCallback animationFinishedCallback, 169 @Nullable Runnable animationCancelledCallback, 170 @Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) { 171 cancelAnimation(t, true /* restarting */, true /* forwardCancel */); 172 mAnimation = anim; 173 mAnimationType = type; 174 mSurfaceAnimationFinishedCallback = animationFinishedCallback; 175 mAnimationCancelledCallback = animationCancelledCallback; 176 final SurfaceControl surface = mAnimatable.getSurfaceControl(); 177 if (surface == null) { 178 Slog.w(TAG, "Unable to start animation, surface is null or no children."); 179 cancelAnimation(); 180 return; 181 } 182 mLeash = freezer != null ? freezer.takeLeashForAnimation() : null; 183 if (mLeash == null) { 184 mLeash = createAnimationLeash(mAnimatable, surface, t, type, 185 mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */, 186 0 /* y */, hidden, mService.mTransactionFactory); 187 mAnimatable.onAnimationLeashCreated(t, mLeash); 188 } 189 mAnimatable.onLeashAnimationStarting(t, mLeash); 190 if (mAnimationStartDelayed) { 191 ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable); 192 return; 193 } 194 mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback); 195 if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) { 196 StringWriter sw = new StringWriter(); 197 PrintWriter pw = new PrintWriter(sw); 198 mAnimation.dump(pw, ""); 199 ProtoLog.d(WM_DEBUG_ANIM, "Animation start for %s, anim=%s", mAnimatable, sw); 200 } 201 if (snapshotAnim != null) { 202 mSnapshot = freezer.takeSnapshotForAnimation(); 203 if (mSnapshot == null) { 204 Slog.e(TAG, "No snapshot target to start animation on for " + mAnimatable); 205 return; 206 } 207 mSnapshot.startAnimation(t, snapshotAnim, type); 208 } 209 } 210 211 void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, 212 @AnimationType int type) { 213 startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */, 214 null /* animationCancelledCallback */, null /* snapshotAnim */, null /* freezer */); 215 } 216 217 /** 218 * Begins with delaying all animations to start. Any subsequent call to {@link #startAnimation} 219 * will not start the animation until {@link #endDelayingAnimationStart} is called. When an 220 * animation start is being delayed, the animator is considered animating already. 221 */ 222 void startDelayingAnimationStart() { 223 224 // We only allow delaying animation start we are not currently animating 225 if (!isAnimating()) { 226 mAnimationStartDelayed = true; 227 } 228 } 229 230 /** 231 * See {@link #startDelayingAnimationStart}. 232 */ 233 void endDelayingAnimationStart() { 234 final boolean delayed = mAnimationStartDelayed; 235 mAnimationStartDelayed = false; 236 if (delayed && mAnimation != null) { 237 mAnimation.startAnimation(mLeash, mAnimatable.getSyncTransaction(), 238 mAnimationType, mInnerAnimationFinishedCallback); 239 mAnimatable.commitPendingTransaction(); 240 } 241 } 242 243 /** 244 * @return Whether we are currently running an animation, or we have a pending animation that 245 * is waiting to be started with {@link #endDelayingAnimationStart} 246 */ 247 boolean isAnimating() { 248 return mAnimation != null; 249 } 250 251 @AnimationType 252 int getAnimationType() { 253 return mAnimationType; 254 } 255 256 /** 257 * @return The current animation spec if we are running an animation, or {@code null} otherwise. 258 */ 259 AnimationAdapter getAnimation() { 260 return mAnimation; 261 } 262 263 /** 264 * Cancels any currently running animation. 265 */ 266 void cancelAnimation() { 267 cancelAnimation(mAnimatable.getSyncTransaction(), false /* restarting */, 268 true /* forwardCancel */); 269 mAnimatable.commitPendingTransaction(); 270 } 271 272 /** 273 * Sets the layer of the surface. 274 * <p> 275 * When the layer of the surface needs to be adjusted, we need to set it on the leash if the 276 * surface is reparented to the leash. This method takes care of that. 277 */ 278 void setLayer(Transaction t, int layer) { 279 t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer); 280 } 281 282 /** 283 * Sets the surface to be relatively layered. 284 * 285 * @see #setLayer 286 */ 287 void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { 288 t.setRelativeLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), relativeTo, layer); 289 } 290 291 /** 292 * Reparents the surface. 293 * 294 * @see #setLayer 295 */ 296 void reparent(Transaction t, SurfaceControl newParent) { 297 t.reparent(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), newParent); 298 } 299 300 /** 301 * @return True if the surface is attached to the leash; false otherwise. 302 */ 303 boolean hasLeash() { 304 return mLeash != null; 305 } 306 307 void transferAnimation(SurfaceAnimator from) { 308 if (from.mLeash == null) { 309 return; 310 } 311 final SurfaceControl surface = mAnimatable.getSurfaceControl(); 312 final SurfaceControl parent = mAnimatable.getAnimationLeashParent(); 313 if (surface == null || parent == null) { 314 Slog.w(TAG, "Unable to transfer animation, surface or parent is null"); 315 cancelAnimation(); 316 return; 317 } else if (from.mAnimationFinished) { 318 Slog.w(TAG, "Unable to transfer animation, because " + from + " animation is finished"); 319 return; 320 } 321 endDelayingAnimationStart(); 322 final Transaction t = mAnimatable.getSyncTransaction(); 323 cancelAnimation(t, true /* restarting */, true /* forwardCancel */); 324 mLeash = from.mLeash; 325 mAnimation = from.mAnimation; 326 mAnimationType = from.mAnimationType; 327 mSurfaceAnimationFinishedCallback = from.mSurfaceAnimationFinishedCallback; 328 mAnimationCancelledCallback = from.mAnimationCancelledCallback; 329 330 // Cancel source animation, but don't let animation runner cancel the animation. 331 from.cancelAnimation(t, false /* restarting */, false /* forwardCancel */); 332 t.reparent(surface, mLeash); 333 t.reparent(mLeash, parent); 334 mAnimatable.onAnimationLeashCreated(t, mLeash); 335 mService.mAnimationTransferMap.put(mAnimation, this); 336 } 337 338 boolean isAnimationStartDelayed() { 339 return mAnimationStartDelayed; 340 } 341 342 /** 343 * Cancels the animation, and resets the leash. 344 * 345 * @param t The transaction to use for all cancelling surface operations. 346 * @param restarting Whether we are restarting the animation. 347 * @param forwardCancel Whether to forward the cancel signal to the adapter executing the 348 * animation. This will be set to false when just transferring an animation 349 * to another animator. 350 */ 351 private void cancelAnimation(Transaction t, boolean restarting, boolean forwardCancel) { 352 ProtoLog.i(WM_DEBUG_ANIM, "Cancelling animation restarting=%b for %s", 353 restarting, mAnimatable); 354 final SurfaceControl leash = mLeash; 355 final AnimationAdapter animation = mAnimation; 356 final @AnimationType int animationType = mAnimationType; 357 final OnAnimationFinishedCallback animationFinishedCallback = 358 mSurfaceAnimationFinishedCallback; 359 final Runnable animationCancelledCallback = mAnimationCancelledCallback; 360 final SurfaceFreezer.Snapshot snapshot = mSnapshot; 361 reset(t, false); 362 if (animation != null) { 363 if (!mAnimationStartDelayed && forwardCancel) { 364 animation.onAnimationCancelled(leash); 365 if (animationCancelledCallback != null) { 366 animationCancelledCallback.run(); 367 } 368 } 369 if (!restarting) { 370 if (mStaticAnimationFinishedCallback != null) { 371 mStaticAnimationFinishedCallback.onAnimationFinished(animationType, animation); 372 } 373 if (animationFinishedCallback != null) { 374 animationFinishedCallback.onAnimationFinished(animationType, animation); 375 } 376 } 377 } 378 379 if (forwardCancel) { 380 if (snapshot != null) { 381 snapshot.cancelAnimation(t, false /* restarting */); 382 } 383 if (leash != null) { 384 t.remove(leash); 385 mService.scheduleAnimationLocked(); 386 } 387 } 388 389 if (!restarting) { 390 mAnimationStartDelayed = false; 391 } 392 } 393 394 private void reset(Transaction t, boolean destroyLeash) { 395 mService.mAnimationTransferMap.remove(mAnimation); 396 mAnimation = null; 397 mSurfaceAnimationFinishedCallback = null; 398 mAnimationType = ANIMATION_TYPE_NONE; 399 final SurfaceFreezer.Snapshot snapshot = mSnapshot; 400 mSnapshot = null; 401 if (snapshot != null) { 402 // Reset the mSnapshot reference before calling the callback to prevent circular reset. 403 snapshot.cancelAnimation(t, !destroyLeash); 404 } 405 if (mLeash == null) { 406 return; 407 } 408 SurfaceControl leash = mLeash; 409 mLeash = null; 410 final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash); 411 mAnimationFinished = false; 412 if (scheduleAnim) { 413 mService.scheduleAnimationLocked(); 414 } 415 } 416 417 static boolean removeLeash(Transaction t, Animatable animatable, @NonNull SurfaceControl leash, 418 boolean destroy) { 419 boolean scheduleAnim = false; 420 final SurfaceControl surface = animatable.getSurfaceControl(); 421 final SurfaceControl parent = animatable.getParentSurfaceControl(); 422 final SurfaceControl curAnimationLeash = animatable.getAnimationLeash(); 423 424 // If the surface was destroyed or the leash is invalid, we don't care to reparent it back. 425 // Note that we also set this variable to true even if the parent isn't valid anymore, in 426 // order to ensure onAnimationLeashLost still gets called in this case. 427 // If the animation leash is set, and it is different from the removing leash, it means the 428 // surface now has a new animation surface. We don't want to reparent for that. 429 final boolean reparent = surface != null && (curAnimationLeash == null 430 || curAnimationLeash.equals(leash)); 431 if (reparent) { 432 ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to original parent: %s for %s", 433 parent, animatable); 434 // We shouldn't really need these isValid checks but we do 435 // b/130364451 436 if (surface.isValid() && parent != null && parent.isValid()) { 437 t.reparent(surface, parent); 438 scheduleAnim = true; 439 } 440 } 441 if (destroy) { 442 t.remove(leash); 443 scheduleAnim = true; 444 } 445 446 if (reparent) { 447 // Make sure to inform the animatable after the surface was reparented (or reparent 448 // wasn't possible, but we still need to invoke the callback) 449 animatable.onAnimationLeashLost(t); 450 scheduleAnim = true; 451 } 452 return scheduleAnim; 453 } 454 455 static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface, 456 Transaction t, @AnimationType int type, int width, int height, int x, int y, 457 boolean hidden, Supplier<Transaction> transactionFactory) { 458 ProtoLog.i(WM_DEBUG_ANIM, "Reparenting to leash for %s", animatable); 459 final SurfaceControl.Builder builder = animatable.makeAnimationLeash() 460 .setParent(animatable.getAnimationLeashParent()) 461 .setName(surface + " - animation-leash of " + animationTypeToString(type)) 462 // TODO(b/151665759) Defer reparent calls 463 // We want the leash to be visible immediately because the transaction which shows 464 // the leash may be deferred but the reparent will not. This will cause the leashed 465 // surface to be invisible until the deferred transaction is applied. If this 466 // doesn't work, you will can see the 2/3 button nav bar flicker during seamless 467 // rotation. 468 .setHidden(hidden) 469 .setEffectLayer() 470 .setCallsite("SurfaceAnimator.createAnimationLeash"); 471 final SurfaceControl leash = builder.build(); 472 t.setWindowCrop(leash, width, height); 473 t.setPosition(leash, x, y); 474 t.show(leash); 475 t.setAlpha(leash, hidden ? 0 : 1); 476 477 t.reparent(surface, leash); 478 return leash; 479 } 480 481 /** 482 * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link 483 * com.android.server.wm.SurfaceAnimatorProto}. 484 * 485 * @param proto Stream to write the SurfaceAnimator object to. 486 * @param fieldId Field Id of the SurfaceAnimator as defined in the parent message. 487 * @hide 488 */ 489 void dumpDebug(ProtoOutputStream proto, long fieldId) { 490 final long token = proto.start(fieldId); 491 if (mAnimation != null) { 492 mAnimation.dumpDebug(proto, ANIMATION_ADAPTER); 493 } 494 if (mLeash != null) { 495 mLeash.dumpDebug(proto, LEASH); 496 } 497 proto.write(ANIMATION_START_DELAYED, mAnimationStartDelayed); 498 proto.end(token); 499 } 500 501 void dump(PrintWriter pw, String prefix) { 502 pw.print(prefix); pw.print("mLeash="); pw.print(mLeash); 503 pw.print(" mAnimationType=" + animationTypeToString(mAnimationType)); 504 pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : ""); 505 pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation); 506 if (mAnimation != null) { 507 mAnimation.dump(pw, prefix + " "); 508 } 509 } 510 511 512 /** 513 * No animation is specified. 514 * @hide 515 */ 516 public static final int ANIMATION_TYPE_NONE = 0; 517 518 /** 519 * Animation for an app transition. 520 * @hide 521 */ 522 public static final int ANIMATION_TYPE_APP_TRANSITION = 1; 523 524 /** 525 * Animation for screen rotation. 526 * @hide 527 */ 528 public static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1; 529 530 /** 531 * Animation for dimming. 532 * @hide 533 */ 534 public static final int ANIMATION_TYPE_DIMMER = 1 << 2; 535 536 /** 537 * Animation for recent apps. 538 * @hide 539 */ 540 public static final int ANIMATION_TYPE_RECENTS = 1 << 3; 541 542 /** 543 * Animation for a {@link WindowState} without animating the activity. 544 * @hide 545 */ 546 public static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4; 547 548 /** 549 * Animation to control insets. This is actually not an animation, but is used to give the 550 * client a leash over the system window causing insets. 551 * @hide 552 */ 553 public static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5; 554 555 /** 556 * Animation applied to a non-app window token, e.g. a fixed rotation transform. 557 * @hide 558 */ 559 public static final int ANIMATION_TYPE_TOKEN_TRANSFORM = 1 << 6; 560 561 /** 562 * Animation when a reveal starting window animation is applied to app window. 563 * @hide 564 */ 565 public static final int ANIMATION_TYPE_STARTING_REVEAL = 1 << 7; 566 567 /** 568 * Animation when a back gesture animation is applied to a window container. 569 * @hide 570 */ 571 public static final int ANIMATION_TYPE_PREDICT_BACK = 1 << 8; 572 /** 573 * Bitmask to include all animation types. This is NOT an {@link AnimationType} 574 * @hide 575 */ 576 public static final int ANIMATION_TYPE_ALL = -1; 577 578 /** 579 * The type of the animation. 580 * @hide 581 */ 582 @IntDef(flag = true, prefix = { "ANIMATION_TYPE_" }, value = { 583 ANIMATION_TYPE_NONE, 584 ANIMATION_TYPE_APP_TRANSITION, 585 ANIMATION_TYPE_SCREEN_ROTATION, 586 ANIMATION_TYPE_DIMMER, 587 ANIMATION_TYPE_RECENTS, 588 ANIMATION_TYPE_WINDOW_ANIMATION, 589 ANIMATION_TYPE_INSETS_CONTROL, 590 ANIMATION_TYPE_TOKEN_TRANSFORM, 591 ANIMATION_TYPE_STARTING_REVEAL, 592 ANIMATION_TYPE_PREDICT_BACK 593 }) 594 @Retention(RetentionPolicy.SOURCE) 595 @interface AnimationType {} 596 597 /** 598 * Converts {@link AnimationType} to String. 599 */ 600 static String animationTypeToString(@AnimationType int type) { 601 switch (type) { 602 case ANIMATION_TYPE_NONE: return "none"; 603 case ANIMATION_TYPE_APP_TRANSITION: return "app_transition"; 604 case ANIMATION_TYPE_SCREEN_ROTATION: return "screen_rotation"; 605 case ANIMATION_TYPE_DIMMER: return "dimmer"; 606 case ANIMATION_TYPE_RECENTS: return "recents_animation"; 607 case ANIMATION_TYPE_WINDOW_ANIMATION: return "window_animation"; 608 case ANIMATION_TYPE_INSETS_CONTROL: return "insets_animation"; 609 case ANIMATION_TYPE_TOKEN_TRANSFORM: return "token_transform"; 610 case ANIMATION_TYPE_STARTING_REVEAL: return "starting_reveal"; 611 case ANIMATION_TYPE_PREDICT_BACK: return "predict_back"; 612 default: return "unknown type:" + type; 613 } 614 } 615 616 /** 617 * Callback to be passed into {@link AnimationAdapter#startAnimation} to be invoked by the 618 * component that is running the animation when the animation is finished. 619 */ 620 interface OnAnimationFinishedCallback { 621 void onAnimationFinished(@AnimationType int type, AnimationAdapter anim); 622 } 623 624 /** 625 * Interface to be animated by {@link SurfaceAnimator}. 626 */ 627 interface Animatable { 628 629 /** 630 * Use this method instead of {@link #getPendingTransaction()} if the transaction should be 631 * synchronized with the client. 632 */ 633 @NonNull Transaction getSyncTransaction(); 634 635 /** 636 * @return The pending transaction that will be committed in the next frame. 637 */ 638 @NonNull Transaction getPendingTransaction(); 639 640 /** 641 * Schedules a commit of the pending transaction. 642 */ 643 void commitPendingTransaction(); 644 645 /** 646 * Called when the animation leash is created. Note that this is also called by 647 * {@link SurfaceFreezer}, so this doesn't mean we're about to start animating. 648 * 649 * @param t The transaction to use to apply any necessary changes. 650 * @param leash The leash that was created. 651 */ 652 void onAnimationLeashCreated(Transaction t, SurfaceControl leash); 653 654 /** 655 * Called when the animator is about to start animating the leash. 656 * 657 * @param t The transaction to use to apply any necessary changes. 658 * @param leash The leash that was created. 659 */ 660 default void onLeashAnimationStarting(Transaction t, SurfaceControl leash) { } 661 662 /** 663 * Called when the leash is being destroyed, or when the leash is being transferred to 664 * another SurfaceAnimator. 665 * 666 * @param t The transaction to use to apply any necessary changes. 667 */ 668 void onAnimationLeashLost(Transaction t); 669 670 /** 671 * Gets the last created animation leash that has not lost yet. 672 */ 673 @Nullable 674 default SurfaceControl getAnimationLeash() { 675 return null; 676 } 677 678 /** 679 * @return A new surface to be used for the animation leash, inserted at the correct 680 * position in the hierarchy. 681 */ 682 SurfaceControl.Builder makeAnimationLeash(); 683 684 /** 685 * @return The parent that should be used for the animation leash. 686 */ 687 @Nullable SurfaceControl getAnimationLeashParent(); 688 689 /** 690 * @return The surface of the object to be animated. 691 * This SurfaceControl must be valid if non-null. 692 */ 693 @Nullable SurfaceControl getSurfaceControl(); 694 695 /** 696 * @return The parent of the surface object to be animated. 697 * This SurfaceControl must be valid if non-null. 698 */ 699 @Nullable SurfaceControl getParentSurfaceControl(); 700 701 /** 702 * @return The width of the surface to be animated. 703 */ 704 int getSurfaceWidth(); 705 706 /** 707 * @return The height of the surface to be animated. 708 */ 709 int getSurfaceHeight(); 710 711 /** 712 * Gets called when the animation is about to finish and gives the client the opportunity to 713 * defer finishing the animation, i.e. it keeps the leash around until the client calls 714 * {@link #cancelAnimation}. 715 * <p> 716 * {@link AnimationAdapter} has a similar method which is called only if this method returns 717 * false. This mean that if both this {@link Animatable} and the {@link AnimationAdapter} 718 * request to be deferred, this method is the sole responsible to call 719 * endDeferFinishCallback. On the other hand, the animation finish might still be deferred 720 * if this method return false and the one from the {@link AnimationAdapter} returns true. 721 * 722 * @param endDeferFinishCallback The callback to call when defer finishing should be ended. 723 * @return Whether the client would like to defer the animation finish. 724 */ 725 default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { 726 return false; 727 } 728 } 729 } 730