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