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_OPEN_CROSS_PROFILE_APPS;
22 import static android.app.ActivityOptions.ANIM_SCALE_UP;
23 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
24 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
25 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
26 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
27 import static android.view.WindowManager.TRANSIT_CHANGE;
28 import static android.view.WindowManager.TRANSIT_CLOSE;
29 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
30 import static android.view.WindowManager.TRANSIT_NONE;
31 import static android.view.WindowManager.TRANSIT_OPEN;
32 import static android.view.WindowManager.TRANSIT_TO_BACK;
33 import static android.view.WindowManager.TRANSIT_TO_FRONT;
34 import static android.view.WindowManager.TransitionFlags;
35 import static android.view.WindowManager.TransitionType;
36 import static android.view.WindowManager.transitTypeToString;
37 
38 import android.annotation.IntDef;
39 import android.annotation.NonNull;
40 import android.annotation.Nullable;
41 import android.app.ActivityManager;
42 import android.graphics.Point;
43 import android.graphics.Rect;
44 import android.hardware.HardwareBuffer;
45 import android.os.Parcel;
46 import android.os.Parcelable;
47 import android.view.Surface;
48 import android.view.SurfaceControl;
49 
50 import java.util.ArrayList;
51 import java.util.List;
52 
53 /**
54  * Used to communicate information about what is changing during a transition to a TransitionPlayer.
55  * @hide
56  */
57 public final class TransitionInfo implements Parcelable {
58 
59     /**
60      * Modes are only a sub-set of all the transit-types since they are per-container
61      * @hide
62      */
63     @IntDef(prefix = { "TRANSIT_" }, value = {
64             TRANSIT_NONE,
65             TRANSIT_OPEN,
66             TRANSIT_CLOSE,
67             // Note: to_front/to_back really mean show/hide respectively at the container level.
68             TRANSIT_TO_FRONT,
69             TRANSIT_TO_BACK,
70             TRANSIT_CHANGE
71     })
72     public @interface TransitionMode {}
73 
74     /** No flags */
75     public static final int FLAG_NONE = 0;
76 
77     /** The container shows the wallpaper behind it. */
78     public static final int FLAG_SHOW_WALLPAPER = 1;
79 
80     /** The container IS the wallpaper. */
81     public static final int FLAG_IS_WALLPAPER = 1 << 1;
82 
83     /** The container is translucent. */
84     public static final int FLAG_TRANSLUCENT = 1 << 2;
85 
86     // TODO: remove when starting-window is moved to Task
87     /** The container is the recipient of a transferred starting-window */
88     public static final int FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT = 1 << 3;
89 
90     /** The container has voice session. */
91     public static final int FLAG_IS_VOICE_INTERACTION = 1 << 4;
92 
93     /** The container is the display. */
94     public static final int FLAG_IS_DISPLAY = 1 << 5;
95 
96     /** The container can show on top of lock screen. */
97     public static final int FLAG_OCCLUDES_KEYGUARD = 1 << 6;
98 
99     /**
100      * Only for IS_DISPLAY containers. Is set if the display has system alert windows. This is
101      * used to prevent seamless rotation.
102      * TODO(b/194540864): Once we can include all windows in transition, then replace this with
103      *         something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations.
104      */
105     public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
106 
107     /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
108     public static final int FLAG_FIRST_CUSTOM = 1 << 8;
109 
110     /** @hide */
111     @IntDef(prefix = { "FLAG_" }, value = {
112             FLAG_NONE,
113             FLAG_SHOW_WALLPAPER,
114             FLAG_IS_WALLPAPER,
115             FLAG_TRANSLUCENT,
116             FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT,
117             FLAG_IS_VOICE_INTERACTION,
118             FLAG_IS_DISPLAY,
119             FLAG_OCCLUDES_KEYGUARD,
120             FLAG_DISPLAY_HAS_ALERT_WINDOWS,
121             FLAG_FIRST_CUSTOM
122     })
123     public @interface ChangeFlags {}
124 
125     private final @TransitionType int mType;
126     private final @TransitionFlags int mFlags;
127     private final ArrayList<Change> mChanges = new ArrayList<>();
128 
129     private SurfaceControl mRootLeash;
130     private final Point mRootOffset = new Point();
131 
132     private AnimationOptions mOptions;
133 
134     /** @hide */
TransitionInfo(@ransitionType int type, @TransitionFlags int flags)135     public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) {
136         mType = type;
137         mFlags = flags;
138     }
139 
TransitionInfo(Parcel in)140     private TransitionInfo(Parcel in) {
141         mType = in.readInt();
142         mFlags = in.readInt();
143         in.readTypedList(mChanges, Change.CREATOR);
144         mRootLeash = new SurfaceControl();
145         mRootLeash.readFromParcel(in);
146         mRootOffset.readFromParcel(in);
147         mOptions = in.readTypedObject(AnimationOptions.CREATOR);
148     }
149 
150     @Override
151     /** @hide */
writeToParcel(@onNull Parcel dest, int flags)152     public void writeToParcel(@NonNull Parcel dest, int flags) {
153         dest.writeInt(mType);
154         dest.writeInt(mFlags);
155         dest.writeTypedList(mChanges);
156         mRootLeash.writeToParcel(dest, flags);
157         mRootOffset.writeToParcel(dest, flags);
158         dest.writeTypedObject(mOptions, flags);
159     }
160 
161     @NonNull
162     public static final Creator<TransitionInfo> CREATOR =
163             new Creator<TransitionInfo>() {
164                 @Override
165                 public TransitionInfo createFromParcel(Parcel in) {
166                     return new TransitionInfo(in);
167                 }
168 
169                 @Override
170                 public TransitionInfo[] newArray(int size) {
171                     return new TransitionInfo[size];
172                 }
173             };
174 
175     @Override
176     /** @hide */
describeContents()177     public int describeContents() {
178         return 0;
179     }
180 
181     /** @see #getRootLeash() */
setRootLeash(@onNull SurfaceControl leash, int offsetLeft, int offsetTop)182     public void setRootLeash(@NonNull SurfaceControl leash, int offsetLeft, int offsetTop) {
183         mRootLeash = leash;
184         mRootOffset.set(offsetLeft, offsetTop);
185     }
186 
setAnimationOptions(AnimationOptions options)187     public void setAnimationOptions(AnimationOptions options) {
188         mOptions = options;
189     }
190 
getType()191     public @TransitionType int getType() {
192         return mType;
193     }
194 
getFlags()195     public int getFlags() {
196         return mFlags;
197     }
198 
199     /**
200      * @return a surfacecontrol that can serve as a parent surfacecontrol for all the changing
201      * participants to animate within. This will generally be placed at the highest-z-order
202      * shared ancestor of all participants. While this is non-null, it's possible for the rootleash
203      * to be invalid if the transition is a no-op.
204      */
205     @NonNull
getRootLeash()206     public SurfaceControl getRootLeash() {
207         if (mRootLeash == null) {
208             throw new IllegalStateException("Trying to get a leash which wasn't set");
209         }
210         return mRootLeash;
211     }
212 
213     /** @return the offset (relative to the screen) of the root leash. */
214     @NonNull
getRootOffset()215     public Point getRootOffset() {
216         return mRootOffset;
217     }
218 
getAnimationOptions()219     public AnimationOptions getAnimationOptions() {
220         return mOptions;
221     }
222 
223     /**
224      * @return the list of {@link Change}s in this transition. The list is sorted top-to-bottom
225      *         in Z (meaning index 0 is the top-most container).
226      */
227     @NonNull
getChanges()228     public List<Change> getChanges() {
229         return mChanges;
230     }
231 
232     /**
233      * @return the Change that a window is undergoing or {@code null} if not directly
234      * represented.
235      */
236     @Nullable
getChange(@onNull WindowContainerToken token)237     public Change getChange(@NonNull WindowContainerToken token) {
238         for (int i = mChanges.size() - 1; i >= 0; --i) {
239             if (token.equals(mChanges.get(i).mContainer)) {
240                 return mChanges.get(i);
241             }
242         }
243         return null;
244     }
245 
246     /**
247      * Add a {@link Change} to this transition.
248      */
addChange(@onNull Change change)249     public void addChange(@NonNull Change change) {
250         mChanges.add(change);
251     }
252 
253     /**
254      * Whether this transition includes keyguard going away.
255      */
isKeyguardGoingAway()256     public boolean isKeyguardGoingAway() {
257         return (mFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0;
258     }
259 
260     @Override
toString()261     public String toString() {
262         StringBuilder sb = new StringBuilder();
263         sb.append("{t=" + transitTypeToString(mType) + " f=0x" + Integer.toHexString(mFlags)
264                 + " ro=" + mRootOffset + " c=[");
265         for (int i = 0; i < mChanges.size(); ++i) {
266             if (i > 0) {
267                 sb.append(',');
268             }
269             sb.append(mChanges.get(i));
270         }
271         sb.append("]}");
272         return sb.toString();
273     }
274 
275     /** Converts a transition mode/action to its string representation. */
276     @NonNull
modeToString(@ransitionMode int mode)277     public static String modeToString(@TransitionMode int mode) {
278         switch(mode) {
279             case TRANSIT_NONE: return "NONE";
280             case TRANSIT_OPEN: return "OPEN";
281             case TRANSIT_CLOSE: return "CLOSE";
282             case TRANSIT_TO_FRONT: return "SHOW";
283             case TRANSIT_TO_BACK: return "HIDE";
284             case TRANSIT_CHANGE: return "CHANGE";
285             default: return "<unknown:" + mode + ">";
286         }
287     }
288 
289     /** Converts change flags into a string representation. */
290     @NonNull
flagsToString(@hangeFlags int flags)291     public static String flagsToString(@ChangeFlags int flags) {
292         if (flags == 0) return "NONE";
293         final StringBuilder sb = new StringBuilder();
294         if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
295             sb.append("SHOW_WALLPAPER");
296         }
297         if ((flags & FLAG_IS_WALLPAPER) != 0) {
298             sb.append("IS_WALLPAPER");
299         }
300         if ((flags & FLAG_TRANSLUCENT) != 0) {
301             sb.append((sb.length() == 0 ? "" : "|") + "TRANSLUCENT");
302         }
303         if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
304             sb.append((sb.length() == 0 ? "" : "|") + "STARTING_WINDOW_TRANSFER");
305         }
306         if ((flags & FLAG_IS_VOICE_INTERACTION) != 0) {
307             sb.append((sb.length() == 0 ? "" : "|") + "IS_VOICE_INTERACTION");
308         }
309         if ((flags & FLAG_IS_DISPLAY) != 0) {
310             sb.append((sb.length() == 0 ? "" : "|") + "IS_DISPLAY");
311         }
312         if ((flags & FLAG_OCCLUDES_KEYGUARD) != 0) {
313             sb.append((sb.length() == 0 ? "" : "|") + "OCCLUDES_KEYGUARD");
314         }
315         if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
316             sb.append((sb.length() == 0 ? "" : "|") + "DISPLAY_HAS_ALERT_WINDOWS");
317         }
318         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
319             sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM");
320         }
321         return sb.toString();
322     }
323 
324     /**
325      * Indication that `change` is independent of parents (ie. it has a different type of
326      * transition vs. "going along for the ride")
327      */
isIndependent(@onNull TransitionInfo.Change change, @NonNull TransitionInfo info)328     public static boolean isIndependent(@NonNull TransitionInfo.Change change,
329             @NonNull TransitionInfo info) {
330         // If the change has no parent (it is root), then it is independent
331         if (change.getParent() == null) return true;
332 
333         // non-visibility changes will just be folded into the parent change, so they aren't
334         // independent either.
335         if (change.getMode() == TRANSIT_CHANGE) return false;
336 
337         TransitionInfo.Change parentChg = info.getChange(change.getParent());
338         while (parentChg != null) {
339             // If the parent is a visibility change, it will include the results of all child
340             // changes into itself, so none of its children can be independent.
341             if (parentChg.getMode() != TRANSIT_CHANGE) return false;
342 
343             // If there are no more parents left, then all the parents, so far, have not been
344             // visibility changes which means this change is indpendent.
345             if (parentChg.getParent() == null) return true;
346 
347             parentChg = info.getChange(parentChg.getParent());
348         }
349         return false;
350     }
351 
352     /** Represents the change a WindowContainer undergoes during a transition */
353     public static final class Change implements Parcelable {
354         private final WindowContainerToken mContainer;
355         private WindowContainerToken mParent;
356         private final SurfaceControl mLeash;
357         private @TransitionMode int mMode = TRANSIT_NONE;
358         private @ChangeFlags int mFlags = FLAG_NONE;
359         private final Rect mStartAbsBounds = new Rect();
360         private final Rect mEndAbsBounds = new Rect();
361         private final Point mEndRelOffset = new Point();
362         private ActivityManager.RunningTaskInfo mTaskInfo = null;
363         private boolean mAllowEnterPip;
364         private int mStartRotation = ROTATION_UNDEFINED;
365         private int mEndRotation = ROTATION_UNDEFINED;
366         private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
367 
Change(@ullable WindowContainerToken container, @NonNull SurfaceControl leash)368         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
369             mContainer = container;
370             mLeash = leash;
371         }
372 
Change(Parcel in)373         private Change(Parcel in) {
374             mContainer = in.readTypedObject(WindowContainerToken.CREATOR);
375             mParent = in.readTypedObject(WindowContainerToken.CREATOR);
376             mLeash = new SurfaceControl();
377             mLeash.readFromParcel(in);
378             mMode = in.readInt();
379             mFlags = in.readInt();
380             mStartAbsBounds.readFromParcel(in);
381             mEndAbsBounds.readFromParcel(in);
382             mEndRelOffset.readFromParcel(in);
383             mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
384             mAllowEnterPip = in.readBoolean();
385             mStartRotation = in.readInt();
386             mEndRotation = in.readInt();
387             mRotationAnimation = in.readInt();
388         }
389 
390         /** Sets the parent of this change's container. The parent must be a participant or null. */
setParent(@ullable WindowContainerToken parent)391         public void setParent(@Nullable WindowContainerToken parent) {
392             mParent = parent;
393         }
394 
395         /** Sets the transition mode for this change */
setMode(@ransitionMode int mode)396         public void setMode(@TransitionMode int mode) {
397             mMode = mode;
398         }
399 
400         /** Sets the flags for this change */
setFlags(@hangeFlags int flags)401         public void setFlags(@ChangeFlags int flags) {
402             mFlags = flags;
403         }
404 
405         /** Sets the bounds this container occupied before the change in screen space */
setStartAbsBounds(@ullable Rect rect)406         public void setStartAbsBounds(@Nullable Rect rect) {
407             mStartAbsBounds.set(rect);
408         }
409 
410         /** Sets the bounds this container will occupy after the change in screen space */
setEndAbsBounds(@ullable Rect rect)411         public void setEndAbsBounds(@Nullable Rect rect) {
412             mEndAbsBounds.set(rect);
413         }
414 
415         /** Sets the offset of this container from its parent surface */
setEndRelOffset(int left, int top)416         public void setEndRelOffset(int left, int top) {
417             mEndRelOffset.set(left, top);
418         }
419 
420         /**
421          * Sets the taskinfo of this container if this is a task. WARNING: this takes the
422          * reference, so don't modify it afterwards.
423          */
setTaskInfo(@ullable ActivityManager.RunningTaskInfo taskInfo)424         public void setTaskInfo(@Nullable ActivityManager.RunningTaskInfo taskInfo) {
425             mTaskInfo = taskInfo;
426         }
427 
428         /** Sets the allowEnterPip flag which represents AppOpsManager check on PiP permission */
setAllowEnterPip(boolean allowEnterPip)429         public void setAllowEnterPip(boolean allowEnterPip) {
430             mAllowEnterPip = allowEnterPip;
431         }
432 
433         /** Sets the start and end rotation of this container. */
setRotation(@urface.Rotation int start, @Surface.Rotation int end)434         public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
435             mStartRotation = start;
436             mEndRotation = end;
437         }
438 
439         /**
440          * Sets the app-requested animation type for rotation. Will be one of the
441          * ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams};
442          */
setRotationAnimation(int anim)443         public void setRotationAnimation(int anim) {
444             mRotationAnimation = anim;
445         }
446 
447         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
448         @Nullable
getContainer()449         public WindowContainerToken getContainer() {
450             return mContainer;
451         }
452 
453         /**
454          * @return the parent of the changing container. This is the parent within the participants,
455          * not necessarily the actual parent.
456          */
457         @Nullable
getParent()458         public WindowContainerToken getParent() {
459             return mParent;
460         }
461 
462         /** @return which action this change represents. */
getMode()463         public @TransitionMode int getMode() {
464             return mMode;
465         }
466 
467         /** @return the flags for this change. */
getFlags()468         public @ChangeFlags int getFlags() {
469             return mFlags;
470         }
471 
472         /**
473          * @return the bounds of the container before the change. It may be empty if the container
474          * is coming into existence.
475          */
476         @NonNull
getStartAbsBounds()477         public Rect getStartAbsBounds() {
478             return mStartAbsBounds;
479         }
480 
481         /**
482          * @return the bounds of the container after the change. It may be empty if the container
483          * is disappearing.
484          */
485         @NonNull
getEndAbsBounds()486         public Rect getEndAbsBounds() {
487             return mEndAbsBounds;
488         }
489 
490         /**
491          * @return the offset of the container's surface from its parent surface after the change.
492          */
493         @NonNull
getEndRelOffset()494         public Point getEndRelOffset() {
495             return mEndRelOffset;
496         }
497 
498         /** @return the leash or surface to animate for this container */
499         @NonNull
getLeash()500         public SurfaceControl getLeash() {
501             return mLeash;
502         }
503 
504         /** @return the task info or null if this isn't a task */
505         @NonNull
getTaskInfo()506         public ActivityManager.RunningTaskInfo getTaskInfo() {
507             return mTaskInfo;
508         }
509 
getAllowEnterPip()510         public boolean getAllowEnterPip() {
511             return mAllowEnterPip;
512         }
513 
getStartRotation()514         public int getStartRotation() {
515             return mStartRotation;
516         }
517 
getEndRotation()518         public int getEndRotation() {
519             return mEndRotation;
520         }
521 
522         /** @return the rotation animation. */
getRotationAnimation()523         public int getRotationAnimation() {
524             return mRotationAnimation;
525         }
526 
527         /** @hide */
528         @Override
writeToParcel(@onNull Parcel dest, int flags)529         public void writeToParcel(@NonNull Parcel dest, int flags) {
530             dest.writeTypedObject(mContainer, flags);
531             dest.writeTypedObject(mParent, flags);
532             mLeash.writeToParcel(dest, flags);
533             dest.writeInt(mMode);
534             dest.writeInt(mFlags);
535             mStartAbsBounds.writeToParcel(dest, flags);
536             mEndAbsBounds.writeToParcel(dest, flags);
537             mEndRelOffset.writeToParcel(dest, flags);
538             dest.writeTypedObject(mTaskInfo, flags);
539             dest.writeBoolean(mAllowEnterPip);
540             dest.writeInt(mStartRotation);
541             dest.writeInt(mEndRotation);
542             dest.writeInt(mRotationAnimation);
543         }
544 
545         @NonNull
546         public static final Creator<Change> CREATOR =
547                 new Creator<Change>() {
548                     @Override
549                     public Change createFromParcel(Parcel in) {
550                         return new Change(in);
551                     }
552 
553                     @Override
554                     public Change[] newArray(int size) {
555                         return new Change[size];
556                     }
557                 };
558 
559         /** @hide */
560         @Override
describeContents()561         public int describeContents() {
562             return 0;
563         }
564 
565         @Override
toString()566         public String toString() {
567             return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
568                     + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
569                     + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
570                     + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation + "}";
571         }
572     }
573 
574     /** Represents animation options during a transition */
575     public static final class AnimationOptions implements Parcelable {
576 
577         private int mType;
578         private int mEnterResId;
579         private int mExitResId;
580         private boolean mOverrideTaskTransition;
581         private String mPackageName;
582         private final Rect mTransitionBounds = new Rect();
583         private HardwareBuffer mThumbnail;
584 
AnimationOptions(int type)585         private AnimationOptions(int type) {
586             mType = type;
587         }
588 
AnimationOptions(Parcel in)589         public AnimationOptions(Parcel in) {
590             mType = in.readInt();
591             mEnterResId = in.readInt();
592             mExitResId = in.readInt();
593             mOverrideTaskTransition = in.readBoolean();
594             mPackageName = in.readString();
595             mTransitionBounds.readFromParcel(in);
596             mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
597         }
598 
makeCustomAnimOptions(String packageName, int enterResId, int exitResId, boolean overrideTaskTransition)599         public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
600                 int exitResId, boolean overrideTaskTransition) {
601             AnimationOptions options = new AnimationOptions(ANIM_CUSTOM);
602             options.mPackageName = packageName;
603             options.mEnterResId = enterResId;
604             options.mExitResId = exitResId;
605             options.mOverrideTaskTransition = overrideTaskTransition;
606             return options;
607         }
608 
makeClipRevealAnimOptions(int startX, int startY, int width, int height)609         public static AnimationOptions makeClipRevealAnimOptions(int startX, int startY, int width,
610                 int height) {
611             AnimationOptions options = new AnimationOptions(ANIM_CLIP_REVEAL);
612             options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
613             return options;
614         }
615 
makeScaleUpAnimOptions(int startX, int startY, int width, int height)616         public static AnimationOptions makeScaleUpAnimOptions(int startX, int startY, int width,
617                 int height) {
618             AnimationOptions options = new AnimationOptions(ANIM_SCALE_UP);
619             options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
620             return options;
621         }
622 
makeThumnbnailAnimOptions(HardwareBuffer srcThumb, int startX, int startY, boolean scaleUp)623         public static AnimationOptions makeThumnbnailAnimOptions(HardwareBuffer srcThumb,
624                 int startX, int startY, boolean scaleUp) {
625             AnimationOptions options = new AnimationOptions(
626                     scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN);
627             options.mTransitionBounds.set(startX, startY, startX, startY);
628             options.mThumbnail = srcThumb;
629             return options;
630         }
631 
makeCrossProfileAnimOptions()632         public static AnimationOptions makeCrossProfileAnimOptions() {
633             AnimationOptions options = new AnimationOptions(ANIM_OPEN_CROSS_PROFILE_APPS);
634             return options;
635         }
636 
getType()637         public int getType() {
638             return mType;
639         }
640 
getEnterResId()641         public int getEnterResId() {
642             return mEnterResId;
643         }
644 
getExitResId()645         public int getExitResId() {
646             return mExitResId;
647         }
648 
getOverrideTaskTransition()649         public boolean getOverrideTaskTransition() {
650             return mOverrideTaskTransition;
651         }
652 
getPackageName()653         public String getPackageName() {
654             return mPackageName;
655         }
656 
getTransitionBounds()657         public Rect getTransitionBounds() {
658             return mTransitionBounds;
659         }
660 
getThumbnail()661         public HardwareBuffer getThumbnail() {
662             return mThumbnail;
663         }
664 
665         @Override
writeToParcel(Parcel dest, int flags)666         public void writeToParcel(Parcel dest, int flags) {
667             dest.writeInt(mType);
668             dest.writeInt(mEnterResId);
669             dest.writeInt(mExitResId);
670             dest.writeBoolean(mOverrideTaskTransition);
671             dest.writeString(mPackageName);
672             mTransitionBounds.writeToParcel(dest, flags);
673             dest.writeTypedObject(mThumbnail, flags);
674         }
675 
676         @NonNull
677         public static final Creator<AnimationOptions> CREATOR =
678                 new Creator<AnimationOptions>() {
679                     @Override
680                     public AnimationOptions createFromParcel(Parcel in) {
681                         return new AnimationOptions(in);
682                     }
683 
684                     @Override
685                     public AnimationOptions[] newArray(int size) {
686                         return new AnimationOptions[size];
687                     }
688                 };
689 
690         /** @hide */
691         @Override
describeContents()692         public int describeContents() {
693             return 0;
694         }
695 
696         @NonNull
typeToString(int mode)697         private static String typeToString(int mode) {
698             switch(mode) {
699                 case ANIM_CUSTOM: return "ANIM_CUSTOM";
700                 case ANIM_CLIP_REVEAL: return "ANIM_CLIP_REVEAL";
701                 case ANIM_SCALE_UP: return "ANIM_SCALE_UP";
702                 case ANIM_THUMBNAIL_SCALE_UP: return "ANIM_THUMBNAIL_SCALE_UP";
703                 case ANIM_THUMBNAIL_SCALE_DOWN: return "ANIM_THUMBNAIL_SCALE_DOWN";
704                 case ANIM_OPEN_CROSS_PROFILE_APPS: return "ANIM_OPEN_CROSS_PROFILE_APPS";
705                 default: return "<unknown:" + mode + ">";
706             }
707         }
708 
709         @Override
toString()710         public String toString() {
711             return "{ AnimationOtions type= " + typeToString(mType) + " package=" + mPackageName
712                     + " override=" + mOverrideTaskTransition + " b=" + mTransitionBounds + "}";
713         }
714     }
715 }
716