1 /*
2  * Copyright (C) 2020 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 android.window;
18 
19 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
20 import static android.app.ActivityOptions.ANIM_CUSTOM;
21 import static android.app.ActivityOptions.ANIM_FROM_STYLE;
22 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
23 import static android.app.ActivityOptions.ANIM_SCALE_UP;
24 import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
25 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
26 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
27 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
28 import static android.view.Display.INVALID_DISPLAY;
29 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
30 import static android.view.WindowManager.TRANSIT_CHANGE;
31 import static android.view.WindowManager.TRANSIT_CLOSE;
32 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
33 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
34 import static android.view.WindowManager.TRANSIT_NONE;
35 import static android.view.WindowManager.TRANSIT_OPEN;
36 import static android.view.WindowManager.TRANSIT_TO_BACK;
37 import static android.view.WindowManager.TRANSIT_TO_FRONT;
38 import static android.view.WindowManager.TransitionFlags;
39 import static android.view.WindowManager.TransitionType;
40 import static android.view.WindowManager.transitTypeToString;
41 
42 import android.annotation.AnimRes;
43 import android.annotation.ColorInt;
44 import android.annotation.IntDef;
45 import android.annotation.NonNull;
46 import android.annotation.Nullable;
47 import android.app.ActivityManager;
48 import android.content.ComponentName;
49 import android.graphics.Point;
50 import android.graphics.Rect;
51 import android.hardware.HardwareBuffer;
52 import android.os.Parcel;
53 import android.os.Parcelable;
54 import android.view.Surface;
55 import android.view.SurfaceControl;
56 import android.view.WindowManager;
57 
58 import com.android.window.flags.Flags;
59 
60 import java.lang.annotation.Retention;
61 import java.lang.annotation.RetentionPolicy;
62 import java.util.ArrayList;
63 import java.util.List;
64 import java.util.Objects;
65 
66 /**
67  * Used to communicate information about what is changing during a transition to a TransitionPlayer.
68  * @hide
69  */
70 public final class TransitionInfo implements Parcelable {
71     private static final String TAG = "TransitionInfo";
72 
73     /**
74      * Modes are only a sub-set of all the transit-types since they are per-container
75      * @hide
76      */
77     @Retention(RetentionPolicy.SOURCE)
78     @IntDef(prefix = { "TRANSIT_" }, value = {
79             TRANSIT_NONE,
80             TRANSIT_OPEN,
81             TRANSIT_CLOSE,
82             // Note: to_front/to_back really mean show/hide respectively at the container level.
83             TRANSIT_TO_FRONT,
84             TRANSIT_TO_BACK,
85             TRANSIT_CHANGE
86     })
87     public @interface TransitionMode {}
88 
89     /** No flags */
90     public static final int FLAG_NONE = 0;
91 
92     /** The container shows the wallpaper behind it. */
93     public static final int FLAG_SHOW_WALLPAPER = 1;
94 
95     /** The container IS the wallpaper. */
96     public static final int FLAG_IS_WALLPAPER = 1 << 1;
97 
98     /** The container is translucent. */
99     public static final int FLAG_TRANSLUCENT = 1 << 2;
100 
101     // TODO: remove when starting-window is moved to Task
102     /** The container is the recipient of a transferred starting-window */
103     public static final int FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT = 1 << 3;
104 
105     /** The container has voice session. */
106     public static final int FLAG_IS_VOICE_INTERACTION = 1 << 4;
107 
108     /** The container is the display. */
109     public static final int FLAG_IS_DISPLAY = 1 << 5;
110 
111     // TODO(b/194540864): Once we can include all windows in transition, then replace this with
112     // something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations.
113     /**
114      * Only for IS_DISPLAY containers. Is set if the display has system alert windows. This is
115      * used to prevent seamless rotation.
116      */
117     public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
118 
119     /** The container is an input-method window. */
120     public static final int FLAG_IS_INPUT_METHOD = 1 << 8;
121 
122     /** The container is in a Task with embedded activity. */
123     public static final int FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY = 1 << 9;
124 
125     /** The container fills its parent Task before and after the transition. */
126     public static final int FLAG_FILLS_TASK = 1 << 10;
127 
128     /** The container is going to show IME on its task after the transition. */
129     public static final int FLAG_WILL_IME_SHOWN = 1 << 11;
130 
131     /** The container attaches owner profile thumbnail for cross profile animation. */
132     public static final int FLAG_CROSS_PROFILE_OWNER_THUMBNAIL = 1 << 12;
133 
134     /** The container attaches work profile thumbnail for cross profile animation. */
135     public static final int FLAG_CROSS_PROFILE_WORK_THUMBNAIL = 1 << 13;
136 
137     /**
138      * Whether the window is covered by an app starting window. This is different from
139      * {@link #FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT} which is only set on the Activity window
140      * that contains the starting window.
141      */
142     public static final int FLAG_IS_BEHIND_STARTING_WINDOW = 1 << 14;
143 
144     /** This change happened underneath something else. */
145     public static final int FLAG_IS_OCCLUDED = 1 << 15;
146 
147     /** The container is a system window, excluding wallpaper and input-method. */
148     public static final int FLAG_IS_SYSTEM_WINDOW = 1 << 16;
149 
150     /** The window was animated by back gesture. */
151     public static final int FLAG_BACK_GESTURE_ANIMATED = 1 << 17;
152 
153     /** The window should have no animation (by policy). */
154     public static final int FLAG_NO_ANIMATION = 1 << 18;
155 
156     /** The task is launching behind home. */
157     public static final int FLAG_TASK_LAUNCHING_BEHIND = 1 << 19;
158 
159     /** The task became the top-most task even if it didn't change visibility. */
160     public static final int FLAG_MOVED_TO_TOP = 1 << 20;
161 
162     /**
163      * This transition must be the only transition when it starts (ie. it must wait for all other
164      * transition animations to finish).
165      */
166     public static final int FLAG_SYNC = 1 << 21;
167 
168     /** This change represents its start configuration for the duration of the animation. */
169     public static final int FLAG_CONFIG_AT_END = 1 << 22;
170 
171     /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
172     public static final int FLAG_FIRST_CUSTOM = 1 << 23;
173 
174     /** The change belongs to a window that won't contain activities. */
175     public static final int FLAGS_IS_NON_APP_WINDOW =
176             FLAG_IS_WALLPAPER | FLAG_IS_INPUT_METHOD | FLAG_IS_SYSTEM_WINDOW;
177 
178     /** The change will not participate in the animation. */
179     public static final int FLAGS_IS_OCCLUDED_NO_ANIMATION = FLAG_IS_OCCLUDED | FLAG_NO_ANIMATION;
180 
181     /** @hide */
182     @Retention(RetentionPolicy.SOURCE)
183     @IntDef(prefix = { "FLAG_" }, value = {
184             FLAG_NONE,
185             FLAG_SHOW_WALLPAPER,
186             FLAG_IS_WALLPAPER,
187             FLAG_TRANSLUCENT,
188             FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT,
189             FLAG_IS_VOICE_INTERACTION,
190             FLAG_IS_DISPLAY,
191             FLAG_DISPLAY_HAS_ALERT_WINDOWS,
192             FLAG_IS_INPUT_METHOD,
193             FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY,
194             FLAG_FILLS_TASK,
195             FLAG_WILL_IME_SHOWN,
196             FLAG_CROSS_PROFILE_OWNER_THUMBNAIL,
197             FLAG_CROSS_PROFILE_WORK_THUMBNAIL,
198             FLAG_IS_BEHIND_STARTING_WINDOW,
199             FLAG_IS_OCCLUDED,
200             FLAG_IS_SYSTEM_WINDOW,
201             FLAG_BACK_GESTURE_ANIMATED,
202             FLAG_NO_ANIMATION,
203             FLAG_TASK_LAUNCHING_BEHIND,
204             FLAG_MOVED_TO_TOP,
205             FLAG_SYNC,
206             FLAG_CONFIG_AT_END,
207             FLAG_FIRST_CUSTOM
208     }, flag = true)
209     public @interface ChangeFlags {}
210 
211     private final @TransitionType int mType;
212     private @TransitionFlags int mFlags;
213     private int mTrack = 0;
214     private final ArrayList<Change> mChanges = new ArrayList<>();
215     private final ArrayList<Root> mRoots = new ArrayList<>();
216 
217     // TODO(b/327332488): Clean-up usages after the flag is fully enabled.
218     @Deprecated
219     private AnimationOptions mOptions;
220 
221     /** This is only a BEST-EFFORT id used for log correlation. DO NOT USE for any real work! */
222     private int mDebugId = -1;
223 
224     /** @hide */
TransitionInfo(@ransitionType int type, @TransitionFlags int flags)225     public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) {
226         mType = type;
227         mFlags = flags;
228     }
229 
TransitionInfo(Parcel in)230     private TransitionInfo(Parcel in) {
231         mType = in.readInt();
232         mFlags = in.readInt();
233         in.readTypedList(mChanges, Change.CREATOR);
234         in.readTypedList(mRoots, Root.CREATOR);
235         mOptions = in.readTypedObject(AnimationOptions.CREATOR);
236         mDebugId = in.readInt();
237         mTrack = in.readInt();
238     }
239 
240     @Override
241     /** @hide */
writeToParcel(@onNull Parcel dest, int flags)242     public void writeToParcel(@NonNull Parcel dest, int flags) {
243         dest.writeInt(mType);
244         dest.writeInt(mFlags);
245         dest.writeTypedList(mChanges);
246         dest.writeTypedList(mRoots, flags);
247         dest.writeTypedObject(mOptions, flags);
248         dest.writeInt(mDebugId);
249         dest.writeInt(mTrack);
250     }
251 
252     @NonNull
253     public static final Creator<TransitionInfo> CREATOR =
254             new Creator<TransitionInfo>() {
255                 @Override
256                 public TransitionInfo createFromParcel(Parcel in) {
257                     return new TransitionInfo(in);
258                 }
259 
260                 @Override
261                 public TransitionInfo[] newArray(int size) {
262                     return new TransitionInfo[size];
263                 }
264             };
265 
266     @Override
267     /** @hide */
describeContents()268     public int describeContents() {
269         return 0;
270     }
271 
272     /** @see #getRoot */
addRootLeash(int displayId, @NonNull SurfaceControl leash, int offsetLeft, int offsetTop)273     public void addRootLeash(int displayId, @NonNull SurfaceControl leash,
274             int offsetLeft, int offsetTop) {
275         mRoots.add(new Root(displayId, leash, offsetLeft, offsetTop));
276     }
277 
278     /** @see #getRoot */
addRoot(@onNull Root other)279     public void addRoot(@NonNull Root other) {
280         mRoots.add(other);
281     }
282 
283     /**
284      * @deprecated Set {@link AnimationOptions} to change. This method is only used if
285      * {@link Flags#FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE} is disabled.
286      */
287     @Deprecated
setAnimationOptions(@ullable AnimationOptions options)288     public void setAnimationOptions(@Nullable AnimationOptions options) {
289         if (Flags.moveAnimationOptionsToChange()) {
290             return;
291         }
292         mOptions = options;
293     }
294 
getType()295     public @TransitionType int getType() {
296         return mType;
297     }
298 
setFlags(int flags)299     public void setFlags(int flags) {
300         mFlags = flags;
301     }
302 
getFlags()303     public int getFlags() {
304         return mFlags;
305     }
306 
307     /**
308      * @return The number of animation roots. Most transitions should have 1, but there may be more
309      *         in some cases (such as a transition spanning multiple displays).
310      */
getRootCount()311     public int getRootCount() {
312         return mRoots.size();
313     }
314 
315     /**
316      * @return the transition-root at a specific index.
317      */
318     @NonNull
getRoot(int idx)319     public Root getRoot(int idx) {
320         return mRoots.get(idx);
321     }
322 
323     /**
324      * @return the index of the transition-root associated with `displayId` or -1 if not found.
325      */
findRootIndex(int displayId)326     public int findRootIndex(int displayId) {
327         for (int i = 0; i < mRoots.size(); ++i) {
328             if (mRoots.get(i).mDisplayId == displayId) {
329                 return i;
330             }
331         }
332         return -1;
333     }
334 
335     /**
336      * @return a surfacecontrol that can serve as a parent surfacecontrol for all the changing
337      * participants to animate within. This will generally be placed at the highest-z-order
338      * shared ancestor of all participants. While this is non-null, it's possible for the rootleash
339      * to be invalid if the transition is a no-op.
340      *
341      * @deprecated Use {@link #getRoot} instead. This call assumes there is only one root.
342      */
343     @Deprecated
344     @NonNull
getRootLeash()345     public SurfaceControl getRootLeash() {
346         if (mRoots.isEmpty()) {
347             throw new IllegalStateException("Trying to get a root leash from a no-op transition.");
348         }
349         if (mRoots.size() > 1) {
350             android.util.Log.e(TAG, "Assuming one animation root when there are more.",
351                     new Throwable());
352         }
353         return mRoots.get(0).mLeash;
354     }
355 
356     /**
357      * @deprecated Use {@link Change#getAnimationOptions()} instead. This method is called only
358      * if {@link Flags#FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE} is disabled.
359      */
360     @Deprecated
361     @Nullable
getAnimationOptions()362     public AnimationOptions getAnimationOptions() {
363         return mOptions;
364     }
365 
366     /**
367      * @return the list of {@link Change}s in this transition. The list is sorted top-to-bottom
368      *         in Z (meaning index 0 is the top-most container).
369      */
370     @NonNull
getChanges()371     public List<Change> getChanges() {
372         return mChanges;
373     }
374 
375     /**
376      * @return the Change that a window is undergoing or {@code null} if not directly
377      * represented.
378      */
379     @Nullable
getChange(@onNull WindowContainerToken token)380     public Change getChange(@NonNull WindowContainerToken token) {
381         for (int i = mChanges.size() - 1; i >= 0; --i) {
382             if (token.equals(mChanges.get(i).mContainer)) {
383                 return mChanges.get(i);
384             }
385         }
386         return null;
387     }
388 
389     /**
390      * Add a {@link Change} to this transition.
391      */
addChange(@onNull Change change)392     public void addChange(@NonNull Change change) {
393         mChanges.add(change);
394     }
395 
396     /**
397      * Whether this transition contains any changes to the window hierarchy,
398      * including keyguard visibility.
399      */
hasChangesOrSideEffects()400     public boolean hasChangesOrSideEffects() {
401         return !mChanges.isEmpty() || isKeyguardGoingAway()
402                 || (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0;
403     }
404 
405     /**
406      * Whether this transition includes keyguard going away.
407      */
isKeyguardGoingAway()408     public boolean isKeyguardGoingAway() {
409         return (mFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0;
410     }
411 
412     /** Gets which animation track this transition should run on. */
getTrack()413     public int getTrack() {
414         return mTrack;
415     }
416 
417     /** Sets which animation track this transition should run on. */
setTrack(int track)418     public void setTrack(int track) {
419         mTrack = track;
420     }
421 
422     /**
423      * Set an arbitrary "debug" id for this info. This id will not be used for any "real work",
424      * it is just for debugging and logging.
425      */
setDebugId(int id)426     public void setDebugId(int id) {
427         mDebugId = id;
428     }
429 
430     /** Get the "debug" id of this info. Do NOT use this for real work, only use for debugging. */
getDebugId()431     public int getDebugId() {
432         return mDebugId;
433     }
434 
435     @Override
toString()436     public String toString() {
437         return toString("");
438     }
439 
440     /**
441      * Returns a string representation of this transition info.
442      * @hide
443      */
toString(@onNull String prefix)444     public String toString(@NonNull String prefix) {
445         final boolean shouldPrettyPrint = !prefix.isEmpty() && !mChanges.isEmpty();
446         final String innerPrefix = shouldPrettyPrint ? prefix + "    " : "";
447         final String changesLineStart = shouldPrettyPrint ? "\n" + prefix : "";
448         final String perChangeLineStart = shouldPrettyPrint ? "\n" + innerPrefix : "";
449         StringBuilder sb = new StringBuilder();
450         sb.append("{id=").append(mDebugId).append(" t=").append(transitTypeToString(mType))
451                 .append(" f=0x").append(Integer.toHexString(mFlags)).append(" trk=").append(mTrack);
452         if (mOptions != null) {
453             sb.append(" opt=").append(mOptions);
454         }
455         sb.append(" r=[");
456         for (int i = 0; i < mRoots.size(); ++i) {
457             if (i > 0) {
458                 sb.append(',');
459             }
460             sb.append(mRoots.get(i).mDisplayId).append("@").append(mRoots.get(i).mOffset);
461         }
462         sb.append("] c=[");
463         sb.append(perChangeLineStart);
464         for (int i = 0; i < mChanges.size(); ++i) {
465             if (i > 0) {
466                 sb.append(',');
467                 sb.append(perChangeLineStart);
468             }
469             sb.append(mChanges.get(i));
470         }
471         sb.append(changesLineStart);
472         sb.append("]}");
473         return sb.toString();
474     }
475 
476     /** Converts a transition mode/action to its string representation. */
477     @NonNull
modeToString(@ransitionMode int mode)478     public static String modeToString(@TransitionMode int mode) {
479         switch(mode) {
480             case TRANSIT_NONE: return "NONE";
481             case TRANSIT_OPEN: return "OPEN";
482             case TRANSIT_CLOSE: return "CLOSE";
483             case TRANSIT_TO_FRONT: return "TO_FRONT";
484             case TRANSIT_TO_BACK: return "TO_BACK";
485             case TRANSIT_CHANGE: return "CHANGE";
486             default: return "<unknown:" + mode + ">";
487         }
488     }
489 
490     /** Converts change flags into a string representation. */
491     @NonNull
flagsToString(@hangeFlags int flags)492     public static String flagsToString(@ChangeFlags int flags) {
493         if (flags == 0) return "NONE";
494         final StringBuilder sb = new StringBuilder();
495         if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
496             sb.append("SHOW_WALLPAPER");
497         }
498         if ((flags & FLAG_IS_WALLPAPER) != 0) {
499             sb.append("IS_WALLPAPER");
500         }
501         if ((flags & FLAG_IS_INPUT_METHOD) != 0) {
502             sb.append("IS_INPUT_METHOD");
503         }
504         if ((flags & FLAG_TRANSLUCENT) != 0) {
505             sb.append(sb.length() == 0 ? "" : "|").append("TRANSLUCENT");
506         }
507         if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
508             sb.append(sb.length() == 0 ? "" : "|").append("STARTING_WINDOW_TRANSFER");
509         }
510         if ((flags & FLAG_IS_VOICE_INTERACTION) != 0) {
511             sb.append(sb.length() == 0 ? "" : "|").append("IS_VOICE_INTERACTION");
512         }
513         if ((flags & FLAG_IS_DISPLAY) != 0) {
514             sb.append(sb.length() == 0 ? "" : "|").append("IS_DISPLAY");
515         }
516         if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
517             sb.append(sb.length() == 0 ? "" : "|").append("DISPLAY_HAS_ALERT_WINDOWS");
518         }
519         if ((flags & FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY) != 0) {
520             sb.append(sb.length() == 0 ? "" : "|").append("IN_TASK_WITH_EMBEDDED_ACTIVITY");
521         }
522         if ((flags & FLAG_FILLS_TASK) != 0) {
523             sb.append(sb.length() == 0 ? "" : "|").append("FILLS_TASK");
524         }
525         if ((flags & FLAG_IS_BEHIND_STARTING_WINDOW) != 0) {
526             sb.append(sb.length() == 0 ? "" : "|").append("IS_BEHIND_STARTING_WINDOW");
527         }
528         if ((flags & FLAG_IS_OCCLUDED) != 0) {
529             sb.append(sb.length() == 0 ? "" : "|").append("IS_OCCLUDED");
530         }
531         if ((flags & FLAG_IS_SYSTEM_WINDOW) != 0) {
532             sb.append(sb.length() == 0 ? "" : "|").append("FLAG_IS_SYSTEM_WINDOW");
533         }
534         if ((flags & FLAG_BACK_GESTURE_ANIMATED) != 0) {
535             sb.append(sb.length() == 0 ? "" : "|").append("FLAG_BACK_GESTURE_ANIMATED");
536         }
537         if ((flags & FLAG_NO_ANIMATION) != 0) {
538             sb.append(sb.length() == 0 ? "" : "|").append("NO_ANIMATION");
539         }
540         if ((flags & FLAG_TASK_LAUNCHING_BEHIND) != 0) {
541             sb.append((sb.length() == 0 ? "" : "|") + "TASK_LAUNCHING_BEHIND");
542         }
543         if ((flags & FLAG_SYNC) != 0) {
544             sb.append((sb.length() == 0 ? "" : "|") + "SYNC");
545         }
546         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
547             sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
548         }
549         if ((flags & FLAG_CONFIG_AT_END) != 0) {
550             sb.append(sb.length() == 0 ? "" : "|").append("CONFIG_AT_END");
551         }
552         if ((flags & FLAG_MOVED_TO_TOP) != 0) {
553             sb.append(sb.length() == 0 ? "" : "|").append("MOVE_TO_TOP");
554         }
555         return sb.toString();
556     }
557 
558     /**
559      * Indication that `change` is independent of parents (ie. it has a different type of
560      * transition vs. "going along for the ride")
561      */
isIndependent(@onNull TransitionInfo.Change change, @NonNull TransitionInfo info)562     public static boolean isIndependent(@NonNull TransitionInfo.Change change,
563             @NonNull TransitionInfo info) {
564         // If the change has no parent (it is root), then it is independent
565         if (change.getParent() == null) return true;
566 
567         if (change.getLastParent() != null && !change.getLastParent().equals(change.getParent())) {
568             // If the change has been reparented, then it's independent.
569             return true;
570         }
571 
572         // non-visibility changes will just be folded into the parent change, so they aren't
573         // independent either.
574         if (change.getMode() == TRANSIT_CHANGE) return false;
575 
576         // Always fold the activity embedding change into the parent change.
577         if (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) return false;
578 
579         TransitionInfo.Change parentChg = info.getChange(change.getParent());
580         while (parentChg != null) {
581             // If the parent is a visibility change, it will include the results of all child
582             // changes into itself, so none of its children can be independent.
583             if (parentChg.getMode() != TRANSIT_CHANGE) return false;
584 
585             // If there are no more parents left, then all the parents, so far, have not been
586             // visibility changes which means this change is independent.
587             if (parentChg.getParent() == null) return true;
588 
589             parentChg = info.getChange(parentChg.getParent());
590         }
591         return false;
592     }
593 
594     /**
595      * Releases temporary-for-animation surfaces referenced by this to potentially free up memory.
596      * This includes root-leash and snapshots.
597      */
releaseAnimSurfaces()598     public void releaseAnimSurfaces() {
599         for (int i = mChanges.size() - 1; i >= 0; --i) {
600             final Change c = mChanges.get(i);
601             if (c.mSnapshot != null) {
602                 c.mSnapshot.release();
603                 c.mSnapshot = null;
604             }
605         }
606         for (int i = 0; i < mRoots.size(); ++i) {
607             mRoots.get(i).mLeash.release();
608         }
609     }
610 
611     /**
612      * Releases ALL the surfaces referenced by this to potentially free up memory. Do NOT use this
613      * if the surface-controls get stored and used elsewhere in the process. To just release
614      * temporary-for-animation surfaces, use {@link #releaseAnimSurfaces}.
615      */
releaseAllSurfaces()616     public void releaseAllSurfaces() {
617         releaseAnimSurfaces();
618         for (int i = mChanges.size() - 1; i >= 0; --i) {
619             mChanges.get(i).getLeash().release();
620         }
621     }
622 
623     /**
624      * Updates the callsites of all the surfaces in this transition, which aids in the debugging of
625      * lingering surfaces.
626      */
setUnreleasedWarningCallSiteForAllSurfaces(@ullable String callsite)627     public void setUnreleasedWarningCallSiteForAllSurfaces(@Nullable String callsite) {
628         for (int i = mChanges.size() - 1; i >= 0; --i) {
629             mChanges.get(i).getLeash().setUnreleasedWarningCallSite(callsite);
630         }
631     }
632 
633     /**
634      * Makes a copy of this as if it were parcel'd and unparcel'd. This implies that surfacecontrol
635      * refcounts are incremented which allows the "remote" receiver to release them without breaking
636      * the caller's references. Use this only if you need to "send" this to a local function which
637      * assumes it is being called from a remote caller.
638      */
639     @NonNull
localRemoteCopy()640     public TransitionInfo localRemoteCopy() {
641         final TransitionInfo out = new TransitionInfo(mType, mFlags);
642         out.mTrack = mTrack;
643         out.mDebugId = mDebugId;
644         for (int i = 0; i < mChanges.size(); ++i) {
645             out.mChanges.add(mChanges.get(i).localRemoteCopy());
646         }
647         for (int i = 0; i < mRoots.size(); ++i) {
648             out.mRoots.add(mRoots.get(i).localRemoteCopy());
649         }
650         // Doesn't have any native stuff, so no need for actual copy
651         out.mOptions = mOptions;
652         return out;
653     }
654 
655     /** Represents the change a WindowContainer undergoes during a transition */
656     public static final class Change implements Parcelable {
657         private final WindowContainerToken mContainer;
658         private WindowContainerToken mParent;
659         private WindowContainerToken mLastParent;
660         private SurfaceControl mLeash;
661         private @TransitionMode int mMode = TRANSIT_NONE;
662         private @ChangeFlags int mFlags = FLAG_NONE;
663         private final Rect mStartAbsBounds = new Rect();
664         private final Rect mEndAbsBounds = new Rect();
665         private final Point mEndRelOffset = new Point();
666         private ActivityManager.RunningTaskInfo mTaskInfo = null;
667         private boolean mAllowEnterPip;
668         private int mStartDisplayId = INVALID_DISPLAY;
669         private int mEndDisplayId = INVALID_DISPLAY;
670         private @Surface.Rotation int mStartRotation = ROTATION_UNDEFINED;
671         private @Surface.Rotation int mEndRotation = ROTATION_UNDEFINED;
672         /**
673          * The end rotation of the top activity after fixed rotation is finished. If the top
674          * activity is not in fixed rotation, it will be {@link ROTATION_UNDEFINED}.
675          */
676         private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;
677         private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
678         private @ColorInt int mBackgroundColor;
679         private SurfaceControl mSnapshot = null;
680         private float mSnapshotLuma;
681         private ComponentName mActivityComponent = null;
682         private AnimationOptions mAnimationOptions = null;
683 
Change(@ullable WindowContainerToken container, @NonNull SurfaceControl leash)684         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
685             mContainer = container;
686             mLeash = leash;
687         }
688 
Change(Parcel in)689         private Change(Parcel in) {
690             mContainer = in.readTypedObject(WindowContainerToken.CREATOR);
691             mParent = in.readTypedObject(WindowContainerToken.CREATOR);
692             mLastParent = in.readTypedObject(WindowContainerToken.CREATOR);
693             mLeash = new SurfaceControl();
694             mLeash.readFromParcel(in);
695             mMode = in.readInt();
696             mFlags = in.readInt();
697             mStartAbsBounds.readFromParcel(in);
698             mEndAbsBounds.readFromParcel(in);
699             mEndRelOffset.readFromParcel(in);
700             mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
701             mAllowEnterPip = in.readBoolean();
702             mStartDisplayId = in.readInt();
703             mEndDisplayId = in.readInt();
704             mStartRotation = in.readInt();
705             mEndRotation = in.readInt();
706             mEndFixedRotation = in.readInt();
707             mRotationAnimation = in.readInt();
708             mBackgroundColor = in.readInt();
709             mSnapshot = in.readTypedObject(SurfaceControl.CREATOR);
710             mSnapshotLuma = in.readFloat();
711             mActivityComponent = in.readTypedObject(ComponentName.CREATOR);
712             mAnimationOptions = in.readTypedObject(AnimationOptions.CREATOR);
713         }
714 
localRemoteCopy()715         private Change localRemoteCopy() {
716             final Change out = new Change(mContainer, new SurfaceControl(mLeash, "localRemote"));
717             out.mParent = mParent;
718             out.mLastParent = mLastParent;
719             out.mMode = mMode;
720             out.mFlags = mFlags;
721             out.mStartAbsBounds.set(mStartAbsBounds);
722             out.mEndAbsBounds.set(mEndAbsBounds);
723             out.mEndRelOffset.set(mEndRelOffset);
724             out.mTaskInfo = mTaskInfo;
725             out.mAllowEnterPip = mAllowEnterPip;
726             out.mStartDisplayId = mStartDisplayId;
727             out.mEndDisplayId = mEndDisplayId;
728             out.mStartRotation = mStartRotation;
729             out.mEndRotation = mEndRotation;
730             out.mEndFixedRotation = mEndFixedRotation;
731             out.mRotationAnimation = mRotationAnimation;
732             out.mBackgroundColor = mBackgroundColor;
733             out.mSnapshot = mSnapshot != null ? new SurfaceControl(mSnapshot, "localRemote") : null;
734             out.mSnapshotLuma = mSnapshotLuma;
735             out.mActivityComponent = mActivityComponent;
736             out.mAnimationOptions = mAnimationOptions;
737             return out;
738         }
739 
740         /** Sets the parent of this change's container. The parent must be a participant or null. */
setParent(@ullable WindowContainerToken parent)741         public void setParent(@Nullable WindowContainerToken parent) {
742             mParent = parent;
743         }
744 
745         /**
746          * Sets the parent of this change's container before the transition if this change's
747          * container is reparented in the transition.
748          */
setLastParent(@ullable WindowContainerToken lastParent)749         public void setLastParent(@Nullable WindowContainerToken lastParent) {
750             mLastParent = lastParent;
751         }
752 
753         /** Sets the animation leash for controlling this change's container */
setLeash(@onNull SurfaceControl leash)754         public void setLeash(@NonNull SurfaceControl leash) {
755             mLeash = Objects.requireNonNull(leash);
756         }
757 
758         /** Sets the transition mode for this change */
setMode(@ransitionMode int mode)759         public void setMode(@TransitionMode int mode) {
760             mMode = mode;
761         }
762 
763         /** Sets the flags for this change */
setFlags(@hangeFlags int flags)764         public void setFlags(@ChangeFlags int flags) {
765             mFlags = flags;
766         }
767 
768         /** Sets the bounds this container occupied before the change in screen space */
setStartAbsBounds(@ullable Rect rect)769         public void setStartAbsBounds(@Nullable Rect rect) {
770             mStartAbsBounds.set(rect);
771         }
772 
773         /** Sets the bounds this container will occupy after the change in screen space */
setEndAbsBounds(@ullable Rect rect)774         public void setEndAbsBounds(@Nullable Rect rect) {
775             mEndAbsBounds.set(rect);
776         }
777 
778         /** Sets the offset of this container from its parent surface */
setEndRelOffset(int left, int top)779         public void setEndRelOffset(int left, int top) {
780             mEndRelOffset.set(left, top);
781         }
782 
783         /**
784          * Sets the taskinfo of this container if this is a task. WARNING: this takes the
785          * reference, so don't modify it afterwards.
786          */
setTaskInfo(@ullable ActivityManager.RunningTaskInfo taskInfo)787         public void setTaskInfo(@Nullable ActivityManager.RunningTaskInfo taskInfo) {
788             mTaskInfo = taskInfo;
789         }
790 
791         /** Sets the allowEnterPip flag which represents AppOpsManager check on PiP permission */
setAllowEnterPip(boolean allowEnterPip)792         public void setAllowEnterPip(boolean allowEnterPip) {
793             mAllowEnterPip = allowEnterPip;
794         }
795 
796         /** Sets the start and end rotation of this container. */
setDisplayId(int start, int end)797         public void setDisplayId(int start, int end) {
798             mStartDisplayId = start;
799             mEndDisplayId = end;
800         }
801 
802         /** Sets the start and end rotation of this container. */
setRotation(@urface.Rotation int start, @Surface.Rotation int end)803         public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
804             mStartRotation = start;
805             mEndRotation = end;
806         }
807 
808         /** Sets end rotation that top activity will be launched to after fixed rotation. */
setEndFixedRotation(@urface.Rotation int endFixedRotation)809         public void setEndFixedRotation(@Surface.Rotation int endFixedRotation) {
810             mEndFixedRotation = endFixedRotation;
811         }
812 
813         /**
814          * Sets the app-requested animation type for rotation. Will be one of the
815          * ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams};
816          */
setRotationAnimation(int anim)817         public void setRotationAnimation(int anim) {
818             mRotationAnimation = anim;
819         }
820 
821         /** Sets the background color of this change's container. */
setBackgroundColor(@olorInt int backgroundColor)822         public void setBackgroundColor(@ColorInt int backgroundColor) {
823             mBackgroundColor = backgroundColor;
824         }
825 
826         /** Sets a snapshot surface for the "start" state of the container. */
setSnapshot(@ullable SurfaceControl snapshot, float luma)827         public void setSnapshot(@Nullable SurfaceControl snapshot, float luma) {
828             mSnapshot = snapshot;
829             mSnapshotLuma = luma;
830         }
831 
832         /** Sets the component-name of the container. Container must be an Activity. */
setActivityComponent(@ullable ComponentName component)833         public void setActivityComponent(@Nullable ComponentName component) {
834             mActivityComponent = component;
835         }
836 
837         /**
838          * Sets {@link AnimationOptions} to override animation.
839          */
setAnimationOptions(@ullable AnimationOptions options)840         public void setAnimationOptions(@Nullable AnimationOptions options) {
841             if (!Flags.moveAnimationOptionsToChange()) {
842                 return;
843             }
844             mAnimationOptions = options;
845         }
846 
847         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
848         @Nullable
getContainer()849         public WindowContainerToken getContainer() {
850             return mContainer;
851         }
852 
853         /**
854          * @return the parent of the changing container. This is the parent within the participants,
855          * not necessarily the actual parent.
856          */
857         @Nullable
getParent()858         public WindowContainerToken getParent() {
859             return mParent;
860         }
861 
862         /**
863          * @return the parent of the changing container before the transition if it is reparented
864          * in the transition. The parent window may not be collected in the transition as a
865          * participant, and it may have been detached from the display. {@code null} if the changing
866          * container has not been reparented in the transition, or if the parent is not organizable.
867          */
868         @Nullable
getLastParent()869         public WindowContainerToken getLastParent() {
870             return mLastParent;
871         }
872 
873         /** @return which action this change represents. */
getMode()874         public @TransitionMode int getMode() {
875             return mMode;
876         }
877 
878         /** @return the flags for this change. */
getFlags()879         public @ChangeFlags int getFlags() {
880             return mFlags;
881         }
882 
883         /** Whether this change contains any of the given change flags. */
hasFlags(@hangeFlags int flags)884         public boolean hasFlags(@ChangeFlags int flags) {
885             return (mFlags & flags) != 0;
886         }
887 
888         /** Whether this change contains all of the given change flags. */
hasAllFlags(@hangeFlags int flags)889         public boolean hasAllFlags(@ChangeFlags int flags) {
890             return (mFlags & flags) == flags;
891         }
892 
893         /**
894          * @return the bounds of the container before the change. It may be empty if the container
895          * is coming into existence.
896          */
897         @NonNull
getStartAbsBounds()898         public Rect getStartAbsBounds() {
899             return mStartAbsBounds;
900         }
901 
902         /**
903          * @return the bounds of the container after the change. It may be empty if the container
904          * is disappearing.
905          */
906         @NonNull
getEndAbsBounds()907         public Rect getEndAbsBounds() {
908             return mEndAbsBounds;
909         }
910 
911         /**
912          * @return the offset of the container's surface from its parent surface after the change.
913          */
914         @NonNull
getEndRelOffset()915         public Point getEndRelOffset() {
916             return mEndRelOffset;
917         }
918 
919         /** @return the leash or surface to animate for this container */
920         @NonNull
getLeash()921         public SurfaceControl getLeash() {
922             return mLeash;
923         }
924 
925         /** @return the task info or null if this isn't a task */
926         @Nullable
getTaskInfo()927         public ActivityManager.RunningTaskInfo getTaskInfo() {
928             return mTaskInfo;
929         }
930 
isAllowEnterPip()931         public boolean isAllowEnterPip() {
932             return mAllowEnterPip;
933         }
934 
getStartDisplayId()935         public int getStartDisplayId() {
936             return mStartDisplayId;
937         }
938 
getEndDisplayId()939         public int getEndDisplayId() {
940             return mEndDisplayId;
941         }
942 
943         @Surface.Rotation
getStartRotation()944         public int getStartRotation() {
945             return mStartRotation;
946         }
947 
948         @Surface.Rotation
getEndRotation()949         public int getEndRotation() {
950             return mEndRotation;
951         }
952 
953         @Surface.Rotation
getEndFixedRotation()954         public int getEndFixedRotation() {
955             return mEndFixedRotation;
956         }
957 
958         /** @return the rotation animation. */
getRotationAnimation()959         public int getRotationAnimation() {
960             return mRotationAnimation;
961         }
962 
963         /** @return get the background color of this change's container. */
964         @ColorInt
getBackgroundColor()965         public int getBackgroundColor() {
966             return mBackgroundColor;
967         }
968 
969         /** @return a snapshot surface (if applicable). */
970         @Nullable
getSnapshot()971         public SurfaceControl getSnapshot() {
972             return mSnapshot;
973         }
974 
975         /** @return the luma calculated for the snapshot surface (if applicable). */
getSnapshotLuma()976         public float getSnapshotLuma() {
977             return mSnapshotLuma;
978         }
979 
980         /** @return the component-name of this container (if it is an activity). */
981         @Nullable
getActivityComponent()982         public ComponentName getActivityComponent() {
983             return mActivityComponent;
984         }
985 
986         /**
987          * Returns the {@link AnimationOptions}.
988          */
989         @Nullable
getAnimationOptions()990         public AnimationOptions getAnimationOptions() {
991             return mAnimationOptions;
992         }
993 
994         /** @hide */
995         @Override
writeToParcel(@onNull Parcel dest, int flags)996         public void writeToParcel(@NonNull Parcel dest, int flags) {
997             dest.writeTypedObject(mContainer, flags);
998             dest.writeTypedObject(mParent, flags);
999             dest.writeTypedObject(mLastParent, flags);
1000             mLeash.writeToParcel(dest, flags);
1001             dest.writeInt(mMode);
1002             dest.writeInt(mFlags);
1003             mStartAbsBounds.writeToParcel(dest, flags);
1004             mEndAbsBounds.writeToParcel(dest, flags);
1005             mEndRelOffset.writeToParcel(dest, flags);
1006             dest.writeTypedObject(mTaskInfo, flags);
1007             dest.writeBoolean(mAllowEnterPip);
1008             dest.writeInt(mStartDisplayId);
1009             dest.writeInt(mEndDisplayId);
1010             dest.writeInt(mStartRotation);
1011             dest.writeInt(mEndRotation);
1012             dest.writeInt(mEndFixedRotation);
1013             dest.writeInt(mRotationAnimation);
1014             dest.writeInt(mBackgroundColor);
1015             dest.writeTypedObject(mSnapshot, flags);
1016             dest.writeFloat(mSnapshotLuma);
1017             dest.writeTypedObject(mActivityComponent, flags);
1018             dest.writeTypedObject(mAnimationOptions, flags);
1019         }
1020 
1021         @NonNull
1022         public static final Creator<Change> CREATOR =
1023                 new Creator<Change>() {
1024                     @Override
1025                     public Change createFromParcel(Parcel in) {
1026                         return new Change(in);
1027                     }
1028 
1029                     @Override
1030                     public Change[] newArray(int size) {
1031                         return new Change[size];
1032                     }
1033                 };
1034 
1035         /** @hide */
1036         @Override
describeContents()1037         public int describeContents() {
1038             return 0;
1039         }
1040 
1041         @Override
toString()1042         public String toString() {
1043             final StringBuilder sb = new StringBuilder();
1044             sb.append('{'); sb.append(mContainer);
1045             sb.append(" m="); sb.append(modeToString(mMode));
1046             sb.append(" f="); sb.append(flagsToString(mFlags));
1047             if (mParent != null) {
1048                 sb.append(" p="); sb.append(mParent);
1049             }
1050             if (mLeash != null) {
1051                 sb.append(" leash="); sb.append(mLeash);
1052             }
1053             sb.append(" sb="); sb.append(mStartAbsBounds);
1054             sb.append(" eb="); sb.append(mEndAbsBounds);
1055             if (mEndRelOffset.x != 0 || mEndRelOffset.y != 0) {
1056                 sb.append(" eo="); sb.append(mEndRelOffset);
1057             }
1058             sb.append(" d=");
1059             if (mStartDisplayId != mEndDisplayId) {
1060                 sb.append(mStartDisplayId).append("->");
1061             }
1062             sb.append(mEndDisplayId);
1063             if (mStartRotation != mEndRotation) {
1064                 sb.append(" r="); sb.append(mStartRotation);
1065                 sb.append("->"); sb.append(mEndRotation);
1066                 sb.append(':'); sb.append(mRotationAnimation);
1067             }
1068             if (mEndFixedRotation != ROTATION_UNDEFINED) {
1069                 sb.append(" endFixedRotation="); sb.append(mEndFixedRotation);
1070             }
1071             if (mBackgroundColor != 0) {
1072                 sb.append(" bc=").append(Integer.toHexString(mBackgroundColor));
1073             }
1074             if (mSnapshot != null) {
1075                 sb.append(" snapshot="); sb.append(mSnapshot);
1076             }
1077             if (mLastParent != null) {
1078                 sb.append(" lastParent="); sb.append(mLastParent);
1079             }
1080             if (mActivityComponent != null) {
1081                 sb.append(" component=");
1082                 sb.append(mActivityComponent.flattenToShortString());
1083             }
1084             if (mTaskInfo != null) {
1085                 sb.append(" taskParent=");
1086                 sb.append(mTaskInfo.parentTaskId);
1087             }
1088             if (mAnimationOptions != null) {
1089                 sb.append(" opt=").append(mAnimationOptions);
1090             }
1091             sb.append('}');
1092             return sb.toString();
1093         }
1094     }
1095 
1096     /** Represents animation options during a transition */
1097     @SuppressWarnings("UserHandleName")
1098     public static final class AnimationOptions implements Parcelable {
1099 
1100         /**
1101          * The default value for animation resources ID, which means to use the system default
1102          * animation.
1103          */
1104         @SuppressWarnings("ResourceType") // Use as a hint to use the system default animation.
1105         @AnimRes
1106         public static final int DEFAULT_ANIMATION_RESOURCES_ID = 0xFFFFFFFF;
1107 
1108         private int mType;
1109         private @AnimRes int mEnterResId = DEFAULT_ANIMATION_RESOURCES_ID;
1110         private @AnimRes int mChangeResId = DEFAULT_ANIMATION_RESOURCES_ID;
1111         private @AnimRes int mExitResId = DEFAULT_ANIMATION_RESOURCES_ID;
1112         private boolean mOverrideTaskTransition;
1113         private String mPackageName;
1114         private final Rect mTransitionBounds = new Rect();
1115         private HardwareBuffer mThumbnail;
1116         private int mAnimations;
1117         // TODO(b/295805497): Extract mBackgroundColor from AnimationOptions
1118         private @ColorInt int mBackgroundColor;
1119         // Customize activity transition animation
1120         private CustomActivityTransition mCustomActivityOpenTransition;
1121         private CustomActivityTransition mCustomActivityCloseTransition;
1122 
AnimationOptions(int type)1123         private AnimationOptions(int type) {
1124             mType = type;
1125         }
1126 
AnimationOptions(Parcel in)1127         private AnimationOptions(Parcel in) {
1128             mType = in.readInt();
1129             mEnterResId = in.readInt();
1130             mChangeResId = in.readInt();
1131             mExitResId = in.readInt();
1132             mBackgroundColor = in.readInt();
1133             mOverrideTaskTransition = in.readBoolean();
1134             mPackageName = in.readString();
1135             mTransitionBounds.readFromParcel(in);
1136             mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
1137             mAnimations = in.readInt();
1138             mCustomActivityOpenTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
1139             mCustomActivityCloseTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
1140         }
1141 
1142         /** Make basic customized animation for a package */
1143         @NonNull
makeCommonAnimOptions(@onNull String packageName)1144         public static AnimationOptions makeCommonAnimOptions(@NonNull String packageName) {
1145             AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
1146             options.mPackageName = packageName;
1147             return options;
1148         }
1149 
1150         /** Make custom animation from the content of LayoutParams */
1151         @NonNull
makeAnimOptionsFromLayoutParameters( @onNull WindowManager.LayoutParams lp)1152         public static AnimationOptions makeAnimOptionsFromLayoutParameters(
1153                 @NonNull WindowManager.LayoutParams lp) {
1154             AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
1155             options.mPackageName = lp.packageName;
1156             options.mAnimations = lp.windowAnimations;
1157             return options;
1158         }
1159 
1160         /** Add customized window animations */
addOptionsFromLayoutParameters(@onNull WindowManager.LayoutParams lp)1161         public void addOptionsFromLayoutParameters(@NonNull WindowManager.LayoutParams lp) {
1162             mAnimations = lp.windowAnimations;
1163         }
1164 
1165         /** Add customized activity animation attributes */
addCustomActivityTransition(boolean isOpen, int enterResId, int exitResId, int backgroundColor)1166         public void addCustomActivityTransition(boolean isOpen,
1167                 int enterResId, int exitResId, int backgroundColor) {
1168             CustomActivityTransition customTransition = isOpen
1169                     ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
1170             if (customTransition == null) {
1171                 customTransition = new CustomActivityTransition();
1172                 if (isOpen) {
1173                     mCustomActivityOpenTransition = customTransition;
1174                 } else {
1175                     mCustomActivityCloseTransition = customTransition;
1176                 }
1177             }
1178             customTransition.addCustomActivityTransition(enterResId, exitResId, backgroundColor);
1179         }
1180 
1181         /**
1182          * Make options for a custom animation based on anim resources.
1183          *
1184          * @param packageName the package name to find the animation resources
1185          * @param enterResId the open animation resources ID
1186          * @param exitResId the close animation resources ID
1187          * @param backgroundColor the background color
1188          * @param overrideTaskTransition whether to override the task transition
1189          */
1190         @NonNull
makeCustomAnimOptions(@onNull String packageName, @AnimRes int enterResId, @AnimRes int exitResId, @ColorInt int backgroundColor, boolean overrideTaskTransition)1191         public static AnimationOptions makeCustomAnimOptions(@NonNull String packageName,
1192                 @AnimRes int enterResId, @AnimRes int exitResId, @ColorInt int backgroundColor,
1193                 boolean overrideTaskTransition) {
1194             return makeCustomAnimOptions(packageName, enterResId, DEFAULT_ANIMATION_RESOURCES_ID,
1195                     exitResId, backgroundColor, overrideTaskTransition);
1196         }
1197 
1198         /**
1199          * Creates a {@link android.app.ActivityOptions#ANIM_CUSTOM} {@link AnimationOptions}.
1200          *
1201          * @param packageName the package name that includes the animation resources.
1202          * @param enterResId the resources ID of open animation.
1203          * @param changeResId the resources ID of change animation.
1204          * @param exitResId the resources ID of close animation.
1205          * @param overrideTaskTransition indicates whether to override task transition.
1206          */
1207         @NonNull
makeCustomAnimOptions(@onNull String packageName, @AnimRes int enterResId, @AnimRes int changeResId, @AnimRes int exitResId, @ColorInt int backgroundColor, boolean overrideTaskTransition)1208         public static AnimationOptions makeCustomAnimOptions(@NonNull String packageName,
1209                 @AnimRes int enterResId, @AnimRes int changeResId, @AnimRes int exitResId,
1210                 @ColorInt int backgroundColor, boolean overrideTaskTransition) {
1211             AnimationOptions options = new AnimationOptions(ANIM_CUSTOM);
1212             options.mPackageName = packageName;
1213             options.mEnterResId = enterResId;
1214             options.mChangeResId = changeResId;
1215             options.mExitResId = exitResId;
1216             options.mBackgroundColor = backgroundColor;
1217             options.mOverrideTaskTransition = overrideTaskTransition;
1218             return options;
1219         }
1220 
1221         /** Make options for a clip-reveal animation. */
1222         @NonNull
makeClipRevealAnimOptions(int startX, int startY, int width, int height)1223         public static AnimationOptions makeClipRevealAnimOptions(int startX, int startY, int width,
1224                 int height) {
1225             AnimationOptions options = new AnimationOptions(ANIM_CLIP_REVEAL);
1226             options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
1227             return options;
1228         }
1229 
1230         /** Make options for a scale-up animation. */
1231         @NonNull
makeScaleUpAnimOptions(int startX, int startY, int width, int height)1232         public static AnimationOptions makeScaleUpAnimOptions(int startX, int startY, int width,
1233                 int height) {
1234             AnimationOptions options = new AnimationOptions(ANIM_SCALE_UP);
1235             options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
1236             return options;
1237         }
1238 
1239         /** Make options for a thumbnail-scaling animation. */
1240         @NonNull
makeThumbnailAnimOptions(@onNull HardwareBuffer srcThumb, int startX, int startY, boolean scaleUp)1241         public static AnimationOptions makeThumbnailAnimOptions(@NonNull HardwareBuffer srcThumb,
1242                 int startX, int startY, boolean scaleUp) {
1243             AnimationOptions options = new AnimationOptions(
1244                     scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN);
1245             options.mTransitionBounds.set(startX, startY, startX, startY);
1246             options.mThumbnail = srcThumb;
1247             return options;
1248         }
1249 
1250         /** Make options for an animation that spans activities of different profiles. */
1251         @NonNull
makeCrossProfileAnimOptions()1252         public static AnimationOptions makeCrossProfileAnimOptions() {
1253             AnimationOptions options = new AnimationOptions(ANIM_OPEN_CROSS_PROFILE_APPS);
1254             return options;
1255         }
1256 
1257         /** Make options designating this as a scene-transition animation. */
1258         @NonNull
makeSceneTransitionAnimOptions()1259         public static AnimationOptions makeSceneTransitionAnimOptions() {
1260             AnimationOptions options = new AnimationOptions(ANIM_SCENE_TRANSITION);
1261             return options;
1262         }
1263 
getType()1264         public int getType() {
1265             return mType;
1266         }
1267 
1268         @AnimRes
getEnterResId()1269         public int getEnterResId() {
1270             return mEnterResId;
1271         }
1272 
1273         @AnimRes
getChangeResId()1274         public int getChangeResId() {
1275             return mChangeResId;
1276         }
1277 
1278         @AnimRes
getExitResId()1279         public int getExitResId() {
1280             return mExitResId;
1281         }
1282 
getBackgroundColor()1283         public @ColorInt int getBackgroundColor() {
1284             return mBackgroundColor;
1285         }
1286 
getOverrideTaskTransition()1287         public boolean getOverrideTaskTransition() {
1288             return mOverrideTaskTransition;
1289         }
1290 
1291         @Nullable
getPackageName()1292         public String getPackageName() {
1293             return mPackageName;
1294         }
1295 
1296         @NonNull
getTransitionBounds()1297         public Rect getTransitionBounds() {
1298             return mTransitionBounds;
1299         }
1300 
1301         @Nullable
getThumbnail()1302         public HardwareBuffer getThumbnail() {
1303             return mThumbnail;
1304         }
1305 
getAnimations()1306         public int getAnimations() {
1307             return mAnimations;
1308         }
1309 
1310         /** Return customized activity transition if existed. */
1311         @Nullable
getCustomActivityTransition(boolean open)1312         public CustomActivityTransition getCustomActivityTransition(boolean open) {
1313             return open ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
1314         }
1315 
1316         @Override
writeToParcel(@onNull Parcel dest, int flags)1317         public void writeToParcel(@NonNull Parcel dest, int flags) {
1318             dest.writeInt(mType);
1319             dest.writeInt(mEnterResId);
1320             dest.writeInt(mChangeResId);
1321             dest.writeInt(mExitResId);
1322             dest.writeInt(mBackgroundColor);
1323             dest.writeBoolean(mOverrideTaskTransition);
1324             dest.writeString(mPackageName);
1325             mTransitionBounds.writeToParcel(dest, flags);
1326             dest.writeTypedObject(mThumbnail, flags);
1327             dest.writeInt(mAnimations);
1328             dest.writeTypedObject(mCustomActivityOpenTransition, flags);
1329             dest.writeTypedObject(mCustomActivityCloseTransition, flags);
1330         }
1331 
1332         @NonNull
1333         public static final Creator<AnimationOptions> CREATOR =
1334                 new Creator<AnimationOptions>() {
1335                     @Override
1336                     public AnimationOptions createFromParcel(Parcel in) {
1337                         return new AnimationOptions(in);
1338                     }
1339 
1340                     @Override
1341                     public AnimationOptions[] newArray(int size) {
1342                         return new AnimationOptions[size];
1343                     }
1344                 };
1345 
1346         /** @hide */
1347         @Override
describeContents()1348         public int describeContents() {
1349             return 0;
1350         }
1351 
1352         @NonNull
typeToString(int mode)1353         private static String typeToString(int mode) {
1354             return switch (mode) {
1355                 case ANIM_CUSTOM -> "CUSTOM";
1356                 case ANIM_SCALE_UP -> "SCALE_UP";
1357                 case ANIM_THUMBNAIL_SCALE_UP -> "THUMBNAIL_SCALE_UP";
1358                 case ANIM_THUMBNAIL_SCALE_DOWN -> "THUMBNAIL_SCALE_DOWN";
1359                 case ANIM_SCENE_TRANSITION -> "SCENE_TRANSITION";
1360                 case ANIM_CLIP_REVEAL -> "CLIP_REVEAL";
1361                 case ANIM_OPEN_CROSS_PROFILE_APPS -> "OPEN_CROSS_PROFILE_APPS";
1362                 case ANIM_FROM_STYLE -> "FROM_STYLE";
1363                 default -> "<" + mode + ">";
1364             };
1365         }
1366 
1367         @Override
1368         @NonNull
toString()1369         public String toString() {
1370             final StringBuilder sb = new StringBuilder(32);
1371             sb.append("{t=").append(typeToString(mType));
1372             if (mOverrideTaskTransition) {
1373                 sb.append(" overrideTask=true");
1374             }
1375             if (!mTransitionBounds.isEmpty()) {
1376                 sb.append(" bounds=").append(mTransitionBounds);
1377             }
1378             if (mEnterResId != DEFAULT_ANIMATION_RESOURCES_ID) {
1379                 sb.append(" enterResId=").append(mEnterResId);
1380             }
1381             if (mChangeResId != DEFAULT_ANIMATION_RESOURCES_ID) {
1382                 sb.append(" changeResId=").append(mChangeResId);
1383             }
1384             if (mExitResId != DEFAULT_ANIMATION_RESOURCES_ID) {
1385                 sb.append(" exitResId=").append(mExitResId);
1386             }
1387             sb.append('}');
1388             return sb.toString();
1389         }
1390 
1391         /** Customized activity transition. */
1392         public static final class CustomActivityTransition implements Parcelable {
1393             private int mCustomEnterResId;
1394             private int mCustomExitResId;
1395             private int mCustomBackgroundColor;
1396 
1397             /** Returns customize activity animation enter resource id */
getCustomEnterResId()1398             public int getCustomEnterResId() {
1399                 return mCustomEnterResId;
1400             }
1401 
1402             /** Returns customize activity animation exit resource id */
getCustomExitResId()1403             public int getCustomExitResId() {
1404                 return mCustomExitResId;
1405             }
1406 
1407             /** Returns customize activity animation background color */
getCustomBackgroundColor()1408             public int getCustomBackgroundColor() {
1409                 return mCustomBackgroundColor;
1410             }
CustomActivityTransition()1411             CustomActivityTransition() {}
1412 
CustomActivityTransition(Parcel in)1413             CustomActivityTransition(Parcel in) {
1414                 mCustomEnterResId = in.readInt();
1415                 mCustomExitResId = in.readInt();
1416                 mCustomBackgroundColor = in.readInt();
1417             }
1418 
1419             /** Add customized activity animation attributes */
addCustomActivityTransition( int enterResId, int exitResId, int backgroundColor)1420             public void addCustomActivityTransition(
1421                     int enterResId, int exitResId, int backgroundColor) {
1422                 mCustomEnterResId = enterResId;
1423                 mCustomExitResId = exitResId;
1424                 mCustomBackgroundColor = backgroundColor;
1425             }
1426 
1427             @Override
describeContents()1428             public int describeContents() {
1429                 return 0;
1430             }
1431 
1432             @Override
writeToParcel(@onNull Parcel dest, int flags)1433             public void writeToParcel(@NonNull Parcel dest, int flags) {
1434                 dest.writeInt(mCustomEnterResId);
1435                 dest.writeInt(mCustomExitResId);
1436                 dest.writeInt(mCustomBackgroundColor);
1437             }
1438 
1439             @NonNull
1440             public static final Creator<CustomActivityTransition> CREATOR =
1441                     new Creator<CustomActivityTransition>() {
1442                         @Override
1443                         public CustomActivityTransition createFromParcel(Parcel in) {
1444                             return new CustomActivityTransition(in);
1445                         }
1446 
1447                         @Override
1448                         public CustomActivityTransition[] newArray(int size) {
1449                             return new CustomActivityTransition[size];
1450                         }
1451                     };
1452         }
1453     }
1454 
1455     /**
1456      * An animation root in a transition. There is one of these for each display that contains
1457      * participants. It will be placed, in z-order, right above the top-most participant and at the
1458      * same position in the hierarchy. As a result, if all participants are animating within a
1459      * part of the screen, the root-leash will only be in that part of the screen. In these cases,
1460      * it's relative position (from the screen) is stored in {@link Root#getOffset}.
1461      */
1462     public static final class Root implements Parcelable {
1463         private final int mDisplayId;
1464         private final SurfaceControl mLeash;
1465         private final Point mOffset = new Point();
1466 
Root(int displayId, @NonNull SurfaceControl leash, int offsetLeft, int offsetTop)1467         public Root(int displayId, @NonNull SurfaceControl leash, int offsetLeft, int offsetTop) {
1468             mDisplayId = displayId;
1469             mLeash = leash;
1470             mOffset.set(offsetLeft, offsetTop);
1471         }
1472 
Root(Parcel in)1473         private Root(Parcel in) {
1474             mDisplayId = in.readInt();
1475             mLeash = new SurfaceControl();
1476             mLeash.readFromParcel(in);
1477             mLeash.setUnreleasedWarningCallSite("TransitionInfo.Root");
1478             mOffset.readFromParcel(in);
1479         }
1480 
localRemoteCopy()1481         private Root localRemoteCopy() {
1482             return new Root(mDisplayId, new SurfaceControl(mLeash, "localRemote"),
1483                     mOffset.x, mOffset.y);
1484         }
1485 
1486         /** @return the id of the display this root is on. */
getDisplayId()1487         public int getDisplayId() {
1488             return mDisplayId;
1489         }
1490 
1491         /** @return the root's leash. Surfaces should be parented to this while animating. */
1492         @NonNull
getLeash()1493         public SurfaceControl getLeash() {
1494             return mLeash;
1495         }
1496 
1497         /** @return the offset (relative to its screen) of the root leash. */
1498         @NonNull
getOffset()1499         public Point getOffset() {
1500             return mOffset;
1501         }
1502 
1503         /** @hide */
1504         @Override
writeToParcel(@onNull Parcel dest, int flags)1505         public void writeToParcel(@NonNull Parcel dest, int flags) {
1506             dest.writeInt(mDisplayId);
1507             mLeash.writeToParcel(dest, flags);
1508             mOffset.writeToParcel(dest, flags);
1509         }
1510 
1511         @NonNull
1512         public static final Creator<Root> CREATOR =
1513                 new Creator<Root>() {
1514                     @Override
1515                     public Root createFromParcel(Parcel in) {
1516                         return new Root(in);
1517                     }
1518 
1519                     @Override
1520                     public Root[] newArray(int size) {
1521                         return new Root[size];
1522                     }
1523                 };
1524 
1525         /** @hide */
1526         @Override
describeContents()1527         public int describeContents() {
1528             return 0;
1529         }
1530 
1531         @Override
toString()1532         public String toString() {
1533             return mDisplayId + "@" + mOffset + ":" + mLeash;
1534         }
1535     }
1536 }
1537