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