• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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