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