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