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