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.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS; 20 import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT; 21 import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT; 22 import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; 23 import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT; 24 import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; 25 import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT; 26 import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; 27 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.annotation.TestApi; 31 import android.app.PendingIntent; 32 import android.app.WindowConfiguration; 33 import android.content.Intent; 34 import android.content.pm.ActivityInfo; 35 import android.content.pm.ShortcutInfo; 36 import android.content.res.Configuration; 37 import android.graphics.Rect; 38 import android.os.Bundle; 39 import android.os.IBinder; 40 import android.os.Parcel; 41 import android.os.Parcelable; 42 import android.util.ArrayMap; 43 import android.view.InsetsFrameProvider; 44 import android.view.SurfaceControl; 45 import android.view.WindowInsets.Type.InsetsType; 46 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.List; 50 import java.util.Map; 51 import java.util.Objects; 52 53 /** 54 * Represents a collection of operations on some WindowContainers that should be applied all at 55 * once. 56 * 57 * @hide 58 */ 59 @TestApi 60 public final class WindowContainerTransaction implements Parcelable { 61 private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>(); 62 63 // Flat list because re-order operations are order-dependent 64 private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>(); 65 66 @Nullable 67 private IBinder mErrorCallbackToken; 68 69 @Nullable 70 private ITaskFragmentOrganizer mTaskFragmentOrganizer; 71 WindowContainerTransaction()72 public WindowContainerTransaction() {} 73 WindowContainerTransaction(Parcel in)74 private WindowContainerTransaction(Parcel in) { 75 in.readMap(mChanges, null /* loader */); 76 in.readTypedList(mHierarchyOps, HierarchyOp.CREATOR); 77 mErrorCallbackToken = in.readStrongBinder(); 78 mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder()); 79 } 80 getOrCreateChange(IBinder token)81 private Change getOrCreateChange(IBinder token) { 82 Change out = mChanges.get(token); 83 if (out == null) { 84 out = new Change(); 85 mChanges.put(token, out); 86 } 87 return out; 88 } 89 90 /** 91 * Clear the transaction object. 92 * This is equivalent to a new empty {@link WindowContainerTransaction} in content. 93 * 94 * @hide 95 */ clear()96 public void clear() { 97 mChanges.clear(); 98 mHierarchyOps.clear(); 99 mErrorCallbackToken = null; 100 mTaskFragmentOrganizer = null; 101 } 102 103 /** 104 * Resize a container. 105 */ 106 @NonNull setBounds( @onNull WindowContainerToken container,@NonNull Rect bounds)107 public WindowContainerTransaction setBounds( 108 @NonNull WindowContainerToken container,@NonNull Rect bounds) { 109 Change chg = getOrCreateChange(container.asBinder()); 110 chg.mConfiguration.windowConfiguration.setBounds(bounds); 111 chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 112 chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS; 113 return this; 114 } 115 116 /** 117 * Resize a container's app bounds. This is the bounds used to report appWidth/Height to an 118 * app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from 119 * the full bounds. 120 */ 121 @NonNull setAppBounds( @onNull WindowContainerToken container,@NonNull Rect appBounds)122 public WindowContainerTransaction setAppBounds( 123 @NonNull WindowContainerToken container,@NonNull Rect appBounds) { 124 Change chg = getOrCreateChange(container.asBinder()); 125 chg.mConfiguration.windowConfiguration.setAppBounds(appBounds); 126 chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 127 chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS; 128 return this; 129 } 130 131 /** 132 * Resize a container's configuration size. The configuration size is what gets reported to the 133 * app via screenWidth/HeightDp and influences which resources get loaded. This size is 134 * derived by subtracting the overlapping portions of both the statusbar and the navbar from 135 * the full bounds. 136 */ 137 @NonNull setScreenSizeDp( @onNull WindowContainerToken container, int w, int h)138 public WindowContainerTransaction setScreenSizeDp( 139 @NonNull WindowContainerToken container, int w, int h) { 140 Change chg = getOrCreateChange(container.asBinder()); 141 chg.mConfiguration.screenWidthDp = w; 142 chg.mConfiguration.screenHeightDp = h; 143 chg.mConfigSetMask |= ActivityInfo.CONFIG_SCREEN_SIZE; 144 return this; 145 } 146 147 /** 148 * Sets the densityDpi value in the configuration for the given container. 149 * @hide 150 */ 151 @NonNull setDensityDpi(@onNull WindowContainerToken container, int densityDpi)152 public WindowContainerTransaction setDensityDpi(@NonNull WindowContainerToken container, 153 int densityDpi) { 154 Change chg = getOrCreateChange(container.asBinder()); 155 chg.mConfiguration.densityDpi = densityDpi; 156 chg.mConfigSetMask |= ActivityInfo.CONFIG_DENSITY; 157 return this; 158 } 159 160 /** 161 * Notify {@link com.android.server.wm.PinnedTaskController} that the picture-in-picture task 162 * has finished the enter animation with the given bounds. 163 */ 164 @NonNull scheduleFinishEnterPip( @onNull WindowContainerToken container,@NonNull Rect bounds)165 public WindowContainerTransaction scheduleFinishEnterPip( 166 @NonNull WindowContainerToken container,@NonNull Rect bounds) { 167 Change chg = getOrCreateChange(container.asBinder()); 168 chg.mPinnedBounds = new Rect(bounds); 169 chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK; 170 171 return this; 172 } 173 174 /** 175 * Send a SurfaceControl transaction to the server, which the server will apply in sync with 176 * the next bounds change. As this uses deferred transaction and not BLAST it is only 177 * able to sync with a single window, and the first visible window in this hierarchy of type 178 * BASE_APPLICATION to resize will be used. If there are bound changes included in this 179 * WindowContainer transaction (from setBounds or scheduleFinishEnterPip), the SurfaceControl 180 * transaction will be synced with those bounds. If there are no changes, then 181 * the SurfaceControl transaction will be synced with the next bounds change. This means 182 * that you can call this, apply the WindowContainer transaction, and then later call 183 * dismissPip() to achieve synchronization. 184 */ 185 @NonNull setBoundsChangeTransaction( @onNull WindowContainerToken container,@NonNull SurfaceControl.Transaction t)186 public WindowContainerTransaction setBoundsChangeTransaction( 187 @NonNull WindowContainerToken container,@NonNull SurfaceControl.Transaction t) { 188 Change chg = getOrCreateChange(container.asBinder()); 189 chg.mBoundsChangeTransaction = t; 190 chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION; 191 return this; 192 } 193 194 /** 195 * Like {@link #setBoundsChangeTransaction} but instead queues up a setPosition/WindowCrop 196 * on a container's surface control. This is useful when a boundsChangeTransaction needs to be 197 * queued up on a Task that won't be organized until the end of this window-container 198 * transaction. 199 * 200 * This requires that, at the end of this transaction, `task` will be organized; otherwise 201 * the server will throw an IllegalArgumentException. 202 * 203 * WARNING: Use this carefully. Whatever is set here should match the expected bounds after 204 * the transaction completes since it will likely be replaced by it. This call is 205 * intended to pre-emptively set bounds on a surface in sync with a buffer when 206 * otherwise the new bounds and the new buffer would update on different frames. 207 * 208 * TODO(b/134365562): remove once TaskOrg drives full-screen or BLAST is enabled. 209 * 210 * @hide 211 */ 212 @NonNull setBoundsChangeTransaction( @onNull WindowContainerToken task, @NonNull Rect surfaceBounds)213 public WindowContainerTransaction setBoundsChangeTransaction( 214 @NonNull WindowContainerToken task, @NonNull Rect surfaceBounds) { 215 Change chg = getOrCreateChange(task.asBinder()); 216 if (chg.mBoundsChangeSurfaceBounds == null) { 217 chg.mBoundsChangeSurfaceBounds = new Rect(); 218 } 219 chg.mBoundsChangeSurfaceBounds.set(surfaceBounds); 220 chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION_RECT; 221 return this; 222 } 223 224 /** 225 * Set the windowing mode of children of a given root task, without changing 226 * the windowing mode of the Task itself. This can be used during transitions 227 * for example to make the activity render it's fullscreen configuration 228 * while the Task is still in PIP, so you can complete the animation. 229 * 230 * TODO(b/134365562): Can be removed once TaskOrg drives full-screen 231 */ 232 @NonNull setActivityWindowingMode( @onNull WindowContainerToken container, int windowingMode)233 public WindowContainerTransaction setActivityWindowingMode( 234 @NonNull WindowContainerToken container, int windowingMode) { 235 Change chg = getOrCreateChange(container.asBinder()); 236 chg.mActivityWindowingMode = windowingMode; 237 return this; 238 } 239 240 /** 241 * Sets the windowing mode of the given container. 242 */ 243 @NonNull setWindowingMode( @onNull WindowContainerToken container, int windowingMode)244 public WindowContainerTransaction setWindowingMode( 245 @NonNull WindowContainerToken container, int windowingMode) { 246 Change chg = getOrCreateChange(container.asBinder()); 247 chg.mWindowingMode = windowingMode; 248 return this; 249 } 250 251 /** 252 * Sets whether a container or any of its children can be focusable. When {@code false}, no 253 * child can be focused; however, when {@code true}, it is still possible for children to be 254 * non-focusable due to WM policy. 255 */ 256 @NonNull setFocusable( @onNull WindowContainerToken container, boolean focusable)257 public WindowContainerTransaction setFocusable( 258 @NonNull WindowContainerToken container, boolean focusable) { 259 Change chg = getOrCreateChange(container.asBinder()); 260 chg.mFocusable = focusable; 261 chg.mChangeMask |= Change.CHANGE_FOCUSABLE; 262 return this; 263 } 264 265 /** 266 * Sets whether a container or its children should be hidden. When {@code false}, the existing 267 * visibility of the container applies, but when {@code true} the container will be forced 268 * to be hidden. 269 */ 270 @NonNull setHidden( @onNull WindowContainerToken container, boolean hidden)271 public WindowContainerTransaction setHidden( 272 @NonNull WindowContainerToken container, boolean hidden) { 273 Change chg = getOrCreateChange(container.asBinder()); 274 chg.mHidden = hidden; 275 chg.mChangeMask |= Change.CHANGE_HIDDEN; 276 return this; 277 } 278 279 /** 280 * Set the smallestScreenWidth of a container. 281 */ 282 @NonNull setSmallestScreenWidthDp( @onNull WindowContainerToken container, int widthDp)283 public WindowContainerTransaction setSmallestScreenWidthDp( 284 @NonNull WindowContainerToken container, int widthDp) { 285 Change cfg = getOrCreateChange(container.asBinder()); 286 cfg.mConfiguration.smallestScreenWidthDp = widthDp; 287 cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 288 return this; 289 } 290 291 /** 292 * Sets whether a container should ignore the orientation request from apps and windows below 293 * it. It currently only applies to {@link com.android.server.wm.DisplayArea}. When 294 * {@code false}, it may rotate based on the orientation request; When {@code true}, it can 295 * never specify orientation, but shows the fixed-orientation apps below it in the letterbox. 296 * @hide 297 */ 298 @NonNull setIgnoreOrientationRequest( @onNull WindowContainerToken container, boolean ignoreOrientationRequest)299 public WindowContainerTransaction setIgnoreOrientationRequest( 300 @NonNull WindowContainerToken container, boolean ignoreOrientationRequest) { 301 Change chg = getOrCreateChange(container.asBinder()); 302 chg.mIgnoreOrientationRequest = ignoreOrientationRequest; 303 chg.mChangeMask |= Change.CHANGE_IGNORE_ORIENTATION_REQUEST; 304 return this; 305 } 306 307 /** 308 * Sets whether a task should be translucent. When {@code false}, the existing translucent of 309 * the task applies, but when {@code true} the task will be forced to be translucent. 310 * @hide 311 */ 312 @NonNull setForceTranslucent( @onNull WindowContainerToken container, boolean forceTranslucent)313 public WindowContainerTransaction setForceTranslucent( 314 @NonNull WindowContainerToken container, boolean forceTranslucent) { 315 Change chg = getOrCreateChange(container.asBinder()); 316 chg.mForceTranslucent = forceTranslucent; 317 chg.mChangeMask |= Change.CHANGE_FORCE_TRANSLUCENT; 318 return this; 319 } 320 321 /** 322 * Used in conjunction with a shell-transition call (usually finishTransition). This is 323 * basically a message to the transition system that a particular task should NOT go into 324 * PIP even though it normally would. This is to deal with some edge-case situations where 325 * Recents will "commit" the transition to go home, but then not actually go-home. 326 * @hide 327 */ 328 @NonNull setDoNotPip(@onNull WindowContainerToken container)329 public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) { 330 Change chg = getOrCreateChange(container.asBinder()); 331 chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP; 332 return this; 333 } 334 335 /** 336 * Resizes a container by providing a bounds in its parent coordinate. 337 * This is only used by {@link TaskFragmentOrganizer}. 338 */ 339 @NonNull setRelativeBounds( @onNull WindowContainerToken container, @NonNull Rect relBounds)340 public WindowContainerTransaction setRelativeBounds( 341 @NonNull WindowContainerToken container, @NonNull Rect relBounds) { 342 Change chg = getOrCreateChange(container.asBinder()); 343 if (chg.mRelativeBounds == null) { 344 chg.mRelativeBounds = new Rect(); 345 } 346 chg.mRelativeBounds.set(relBounds); 347 chg.mChangeMask |= Change.CHANGE_RELATIVE_BOUNDS; 348 // Bounds will be overridden. 349 chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 350 chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS; 351 return this; 352 } 353 354 /** 355 * Reparents a container into another one. The effect of a {@code null} parent can vary. For 356 * example, reparenting a stack to {@code null} will reparent it to its display. 357 * 358 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to 359 * the bottom. 360 */ 361 @NonNull reparent(@onNull WindowContainerToken child, @Nullable WindowContainerToken parent, boolean onTop)362 public WindowContainerTransaction reparent(@NonNull WindowContainerToken child, 363 @Nullable WindowContainerToken parent, boolean onTop) { 364 mHierarchyOps.add(HierarchyOp.createForReparent(child.asBinder(), 365 parent == null ? null : parent.asBinder(), 366 onTop)); 367 return this; 368 } 369 370 /** 371 * Reorders a container within its parent. 372 * 373 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to 374 * the bottom. 375 */ 376 @NonNull reorder(@onNull WindowContainerToken child, boolean onTop)377 public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop) { 378 return reorder(child, onTop, false /* includingParents */); 379 } 380 381 /** 382 * Reorders a container within its parent with an option to reorder all the parents in the 383 * hierarchy above among their respective siblings. 384 * 385 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to 386 * the bottom. 387 * @param includingParents When {@code true}, all the parents in the hierarchy above are also 388 * reordered among their respective siblings. 389 * @hide 390 */ 391 @NonNull reorder(@onNull WindowContainerToken child, boolean onTop, boolean includingParents)392 public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop, 393 boolean includingParents) { 394 mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop, includingParents)); 395 return this; 396 } 397 398 /** 399 * Reparent's all children tasks or the top task of {@param currentParent} in the specified 400 * {@param windowingMode} and {@param activityType} to {@param newParent} in their current 401 * z-order. 402 * 403 * @param currentParent of the tasks to perform the operation no. 404 * {@code null} will perform the operation on the display. 405 * @param newParent for the tasks. {@code null} will perform the operation on the display. 406 * @param windowingModes of the tasks to reparent. 407 * @param activityTypes of the tasks to reparent. 408 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to 409 * the bottom. 410 * @param reparentTopOnly When {@code true}, only reparent the top task which fit windowingModes 411 * and activityTypes. 412 * @hide 413 */ 414 @NonNull reparentTasks(@ullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly)415 public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, 416 @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, 417 @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) { 418 mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent( 419 currentParent != null ? currentParent.asBinder() : null, 420 newParent != null ? newParent.asBinder() : null, 421 windowingModes, 422 activityTypes, 423 onTop, 424 reparentTopOnly)); 425 return this; 426 } 427 428 /** 429 * Reparent's all children tasks of {@param currentParent} in the specified 430 * {@param windowingMode} and {@param activityType} to {@param newParent} in their current 431 * z-order. 432 * 433 * @param currentParent of the tasks to perform the operation no. 434 * {@code null} will perform the operation on the display. 435 * @param newParent for the tasks. {@code null} will perform the operation on the display. 436 * @param windowingModes of the tasks to reparent. {@code null} ignore this attribute when 437 * perform the operation. 438 * @param activityTypes of the tasks to reparent. {@code null} ignore this attribute when 439 * perform the operation. 440 * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to 441 * the bottom. 442 */ 443 @NonNull reparentTasks(@ullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, @Nullable int[] activityTypes, boolean onTop)444 public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, 445 @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, 446 @Nullable int[] activityTypes, boolean onTop) { 447 return reparentTasks(currentParent, newParent, windowingModes, activityTypes, onTop, 448 false /* reparentTopOnly */); 449 } 450 451 /** 452 * Sets whether a container should be the launch root for the specified windowing mode and 453 * activity type. This currently only applies to Task containers created by organizer. 454 */ 455 @NonNull setLaunchRoot(@onNull WindowContainerToken container, @Nullable int[] windowingModes, @Nullable int[] activityTypes)456 public WindowContainerTransaction setLaunchRoot(@NonNull WindowContainerToken container, 457 @Nullable int[] windowingModes, @Nullable int[] activityTypes) { 458 mHierarchyOps.add(HierarchyOp.createForSetLaunchRoot( 459 container.asBinder(), 460 windowingModes, 461 activityTypes)); 462 return this; 463 } 464 465 /** 466 * Sets to containers adjacent to each other. Containers below two visible adjacent roots will 467 * be made invisible. This currently only applies to TaskFragment containers created by 468 * organizer. 469 * @param root1 the first root. 470 * @param root2 the second root. 471 */ 472 @NonNull setAdjacentRoots( @onNull WindowContainerToken root1, @NonNull WindowContainerToken root2)473 public WindowContainerTransaction setAdjacentRoots( 474 @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) { 475 mHierarchyOps.add(HierarchyOp.createForAdjacentRoots( 476 root1.asBinder(), 477 root2.asBinder())); 478 return this; 479 } 480 481 /** 482 * Sets the container as launch adjacent flag root. Task starting with 483 * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} will be launching to. 484 */ 485 @NonNull setLaunchAdjacentFlagRoot( @onNull WindowContainerToken container)486 public WindowContainerTransaction setLaunchAdjacentFlagRoot( 487 @NonNull WindowContainerToken container) { 488 mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(), 489 false /* clearRoot */)); 490 return this; 491 } 492 493 /** 494 * Clears launch adjacent flag root for the display area of passing container. 495 */ 496 @NonNull clearLaunchAdjacentFlagRoot( @onNull WindowContainerToken container)497 public WindowContainerTransaction clearLaunchAdjacentFlagRoot( 498 @NonNull WindowContainerToken container) { 499 mHierarchyOps.add(HierarchyOp.createForSetLaunchAdjacentFlagRoot(container.asBinder(), 500 true /* clearRoot */)); 501 return this; 502 } 503 504 /** 505 * Starts a task by id. The task is expected to already exist (eg. as a recent task). 506 * @param taskId Id of task to start. 507 * @param options bundle containing ActivityOptions for the task's top activity. 508 * @hide 509 */ 510 @NonNull startTask(int taskId, @Nullable Bundle options)511 public WindowContainerTransaction startTask(int taskId, @Nullable Bundle options) { 512 mHierarchyOps.add(HierarchyOp.createForTaskLaunch(taskId, options)); 513 return this; 514 } 515 516 /** 517 * Finds and removes a task and its children using its container token. The task is removed 518 * from recents. 519 * @param containerToken ContainerToken of Task to be removed 520 */ 521 @NonNull removeTask(@onNull WindowContainerToken containerToken)522 public WindowContainerTransaction removeTask(@NonNull WindowContainerToken containerToken) { 523 mHierarchyOps.add(HierarchyOp.createForRemoveTask(containerToken.asBinder())); 524 return this; 525 } 526 527 /** 528 * Sets whether a container is being drag-resized. 529 * When {@code true}, the client will reuse a single (larger) surface size to avoid 530 * continuous allocations on every size change. 531 * 532 * @param container WindowContainerToken of the task that changed its drag resizing state 533 * @hide 534 */ 535 @NonNull setDragResizing(@onNull WindowContainerToken container, boolean dragResizing)536 public WindowContainerTransaction setDragResizing(@NonNull WindowContainerToken container, 537 boolean dragResizing) { 538 final Change change = getOrCreateChange(container.asBinder()); 539 change.mChangeMask |= Change.CHANGE_DRAG_RESIZING; 540 change.mDragResizing = dragResizing; 541 return this; 542 } 543 544 /** 545 * Sends a pending intent in sync. 546 * @param sender The PendingIntent sender. 547 * @param intent The fillIn intent to patch over the sender's base intent. 548 * @param options bundle containing ActivityOptions for the task's top activity. 549 * @hide 550 */ 551 @NonNull sendPendingIntent(PendingIntent sender, Intent intent, @Nullable Bundle options)552 public WindowContainerTransaction sendPendingIntent(PendingIntent sender, Intent intent, 553 @Nullable Bundle options) { 554 mHierarchyOps.add(new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT) 555 .setLaunchOptions(options) 556 .setPendingIntent(sender) 557 .setActivityIntent(intent) 558 .build()); 559 return this; 560 } 561 562 /** 563 * Starts activity(s) from a shortcut. 564 * @param callingPackage The package launching the shortcut. 565 * @param shortcutInfo Information about the shortcut to start 566 * @param options bundle containing ActivityOptions for the task's top activity. 567 * @hide 568 */ 569 @NonNull startShortcut(@onNull String callingPackage, @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options)570 public WindowContainerTransaction startShortcut(@NonNull String callingPackage, 571 @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) { 572 mHierarchyOps.add(HierarchyOp.createForStartShortcut( 573 callingPackage, shortcutInfo, options)); 574 return this; 575 } 576 577 /** 578 * Creates a new TaskFragment with the given options. 579 * @param taskFragmentCreationParams the options used to create the TaskFragment. 580 */ 581 @NonNull createTaskFragment( @onNull TaskFragmentCreationParams taskFragmentCreationParams)582 public WindowContainerTransaction createTaskFragment( 583 @NonNull TaskFragmentCreationParams taskFragmentCreationParams) { 584 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 585 OP_TYPE_CREATE_TASK_FRAGMENT) 586 .setTaskFragmentCreationParams(taskFragmentCreationParams) 587 .build(); 588 return addTaskFragmentOperation(taskFragmentCreationParams.getFragmentToken(), operation); 589 } 590 591 /** 592 * Deletes an existing TaskFragment. Any remaining activities below it will be destroyed. 593 * @param fragmentToken client assigned unique token to create TaskFragment with specified in 594 * {@link TaskFragmentCreationParams#getFragmentToken()}. 595 */ 596 @NonNull deleteTaskFragment(@onNull IBinder fragmentToken)597 public WindowContainerTransaction deleteTaskFragment(@NonNull IBinder fragmentToken) { 598 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 599 OP_TYPE_DELETE_TASK_FRAGMENT) 600 .build(); 601 return addTaskFragmentOperation(fragmentToken, operation); 602 } 603 604 /** 605 * Starts an activity in the TaskFragment. 606 * @param fragmentToken client assigned unique token to create TaskFragment with specified in 607 * {@link TaskFragmentCreationParams#getFragmentToken()}. 608 * @param callerToken the activity token that initialized the activity launch. 609 * @param activityIntent intent to start the activity. 610 * @param activityOptions ActivityOptions to start the activity with. 611 * @see android.content.Context#startActivity(Intent, Bundle). 612 */ 613 @NonNull startActivityInTaskFragment( @onNull IBinder fragmentToken, @NonNull IBinder callerToken, @NonNull Intent activityIntent, @Nullable Bundle activityOptions)614 public WindowContainerTransaction startActivityInTaskFragment( 615 @NonNull IBinder fragmentToken, @NonNull IBinder callerToken, 616 @NonNull Intent activityIntent, @Nullable Bundle activityOptions) { 617 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 618 OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT) 619 .setActivityToken(callerToken) 620 .setActivityIntent(activityIntent) 621 .setBundle(activityOptions) 622 .build(); 623 return addTaskFragmentOperation(fragmentToken, operation); 624 } 625 626 /** 627 * Moves an activity into the TaskFragment. 628 * @param fragmentToken client assigned unique token to create TaskFragment with specified in 629 * {@link TaskFragmentCreationParams#getFragmentToken()}. 630 * @param activityToken activity to be reparented. 631 */ 632 @NonNull reparentActivityToTaskFragment( @onNull IBinder fragmentToken, @NonNull IBinder activityToken)633 public WindowContainerTransaction reparentActivityToTaskFragment( 634 @NonNull IBinder fragmentToken, @NonNull IBinder activityToken) { 635 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 636 OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT) 637 .setActivityToken(activityToken) 638 .build(); 639 return addTaskFragmentOperation(fragmentToken, operation); 640 } 641 642 /** 643 * Sets to TaskFragments adjacent to each other. Containers below two visible adjacent 644 * TaskFragments will be made invisible. This is similar to 645 * {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with 646 * fragmentTokens when that TaskFragments haven't been created (but will be created in the same 647 * {@link WindowContainerTransaction}). 648 * @param fragmentToken1 client assigned unique token to create TaskFragment with specified 649 * in {@link TaskFragmentCreationParams#getFragmentToken()}. 650 * @param fragmentToken2 client assigned unique token to create TaskFragment with specified 651 * in {@link TaskFragmentCreationParams#getFragmentToken()}. 652 */ 653 @NonNull setAdjacentTaskFragments( @onNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2, @Nullable TaskFragmentAdjacentParams params)654 public WindowContainerTransaction setAdjacentTaskFragments( 655 @NonNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2, 656 @Nullable TaskFragmentAdjacentParams params) { 657 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 658 OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS) 659 .setSecondaryFragmentToken(fragmentToken2) 660 .setBundle(params != null ? params.toBundle() : null) 661 .build(); 662 return addTaskFragmentOperation(fragmentToken1, operation); 663 } 664 665 /** 666 * Clears the adjacent TaskFragments relationship that is previously set through 667 * {@link #setAdjacentTaskFragments}. Clear operation on one TaskFragment will also clear its 668 * current adjacent TaskFragment's. 669 * @param fragmentToken client assigned unique token to create TaskFragment with specified 670 * in {@link TaskFragmentCreationParams#getFragmentToken()}. 671 */ 672 @NonNull clearAdjacentTaskFragments(@onNull IBinder fragmentToken)673 public WindowContainerTransaction clearAdjacentTaskFragments(@NonNull IBinder fragmentToken) { 674 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 675 OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS) 676 .build(); 677 return addTaskFragmentOperation(fragmentToken, operation); 678 } 679 680 /** 681 * If `container` was brought to front as a transient-launch (eg. recents), this will reorder 682 * the container back to where it was prior to the transient-launch. This way if a transient 683 * launch is "aborted", the z-ordering of containers in WM should be restored to before the 684 * launch. 685 * @hide 686 */ 687 @NonNull restoreTransientOrder( @onNull WindowContainerToken container)688 public WindowContainerTransaction restoreTransientOrder( 689 @NonNull WindowContainerToken container) { 690 final HierarchyOp hierarchyOp = 691 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER) 692 .setContainer(container.asBinder()) 693 .build(); 694 mHierarchyOps.add(hierarchyOp); 695 return this; 696 } 697 698 /** 699 * Adds a given {@code Rect} as an insets source frame on the {@code receiver}. 700 * 701 * @param receiver The window container that the insets source is added to. 702 * @param owner The owner of the insets source. An insets source can only be modified by its 703 * owner. 704 * @param index An owner might add multiple insets sources with the same type. 705 * This identifies them. 706 * @param type The {@link InsetsType} of the insets source. 707 * @param frame The rectangle area of the insets source. 708 * @param boundingRects The bounding rects within this inset, relative to the |frame|. 709 * @hide 710 */ 711 @NonNull addInsetsSource( @onNull WindowContainerToken receiver, IBinder owner, int index, @InsetsType int type, Rect frame, Rect[] boundingRects)712 public WindowContainerTransaction addInsetsSource( 713 @NonNull WindowContainerToken receiver, 714 IBinder owner, int index, @InsetsType int type, Rect frame, Rect[] boundingRects) { 715 final HierarchyOp hierarchyOp = 716 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER) 717 .setContainer(receiver.asBinder()) 718 .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type) 719 .setSource(InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE) 720 .setArbitraryRectangle(frame) 721 .setBoundingRects(boundingRects)) 722 .setInsetsFrameOwner(owner) 723 .build(); 724 mHierarchyOps.add(hierarchyOp); 725 return this; 726 } 727 728 /** 729 * Removes the insets source from the {@code receiver}. 730 * 731 * @param receiver The window container that the insets source was added to. 732 * @param owner The owner of the insets source. An insets source can only be modified by its 733 * owner. 734 * @param index An owner might add multiple insets sources with the same type. 735 * This identifies them. 736 * @param type The {@link InsetsType} of the insets source. 737 * @hide 738 */ 739 @NonNull removeInsetsSource( @onNull WindowContainerToken receiver, IBinder owner, int index, @InsetsType int type)740 public WindowContainerTransaction removeInsetsSource( 741 @NonNull WindowContainerToken receiver, 742 IBinder owner, int index, @InsetsType int type) { 743 final HierarchyOp hierarchyOp = 744 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER) 745 .setContainer(receiver.asBinder()) 746 .setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type)) 747 .setInsetsFrameOwner(owner) 748 .build(); 749 mHierarchyOps.add(hierarchyOp); 750 return this; 751 } 752 753 /** 754 * Requests focus on the top running Activity in the given TaskFragment. This will only take 755 * effect if there is no focus, or if the current focus is in the same Task as the requested 756 * TaskFragment. 757 * @param fragmentToken client assigned unique token to create TaskFragment with specified in 758 * {@link TaskFragmentCreationParams#getFragmentToken()}. 759 */ 760 @NonNull requestFocusOnTaskFragment(@onNull IBinder fragmentToken)761 public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) { 762 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 763 OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT) 764 .build(); 765 return addTaskFragmentOperation(fragmentToken, operation); 766 } 767 768 /** 769 * Finishes the Activity. 770 * Comparing to directly calling {@link android.app.Activity#finish()}, calling this can make 771 * sure the finishing happens in the same transaction with other operations. 772 * @param activityToken activity to be finished. 773 */ 774 @NonNull finishActivity(@onNull IBinder activityToken)775 public WindowContainerTransaction finishActivity(@NonNull IBinder activityToken) { 776 final HierarchyOp hierarchyOp = 777 new HierarchyOp.Builder( 778 HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY) 779 .setContainer(activityToken) 780 .build(); 781 mHierarchyOps.add(hierarchyOp); 782 return this; 783 } 784 785 /** 786 * Sets the TaskFragment {@code fragmentToken} to have a companion TaskFragment 787 * {@code companionFragmentToken}. 788 * This indicates that the organizer will remove the TaskFragment when the companion 789 * TaskFragment is removed. 790 * 791 * @param fragmentToken client assigned unique token to create TaskFragment with specified 792 * in {@link TaskFragmentCreationParams#getFragmentToken()}. 793 * @param companionFragmentToken client assigned unique token to create TaskFragment with 794 * specified in 795 * {@link TaskFragmentCreationParams#getFragmentToken()}. 796 * If it is {@code null}, the transaction will reset the companion 797 * TaskFragment. 798 * @hide 799 */ 800 @NonNull setCompanionTaskFragment(@onNull IBinder fragmentToken, @Nullable IBinder companionFragmentToken)801 public WindowContainerTransaction setCompanionTaskFragment(@NonNull IBinder fragmentToken, 802 @Nullable IBinder companionFragmentToken) { 803 final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( 804 OP_TYPE_SET_COMPANION_TASK_FRAGMENT) 805 .setSecondaryFragmentToken(companionFragmentToken) 806 .build(); 807 return addTaskFragmentOperation(fragmentToken, operation); 808 } 809 810 /** 811 * Adds a {@link TaskFragmentOperation} to apply to the given TaskFragment. 812 * 813 * @param fragmentToken client assigned unique token to create TaskFragment with specified in 814 * {@link TaskFragmentCreationParams#getFragmentToken()}. 815 * @param taskFragmentOperation the {@link TaskFragmentOperation} to apply to the given 816 * TaskFramgent. 817 * @hide 818 */ 819 @NonNull addTaskFragmentOperation(@onNull IBinder fragmentToken, @NonNull TaskFragmentOperation taskFragmentOperation)820 public WindowContainerTransaction addTaskFragmentOperation(@NonNull IBinder fragmentToken, 821 @NonNull TaskFragmentOperation taskFragmentOperation) { 822 Objects.requireNonNull(fragmentToken); 823 Objects.requireNonNull(taskFragmentOperation); 824 final HierarchyOp hierarchyOp = 825 new HierarchyOp.Builder( 826 HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION) 827 .setContainer(fragmentToken) 828 .setTaskFragmentOperation(taskFragmentOperation) 829 .build(); 830 mHierarchyOps.add(hierarchyOp); 831 return this; 832 } 833 834 /** 835 * Sets/removes the always on top flag for this {@code windowContainer}. See 836 * {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}. 837 * Please note that this method is only intended to be used for a 838 * {@link com.android.server.wm.Task} or {@link com.android.server.wm.DisplayArea}. 839 * 840 * <p> 841 * Setting always on top to {@code True} will also make the {@code windowContainer} to move 842 * to the top. 843 * </p> 844 * <p> 845 * Setting always on top to {@code False} will make this {@code windowContainer} to move 846 * below the other always on top sibling containers. 847 * </p> 848 * 849 * @param windowContainer the container which the flag need to be updated for. 850 * @param alwaysOnTop denotes whether or not always on top flag should be set. 851 * @hide 852 */ 853 @NonNull setAlwaysOnTop( @onNull WindowContainerToken windowContainer, boolean alwaysOnTop)854 public WindowContainerTransaction setAlwaysOnTop( 855 @NonNull WindowContainerToken windowContainer, 856 boolean alwaysOnTop) { 857 final HierarchyOp hierarchyOp = 858 new HierarchyOp.Builder( 859 HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP) 860 .setContainer(windowContainer.asBinder()) 861 .setAlwaysOnTop(alwaysOnTop) 862 .build(); 863 mHierarchyOps.add(hierarchyOp); 864 return this; 865 } 866 867 /** 868 * When this {@link WindowContainerTransaction} failed to finish on the server side, it will 869 * trigger callback with this {@param errorCallbackToken}. 870 * @param errorCallbackToken client provided token that will be passed back as parameter in 871 * the callback if there is an error on the server side. 872 * @see ITaskFragmentOrganizer#onTaskFragmentError 873 */ 874 @NonNull setErrorCallbackToken(@onNull IBinder errorCallbackToken)875 public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) { 876 if (mErrorCallbackToken != null) { 877 throw new IllegalStateException("Can't set multiple error token for one transaction."); 878 } 879 mErrorCallbackToken = errorCallbackToken; 880 return this; 881 } 882 883 /** 884 * Sets the {@link TaskFragmentOrganizer} that applies this {@link WindowContainerTransaction}. 885 * When this is set, the server side will not check for the permission of 886 * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, but will ensure this WCT only 887 * contains operations that are allowed for this organizer, such as modifying TaskFragments that 888 * are organized by this organizer. 889 * @hide 890 */ 891 @NonNull setTaskFragmentOrganizer( @onNull ITaskFragmentOrganizer organizer)892 public WindowContainerTransaction setTaskFragmentOrganizer( 893 @NonNull ITaskFragmentOrganizer organizer) { 894 mTaskFragmentOrganizer = organizer; 895 return this; 896 } 897 898 /** 899 * Clears container adjacent. 900 * @param root the root container to clear the adjacent roots for. 901 * @hide 902 */ 903 @NonNull clearAdjacentRoots( @onNull WindowContainerToken root)904 public WindowContainerTransaction clearAdjacentRoots( 905 @NonNull WindowContainerToken root) { 906 mHierarchyOps.add(HierarchyOp.createForClearAdjacentRoots(root.asBinder())); 907 return this; 908 } 909 910 /** 911 * Sets/removes the reparent leaf task flag for this {@code windowContainer}. 912 * When this is set, the server side will try to reparent the leaf task to task display area 913 * if there is an existing activity in history during the activity launch. This operation only 914 * support on the organized root task. 915 * @hide 916 */ 917 @NonNull setReparentLeafTaskIfRelaunch( @onNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch)918 public WindowContainerTransaction setReparentLeafTaskIfRelaunch( 919 @NonNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch) { 920 final HierarchyOp hierarchyOp = 921 new HierarchyOp.Builder( 922 HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH) 923 .setContainer(windowContainer.asBinder()) 924 .setReparentLeafTaskIfRelaunch(reparentLeafTaskIfRelaunch) 925 .build(); 926 mHierarchyOps.add(hierarchyOp); 927 return this; 928 } 929 930 /** 931 * Moves the PiP activity of a parent task to a pinned root task. 932 * @param parentToken the parent task of the PiP activity 933 * @param bounds the entry bounds 934 * @hide 935 */ 936 @NonNull movePipActivityToPinnedRootTask( @onNull WindowContainerToken parentToken, @NonNull Rect bounds)937 public WindowContainerTransaction movePipActivityToPinnedRootTask( 938 @NonNull WindowContainerToken parentToken, @NonNull Rect bounds) { 939 mHierarchyOps.add(new HierarchyOp 940 .Builder(HierarchyOp.HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK) 941 .setContainer(parentToken.asBinder()) 942 .setBounds(bounds) 943 .build()); 944 return this; 945 } 946 947 /** 948 * Defers client-facing configuration changes for activities in `container` until the end of 949 * the transition animation. The configuration will still be applied to the WMCore hierarchy 950 * at the normal time (beginning); so, special consideration must be made for this in the 951 * animation. 952 * 953 * @param container WindowContainerToken who's children should defer config notification. 954 * @hide 955 */ 956 @NonNull deferConfigToTransitionEnd( @onNull WindowContainerToken container)957 public WindowContainerTransaction deferConfigToTransitionEnd( 958 @NonNull WindowContainerToken container) { 959 final Change change = getOrCreateChange(container.asBinder()); 960 change.mConfigAtTransitionEnd = true; 961 return this; 962 } 963 964 /** 965 * Merges another WCT into this one. 966 * @param transfer When true, this will transfer everything from other potentially leaving 967 * other in an unusable state. When false, other is left alone, but 968 * SurfaceFlinger Transactions will not be merged. 969 * @hide 970 */ merge(WindowContainerTransaction other, boolean transfer)971 public void merge(WindowContainerTransaction other, boolean transfer) { 972 for (int i = 0, n = other.mChanges.size(); i < n; ++i) { 973 final IBinder key = other.mChanges.keyAt(i); 974 Change existing = mChanges.get(key); 975 if (existing == null) { 976 existing = new Change(); 977 mChanges.put(key, existing); 978 } 979 existing.merge(other.mChanges.valueAt(i), transfer); 980 } 981 for (int i = 0, n = other.mHierarchyOps.size(); i < n; ++i) { 982 mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i) 983 : new HierarchyOp(other.mHierarchyOps.get(i))); 984 } 985 if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken 986 != other.mErrorCallbackToken) { 987 throw new IllegalArgumentException("Can't merge two WCTs with different error token"); 988 } 989 final IBinder taskFragmentOrganizerAsBinder = mTaskFragmentOrganizer != null 990 ? mTaskFragmentOrganizer.asBinder() 991 : null; 992 final IBinder otherTaskFragmentOrganizerAsBinder = other.mTaskFragmentOrganizer != null 993 ? other.mTaskFragmentOrganizer.asBinder() 994 : null; 995 if (!Objects.equals(taskFragmentOrganizerAsBinder, otherTaskFragmentOrganizerAsBinder)) { 996 throw new IllegalArgumentException( 997 "Can't merge two WCTs from different TaskFragmentOrganizers"); 998 } 999 mErrorCallbackToken = mErrorCallbackToken != null 1000 ? mErrorCallbackToken 1001 : other.mErrorCallbackToken; 1002 } 1003 1004 /** @hide */ isEmpty()1005 public boolean isEmpty() { 1006 return mChanges.isEmpty() && mHierarchyOps.isEmpty(); 1007 } 1008 1009 /** @hide */ getChanges()1010 public Map<IBinder, Change> getChanges() { 1011 return mChanges; 1012 } 1013 1014 /** @hide */ getHierarchyOps()1015 public List<HierarchyOp> getHierarchyOps() { 1016 return mHierarchyOps; 1017 } 1018 1019 /** @hide */ 1020 @Nullable getErrorCallbackToken()1021 public IBinder getErrorCallbackToken() { 1022 return mErrorCallbackToken; 1023 } 1024 1025 /** @hide */ 1026 @Nullable getTaskFragmentOrganizer()1027 public ITaskFragmentOrganizer getTaskFragmentOrganizer() { 1028 return mTaskFragmentOrganizer; 1029 } 1030 1031 @Override 1032 @NonNull toString()1033 public String toString() { 1034 return "WindowContainerTransaction {" 1035 + " changes = " + mChanges 1036 + " hops = " + mHierarchyOps 1037 + " errorCallbackToken=" + mErrorCallbackToken 1038 + " taskFragmentOrganizer=" + mTaskFragmentOrganizer 1039 + " }"; 1040 } 1041 1042 @Override writeToParcel(@onNull Parcel dest, int flags)1043 public void writeToParcel(@NonNull Parcel dest, int flags) { 1044 dest.writeMap(mChanges); 1045 dest.writeTypedList(mHierarchyOps); 1046 dest.writeStrongBinder(mErrorCallbackToken); 1047 dest.writeStrongInterface(mTaskFragmentOrganizer); 1048 } 1049 1050 @Override describeContents()1051 public int describeContents() { 1052 return 0; 1053 } 1054 1055 @NonNull 1056 public static final Creator<WindowContainerTransaction> CREATOR = 1057 new Creator<WindowContainerTransaction>() { 1058 @Override 1059 public WindowContainerTransaction createFromParcel(Parcel in) { 1060 return new WindowContainerTransaction(in); 1061 } 1062 1063 @Override 1064 public WindowContainerTransaction[] newArray(int size) { 1065 return new WindowContainerTransaction[size]; 1066 } 1067 }; 1068 1069 /** 1070 * Holds changes on a single WindowContainer including Configuration changes. 1071 * @hide 1072 */ 1073 public static class Change implements Parcelable { 1074 public static final int CHANGE_FOCUSABLE = 1; 1075 public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1; 1076 public static final int CHANGE_PIP_CALLBACK = 1 << 2; 1077 public static final int CHANGE_HIDDEN = 1 << 3; 1078 public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4; 1079 public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5; 1080 public static final int CHANGE_FORCE_NO_PIP = 1 << 6; 1081 public static final int CHANGE_FORCE_TRANSLUCENT = 1 << 7; 1082 public static final int CHANGE_DRAG_RESIZING = 1 << 8; 1083 public static final int CHANGE_RELATIVE_BOUNDS = 1 << 9; 1084 1085 private final Configuration mConfiguration = new Configuration(); 1086 private boolean mFocusable = true; 1087 private boolean mHidden = false; 1088 private boolean mIgnoreOrientationRequest = false; 1089 private boolean mForceTranslucent = false; 1090 private boolean mDragResizing = false; 1091 1092 private int mChangeMask = 0; 1093 private @ActivityInfo.Config int mConfigSetMask = 0; 1094 private @WindowConfiguration.WindowConfig int mWindowSetMask = 0; 1095 1096 private Rect mPinnedBounds = null; 1097 private SurfaceControl.Transaction mBoundsChangeTransaction = null; 1098 private Rect mBoundsChangeSurfaceBounds = null; 1099 @Nullable 1100 private Rect mRelativeBounds = null; 1101 private boolean mConfigAtTransitionEnd = false; 1102 1103 private int mActivityWindowingMode = -1; 1104 private int mWindowingMode = -1; 1105 Change()1106 public Change() {} 1107 Change(Parcel in)1108 protected Change(Parcel in) { 1109 mConfiguration.readFromParcel(in); 1110 mFocusable = in.readBoolean(); 1111 mHidden = in.readBoolean(); 1112 mIgnoreOrientationRequest = in.readBoolean(); 1113 mForceTranslucent = in.readBoolean(); 1114 mDragResizing = in.readBoolean(); 1115 mChangeMask = in.readInt(); 1116 mConfigSetMask = in.readInt(); 1117 mWindowSetMask = in.readInt(); 1118 if ((mChangeMask & Change.CHANGE_PIP_CALLBACK) != 0) { 1119 mPinnedBounds = new Rect(); 1120 mPinnedBounds.readFromParcel(in); 1121 } 1122 if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION) != 0) { 1123 mBoundsChangeTransaction = 1124 SurfaceControl.Transaction.CREATOR.createFromParcel(in); 1125 } 1126 if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION_RECT) != 0) { 1127 mBoundsChangeSurfaceBounds = new Rect(); 1128 mBoundsChangeSurfaceBounds.readFromParcel(in); 1129 } 1130 if ((mChangeMask & Change.CHANGE_RELATIVE_BOUNDS) != 0) { 1131 mRelativeBounds = new Rect(); 1132 mRelativeBounds.readFromParcel(in); 1133 } 1134 mConfigAtTransitionEnd = in.readBoolean(); 1135 1136 mWindowingMode = in.readInt(); 1137 mActivityWindowingMode = in.readInt(); 1138 } 1139 1140 /** 1141 * @param transfer When true, this will transfer other into this leaving other in an 1142 * undefined state. Use this if you don't intend to use other. When false, 1143 * SurfaceFlinger Transactions will not merge. 1144 */ merge(Change other, boolean transfer)1145 public void merge(Change other, boolean transfer) { 1146 mConfiguration.setTo(other.mConfiguration, other.mConfigSetMask, other.mWindowSetMask); 1147 mConfigSetMask |= other.mConfigSetMask; 1148 mWindowSetMask |= other.mWindowSetMask; 1149 if ((other.mChangeMask & CHANGE_FOCUSABLE) != 0) { 1150 mFocusable = other.mFocusable; 1151 } 1152 if (transfer && (other.mChangeMask & CHANGE_BOUNDS_TRANSACTION) != 0) { 1153 mBoundsChangeTransaction = other.mBoundsChangeTransaction; 1154 other.mBoundsChangeTransaction = null; 1155 } 1156 if ((other.mChangeMask & CHANGE_PIP_CALLBACK) != 0) { 1157 mPinnedBounds = transfer ? other.mPinnedBounds : new Rect(other.mPinnedBounds); 1158 } 1159 if ((other.mChangeMask & CHANGE_HIDDEN) != 0) { 1160 mHidden = other.mHidden; 1161 } 1162 if ((other.mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) { 1163 mIgnoreOrientationRequest = other.mIgnoreOrientationRequest; 1164 } 1165 if ((other.mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) { 1166 mForceTranslucent = other.mForceTranslucent; 1167 } 1168 if ((other.mChangeMask & CHANGE_DRAG_RESIZING) != 0) { 1169 mDragResizing = other.mDragResizing; 1170 } 1171 mChangeMask |= other.mChangeMask; 1172 if (other.mActivityWindowingMode >= 0) { 1173 mActivityWindowingMode = other.mActivityWindowingMode; 1174 } 1175 if (other.mWindowingMode >= 0) { 1176 mWindowingMode = other.mWindowingMode; 1177 } 1178 if (other.mBoundsChangeSurfaceBounds != null) { 1179 mBoundsChangeSurfaceBounds = transfer ? other.mBoundsChangeSurfaceBounds 1180 : new Rect(other.mBoundsChangeSurfaceBounds); 1181 } 1182 if (other.mRelativeBounds != null) { 1183 mRelativeBounds = transfer 1184 ? other.mRelativeBounds 1185 : new Rect(other.mRelativeBounds); 1186 } 1187 mConfigAtTransitionEnd = mConfigAtTransitionEnd 1188 || other.mConfigAtTransitionEnd; 1189 } 1190 getWindowingMode()1191 public int getWindowingMode() { 1192 return mWindowingMode; 1193 } 1194 getActivityWindowingMode()1195 public int getActivityWindowingMode() { 1196 return mActivityWindowingMode; 1197 } 1198 getConfiguration()1199 public Configuration getConfiguration() { 1200 return mConfiguration; 1201 } 1202 1203 /** Gets the requested focusable state */ getFocusable()1204 public boolean getFocusable() { 1205 if ((mChangeMask & CHANGE_FOCUSABLE) == 0) { 1206 throw new RuntimeException("Focusable not set. check CHANGE_FOCUSABLE first"); 1207 } 1208 return mFocusable; 1209 } 1210 1211 /** Gets the requested hidden state */ getHidden()1212 public boolean getHidden() { 1213 if ((mChangeMask & CHANGE_HIDDEN) == 0) { 1214 throw new RuntimeException("Hidden not set. check CHANGE_HIDDEN first"); 1215 } 1216 return mHidden; 1217 } 1218 1219 /** Gets the requested state of whether to ignore orientation request. */ getIgnoreOrientationRequest()1220 public boolean getIgnoreOrientationRequest() { 1221 if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) == 0) { 1222 throw new RuntimeException("IgnoreOrientationRequest not set. " 1223 + "Check CHANGE_IGNORE_ORIENTATION_REQUEST first"); 1224 } 1225 return mIgnoreOrientationRequest; 1226 } 1227 1228 /** Gets the requested force translucent state. */ getForceTranslucent()1229 public boolean getForceTranslucent() { 1230 if ((mChangeMask & CHANGE_FORCE_TRANSLUCENT) == 0) { 1231 throw new RuntimeException("Force translucent not set. " 1232 + "Check CHANGE_FORCE_TRANSLUCENT first"); 1233 } 1234 return mForceTranslucent; 1235 } 1236 1237 /** Gets the requested drag resizing state. */ getDragResizing()1238 public boolean getDragResizing() { 1239 if ((mChangeMask & CHANGE_DRAG_RESIZING) == 0) { 1240 throw new RuntimeException("Drag resizing not set. " 1241 + "Check CHANGE_DRAG_RESIZING first"); 1242 } 1243 return mDragResizing; 1244 } 1245 1246 /** Gets whether the config should be sent to the client at the end of the transition. */ getConfigAtTransitionEnd()1247 public boolean getConfigAtTransitionEnd() { 1248 return mConfigAtTransitionEnd; 1249 } 1250 getChangeMask()1251 public int getChangeMask() { 1252 return mChangeMask; 1253 } 1254 1255 @ActivityInfo.Config getConfigSetMask()1256 public int getConfigSetMask() { 1257 return mConfigSetMask; 1258 } 1259 1260 @WindowConfiguration.WindowConfig getWindowSetMask()1261 public int getWindowSetMask() { 1262 return mWindowSetMask; 1263 } 1264 1265 /** 1266 * Returns the bounds to be used for scheduling the enter pip callback 1267 * or null if no callback is to be scheduled. 1268 */ getEnterPipBounds()1269 public Rect getEnterPipBounds() { 1270 return mPinnedBounds; 1271 } 1272 getBoundsChangeTransaction()1273 public SurfaceControl.Transaction getBoundsChangeTransaction() { 1274 return mBoundsChangeTransaction; 1275 } 1276 getBoundsChangeSurfaceBounds()1277 public Rect getBoundsChangeSurfaceBounds() { 1278 return mBoundsChangeSurfaceBounds; 1279 } 1280 1281 @Nullable getRelativeBounds()1282 public Rect getRelativeBounds() { 1283 return mRelativeBounds; 1284 } 1285 1286 @Override toString()1287 public String toString() { 1288 final boolean changesBounds = 1289 (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0 1290 && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) 1291 != 0); 1292 final boolean changesAppBounds = 1293 (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0 1294 && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS) 1295 != 0); 1296 final boolean changesSs = (mConfigSetMask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0; 1297 final boolean changesSss = 1298 (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0; 1299 StringBuilder sb = new StringBuilder(); 1300 sb.append('{'); 1301 if (changesBounds) { 1302 sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ","); 1303 } 1304 if (changesAppBounds) { 1305 sb.append("appbounds:" + mConfiguration.windowConfiguration.getAppBounds() + ","); 1306 } 1307 if (changesSss) { 1308 sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ","); 1309 } 1310 if (changesSs) { 1311 sb.append("sw/h:" + mConfiguration.screenWidthDp + "x" 1312 + mConfiguration.screenHeightDp + ","); 1313 } 1314 if ((mChangeMask & CHANGE_FOCUSABLE) != 0) { 1315 sb.append("focusable:" + mFocusable + ","); 1316 } 1317 if ((mChangeMask & CHANGE_FORCE_TRANSLUCENT) != 0) { 1318 sb.append("forceTranslucent:" + mForceTranslucent + ","); 1319 } 1320 if ((mChangeMask & CHANGE_HIDDEN) != 0) { 1321 sb.append("hidden:" + mHidden + ","); 1322 } 1323 if ((mChangeMask & CHANGE_DRAG_RESIZING) != 0) { 1324 sb.append("dragResizing:" + mDragResizing + ","); 1325 } 1326 if (mBoundsChangeTransaction != null) { 1327 sb.append("hasBoundsTransaction,"); 1328 } 1329 if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) { 1330 sb.append("ignoreOrientationRequest:" + mIgnoreOrientationRequest + ","); 1331 } 1332 if ((mChangeMask & CHANGE_RELATIVE_BOUNDS) != 0) { 1333 sb.append("relativeBounds:").append(mRelativeBounds).append(","); 1334 } 1335 if (mConfigAtTransitionEnd) { 1336 sb.append("configAtTransitionEnd").append(","); 1337 } 1338 sb.append("}"); 1339 return sb.toString(); 1340 } 1341 1342 @Override writeToParcel(Parcel dest, int flags)1343 public void writeToParcel(Parcel dest, int flags) { 1344 mConfiguration.writeToParcel(dest, flags); 1345 dest.writeBoolean(mFocusable); 1346 dest.writeBoolean(mHidden); 1347 dest.writeBoolean(mIgnoreOrientationRequest); 1348 dest.writeBoolean(mForceTranslucent); 1349 dest.writeBoolean(mDragResizing); 1350 dest.writeInt(mChangeMask); 1351 dest.writeInt(mConfigSetMask); 1352 dest.writeInt(mWindowSetMask); 1353 1354 if (mPinnedBounds != null) { 1355 mPinnedBounds.writeToParcel(dest, flags); 1356 } 1357 if (mBoundsChangeTransaction != null) { 1358 mBoundsChangeTransaction.writeToParcel(dest, flags); 1359 } 1360 if (mBoundsChangeSurfaceBounds != null) { 1361 mBoundsChangeSurfaceBounds.writeToParcel(dest, flags); 1362 } 1363 if (mRelativeBounds != null) { 1364 mRelativeBounds.writeToParcel(dest, flags); 1365 } 1366 dest.writeBoolean(mConfigAtTransitionEnd); 1367 1368 dest.writeInt(mWindowingMode); 1369 dest.writeInt(mActivityWindowingMode); 1370 } 1371 1372 @Override describeContents()1373 public int describeContents() { 1374 return 0; 1375 } 1376 1377 public static final Creator<Change> CREATOR = new Creator<Change>() { 1378 @Override 1379 public Change createFromParcel(Parcel in) { 1380 return new Change(in); 1381 } 1382 1383 @Override 1384 public Change[] newArray(int size) { 1385 return new Change[size]; 1386 } 1387 }; 1388 } 1389 1390 /** 1391 * Holds information about a reparent/reorder operation in the hierarchy. This is separate from 1392 * Changes because they must be executed in the same order that they are added. 1393 * @hide 1394 */ 1395 public static final class HierarchyOp implements Parcelable { 1396 public static final int HIERARCHY_OP_TYPE_REPARENT = 0; 1397 public static final int HIERARCHY_OP_TYPE_REORDER = 1; 1398 public static final int HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT = 2; 1399 public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT = 3; 1400 public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4; 1401 public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5; 1402 public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6; 1403 public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 7; 1404 public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 8; 1405 public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 9; 1406 public static final int HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER = 10; 1407 public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER = 11; 1408 public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 12; 1409 public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 13; 1410 public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 14; 1411 public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 15; 1412 public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 16; 1413 public static final int HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION = 17; 1414 public static final int HIERARCHY_OP_TYPE_MOVE_PIP_ACTIVITY_TO_PINNED_TASK = 18; 1415 1416 // The following key(s) are for use with mLaunchOptions: 1417 // When launching a task (eg. from recents), this is the taskId to be launched. 1418 public static final String LAUNCH_KEY_TASK_ID = "android:transaction.hop.taskId"; 1419 1420 // When starting from a shortcut, this contains the calling package. 1421 public static final String LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE = 1422 "android:transaction.hop.shortcut_calling_package"; 1423 1424 private final int mType; 1425 1426 // Container we are performing the operation on. 1427 @Nullable 1428 private IBinder mContainer; 1429 1430 // If this is same as mContainer, then only change position, don't reparent. 1431 @Nullable 1432 private IBinder mReparent; 1433 1434 @Nullable 1435 private InsetsFrameProvider mInsetsFrameProvider; 1436 1437 @Nullable 1438 private IBinder mInsetsFrameOwner; 1439 1440 // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom. 1441 private boolean mToTop; 1442 1443 private boolean mReparentTopOnly; 1444 1445 @Nullable 1446 private int[] mWindowingModes; 1447 1448 @Nullable 1449 private int[] mActivityTypes; 1450 1451 @Nullable 1452 private Bundle mLaunchOptions; 1453 1454 @Nullable 1455 private Intent mActivityIntent; 1456 1457 /** Used as options for {@link #addTaskFragmentOperation}. */ 1458 @Nullable 1459 private TaskFragmentOperation mTaskFragmentOperation; 1460 1461 @Nullable 1462 private PendingIntent mPendingIntent; 1463 1464 @Nullable 1465 private ShortcutInfo mShortcutInfo; 1466 1467 @Nullable 1468 private Rect mBounds; 1469 1470 private boolean mIncludingParents; 1471 1472 private boolean mAlwaysOnTop; 1473 1474 private boolean mReparentLeafTaskIfRelaunch; 1475 createForReparent( @onNull IBinder container, @Nullable IBinder reparent, boolean toTop)1476 public static HierarchyOp createForReparent( 1477 @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) { 1478 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT) 1479 .setContainer(container) 1480 .setReparentContainer(reparent) 1481 .setToTop(toTop) 1482 .build(); 1483 } 1484 1485 /** 1486 * Creates the {@link HierarchyOp} for the reorder operation. 1487 * 1488 * @param container which needs to be reordered 1489 * @param toTop if true, the container reorders 1490 * @param includingParents if true, all the parents in the hierarchy above are also 1491 * reoredered among their respective siblings 1492 * @return 1493 */ createForReorder(@onNull IBinder container, boolean toTop, boolean includingParents)1494 public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop, 1495 boolean includingParents) { 1496 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REORDER) 1497 .setContainer(container) 1498 .setReparentContainer(container) 1499 .setToTop(toTop) 1500 .setIncludingParents(includingParents) 1501 .build(); 1502 } 1503 createForChildrenTasksReparent(IBinder currentParent, IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop, boolean reparentTopOnly)1504 public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent, 1505 IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop, 1506 boolean reparentTopOnly) { 1507 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT) 1508 .setContainer(currentParent) 1509 .setReparentContainer(newParent) 1510 .setWindowingModes(windowingModes) 1511 .setActivityTypes(activityTypes) 1512 .setToTop(onTop) 1513 .setReparentTopOnly(reparentTopOnly) 1514 .build(); 1515 } 1516 createForSetLaunchRoot(IBinder container, int[] windowingModes, int[] activityTypes)1517 public static HierarchyOp createForSetLaunchRoot(IBinder container, 1518 int[] windowingModes, int[] activityTypes) { 1519 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT) 1520 .setContainer(container) 1521 .setWindowingModes(windowingModes) 1522 .setActivityTypes(activityTypes) 1523 .build(); 1524 } 1525 1526 /** Create a hierarchy op for setting adjacent root tasks. */ createForAdjacentRoots(IBinder root1, IBinder root2)1527 public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2) { 1528 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS) 1529 .setContainer(root1) 1530 .setReparentContainer(root2) 1531 .build(); 1532 } 1533 1534 /** Create a hierarchy op for launching a task. */ createForTaskLaunch(int taskId, @Nullable Bundle options)1535 public static HierarchyOp createForTaskLaunch(int taskId, @Nullable Bundle options) { 1536 final Bundle fullOptions = options == null ? new Bundle() : options; 1537 fullOptions.putInt(LAUNCH_KEY_TASK_ID, taskId); 1538 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_LAUNCH_TASK) 1539 .setToTop(true) 1540 .setLaunchOptions(fullOptions) 1541 .build(); 1542 } 1543 1544 /** Create a hierarchy op for starting a shortcut. */ createForStartShortcut(@onNull String callingPackage, @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options)1545 public static HierarchyOp createForStartShortcut(@NonNull String callingPackage, 1546 @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) { 1547 final Bundle fullOptions = options == null ? new Bundle() : options; 1548 fullOptions.putString(LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE, callingPackage); 1549 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_START_SHORTCUT) 1550 .setShortcutInfo(shortcutInfo) 1551 .setLaunchOptions(fullOptions) 1552 .build(); 1553 } 1554 1555 /** Create a hierarchy op for setting launch adjacent flag root. */ createForSetLaunchAdjacentFlagRoot(IBinder container, boolean clearRoot)1556 public static HierarchyOp createForSetLaunchAdjacentFlagRoot(IBinder container, 1557 boolean clearRoot) { 1558 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT) 1559 .setContainer(container) 1560 .setToTop(clearRoot) 1561 .build(); 1562 } 1563 1564 /** create a hierarchy op for deleting a task **/ createForRemoveTask(@onNull IBinder container)1565 public static HierarchyOp createForRemoveTask(@NonNull IBinder container) { 1566 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK) 1567 .setContainer(container) 1568 .build(); 1569 } 1570 1571 /** Create a hierarchy op for clearing adjacent root tasks. */ createForClearAdjacentRoots(@onNull IBinder root)1572 public static HierarchyOp createForClearAdjacentRoots(@NonNull IBinder root) { 1573 return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS) 1574 .setContainer(root) 1575 .build(); 1576 } 1577 1578 /** Only creates through {@link Builder}. */ HierarchyOp(int type)1579 private HierarchyOp(int type) { 1580 mType = type; 1581 } 1582 HierarchyOp(@onNull HierarchyOp copy)1583 public HierarchyOp(@NonNull HierarchyOp copy) { 1584 mType = copy.mType; 1585 mContainer = copy.mContainer; 1586 mBounds = copy.mBounds; 1587 mIncludingParents = copy.mIncludingParents; 1588 mReparent = copy.mReparent; 1589 mInsetsFrameProvider = copy.mInsetsFrameProvider; 1590 mInsetsFrameOwner = copy.mInsetsFrameOwner; 1591 mToTop = copy.mToTop; 1592 mReparentTopOnly = copy.mReparentTopOnly; 1593 mWindowingModes = copy.mWindowingModes; 1594 mActivityTypes = copy.mActivityTypes; 1595 mLaunchOptions = copy.mLaunchOptions; 1596 mActivityIntent = copy.mActivityIntent; 1597 mTaskFragmentOperation = copy.mTaskFragmentOperation; 1598 mPendingIntent = copy.mPendingIntent; 1599 mShortcutInfo = copy.mShortcutInfo; 1600 mAlwaysOnTop = copy.mAlwaysOnTop; 1601 mReparentLeafTaskIfRelaunch = copy.mReparentLeafTaskIfRelaunch; 1602 } 1603 HierarchyOp(Parcel in)1604 protected HierarchyOp(Parcel in) { 1605 mType = in.readInt(); 1606 mContainer = in.readStrongBinder(); 1607 mBounds = in.readTypedObject(Rect.CREATOR); 1608 mIncludingParents = in.readBoolean(); 1609 mReparent = in.readStrongBinder(); 1610 mInsetsFrameProvider = in.readTypedObject(InsetsFrameProvider.CREATOR); 1611 mInsetsFrameOwner = in.readStrongBinder(); 1612 mToTop = in.readBoolean(); 1613 mReparentTopOnly = in.readBoolean(); 1614 mWindowingModes = in.createIntArray(); 1615 mActivityTypes = in.createIntArray(); 1616 mLaunchOptions = in.readBundle(); 1617 mActivityIntent = in.readTypedObject(Intent.CREATOR); 1618 mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR); 1619 mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); 1620 mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR); 1621 mAlwaysOnTop = in.readBoolean(); 1622 mReparentLeafTaskIfRelaunch = in.readBoolean(); 1623 } 1624 getType()1625 public int getType() { 1626 return mType; 1627 } 1628 isReparent()1629 public boolean isReparent() { 1630 return mType == HIERARCHY_OP_TYPE_REPARENT; 1631 } 1632 1633 @Nullable getNewParent()1634 public IBinder getNewParent() { 1635 return mReparent; 1636 } 1637 1638 @Nullable getInsetsFrameProvider()1639 public InsetsFrameProvider getInsetsFrameProvider() { 1640 return mInsetsFrameProvider; 1641 } 1642 1643 @Nullable getInsetsFrameOwner()1644 public IBinder getInsetsFrameOwner() { 1645 return mInsetsFrameOwner; 1646 } 1647 1648 @NonNull getContainer()1649 public IBinder getContainer() { 1650 return mContainer; 1651 } 1652 1653 @NonNull getAdjacentRoot()1654 public IBinder getAdjacentRoot() { 1655 return mReparent; 1656 } 1657 getToTop()1658 public boolean getToTop() { 1659 return mToTop; 1660 } 1661 getReparentTopOnly()1662 public boolean getReparentTopOnly() { 1663 return mReparentTopOnly; 1664 } 1665 getWindowingModes()1666 public int[] getWindowingModes() { 1667 return mWindowingModes; 1668 } 1669 getActivityTypes()1670 public int[] getActivityTypes() { 1671 return mActivityTypes; 1672 } 1673 1674 @Nullable getLaunchOptions()1675 public Bundle getLaunchOptions() { 1676 return mLaunchOptions; 1677 } 1678 1679 @Nullable getActivityIntent()1680 public Intent getActivityIntent() { 1681 return mActivityIntent; 1682 } 1683 isAlwaysOnTop()1684 public boolean isAlwaysOnTop() { 1685 return mAlwaysOnTop; 1686 } 1687 isReparentLeafTaskIfRelaunch()1688 public boolean isReparentLeafTaskIfRelaunch() { 1689 return mReparentLeafTaskIfRelaunch; 1690 } 1691 1692 @Nullable getTaskFragmentOperation()1693 public TaskFragmentOperation getTaskFragmentOperation() { 1694 return mTaskFragmentOperation; 1695 } 1696 1697 @Nullable getPendingIntent()1698 public PendingIntent getPendingIntent() { 1699 return mPendingIntent; 1700 } 1701 1702 @Nullable getShortcutInfo()1703 public ShortcutInfo getShortcutInfo() { 1704 return mShortcutInfo; 1705 } 1706 1707 @NonNull getBounds()1708 public Rect getBounds() { 1709 return mBounds; 1710 } 1711 1712 /** Denotes whether the parents should also be included in the op. */ 1713 @NonNull includingParents()1714 public boolean includingParents() { 1715 return mIncludingParents; 1716 } 1717 1718 /** Gets a string representation of a hierarchy-op type. */ hopToString(int type)1719 public static String hopToString(int type) { 1720 switch (type) { 1721 case HIERARCHY_OP_TYPE_REPARENT: return "reparent"; 1722 case HIERARCHY_OP_TYPE_REORDER: return "reorder"; 1723 case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "ChildrenTasksReparent"; 1724 case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "SetLaunchRoot"; 1725 case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "SetAdjacentRoot"; 1726 case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "LaunchTask"; 1727 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "SetAdjacentFlagRoot"; 1728 case HIERARCHY_OP_TYPE_PENDING_INTENT: return "PendingIntent"; 1729 case HIERARCHY_OP_TYPE_START_SHORTCUT: return "StartShortcut"; 1730 case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER: return "addInsetsFrameProvider"; 1731 case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER: 1732 return "removeInsetsFrameProvider"; 1733 case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop"; 1734 case HIERARCHY_OP_TYPE_REMOVE_TASK: return "RemoveTask"; 1735 case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity"; 1736 case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "ClearAdjacentRoot"; 1737 case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: 1738 return "setReparentLeafTaskIfRelaunch"; 1739 case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: 1740 return "addTaskFragmentOperation"; 1741 default: return "HOP(" + type + ")"; 1742 } 1743 } 1744 1745 @Override toString()1746 public String toString() { 1747 StringBuilder sb = new StringBuilder(); 1748 sb.append("{").append(hopToString(mType)).append(": "); 1749 switch (mType) { 1750 case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: 1751 sb.append("from=").append(mContainer).append(" to=").append(mReparent) 1752 .append(" mToTop=").append(mToTop) 1753 .append(" mReparentTopOnly=").append(mReparentTopOnly) 1754 .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes)) 1755 .append(" mActivityType=").append(Arrays.toString(mActivityTypes)); 1756 break; 1757 case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: 1758 sb.append("container=").append(mContainer) 1759 .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes)) 1760 .append(" mActivityType=").append(Arrays.toString(mActivityTypes)); 1761 break; 1762 case HIERARCHY_OP_TYPE_REPARENT: 1763 sb.append(mContainer).append(" to ").append(mToTop ? "top of " : "bottom of ") 1764 .append(mReparent); 1765 break; 1766 case HIERARCHY_OP_TYPE_REORDER: 1767 sb.append(mContainer).append(" to ").append(mToTop ? "top" : "bottom"); 1768 break; 1769 case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: 1770 sb.append("container=").append(mContainer) 1771 .append(" adjacentRoot=").append(mReparent); 1772 break; 1773 case HIERARCHY_OP_TYPE_LAUNCH_TASK: 1774 sb.append(mLaunchOptions); 1775 break; 1776 case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: 1777 sb.append("container=").append(mContainer).append(" clearRoot=").append(mToTop); 1778 break; 1779 case HIERARCHY_OP_TYPE_START_SHORTCUT: 1780 sb.append("options=").append(mLaunchOptions) 1781 .append(" info=").append(mShortcutInfo); 1782 break; 1783 case HIERARCHY_OP_TYPE_PENDING_INTENT: 1784 sb.append("options=").append(mLaunchOptions); 1785 break; 1786 case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER: 1787 case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER: 1788 sb.append("container=").append(mContainer) 1789 .append(" provider=").append(mInsetsFrameProvider) 1790 .append(" owner=").append(mInsetsFrameOwner); 1791 break; 1792 case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: 1793 sb.append("container=").append(mContainer) 1794 .append(" alwaysOnTop=").append(mAlwaysOnTop); 1795 break; 1796 case HIERARCHY_OP_TYPE_REMOVE_TASK: 1797 sb.append("task=").append(mContainer); 1798 break; 1799 case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: 1800 sb.append("activity=").append(mContainer); 1801 break; 1802 case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: 1803 sb.append("container=").append(mContainer); 1804 break; 1805 case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: 1806 sb.append("container= ").append(mContainer) 1807 .append(" reparentLeafTaskIfRelaunch= ") 1808 .append(mReparentLeafTaskIfRelaunch); 1809 break; 1810 case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: 1811 sb.append("fragmentToken= ").append(mContainer) 1812 .append(" operation= ").append(mTaskFragmentOperation); 1813 break; 1814 default: 1815 sb.append("container=").append(mContainer) 1816 .append(" reparent=").append(mReparent) 1817 .append(" mToTop=").append(mToTop) 1818 .append(" mWindowingMode=").append(Arrays.toString(mWindowingModes)) 1819 .append(" mActivityType=").append(Arrays.toString(mActivityTypes)); 1820 } 1821 return sb.append("}").toString(); 1822 } 1823 1824 @Override writeToParcel(Parcel dest, int flags)1825 public void writeToParcel(Parcel dest, int flags) { 1826 dest.writeInt(mType); 1827 dest.writeStrongBinder(mContainer); 1828 dest.writeTypedObject(mBounds, flags); 1829 dest.writeBoolean(mIncludingParents); 1830 dest.writeStrongBinder(mReparent); 1831 dest.writeTypedObject(mInsetsFrameProvider, flags); 1832 dest.writeStrongBinder(mInsetsFrameOwner); 1833 dest.writeBoolean(mToTop); 1834 dest.writeBoolean(mReparentTopOnly); 1835 dest.writeIntArray(mWindowingModes); 1836 dest.writeIntArray(mActivityTypes); 1837 dest.writeBundle(mLaunchOptions); 1838 dest.writeTypedObject(mActivityIntent, flags); 1839 dest.writeTypedObject(mTaskFragmentOperation, flags); 1840 dest.writeTypedObject(mPendingIntent, flags); 1841 dest.writeTypedObject(mShortcutInfo, flags); 1842 dest.writeBoolean(mAlwaysOnTop); 1843 dest.writeBoolean(mReparentLeafTaskIfRelaunch); 1844 } 1845 1846 @Override describeContents()1847 public int describeContents() { 1848 return 0; 1849 } 1850 1851 public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() { 1852 @Override 1853 public HierarchyOp createFromParcel(Parcel in) { 1854 return new HierarchyOp(in); 1855 } 1856 1857 @Override 1858 public HierarchyOp[] newArray(int size) { 1859 return new HierarchyOp[size]; 1860 } 1861 }; 1862 1863 private static class Builder { 1864 1865 private final int mType; 1866 1867 @Nullable 1868 private IBinder mContainer; 1869 1870 @Nullable 1871 private IBinder mReparent; 1872 1873 @Nullable 1874 private InsetsFrameProvider mInsetsFrameProvider; 1875 1876 @Nullable 1877 private IBinder mInsetsFrameOwner; 1878 1879 private boolean mToTop; 1880 1881 private boolean mReparentTopOnly; 1882 1883 @Nullable 1884 private int[] mWindowingModes; 1885 1886 @Nullable 1887 private int[] mActivityTypes; 1888 1889 @Nullable 1890 private Bundle mLaunchOptions; 1891 1892 @Nullable 1893 private Intent mActivityIntent; 1894 1895 @Nullable 1896 private TaskFragmentOperation mTaskFragmentOperation; 1897 1898 @Nullable 1899 private PendingIntent mPendingIntent; 1900 1901 @Nullable 1902 private ShortcutInfo mShortcutInfo; 1903 1904 @Nullable 1905 private Rect mBounds; 1906 1907 private boolean mIncludingParents; 1908 1909 private boolean mAlwaysOnTop; 1910 1911 private boolean mReparentLeafTaskIfRelaunch; 1912 Builder(int type)1913 Builder(int type) { 1914 mType = type; 1915 } 1916 setContainer(@ullable IBinder container)1917 Builder setContainer(@Nullable IBinder container) { 1918 mContainer = container; 1919 return this; 1920 } 1921 setReparentContainer(@ullable IBinder reparentContainer)1922 Builder setReparentContainer(@Nullable IBinder reparentContainer) { 1923 mReparent = reparentContainer; 1924 return this; 1925 } 1926 setInsetsFrameProvider(InsetsFrameProvider provider)1927 Builder setInsetsFrameProvider(InsetsFrameProvider provider) { 1928 mInsetsFrameProvider = provider; 1929 return this; 1930 } 1931 setInsetsFrameOwner(IBinder owner)1932 Builder setInsetsFrameOwner(IBinder owner) { 1933 mInsetsFrameOwner = owner; 1934 return this; 1935 } 1936 setToTop(boolean toTop)1937 Builder setToTop(boolean toTop) { 1938 mToTop = toTop; 1939 return this; 1940 } 1941 setReparentTopOnly(boolean reparentTopOnly)1942 Builder setReparentTopOnly(boolean reparentTopOnly) { 1943 mReparentTopOnly = reparentTopOnly; 1944 return this; 1945 } 1946 setWindowingModes(@ullable int[] windowingModes)1947 Builder setWindowingModes(@Nullable int[] windowingModes) { 1948 mWindowingModes = windowingModes; 1949 return this; 1950 } 1951 setActivityTypes(@ullable int[] activityTypes)1952 Builder setActivityTypes(@Nullable int[] activityTypes) { 1953 mActivityTypes = activityTypes; 1954 return this; 1955 } 1956 setLaunchOptions(@ullable Bundle launchOptions)1957 Builder setLaunchOptions(@Nullable Bundle launchOptions) { 1958 mLaunchOptions = launchOptions; 1959 return this; 1960 } 1961 setActivityIntent(@ullable Intent activityIntent)1962 Builder setActivityIntent(@Nullable Intent activityIntent) { 1963 mActivityIntent = activityIntent; 1964 return this; 1965 } 1966 setPendingIntent(@ullable PendingIntent sender)1967 Builder setPendingIntent(@Nullable PendingIntent sender) { 1968 mPendingIntent = sender; 1969 return this; 1970 } 1971 setAlwaysOnTop(boolean alwaysOnTop)1972 Builder setAlwaysOnTop(boolean alwaysOnTop) { 1973 mAlwaysOnTop = alwaysOnTop; 1974 return this; 1975 } 1976 setTaskFragmentOperation( @ullable TaskFragmentOperation taskFragmentOperation)1977 Builder setTaskFragmentOperation( 1978 @Nullable TaskFragmentOperation taskFragmentOperation) { 1979 mTaskFragmentOperation = taskFragmentOperation; 1980 return this; 1981 } 1982 setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch)1983 Builder setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) { 1984 mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch; 1985 return this; 1986 } 1987 setShortcutInfo(@ullable ShortcutInfo shortcutInfo)1988 Builder setShortcutInfo(@Nullable ShortcutInfo shortcutInfo) { 1989 mShortcutInfo = shortcutInfo; 1990 return this; 1991 } 1992 setBounds(@onNull Rect bounds)1993 Builder setBounds(@NonNull Rect bounds) { 1994 mBounds = bounds; 1995 return this; 1996 } 1997 setIncludingParents(boolean value)1998 Builder setIncludingParents(boolean value) { 1999 mIncludingParents = value; 2000 return this; 2001 } 2002 build()2003 HierarchyOp build() { 2004 final HierarchyOp hierarchyOp = new HierarchyOp(mType); 2005 hierarchyOp.mContainer = mContainer; 2006 hierarchyOp.mReparent = mReparent; 2007 hierarchyOp.mWindowingModes = mWindowingModes != null 2008 ? Arrays.copyOf(mWindowingModes, mWindowingModes.length) 2009 : null; 2010 hierarchyOp.mActivityTypes = mActivityTypes != null 2011 ? Arrays.copyOf(mActivityTypes, mActivityTypes.length) 2012 : null; 2013 hierarchyOp.mInsetsFrameProvider = mInsetsFrameProvider; 2014 hierarchyOp.mInsetsFrameOwner = mInsetsFrameOwner; 2015 hierarchyOp.mToTop = mToTop; 2016 hierarchyOp.mReparentTopOnly = mReparentTopOnly; 2017 hierarchyOp.mLaunchOptions = mLaunchOptions; 2018 hierarchyOp.mActivityIntent = mActivityIntent; 2019 hierarchyOp.mPendingIntent = mPendingIntent; 2020 hierarchyOp.mAlwaysOnTop = mAlwaysOnTop; 2021 hierarchyOp.mTaskFragmentOperation = mTaskFragmentOperation; 2022 hierarchyOp.mShortcutInfo = mShortcutInfo; 2023 hierarchyOp.mBounds = mBounds; 2024 hierarchyOp.mIncludingParents = mIncludingParents; 2025 hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch; 2026 2027 return hierarchyOp; 2028 } 2029 } 2030 } 2031 2032 /** 2033 * Helper class for building an options Bundle that can be used to set adjacent rules of 2034 * TaskFragments. 2035 */ 2036 public static class TaskFragmentAdjacentParams { 2037 private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL = 2038 "android:transaction.adjacent.option.delay_primary_removal"; 2039 private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL = 2040 "android:transaction.adjacent.option.delay_secondary_removal"; 2041 2042 private boolean mDelayPrimaryLastActivityRemoval; 2043 private boolean mDelaySecondaryLastActivityRemoval; 2044 TaskFragmentAdjacentParams()2045 public TaskFragmentAdjacentParams() { 2046 } 2047 TaskFragmentAdjacentParams(@onNull Bundle bundle)2048 public TaskFragmentAdjacentParams(@NonNull Bundle bundle) { 2049 mDelayPrimaryLastActivityRemoval = bundle.getBoolean( 2050 DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL); 2051 mDelaySecondaryLastActivityRemoval = bundle.getBoolean( 2052 DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL); 2053 } 2054 2055 /** @see #shouldDelayPrimaryLastActivityRemoval() */ setShouldDelayPrimaryLastActivityRemoval(boolean delay)2056 public void setShouldDelayPrimaryLastActivityRemoval(boolean delay) { 2057 mDelayPrimaryLastActivityRemoval = delay; 2058 } 2059 2060 /** @see #shouldDelaySecondaryLastActivityRemoval() */ setShouldDelaySecondaryLastActivityRemoval(boolean delay)2061 public void setShouldDelaySecondaryLastActivityRemoval(boolean delay) { 2062 mDelaySecondaryLastActivityRemoval = delay; 2063 } 2064 2065 /** 2066 * Whether to delay the last activity of the primary adjacent TaskFragment being immediately 2067 * removed while finishing. 2068 * <p> 2069 * It is usually set to {@code true} to give organizer an opportunity to perform other 2070 * actions or animations. An example is to finish together with the adjacent TaskFragment. 2071 * </p> 2072 */ shouldDelayPrimaryLastActivityRemoval()2073 public boolean shouldDelayPrimaryLastActivityRemoval() { 2074 return mDelayPrimaryLastActivityRemoval; 2075 } 2076 2077 /** 2078 * Similar to {@link #shouldDelayPrimaryLastActivityRemoval()}, but for the secondary 2079 * TaskFragment. 2080 */ shouldDelaySecondaryLastActivityRemoval()2081 public boolean shouldDelaySecondaryLastActivityRemoval() { 2082 return mDelaySecondaryLastActivityRemoval; 2083 } 2084 toBundle()2085 Bundle toBundle() { 2086 final Bundle b = new Bundle(); 2087 b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval); 2088 b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval); 2089 return b; 2090 } 2091 } 2092 } 2093