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 com.android.server.wm; 18 19 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 28 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 29 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 30 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT; 31 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 32 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 33 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 34 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 35 import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER; 36 37 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; 38 import static com.android.server.wm.ActivityRecord.State.RESUMED; 39 import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK; 40 import static com.android.server.wm.DisplayContent.alwaysCreateRootTask; 41 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK; 42 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 43 44 import static java.lang.Integer.MIN_VALUE; 45 46 import android.annotation.ColorInt; 47 import android.annotation.Nullable; 48 import android.app.ActivityOptions; 49 import android.app.WindowConfiguration; 50 import android.content.pm.ActivityInfo; 51 import android.content.res.Configuration; 52 import android.os.UserHandle; 53 import android.util.IntArray; 54 import android.util.Slog; 55 import android.view.RemoteAnimationTarget; 56 import android.view.SurfaceControl; 57 import android.window.WindowContainerToken; 58 import android.window.WindowContainerTransaction; 59 60 import com.android.internal.annotations.VisibleForTesting; 61 import com.android.internal.protolog.common.ProtoLog; 62 import com.android.internal.util.ArrayUtils; 63 import com.android.internal.util.ToBooleanFunction; 64 import com.android.internal.util.function.pooled.PooledLambda; 65 import com.android.internal.util.function.pooled.PooledPredicate; 66 import com.android.server.wm.LaunchParamsController.LaunchParams; 67 68 import java.io.PrintWriter; 69 import java.util.ArrayList; 70 import java.util.Arrays; 71 import java.util.List; 72 import java.util.function.BiFunction; 73 import java.util.function.Consumer; 74 import java.util.function.Function; 75 76 /** 77 * {@link DisplayArea} that represents a section of a screen that contains app window containers. 78 * 79 * The children can be either {@link Task} or {@link TaskDisplayArea}. 80 */ 81 final class TaskDisplayArea extends DisplayArea<WindowContainer> { 82 83 DisplayContent mDisplayContent; 84 85 /** 86 * A color layer that serves as a solid color background to certain animations. 87 */ 88 private SurfaceControl mColorBackgroundLayer; 89 90 /** 91 * This counter is used to make sure we don't prematurely clear the background color in the 92 * case that background color animations are interleaved. 93 * NOTE: The last set color will remain until the counter is reset to 0, which means that an 94 * animation background color may sometime remain after the animation has finished through an 95 * animation with a different background color if an animation starts after and ends before 96 * another where both set different background colors. However, this is not a concern as 97 * currently all task animation backgrounds are the same color. 98 */ 99 private int mColorLayerCounter = 0; 100 101 /** 102 * Given that the split-screen divider does not have an AppWindowToken, it 103 * will have to live inside of a "NonAppWindowContainer". However, in visual Z order 104 * it will need to be interleaved with some of our children, appearing on top of 105 * both docked root tasks but underneath any assistant root tasks. 106 * 107 * To solve this problem we have this anchor control, which will always exist so 108 * we can always assign it the correct value in our {@link #assignChildLayers}. 109 * Likewise since it always exists, we can always 110 * assign the divider a layer relative to it. This way we prevent linking lifecycle 111 * events between tasks and the divider window. 112 */ 113 private SurfaceControl mSplitScreenDividerAnchor; 114 115 // Cached reference to some special tasks we tend to get a lot so we don't need to loop 116 // through the list to find them. 117 private Task mRootHomeTask; 118 private Task mRootPinnedTask; 119 private Task mRootSplitScreenPrimaryTask; 120 121 // TODO(b/159029784): Remove when getStack() behavior is cleaned-up 122 private Task mRootRecentsTask; 123 124 private final ArrayList<WindowContainer> mTmpAlwaysOnTopChildren = new ArrayList<>(); 125 private final ArrayList<WindowContainer> mTmpNormalChildren = new ArrayList<>(); 126 private final ArrayList<WindowContainer> mTmpHomeChildren = new ArrayList<>(); 127 private final IntArray mTmpNeedsZBoostIndexes = new IntArray(); 128 129 private ArrayList<Task> mTmpTasks = new ArrayList<>(); 130 131 private ActivityTaskManagerService mAtmService; 132 133 private RootWindowContainer mRootWindowContainer; 134 135 // Launch root tasks by activityType then by windowingMode. 136 static private class LaunchRootTaskDef { 137 Task task; 138 int[] windowingModes; 139 int[] activityTypes; 140 contains(int windowingMode, int activityType)141 boolean contains(int windowingMode, int activityType) { 142 return ArrayUtils.contains(windowingModes, windowingMode) 143 && ArrayUtils.contains(activityTypes, activityType); 144 } 145 } 146 private final ArrayList<LaunchRootTaskDef> mLaunchRootTasks = new ArrayList<>(); 147 148 /** 149 * A launch root task for activity launching with {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} flag. 150 */ 151 @VisibleForTesting 152 Task mLaunchAdjacentFlagRootTask; 153 154 /** 155 * A focusable root task that is purposely to be positioned at the top. Although the root 156 * task may not have the topmost index, it is used as a preferred candidate to prevent being 157 * unable to resume target root task properly when there are other focusable always-on-top 158 * root tasks. 159 */ 160 @VisibleForTesting 161 Task mPreferredTopFocusableRootTask; 162 163 /** 164 * If this is the same as {@link #getFocusedRootTask} then the activity on the top of the 165 * focused root task has been resumed. If root tasks are changing position this will hold the 166 * old root task until the new root task becomes resumed after which it will be set to 167 * current focused root task. 168 */ 169 Task mLastFocusedRootTask; 170 /** 171 * All of the root tasks on this display. Order matters, topmost root task is in front of all 172 * other root tasks, bottommost behind. Accessed directly by ActivityManager package classes. 173 * Any calls changing the list should also call {@link #onRootTaskOrderChanged(Task)}. 174 */ 175 private ArrayList<OnRootTaskOrderChangedListener> mRootTaskOrderChangedCallbacks = 176 new ArrayList<>(); 177 178 /** 179 * The task display area is removed from the system and we are just waiting for all activities 180 * on it to be finished before removing this object. 181 */ 182 private boolean mRemoved; 183 184 /** 185 * The id of a leaf task that most recently being moved to front. 186 */ 187 private int mLastLeafTaskToFrontId; 188 189 /** 190 * Whether this TaskDisplayArea was created by a {@link android.window.DisplayAreaOrganizer}. 191 * If {@code true}, this will be removed when the organizer is unregistered. 192 */ 193 final boolean mCreatedByOrganizer; 194 195 /** 196 * True if this TaskDisplayArea can have a home task 197 * {@link WindowConfiguration#ACTIVITY_TYPE_HOME} 198 */ 199 private final boolean mCanHostHomeTask; 200 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, int displayAreaFeature)201 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, 202 int displayAreaFeature) { 203 this(displayContent, service, name, displayAreaFeature, false /* createdByOrganizer */, 204 true /* canHostHomeTask */); 205 } 206 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, int displayAreaFeature, boolean createdByOrganizer)207 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, 208 int displayAreaFeature, boolean createdByOrganizer) { 209 this(displayContent, service, name, displayAreaFeature, createdByOrganizer, 210 true /* canHostHomeTask */); 211 } 212 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, int displayAreaFeature, boolean createdByOrganizer, boolean canHostHomeTask)213 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, 214 int displayAreaFeature, boolean createdByOrganizer, 215 boolean canHostHomeTask) { 216 super(service, Type.ANY, name, displayAreaFeature); 217 mDisplayContent = displayContent; 218 mRootWindowContainer = service.mRoot; 219 mAtmService = service.mAtmService; 220 mCreatedByOrganizer = createdByOrganizer; 221 mCanHostHomeTask = canHostHomeTask; 222 } 223 224 /** 225 * Returns the topmost root task on the display that is compatible with the input windowing mode 226 * and activity type. Null is no compatible root task on the display. 227 */ 228 @Nullable getRootTask(int windowingMode, int activityType)229 Task getRootTask(int windowingMode, int activityType) { 230 if (activityType == ACTIVITY_TYPE_HOME) { 231 return mRootHomeTask; 232 } else if (activityType == ACTIVITY_TYPE_RECENTS) { 233 return mRootRecentsTask; 234 } 235 if (windowingMode == WINDOWING_MODE_PINNED) { 236 return mRootPinnedTask; 237 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 238 return mRootSplitScreenPrimaryTask; 239 } 240 return getRootTask(rootTask -> { 241 if (activityType == ACTIVITY_TYPE_UNDEFINED 242 && windowingMode == rootTask.getWindowingMode()) { 243 // Passing in undefined type means we want to match the topmost root task with the 244 // windowing mode. 245 return true; 246 } 247 return rootTask.isCompatible(windowingMode, activityType); 248 }); 249 } 250 251 @VisibleForTesting 252 Task getTopRootTask() { 253 return getRootTask(t -> true); 254 } 255 256 @Nullable 257 Task getRootHomeTask() { 258 return mRootHomeTask; 259 } 260 261 @Nullable 262 Task getRootRecentsTask() { 263 return mRootRecentsTask; 264 } 265 266 Task getRootPinnedTask() { 267 return mRootPinnedTask; 268 } 269 270 Task getRootSplitScreenPrimaryTask() { 271 return mRootSplitScreenPrimaryTask; 272 } 273 274 Task getRootSplitScreenSecondaryTask() { 275 // Only check the direct child Task for now, since the primary is also a direct child Task. 276 for (int i = mChildren.size() - 1; i >= 0; --i) { 277 final Task task = mChildren.get(i).asTask(); 278 if (task != null && task.inSplitScreenSecondaryWindowingMode()) { 279 return task; 280 } 281 } 282 return null; 283 } 284 285 ArrayList<Task> getVisibleTasks() { 286 final ArrayList<Task> visibleTasks = new ArrayList<>(); 287 forAllTasks(task -> { 288 if (task.isLeafTask() && task.isVisible()) { 289 visibleTasks.add(task); 290 } 291 }); 292 return visibleTasks; 293 } 294 295 void onRootTaskWindowingModeChanged(Task rootTask) { 296 removeRootTaskReferenceIfNeeded(rootTask); 297 addRootTaskReferenceIfNeeded(rootTask); 298 if (rootTask == mRootPinnedTask && getTopRootTask() != rootTask) { 299 // Looks like this root task changed windowing mode to pinned. Move it to the top. 300 positionChildAt(POSITION_TOP, rootTask, false /* includingParents */); 301 } 302 } 303 304 void addRootTaskReferenceIfNeeded(Task rootTask) { 305 if (rootTask.isActivityTypeHome()) { 306 if (mRootHomeTask != null) { 307 if (!rootTask.isDescendantOf(mRootHomeTask)) { 308 throw new IllegalArgumentException("addRootTaskReferenceIfNeeded: root home" 309 + " task=" + mRootHomeTask + " already exist on display=" + this 310 + " rootTask=" + rootTask); 311 } 312 } else { 313 mRootHomeTask = rootTask; 314 } 315 } else if (rootTask.isActivityTypeRecents()) { 316 if (mRootRecentsTask != null) { 317 if (!rootTask.isDescendantOf(mRootRecentsTask)) { 318 throw new IllegalArgumentException("addRootTaskReferenceIfNeeded: root recents" 319 + " task=" + mRootRecentsTask + " already exist on display=" + this 320 + " rootTask=" + rootTask); 321 } 322 } else { 323 mRootRecentsTask = rootTask; 324 } 325 } 326 327 if (!rootTask.isRootTask()) { 328 return; 329 } 330 final int windowingMode = rootTask.getWindowingMode(); 331 if (windowingMode == WINDOWING_MODE_PINNED) { 332 if (mRootPinnedTask != null) { 333 throw new IllegalArgumentException( 334 "addRootTaskReferenceIfNeeded: root pinned task=" + mRootPinnedTask 335 + " already exist on display=" + this + " rootTask=" + rootTask); 336 } 337 mRootPinnedTask = rootTask; 338 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 339 if (mRootSplitScreenPrimaryTask != null) { 340 throw new IllegalArgumentException( 341 "addRootTaskReferenceIfNeeded: root split screen primary task=" 342 + mRootSplitScreenPrimaryTask 343 + " already exist on display=" + this + " rootTask=" + rootTask); 344 } 345 mRootSplitScreenPrimaryTask = rootTask; 346 } 347 } 348 349 void removeRootTaskReferenceIfNeeded(Task rootTask) { 350 if (rootTask == mRootHomeTask) { 351 mRootHomeTask = null; 352 } else if (rootTask == mRootRecentsTask) { 353 mRootRecentsTask = null; 354 } else if (rootTask == mRootPinnedTask) { 355 mRootPinnedTask = null; 356 } else if (rootTask == mRootSplitScreenPrimaryTask) { 357 mRootSplitScreenPrimaryTask = null; 358 } 359 } 360 361 @Override 362 void addChild(WindowContainer child, int position) { 363 if (child.asTaskDisplayArea() != null) { 364 if (DEBUG_ROOT_TASK) { 365 Slog.d(TAG_WM, "Set TaskDisplayArea=" + child + " on taskDisplayArea=" + this); 366 } 367 super.addChild(child, position); 368 } else if (child.asTask() != null) { 369 addChildTask(child.asTask(), position); 370 } else { 371 throw new IllegalArgumentException( 372 "TaskDisplayArea can only add Task and TaskDisplayArea, but found " 373 + child); 374 } 375 } 376 377 private void addChildTask(Task task, int position) { 378 if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this); 379 380 addRootTaskReferenceIfNeeded(task); 381 position = findPositionForRootTask(position, task, true /* adding */); 382 383 super.addChild(task, position); 384 if (mPreferredTopFocusableRootTask != null 385 && task.isFocusable() 386 && mPreferredTopFocusableRootTask.compareTo(task) < 0) { 387 // Clear preferred top because the adding focusable task has a higher z-order. 388 mPreferredTopFocusableRootTask = null; 389 } 390 mAtmService.updateSleepIfNeededLocked(); 391 onRootTaskOrderChanged(task); 392 } 393 394 @Override 395 protected void removeChild(WindowContainer child) { 396 if (child.asTaskDisplayArea() != null) { 397 super.removeChild(child); 398 } else if (child.asTask() != null) { 399 removeChildTask(child.asTask()); 400 } else { 401 throw new IllegalArgumentException( 402 "TaskDisplayArea can only remove Task and TaskDisplayArea, but found " 403 + child); 404 } 405 } 406 407 private void removeChildTask(Task task) { 408 super.removeChild(task); 409 onRootTaskRemoved(task); 410 mAtmService.updateSleepIfNeededLocked(); 411 removeRootTaskReferenceIfNeeded(task); 412 } 413 414 @Override 415 boolean isOnTop() { 416 // Considered always on top 417 return true; 418 } 419 420 @Override 421 void positionChildAt(int position, WindowContainer child, boolean includingParents) { 422 if (child.asTaskDisplayArea() != null) { 423 super.positionChildAt(position, child, includingParents); 424 } else if (child.asTask() != null) { 425 positionChildTaskAt(position, child.asTask(), includingParents); 426 } else { 427 throw new IllegalArgumentException( 428 "TaskDisplayArea can only position Task and TaskDisplayArea, but found " 429 + child); 430 } 431 } 432 433 private void positionChildTaskAt(int position, Task child, boolean includingParents) { 434 final boolean moveToTop = position >= getChildCount() - 1; 435 final boolean moveToBottom = position <= 0; 436 437 final int oldPosition = mChildren.indexOf(child); 438 if (child.isAlwaysOnTop() && !moveToTop) { 439 // This root task is always-on-top, override the default behavior. 440 Slog.w(TAG_WM, "Ignoring move of always-on-top root task=" + this + " to bottom"); 441 442 // Moving to its current position, as we must call super but we don't want to 443 // perform any meaningful action. 444 super.positionChildAt(oldPosition, child, false /* includingParents */); 445 return; 446 } 447 // We don't allow untrusted display to top when root task moves to top, 448 // until user tapping this display to change display position as top intentionally. 449 // 450 // Displays with {@code mDontMoveToTop} property set to {@code true} won't be 451 // allowed to top neither. 452 if ((!mDisplayContent.isTrusted() || mDisplayContent.mDontMoveToTop) 453 && !getParent().isOnTop()) { 454 includingParents = false; 455 } 456 final int targetPosition = findPositionForRootTask(position, child, false /* adding */); 457 super.positionChildAt(targetPosition, child, false /* includingParents */); 458 459 if (includingParents && getParent() != null && (moveToTop || moveToBottom)) { 460 getParent().positionChildAt(moveToTop ? POSITION_TOP : POSITION_BOTTOM, 461 this /* child */, true /* includingParents */); 462 } 463 464 child.updateTaskMovement(moveToTop, targetPosition); 465 466 mDisplayContent.layoutAndAssignWindowLayersIfNeeded(); 467 468 // The insert position may be adjusted to non-top when there is always-on-top root task. 469 // Since the original position is preferred to be top, the root task should have higher 470 // priority when we are looking for top focusable root task. The condition {@code 471 // wasContained} restricts the preferred root task is set only when moving an existing 472 // root task to top instead of adding a new root task that may be too early (e.g. in the 473 // middle of launching or reparenting). 474 if (moveToTop && child.isFocusableAndVisible()) { 475 mPreferredTopFocusableRootTask = child; 476 } else if (mPreferredTopFocusableRootTask == child) { 477 mPreferredTopFocusableRootTask = null; 478 } 479 480 // Update the top resumed activity because the preferred top focusable task may be changed. 481 mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded(); 482 483 final ActivityRecord r = child.getTopResumedActivity(); 484 if (r != null && r == mRootWindowContainer.getTopResumedActivity()) { 485 mAtmService.setResumedActivityUncheckLocked(r, "positionChildAt"); 486 } 487 488 if (mChildren.indexOf(child) != oldPosition) { 489 onRootTaskOrderChanged(child); 490 } 491 } 492 493 void onLeafTaskRemoved(int taskId) { 494 if (mLastLeafTaskToFrontId == taskId) { 495 mLastLeafTaskToFrontId = INVALID_TASK_ID; 496 } 497 } 498 499 void onLeafTaskMoved(Task t, boolean toTop) { 500 if (!toTop) { 501 if (t.mTaskId == mLastLeafTaskToFrontId) { 502 mLastLeafTaskToFrontId = INVALID_TASK_ID; 503 } 504 return; 505 } 506 if (t.mTaskId == mLastLeafTaskToFrontId || t.topRunningActivityLocked() == null) { 507 return; 508 } 509 510 mLastLeafTaskToFrontId = t.mTaskId; 511 EventLogTags.writeWmTaskToFront(t.mUserId, t.mTaskId); 512 // Notifying only when a leaf task moved to front. Or the listeners would be notified 513 // couple times from the leaf task all the way up to the root task. 514 mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(t.getTaskInfo()); 515 } 516 517 @Override 518 void onChildPositionChanged(WindowContainer child) { 519 super.onChildPositionChanged(child); 520 mRootWindowContainer.invalidateTaskLayers(); 521 } 522 523 @Override 524 boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback, 525 boolean traverseTopToBottom) { 526 // Apply the callback to all TDAs at or below this container. If the callback returns true, 527 // stop early. 528 if (traverseTopToBottom) { 529 // When it is top to bottom, run on child TDA first as they are on top of the parent. 530 return super.forAllTaskDisplayAreas(callback, traverseTopToBottom) 531 || callback.apply(this); 532 } 533 return callback.apply(this) || super.forAllTaskDisplayAreas(callback, traverseTopToBottom); 534 } 535 536 @Override 537 void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) { 538 if (traverseTopToBottom) { 539 super.forAllTaskDisplayAreas(callback, traverseTopToBottom); 540 callback.accept(this); 541 } else { 542 callback.accept(this); 543 super.forAllTaskDisplayAreas(callback, traverseTopToBottom); 544 } 545 } 546 547 @Nullable 548 @Override 549 <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, 550 @Nullable R initValue, boolean traverseTopToBottom) { 551 if (traverseTopToBottom) { 552 final R result = 553 super.reduceOnAllTaskDisplayAreas(accumulator, initValue, traverseTopToBottom); 554 return accumulator.apply(this, result); 555 } else { 556 final R result = accumulator.apply(this, initValue); 557 return super.reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom); 558 559 } 560 } 561 562 @Nullable 563 @Override 564 <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, 565 boolean traverseTopToBottom) { 566 if (traverseTopToBottom) { 567 final R item = super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom); 568 return item != null ? item : callback.apply(this); 569 } else { 570 final R item = callback.apply(this); 571 return item != null 572 ? item 573 : super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom); 574 } 575 } 576 577 /** 578 * Assigns a priority number to root task types. This priority defines an order between the 579 * types of root task that are added to the task display area. 580 * 581 * Higher priority number indicates that the root task should have a higher z-order. 582 * 583 * For child {@link TaskDisplayArea}, it will be the priority of its top child. 584 * 585 * @return the priority of the root task 586 */ 587 private int getPriority(WindowContainer child) { 588 final TaskDisplayArea tda = child.asTaskDisplayArea(); 589 if (tda != null) { 590 // Use the top child priority as the TaskDisplayArea priority. 591 return tda.getPriority(tda.getTopChild()); 592 } 593 final Task rootTask = child.asTask(); 594 if (mWmService.mAssistantOnTopOfDream && rootTask.isActivityTypeAssistant()) return 4; 595 if (rootTask.isActivityTypeDream()) return 3; 596 if (rootTask.inPinnedWindowingMode()) return 2; 597 if (rootTask.isAlwaysOnTop()) return 1; 598 return 0; 599 } 600 601 private int findMinPositionForRootTask(Task rootTask) { 602 int minPosition = POSITION_BOTTOM; 603 for (int i = 0; i < mChildren.size(); ++i) { 604 if (getPriority(mChildren.get(i)) < getPriority(rootTask)) { 605 minPosition = i; 606 } else { 607 break; 608 } 609 } 610 611 if (rootTask.isAlwaysOnTop()) { 612 // Since a root task could be repositioned while still being one of the children, we 613 // check if this always-on-top root task already exists and if so, set the minPosition 614 // to its previous position. 615 // Use mChildren.indexOf instead of getTaskIndexOf because we need to place the rootTask 616 // as a direct child. 617 final int currentIndex = mChildren.indexOf(rootTask); 618 if (currentIndex > minPosition) { 619 minPosition = currentIndex; 620 } 621 } 622 return minPosition; 623 } 624 625 private int findMaxPositionForRootTask(Task rootTask) { 626 for (int i = mChildren.size() - 1; i >= 0; --i) { 627 final WindowContainer curr = mChildren.get(i); 628 // Since a root task could be repositioned while still being one of the children, we 629 // check if 'curr' is the same root task and skip it if so 630 final boolean sameRootTask = curr == rootTask; 631 if (getPriority(curr) <= getPriority(rootTask) && !sameRootTask) { 632 return i; 633 } 634 } 635 return 0; 636 } 637 638 /** 639 * When root task is added or repositioned, find a proper position for it. 640 * 641 * The order is defined as: 642 * - Dream is on top of everything 643 * - PiP is directly below the Dream 644 * - always-on-top root tasks are directly below PiP; new always-on-top root tasks are added 645 * above existing ones 646 * - other non-always-on-top root tasks come directly below always-on-top root tasks; new 647 * non-always-on-top root tasks are added directly below always-on-top root tasks and above 648 * existing non-always-on-top root tasks 649 * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything 650 * (including the Dream); otherwise, it is a normal non-always-on-top root task 651 * 652 * @param requestedPosition Position requested by caller. 653 * @param rootTask Root task to be added or positioned. 654 * @param adding Flag indicates whether we're adding a new root task or positioning 655 * an existing. 656 * @return The proper position for the root task. 657 */ 658 private int findPositionForRootTask(int requestedPosition, Task rootTask, boolean adding) { 659 // The max possible position we can insert the root task at. 660 int maxPosition = findMaxPositionForRootTask(rootTask); 661 // The min possible position we can insert the root task at. 662 int minPosition = findMinPositionForRootTask(rootTask); 663 664 // Cap the requested position to something reasonable for the previous position check 665 // below. 666 if (requestedPosition == POSITION_TOP) { 667 requestedPosition = mChildren.size(); 668 } else if (requestedPosition == POSITION_BOTTOM) { 669 requestedPosition = 0; 670 } 671 672 int targetPosition = requestedPosition; 673 targetPosition = Math.min(targetPosition, maxPosition); 674 targetPosition = Math.max(targetPosition, minPosition); 675 676 int prevPosition = mChildren.indexOf(rootTask); 677 // The positions we calculated above (maxPosition, minPosition) do not take into 678 // consideration the following edge cases. 679 // 1) We need to adjust the position depending on the value "adding". 680 // 2) When we are moving a root task to another position, we also need to adjust the 681 // position depending on whether the root task is moving to a higher or lower position. 682 if ((targetPosition != requestedPosition) && (adding || targetPosition < prevPosition)) { 683 targetPosition++; 684 } 685 686 return targetPosition; 687 } 688 689 @Override 690 boolean forAllWindows(ToBooleanFunction<WindowState> callback, 691 boolean traverseTopToBottom) { 692 if (traverseTopToBottom) { 693 if (super.forAllWindows(callback, traverseTopToBottom)) { 694 return true; 695 } 696 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { 697 return true; 698 } 699 } else { 700 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { 701 return true; 702 } 703 if (super.forAllWindows(callback, traverseTopToBottom)) { 704 return true; 705 } 706 } 707 return false; 708 } 709 710 private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback, 711 boolean traverseTopToBottom) { 712 // For legacy reasons we process the RootTask.mExitingActivities first here before the 713 // app tokens. 714 // TODO: Investigate if we need to continue to do this or if we can just process them 715 // in-order. 716 if (traverseTopToBottom) { 717 for (int i = mChildren.size() - 1; i >= 0; --i) { 718 // Only run on those of direct Task child, because child TaskDisplayArea has run on 719 // its child in #forAllWindows() 720 if (mChildren.get(i).asTask() == null) { 721 continue; 722 } 723 final List<ActivityRecord> activities = 724 mChildren.get(i).asTask().mExitingActivities; 725 for (int j = activities.size() - 1; j >= 0; --j) { 726 if (activities.get(j).forAllWindowsUnchecked(callback, 727 traverseTopToBottom)) { 728 return true; 729 } 730 } 731 } 732 } else { 733 final int count = mChildren.size(); 734 for (int i = 0; i < count; ++i) { 735 // Only run on those of direct Task child, because child TaskDisplayArea has run on 736 // its child in #forAllWindows() 737 if (mChildren.get(i).asTask() == null) { 738 continue; 739 } 740 final List<ActivityRecord> activities = 741 mChildren.get(i).asTask().mExitingActivities; 742 final int appTokensCount = activities.size(); 743 for (int j = 0; j < appTokensCount; j++) { 744 if (activities.get(j).forAllWindowsUnchecked(callback, 745 traverseTopToBottom)) { 746 return true; 747 } 748 } 749 } 750 } 751 return false; 752 } 753 754 @Override 755 int getOrientation(int candidate) { 756 mLastOrientationSource = null; 757 if (mIgnoreOrientationRequest) { 758 return SCREEN_ORIENTATION_UNSET; 759 } 760 if (!canSpecifyOrientation()) { 761 // We only respect orientation of the focused TDA, which can be a child of this TDA. 762 return reduceOnAllTaskDisplayAreas((taskDisplayArea, orientation) -> { 763 if (taskDisplayArea == this || orientation != SCREEN_ORIENTATION_UNSET) { 764 return orientation; 765 } 766 return taskDisplayArea.getOrientation(candidate); 767 }, SCREEN_ORIENTATION_UNSET); 768 } 769 770 if (isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { 771 // Apps and their containers are not allowed to specify an orientation while using 772 // root tasks...except for the root home task if it is not resizable and currently 773 // visible (top of) its root task. 774 if (mRootHomeTask != null && !mRootHomeTask.isResizeable()) { 775 // Manually nest one-level because because getOrientation() checks fillsParent() 776 // which checks that requestedOverrideBounds() is empty. However, in this case, 777 // it is not empty because it's been overridden to maintain the fullscreen size 778 // within a smaller split-root. 779 final Task topHomeTask = mRootHomeTask.getTopMostTask(); 780 final ActivityRecord topHomeActivity = topHomeTask.getTopNonFinishingActivity(); 781 // If a home activity is in the process of launching and isn't yet visible we 782 // should still respect the root task's preferred orientation to ensure rotation 783 // occurs before the home activity finishes launching. 784 final boolean isHomeActivityLaunching = topHomeActivity != null 785 && topHomeActivity.mVisibleRequested; 786 if (topHomeTask.isVisible() || isHomeActivityLaunching) { 787 final int orientation = topHomeTask.getOrientation(); 788 if (orientation != SCREEN_ORIENTATION_UNSET) { 789 return orientation; 790 } 791 } 792 } 793 return SCREEN_ORIENTATION_UNSPECIFIED; 794 } else { 795 // Apps and their containers are not allowed to specify an orientation of non floating 796 // visible tasks created by organizer. The organizer handles the orientation instead. 797 final Task nonFloatingTopTask = 798 getRootTask(t -> !t.getWindowConfiguration().tasksAreFloating()); 799 if (nonFloatingTopTask != null && nonFloatingTopTask.mCreatedByOrganizer 800 && nonFloatingTopTask.isVisible()) { 801 return SCREEN_ORIENTATION_UNSPECIFIED; 802 } 803 } 804 805 final int orientation = super.getOrientation(candidate); 806 if (orientation != SCREEN_ORIENTATION_UNSET 807 && orientation != SCREEN_ORIENTATION_BEHIND) { 808 ProtoLog.v(WM_DEBUG_ORIENTATION, 809 "App is requesting an orientation, return %d for display id=%d", 810 orientation, mDisplayContent.mDisplayId); 811 return orientation; 812 } 813 814 ProtoLog.v(WM_DEBUG_ORIENTATION, 815 "No app is requesting an orientation, return %d for display id=%d", 816 mDisplayContent.getLastOrientation(), mDisplayContent.mDisplayId); 817 // The next app has not been requested to be visible, so we keep the current orientation 818 // to prevent freezing/unfreezing the display too early. 819 return mDisplayContent.getLastOrientation(); 820 } 821 822 @Override 823 void assignChildLayers(SurfaceControl.Transaction t) { 824 assignRootTaskOrdering(t); 825 826 for (int i = 0; i < mChildren.size(); i++) { 827 mChildren.get(i).assignChildLayers(t); 828 } 829 } 830 831 void assignRootTaskOrdering(SurfaceControl.Transaction t) { 832 if (getParent() == null) { 833 return; 834 } 835 mTmpAlwaysOnTopChildren.clear(); 836 mTmpHomeChildren.clear(); 837 mTmpNormalChildren.clear(); 838 for (int i = 0; i < mChildren.size(); ++i) { 839 final WindowContainer child = mChildren.get(i); 840 final TaskDisplayArea childTda = child.asTaskDisplayArea(); 841 if (childTda != null) { 842 final Task childTdaTopRootTask = childTda.getTopRootTask(); 843 if (childTdaTopRootTask == null) { 844 mTmpNormalChildren.add(childTda); 845 } else if (childTdaTopRootTask.isAlwaysOnTop()) { 846 mTmpAlwaysOnTopChildren.add(childTda); 847 } else if (childTdaTopRootTask.isActivityTypeHome()) { 848 mTmpHomeChildren.add(childTda); 849 } else { 850 mTmpNormalChildren.add(childTda); 851 } 852 continue; 853 } 854 855 final Task childTask = child.asTask(); 856 if (childTask.isAlwaysOnTop()) { 857 mTmpAlwaysOnTopChildren.add(childTask); 858 } else if (childTask.isActivityTypeHome()) { 859 mTmpHomeChildren.add(childTask); 860 } else { 861 mTmpNormalChildren.add(childTask); 862 } 863 } 864 865 int layer = 0; 866 // Place root home tasks to the bottom. 867 layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer); 868 layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer); 869 // TODO(b/207185041): Remove this divider workaround after we full remove leagacy split and 870 // make app pair split only have single root then we can just attach the 871 // divider to the single root task in shell. 872 layer = Math.max(layer, SPLIT_DIVIDER_LAYER + 1); 873 adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer); 874 t.setLayer(mSplitScreenDividerAnchor, SPLIT_DIVIDER_LAYER); 875 } 876 877 /** 878 * Adjusts the layer of the root task which belongs to the same group. 879 * Note that there are three root task groups: home rootTasks, always on top rootTasks, and 880 * normal rootTasks. 881 * 882 * @param startLayer The beginning layer of this group of rootTasks. 883 * @return The adjusted layer value. 884 */ 885 private int adjustRootTaskLayer(SurfaceControl.Transaction t, 886 ArrayList<WindowContainer> children, int startLayer) { 887 mTmpNeedsZBoostIndexes.clear(); 888 final int childCount = children.size(); 889 boolean hasAdjacentTask = false; 890 for (int i = 0; i < childCount; i++) { 891 final WindowContainer child = children.get(i); 892 final TaskDisplayArea childTda = child.asTaskDisplayArea(); 893 final boolean childNeedsZBoost = childTda != null 894 ? childTda.childrenNeedZBoost() 895 : child.needsZBoost(); 896 897 if (childNeedsZBoost) { 898 mTmpNeedsZBoostIndexes.add(i); 899 continue; 900 } 901 902 final Task childTask = child.asTask(); 903 final boolean inAdjacentTask = childTask != null 904 && child.inMultiWindowMode() 905 && childTask.getRootTask().getAdjacentTaskFragment() != null; 906 907 if (inAdjacentTask || child.inSplitScreenWindowingMode()) { 908 hasAdjacentTask = true; 909 } else if (hasAdjacentTask && startLayer < SPLIT_DIVIDER_LAYER) { 910 // Task on top of adjacent tasks should be higher than split divider layer so 911 // set it as start. 912 startLayer = SPLIT_DIVIDER_LAYER + 1; 913 } 914 915 child.assignLayer(t, startLayer++); 916 } 917 918 final int zBoostSize = mTmpNeedsZBoostIndexes.size(); 919 for (int i = 0; i < zBoostSize; i++) { 920 final WindowContainer child = children.get(mTmpNeedsZBoostIndexes.get(i)); 921 child.assignLayer(t, startLayer++); 922 } 923 return startLayer; 924 } 925 926 private boolean childrenNeedZBoost() { 927 final boolean[] needsZBoost = new boolean[1]; 928 forAllRootTasks(task -> { 929 needsZBoost[0] |= task.needsZBoost(); 930 }); 931 return needsZBoost[0]; 932 } 933 934 @Override 935 RemoteAnimationTarget createRemoteAnimationTarget( 936 RemoteAnimationController.RemoteAnimationRecord record) { 937 final ActivityRecord activity = getTopMostActivity(); 938 return activity != null ? activity.createRemoteAnimationTarget(record) : null; 939 } 940 941 SurfaceControl getSplitScreenDividerAnchor() { 942 return mSplitScreenDividerAnchor; 943 } 944 945 @Override 946 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { 947 if (getParent() != null) { 948 super.onParentChanged(newParent, oldParent, () -> { 949 mColorBackgroundLayer = makeChildSurface(null) 950 .setColorLayer() 951 .setName("colorBackgroundLayer") 952 .setCallsite("TaskDisplayArea.onParentChanged") 953 .build(); 954 mSplitScreenDividerAnchor = makeChildSurface(null) 955 .setName("splitScreenDividerAnchor") 956 .setCallsite("TaskDisplayArea.onParentChanged") 957 .build(); 958 959 getSyncTransaction() 960 .show(mSplitScreenDividerAnchor); 961 }); 962 } else { 963 super.onParentChanged(newParent, oldParent); 964 mWmService.mTransactionFactory.get() 965 .remove(mColorBackgroundLayer) 966 .remove(mSplitScreenDividerAnchor) 967 .apply(); 968 mColorBackgroundLayer = null; 969 mSplitScreenDividerAnchor = null; 970 } 971 } 972 973 void setBackgroundColor(@ColorInt int color) { 974 if (mColorBackgroundLayer == null) { 975 return; 976 } 977 978 float r = ((color >> 16) & 0xff) / 255.0f; 979 float g = ((color >> 8) & 0xff) / 255.0f; 980 float b = ((color >> 0) & 0xff) / 255.0f; 981 float a = ((color >> 24) & 0xff) / 255.0f; 982 983 mColorLayerCounter++; 984 985 getPendingTransaction().setLayer(mColorBackgroundLayer, MIN_VALUE) 986 .setColor(mColorBackgroundLayer, new float[]{r, g, b}) 987 .setAlpha(mColorBackgroundLayer, a) 988 .setWindowCrop(mColorBackgroundLayer, getSurfaceWidth(), getSurfaceHeight()) 989 .setPosition(mColorBackgroundLayer, 0, 0) 990 .show(mColorBackgroundLayer); 991 992 scheduleAnimation(); 993 } 994 995 void clearBackgroundColor() { 996 mColorLayerCounter--; 997 998 // Only clear the color layer if we have received the same amounts of clear as set 999 // requests. 1000 if (mColorLayerCounter == 0) { 1001 getPendingTransaction().hide(mColorBackgroundLayer); 1002 scheduleAnimation(); 1003 } 1004 } 1005 1006 @Override 1007 void migrateToNewSurfaceControl(SurfaceControl.Transaction t) { 1008 super.migrateToNewSurfaceControl(t); 1009 if (mColorBackgroundLayer == null) { 1010 return; 1011 } 1012 1013 // As TaskDisplayArea is getting a new surface, reparent and reorder the child surfaces. 1014 t.reparent(mColorBackgroundLayer, mSurfaceControl); 1015 t.reparent(mSplitScreenDividerAnchor, mSurfaceControl); 1016 reassignLayer(t); 1017 scheduleAnimation(); 1018 } 1019 1020 void onRootTaskRemoved(Task rootTask) { 1021 if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { 1022 Slog.v(TAG_ROOT_TASK, "onRootTaskRemoved: detaching " + rootTask + " from displayId=" 1023 + mDisplayContent.mDisplayId); 1024 } 1025 if (mPreferredTopFocusableRootTask == rootTask) { 1026 mPreferredTopFocusableRootTask = null; 1027 } 1028 if (mLaunchAdjacentFlagRootTask == rootTask) { 1029 mLaunchAdjacentFlagRootTask = null; 1030 } 1031 mDisplayContent.releaseSelfIfNeeded(); 1032 onRootTaskOrderChanged(rootTask); 1033 } 1034 1035 /** 1036 * Moves/reparents `task` to the back of whatever container the root home task is in. This is 1037 * for when we just want to move a task to "the back" vs. a specific place. The primary use-case 1038 * is to make sure that moved-to-back apps go into secondary split when in split-screen mode. 1039 */ 1040 void positionTaskBehindHome(Task task) { 1041 final Task home = getOrCreateRootHomeTask(); 1042 final WindowContainer homeParent = home.getParent(); 1043 final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; 1044 if (homeParentTask == null) { 1045 // reparent throws if parent didn't change... 1046 if (task.getParent() == this) { 1047 positionChildAt(POSITION_BOTTOM, task, false /*includingParents*/); 1048 } else { 1049 task.reparent(this, false /* onTop */); 1050 } 1051 } else if (homeParentTask == task.getParent()) { 1052 // Apparently reparent early-outs if same root task, so we have to explicitly reorder. 1053 homeParentTask.positionChildAtBottom(task); 1054 } else { 1055 task.reparent(homeParentTask, false /* toTop */, 1056 Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE, false /* animate */, 1057 false /* deferResume */, "positionTaskBehindHome"); 1058 } 1059 } 1060 1061 /** 1062 * Returns an existing root task compatible with the windowing mode and activity type or 1063 * creates one if a compatible root task doesn't exist. 1064 * 1065 * @see #getOrCreateRootTask(int, int, boolean, Task, Task, ActivityOptions, int) 1066 */ 1067 Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) { 1068 return getOrCreateRootTask(windowingMode, activityType, onTop, null /* candidateTask */, 1069 null /* sourceTask */, null /* options */, 0 /* intent */); 1070 } 1071 1072 /** 1073 * When two level tasks are required for given windowing mode and activity type, returns an 1074 * existing compatible root task or creates a new one. 1075 * For one level task, the candidate task would be reused to also be the root task or create 1076 * a new root task if no candidate task. 1077 * 1078 * @param windowingMode The windowing mode the root task should be created in. 1079 * @param activityType The activityType the root task should be created in. 1080 * @param onTop If true the root task will be created at the top of the display, 1081 * else at the bottom. 1082 * @param candidateTask The possible task the activity might be launched in. Can be null. 1083 * @param sourceTask The task requesting to start activity. Used to determine which of the 1084 * adjacent roots should be launch root of the new task. Can be null. 1085 * @param options The activity options used to the launch. Can be null. 1086 * @param launchFlags The launch flags for this launch. 1087 * @return The root task to use for the launch. 1088 * @see #getRootTask(int, int) 1089 */ 1090 Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop, 1091 @Nullable Task candidateTask, @Nullable Task sourceTask, 1092 @Nullable ActivityOptions options, int launchFlags) { 1093 // Need to pass in a determined windowing mode to see if a new root task should be created, 1094 // so use its parent's windowing mode if it is undefined. 1095 if (!alwaysCreateRootTask( 1096 windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(), 1097 activityType)) { 1098 Task rootTask = getRootTask(windowingMode, activityType); 1099 if (rootTask != null) { 1100 return rootTask; 1101 } 1102 } else if (candidateTask != null) { 1103 final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; 1104 final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options, 1105 sourceTask, launchFlags); 1106 if (launchRootTask != null) { 1107 if (candidateTask.getParent() == null) { 1108 launchRootTask.addChild(candidateTask, position); 1109 } else if (candidateTask.getParent() != launchRootTask) { 1110 candidateTask.reparent(launchRootTask, position); 1111 } 1112 } else if (candidateTask.getDisplayArea() != this || !candidateTask.isRootTask()) { 1113 if (candidateTask.getParent() == null) { 1114 addChild(candidateTask, position); 1115 } else { 1116 candidateTask.reparent(this, onTop); 1117 } 1118 } 1119 // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen. 1120 if (candidateTask.getWindowingMode() != windowingMode) { 1121 candidateTask.setWindowingMode(windowingMode); 1122 } 1123 return candidateTask.getRootTask(); 1124 } 1125 return new Task.Builder(mAtmService) 1126 .setWindowingMode(windowingMode) 1127 .setActivityType(activityType) 1128 .setOnTop(onTop) 1129 .setParent(this) 1130 .setSourceTask(sourceTask) 1131 .setActivityOptions(options) 1132 .setLaunchFlags(launchFlags) 1133 .build(); 1134 } 1135 1136 /** 1137 * Returns an existing root task compatible with the input params or creates one 1138 * if a compatible root task doesn't exist. 1139 * 1140 * @see #getOrCreateRootTask(int, int, boolean) 1141 */ 1142 Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options, 1143 @Nullable Task candidateTask, @Nullable Task sourceTask, 1144 @Nullable LaunchParams launchParams, int launchFlags, int activityType, boolean onTop) { 1145 int windowingMode = WINDOWING_MODE_UNDEFINED; 1146 if (launchParams != null) { 1147 // If launchParams isn't null, windowing mode is already resolved. 1148 windowingMode = launchParams.mWindowingMode; 1149 } else if (options != null) { 1150 // If launchParams is null and options isn't let's use the windowing mode in the 1151 // options. 1152 windowingMode = options.getLaunchWindowingMode(); 1153 } 1154 // Validate that our desired windowingMode will work under the current conditions. 1155 // UNDEFINED windowing mode is a valid result and means that the new root task will inherit 1156 // it's display's windowing mode. 1157 windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType); 1158 return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask, 1159 options, launchFlags); 1160 } 1161 1162 @VisibleForTesting 1163 int getNextRootTaskId() { 1164 return mAtmService.mTaskSupervisor.getNextTaskIdForUser(); 1165 } 1166 1167 Task createRootTask(int windowingMode, int activityType, boolean onTop) { 1168 return createRootTask(windowingMode, activityType, onTop, null /* activityOptions */); 1169 } 1170 1171 /** 1172 * A convinenit method of creating a root task by providing windowing mode and activity type 1173 * on this display. 1174 * 1175 * @param windowingMode The windowing mode the root task should be created in. If 1176 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the 1177 * root task will inherit its parent's windowing mode. 1178 * @param activityType The activityType the root task should be created in. If 1179 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the 1180 * root task will be created in 1181 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}. 1182 * @param onTop If true the root task will be created at the top of the display, 1183 * else at the bottom. 1184 * @param opts The activity options. 1185 * @return The newly created root task. 1186 */ 1187 Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityOptions opts) { 1188 return new Task.Builder(mAtmService) 1189 .setWindowingMode(windowingMode) 1190 .setActivityType(activityType) 1191 .setParent(this) 1192 .setOnTop(onTop) 1193 .setActivityOptions(opts) 1194 .build(); 1195 } 1196 1197 // TODO: Also clear when task is removed from system? 1198 void setLaunchRootTask(Task rootTask, int[] windowingModes, int[] activityTypes) { 1199 if (!rootTask.mCreatedByOrganizer) { 1200 throw new IllegalArgumentException( 1201 "Can't set not mCreatedByOrganizer as launch root tr=" + rootTask); 1202 } 1203 1204 LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask); 1205 if (def != null) { 1206 // Remove so we add to the end of the list. 1207 mLaunchRootTasks.remove(def); 1208 } else { 1209 def = new LaunchRootTaskDef(); 1210 def.task = rootTask; 1211 } 1212 1213 def.activityTypes = activityTypes; 1214 def.windowingModes = windowingModes; 1215 if (!ArrayUtils.isEmpty(windowingModes) || !ArrayUtils.isEmpty(activityTypes)) { 1216 mLaunchRootTasks.add(def); 1217 } 1218 } 1219 1220 void removeLaunchRootTask(Task rootTask) { 1221 LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask); 1222 if (def != null) { 1223 mLaunchRootTasks.remove(def); 1224 } 1225 } 1226 1227 void setLaunchAdjacentFlagRootTask(@Nullable Task adjacentFlagRootTask) { 1228 if (adjacentFlagRootTask != null) { 1229 if (!adjacentFlagRootTask.mCreatedByOrganizer) { 1230 throw new IllegalArgumentException( 1231 "Can't set not mCreatedByOrganizer as launch adjacent flag root tr=" 1232 + adjacentFlagRootTask); 1233 } 1234 1235 if (adjacentFlagRootTask.getAdjacentTaskFragment() == null) { 1236 throw new UnsupportedOperationException( 1237 "Can't set non-adjacent root as launch adjacent flag root tr=" 1238 + adjacentFlagRootTask); 1239 } 1240 } 1241 1242 mLaunchAdjacentFlagRootTask = adjacentFlagRootTask; 1243 } 1244 1245 private @Nullable LaunchRootTaskDef getLaunchRootTaskDef(Task rootTask) { 1246 LaunchRootTaskDef def = null; 1247 for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { 1248 if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue; 1249 def = mLaunchRootTasks.get(i); 1250 break; 1251 } 1252 return def; 1253 } 1254 1255 @Nullable 1256 Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options, 1257 @Nullable Task sourceTask, int launchFlags) { 1258 // Try to use the launch root task in options if available. 1259 if (options != null) { 1260 final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask()); 1261 // We only allow this for created by organizer tasks. 1262 if (launchRootTask != null && launchRootTask.mCreatedByOrganizer) { 1263 return launchRootTask; 1264 } 1265 } 1266 1267 // Use launch-adjacent-flag-root if launching with launch-adjacent flag. 1268 if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0 1269 && mLaunchAdjacentFlagRootTask != null) { 1270 // If the adjacent launch is coming from the same root, launch to adjacent root instead. 1271 if (sourceTask != null 1272 && sourceTask.getRootTask().mTaskId == mLaunchAdjacentFlagRootTask.mTaskId 1273 && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null) { 1274 return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask(); 1275 } else { 1276 return mLaunchAdjacentFlagRootTask; 1277 } 1278 } 1279 1280 for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { 1281 if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) { 1282 final Task launchRootTask = mLaunchRootTasks.get(i).task; 1283 final TaskFragment adjacentTaskFragment = launchRootTask != null 1284 ? launchRootTask.getAdjacentTaskFragment() : null; 1285 final Task adjacentRootTask = 1286 adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null; 1287 if (sourceTask != null && sourceTask.getRootTask() == adjacentRootTask) { 1288 return adjacentRootTask; 1289 } else { 1290 return launchRootTask; 1291 } 1292 } 1293 } 1294 // For better split UX, If task launch by the source task which root task is created by 1295 // organizer, it should also launch in that root too. 1296 if (sourceTask != null && sourceTask.getRootTask().mCreatedByOrganizer) { 1297 return sourceTask.getRootTask(); 1298 } 1299 return null; 1300 } 1301 1302 /** 1303 * Get the preferred focusable root task in priority. If the preferred root task does not exist, 1304 * find a focusable and visible root task from the top of root tasks in this display. 1305 */ 1306 Task getFocusedRootTask() { 1307 if (mPreferredTopFocusableRootTask != null) { 1308 return mPreferredTopFocusableRootTask; 1309 } 1310 1311 for (int i = mChildren.size() - 1; i >= 0; --i) { 1312 final WindowContainer child = mChildren.get(i); 1313 if (child.asTaskDisplayArea() != null) { 1314 final Task rootTask = child.asTaskDisplayArea().getFocusedRootTask(); 1315 if (rootTask != null) { 1316 return rootTask; 1317 } 1318 continue; 1319 } 1320 1321 final Task rootTask = mChildren.get(i).asTask(); 1322 if (rootTask.isFocusableAndVisible()) { 1323 return rootTask; 1324 } 1325 } 1326 1327 return null; 1328 } 1329 1330 Task getNextFocusableRootTask(Task currentFocus, boolean ignoreCurrent) { 1331 final int currentWindowingMode = currentFocus != null 1332 ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED; 1333 1334 Task candidate = null; 1335 for (int i = mChildren.size() - 1; i >= 0; --i) { 1336 final WindowContainer child = mChildren.get(i); 1337 if (child.asTaskDisplayArea() != null) { 1338 final Task rootTask = child.asTaskDisplayArea() 1339 .getNextFocusableRootTask(currentFocus, ignoreCurrent); 1340 if (rootTask != null) { 1341 return rootTask; 1342 } 1343 continue; 1344 } 1345 1346 final Task rootTask = mChildren.get(i).asTask(); 1347 if (ignoreCurrent && rootTask == currentFocus) { 1348 continue; 1349 } 1350 if (!rootTask.isFocusableAndVisible()) { 1351 continue; 1352 } 1353 1354 if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 1355 && candidate == null && rootTask.inSplitScreenPrimaryWindowingMode()) { 1356 // If the currently focused root task is in split-screen secondary we save off the 1357 // top primary split-screen root task as a candidate for focus because we might 1358 // prefer focus to move to an other root task to avoid primary split-screen root 1359 // task overlapping with a fullscreen root task when a fullscreen root task is 1360 // higher in z than the next split-screen root task. Assistant root task, I am 1361 // looking at you... 1362 // We only move the focus to the primary-split screen root task if there isn't a 1363 // better alternative. 1364 candidate = rootTask; 1365 continue; 1366 } 1367 if (candidate != null && rootTask.inSplitScreenSecondaryWindowingMode()) { 1368 // Use the candidate root task since we are now at the secondary split-screen. 1369 return candidate; 1370 } 1371 return rootTask; 1372 } 1373 return candidate; 1374 } 1375 1376 ActivityRecord getFocusedActivity() { 1377 final Task focusedRootTask = getFocusedRootTask(); 1378 if (focusedRootTask == null) { 1379 return null; 1380 } 1381 // TODO(b/111541062): Move this into Task#getResumedActivity() 1382 // Check if the focused root task has the resumed activity 1383 ActivityRecord resumedActivity = focusedRootTask.getTopResumedActivity(); 1384 if (resumedActivity == null || resumedActivity.app == null) { 1385 // If there is no registered resumed activity in the root task or it is not running - 1386 // try to use previously resumed one. 1387 resumedActivity = focusedRootTask.getTopPausingActivity(); 1388 if (resumedActivity == null || resumedActivity.app == null) { 1389 // If previously resumed activity doesn't work either - find the topmost running 1390 // activity that can be focused. 1391 resumedActivity = focusedRootTask.topRunningActivity(true /* focusableOnly */); 1392 } 1393 } 1394 return resumedActivity; 1395 } 1396 1397 Task getLastFocusedRootTask() { 1398 return mLastFocusedRootTask; 1399 } 1400 1401 void updateLastFocusedRootTask(Task prevFocusedTask, String updateLastFocusedTaskReason) { 1402 if (updateLastFocusedTaskReason == null) { 1403 return; 1404 } 1405 1406 final Task currentFocusedTask = getFocusedRootTask(); 1407 if (currentFocusedTask == prevFocusedTask) { 1408 return; 1409 } 1410 1411 // Clear last paused activity if focused root task changed while sleeping, so that the 1412 // top activity of current focused task can be resumed. 1413 if (mDisplayContent.isSleeping()) { 1414 currentFocusedTask.clearLastPausedActivity(); 1415 } 1416 1417 mLastFocusedRootTask = prevFocusedTask; 1418 EventLogTags.writeWmFocusedRootTask(mRootWindowContainer.mCurrentUser, 1419 mDisplayContent.mDisplayId, 1420 currentFocusedTask == null ? -1 : currentFocusedTask.getRootTaskId(), 1421 mLastFocusedRootTask == null ? -1 : mLastFocusedRootTask.getRootTaskId(), 1422 updateLastFocusedTaskReason); 1423 } 1424 1425 boolean allResumedActivitiesComplete() { 1426 for (int i = mChildren.size() - 1; i >= 0; --i) { 1427 final WindowContainer child = mChildren.get(i); 1428 if (child.asTaskDisplayArea() != null) { 1429 if (!child.asTaskDisplayArea().allResumedActivitiesComplete()) { 1430 return false; 1431 } 1432 continue; 1433 } 1434 1435 final ActivityRecord r = mChildren.get(i).asTask().getTopResumedActivity(); 1436 if (r != null && !r.isState(RESUMED)) { 1437 return false; 1438 } 1439 } 1440 final Task currentFocusedRootTask = getFocusedRootTask(); 1441 if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { 1442 Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: currentFocusedRootTask " 1443 + "changing from=" + mLastFocusedRootTask + " to=" + currentFocusedRootTask); 1444 } 1445 mLastFocusedRootTask = currentFocusedRootTask; 1446 return true; 1447 } 1448 1449 /** 1450 * Pause all activities in either all of the root tasks or just the back root tasks. This is 1451 * done before resuming a new activity and to make sure that previously active activities are 1452 * paused in root tasks that are no longer visible or in pinned windowing mode. This does not 1453 * pause activities in visible root tasks, so if an activity is launched within the same root 1454 * task, hen we should explicitly pause that root task's top activity. 1455 * 1456 * @param resuming The resuming activity. 1457 * @return {@code true} if any activity was paused as a result of this call. 1458 */ 1459 boolean pauseBackTasks(ActivityRecord resuming) { 1460 final int[] someActivityPaused = {0}; 1461 forAllLeafTasks(leafTask -> { 1462 // Check if the direct child resumed activity in the leaf task needed to be paused if 1463 // the leaf task is not a leaf task fragment. 1464 if (!leafTask.isLeafTaskFragment()) { 1465 final ActivityRecord top = topRunningActivity(); 1466 final ActivityRecord resumedActivity = leafTask.getResumedActivity(); 1467 if (resumedActivity != null && top.getTaskFragment() != leafTask) { 1468 // Pausing the resumed activity because it is occluded by other task fragment. 1469 if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) { 1470 someActivityPaused[0]++; 1471 } 1472 } 1473 } 1474 1475 leafTask.forAllLeafTaskFragments((taskFrag) -> { 1476 final ActivityRecord resumedActivity = taskFrag.getResumedActivity(); 1477 if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) { 1478 if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) { 1479 someActivityPaused[0]++; 1480 } 1481 } 1482 }, true /* traverseTopToBottom */); 1483 }, true /* traverseTopToBottom */); 1484 return someActivityPaused[0] > 0; 1485 } 1486 1487 void onSplitScreenModeDismissed() { 1488 // The focused task could be a non-resizeable fullscreen root task that is on top of the 1489 // other split-screen tasks, therefore had to dismiss split-screen, make sure the current 1490 // focused root task can still be on top after dismissal 1491 final Task rootTask = getFocusedRootTask(); 1492 final Task toTop = 1493 rootTask != null && !rootTask.inSplitScreenWindowingMode() ? rootTask : null; 1494 onSplitScreenModeDismissed(toTop); 1495 } 1496 1497 void onSplitScreenModeDismissed(Task toTop) { 1498 mAtmService.deferWindowLayout(); 1499 try { 1500 moveSplitScreenTasksToFullScreen(); 1501 } finally { 1502 final Task topFullscreenRootTask = toTop != null 1503 ? toTop : getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN); 1504 final Task rootHomeTask = getOrCreateRootHomeTask(); 1505 if (rootHomeTask != null && ((topFullscreenRootTask != null && !isTopRootTask( 1506 rootHomeTask)) || toTop != null)) { 1507 // Whenever split-screen is dismissed we want the root home task directly behind the 1508 // current top fullscreen root task so it shows up when the top root task is 1509 // finished. Or, if the caller specified a root task to be on top after 1510 // split-screen is dismissed. 1511 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however 1512 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch 1513 // once we have that. 1514 rootHomeTask.moveToFront("onSplitScreenModeDismissed"); 1515 topFullscreenRootTask.moveToFront("onSplitScreenModeDismissed"); 1516 } 1517 mAtmService.continueWindowLayout(); 1518 } 1519 } 1520 1521 private void moveSplitScreenTasksToFullScreen() { 1522 final WindowContainerTransaction wct = new WindowContainerTransaction(); 1523 mTmpTasks.clear(); 1524 forAllTasks(task -> { 1525 if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) { 1526 mTmpTasks.add(task); 1527 } 1528 }); 1529 1530 for (int i = mTmpTasks.size() - 1; i >= 0; i--) { 1531 final Task root = mTmpTasks.get(i); 1532 for (int j = 0; j < root.getChildCount(); j++) { 1533 final WindowContainerToken token = 1534 root.getChildAt(j).mRemoteToken.toWindowContainerToken(); 1535 wct.reparent(token, null, true /* toTop */); 1536 wct.setBounds(token, null); 1537 } 1538 } 1539 mAtmService.mWindowOrganizerController.applyTransaction(wct); 1540 } 1541 1542 /** 1543 * Returns true if the {@param windowingMode} is supported based on other parameters passed in. 1544 * 1545 * @param windowingMode The windowing mode we are checking support for. 1546 * @param supportsMultiWindow If we should consider support for multi-window mode in general. 1547 * @param supportsSplitScreen If we should consider support for split-screen multi-window. 1548 * @param supportsFreeform If we should consider support for freeform multi-window. 1549 * @param supportsPip If we should consider support for picture-in-picture mutli-window. 1550 * @param activityType The activity type under consideration. 1551 * @return true if the windowing mode is supported. 1552 */ 1553 static boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, 1554 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, 1555 int activityType) { 1556 1557 if (windowingMode == WINDOWING_MODE_UNDEFINED 1558 || windowingMode == WINDOWING_MODE_FULLSCREEN) { 1559 return true; 1560 } 1561 if (!supportsMultiWindow) { 1562 return false; 1563 } 1564 1565 if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) { 1566 return true; 1567 } 1568 1569 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 1570 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { 1571 return supportsSplitScreen 1572 && WindowConfiguration.supportSplitScreenWindowingMode(activityType); 1573 } 1574 1575 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) { 1576 return false; 1577 } 1578 1579 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) { 1580 return false; 1581 } 1582 return true; 1583 } 1584 1585 /** 1586 * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this 1587 * display with the provided parameters. 1588 * 1589 * @param r The ActivityRecord in question. 1590 * @param options Options to start with. 1591 * @param task The task within-which the activity would start. 1592 * @param activityType The type of activity to start. 1593 * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in. 1594 */ 1595 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, 1596 @Nullable Task task, int activityType) { 1597 1598 // First preference if the windowing mode in the activity options if set. 1599 int windowingMode = (options != null) 1600 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED; 1601 1602 // If windowing mode is unset, then next preference is the candidate task, then the 1603 // activity record. 1604 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 1605 if (task != null) { 1606 windowingMode = task.getWindowingMode(); 1607 } 1608 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) { 1609 windowingMode = r.getWindowingMode(); 1610 } 1611 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 1612 // Use the display's windowing mode. 1613 windowingMode = getWindowingMode(); 1614 } 1615 } 1616 windowingMode = validateWindowingMode(windowingMode, r, task, activityType); 1617 return windowingMode != WINDOWING_MODE_UNDEFINED 1618 ? windowingMode : WINDOWING_MODE_FULLSCREEN; 1619 } 1620 1621 /** 1622 * Check if the requested windowing-mode is appropriate for the specified task and/or activity 1623 * on this display. 1624 * 1625 * @param windowingMode The windowing-mode to validate. 1626 * @param r The {@link ActivityRecord} to check against. 1627 * @param task The {@link Task} to check against. 1628 * @param activityType An activity type. 1629 * @return {@code true} if windowingMode is valid, {@code false} otherwise. 1630 */ 1631 boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task, 1632 int activityType) { 1633 // Make sure the windowing mode we are trying to use makes sense for what is supported. 1634 boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow; 1635 boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow; 1636 boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement; 1637 boolean supportsPip = mAtmService.mSupportsPictureInPicture; 1638 if (supportsMultiWindow) { 1639 if (task != null) { 1640 supportsSplitScreen = task.supportsSplitScreenWindowingModeInDisplayArea(this); 1641 supportsFreeform = task.supportsFreeformInDisplayArea(this); 1642 supportsMultiWindow = task.supportsMultiWindowInDisplayArea(this) 1643 // When the activity needs to be moved to PIP while the Task is not in PIP, 1644 // it can be moved to a new created PIP Task, so WINDOWING_MODE_PINNED is 1645 // always valid for Task as long as the device supports it. 1646 || (windowingMode == WINDOWING_MODE_PINNED && supportsPip); 1647 } else if (r != null) { 1648 supportsSplitScreen = r.supportsSplitScreenWindowingModeInDisplayArea(this); 1649 supportsFreeform = r.supportsFreeformInDisplayArea(this); 1650 supportsPip = r.supportsPictureInPicture(); 1651 supportsMultiWindow = r.supportsMultiWindowInDisplayArea(this); 1652 } 1653 } 1654 1655 return windowingMode != WINDOWING_MODE_UNDEFINED 1656 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen, 1657 supportsFreeform, supportsPip, activityType); 1658 } 1659 1660 /** 1661 * Check that the requested windowing-mode is appropriate for the specified task and/or activity 1662 * on this display. 1663 * 1664 * @param windowingMode The windowing-mode to validate. 1665 * @param r The {@link ActivityRecord} to check against. 1666 * @param task The {@link Task} to check against. 1667 * @param activityType An activity type. 1668 * @return The provided windowingMode or the closest valid mode which is appropriate. 1669 */ 1670 int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task, 1671 int activityType) { 1672 final boolean inSplitScreenMode = isSplitScreenModeActivated(); 1673 if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { 1674 // Switch to the display's windowing mode if we are not in split-screen mode and we are 1675 // trying to launch in split-screen secondary. 1676 windowingMode = WINDOWING_MODE_UNDEFINED; 1677 } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_UNDEFINED) { 1678 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 1679 } 1680 if (!isValidWindowingMode(windowingMode, r, task, activityType)) { 1681 return WINDOWING_MODE_UNDEFINED; 1682 } 1683 return windowingMode; 1684 } 1685 1686 /** 1687 * Whether we can show non-resizable activities in multi window below this 1688 * {@link TaskDisplayArea} 1689 */ 1690 boolean supportsNonResizableMultiWindow() { 1691 final int configSupportsNonResizableMultiWindow = 1692 mAtmService.mSupportsNonResizableMultiWindow; 1693 if (mAtmService.mDevEnableNonResizableMultiWindow 1694 || configSupportsNonResizableMultiWindow == 1) { 1695 // Device override to support. 1696 return true; 1697 } 1698 if (configSupportsNonResizableMultiWindow == -1) { 1699 // Device override to not support. 1700 return false; 1701 } 1702 // Support on large screen. 1703 return isLargeEnoughForMultiWindow(); 1704 } 1705 1706 /** 1707 * Whether we can show activity requesting the given min width/height in multi window below 1708 * this {@link TaskDisplayArea}. 1709 */ 1710 boolean supportsActivityMinWidthHeightMultiWindow(int minWidth, int minHeight, 1711 @Nullable ActivityInfo activityInfo) { 1712 if (activityInfo != null && !activityInfo.shouldCheckMinWidthHeightForMultiWindow()) { 1713 return true; 1714 } 1715 if (minWidth <= 0 && minHeight <= 0) { 1716 // No request min width/height. 1717 return true; 1718 } 1719 final int configRespectsActivityMinWidthHeightMultiWindow = 1720 mAtmService.mRespectsActivityMinWidthHeightMultiWindow; 1721 if (configRespectsActivityMinWidthHeightMultiWindow == -1) { 1722 // Device override to ignore min width/height. 1723 return true; 1724 } 1725 if (configRespectsActivityMinWidthHeightMultiWindow == 0 1726 && isLargeEnoughForMultiWindow()) { 1727 // Ignore min width/height on large screen. 1728 return true; 1729 } 1730 // Check if the request min width/height is supported in multi window. 1731 final Configuration config = getConfiguration(); 1732 final int orientation = config.orientation; 1733 if (orientation == ORIENTATION_LANDSCAPE) { 1734 final int maxSupportMinWidth = (int) (mAtmService.mMinPercentageMultiWindowSupportWidth 1735 * config.screenWidthDp * mDisplayContent.getDisplayMetrics().density); 1736 return minWidth <= maxSupportMinWidth; 1737 } else { 1738 final int maxSupportMinHeight = 1739 (int) (mAtmService.mMinPercentageMultiWindowSupportHeight 1740 * config.screenHeightDp * mDisplayContent.getDisplayMetrics().density); 1741 return minHeight <= maxSupportMinHeight; 1742 } 1743 } 1744 1745 /** 1746 * Whether this is large enough to support non-resizable, and activities with min width/height 1747 * in multi window. 1748 */ 1749 private boolean isLargeEnoughForMultiWindow() { 1750 return getConfiguration().smallestScreenWidthDp 1751 >= mAtmService.mLargeScreenSmallestScreenWidthDp; 1752 } 1753 1754 boolean isTopRootTask(Task rootTask) { 1755 return rootTask == getTopRootTask(); 1756 } 1757 1758 ActivityRecord topRunningActivity() { 1759 return topRunningActivity(false /* considerKeyguardState */); 1760 } 1761 1762 /** 1763 * Returns the top running activity in the focused root task. In the case the focused root 1764 * task has no such activity, the next focusable root task on this display is returned. 1765 * 1766 * @param considerKeyguardState Indicates whether the locked state should be considered. if 1767 * {@code true} and the keyguard is locked, only activities that 1768 * can be shown on top of the keyguard will be considered. 1769 * @return The top running activity. {@code null} if none is available. 1770 */ 1771 ActivityRecord topRunningActivity(boolean considerKeyguardState) { 1772 ActivityRecord topRunning = null; 1773 final Task focusedRootTask = getFocusedRootTask(); 1774 if (focusedRootTask != null) { 1775 topRunning = focusedRootTask.topRunningActivity(); 1776 } 1777 1778 // Look in other focusable root tasks. 1779 if (topRunning == null) { 1780 for (int i = mChildren.size() - 1; i >= 0; --i) { 1781 final WindowContainer child = mChildren.get(i); 1782 if (child.asTaskDisplayArea() != null) { 1783 topRunning = 1784 child.asTaskDisplayArea().topRunningActivity(considerKeyguardState); 1785 if (topRunning != null) { 1786 break; 1787 } 1788 continue; 1789 } 1790 final Task rootTask = mChildren.get(i).asTask(); 1791 // Only consider focusable root tasks other than the current focused one. 1792 if (rootTask == focusedRootTask || !rootTask.isTopActivityFocusable()) { 1793 continue; 1794 } 1795 topRunning = rootTask.topRunningActivity(); 1796 if (topRunning != null) { 1797 break; 1798 } 1799 } 1800 } 1801 1802 // This activity can be considered the top running activity if we are not considering 1803 // the locked state, the keyguard isn't locked, or we can show when locked. 1804 if (topRunning != null && considerKeyguardState 1805 && mRootWindowContainer.mTaskSupervisor.getKeyguardController() 1806 .isKeyguardLocked() 1807 && !topRunning.canShowWhenLocked()) { 1808 return null; 1809 } 1810 1811 return topRunning; 1812 } 1813 1814 protected int getRootTaskCount() { 1815 final int[] count = new int[1]; 1816 forAllRootTasks(task -> { 1817 count[0]++; 1818 }); 1819 return count[0]; 1820 } 1821 1822 @Nullable 1823 Task getOrCreateRootHomeTask() { 1824 return getOrCreateRootHomeTask(false /* onTop */); 1825 } 1826 1827 /** 1828 * Returns the existing root home task or creates and returns a new one if it should exist 1829 * for the display. 1830 * 1831 * @param onTop Only be used when there is no existing root home task. If true the root home 1832 * task will be created at the top of the display, else at the bottom. 1833 */ 1834 @Nullable 1835 Task getOrCreateRootHomeTask(boolean onTop) { 1836 Task homeTask = getRootHomeTask(); 1837 // Take into account if this TaskDisplayArea can have a home task before trying to 1838 // create the root task 1839 if (homeTask == null && canHostHomeTask()) { 1840 homeTask = createRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop); 1841 } 1842 return homeTask; 1843 } 1844 1845 boolean isSplitScreenModeActivated() { 1846 Task task = getRootSplitScreenPrimaryTask(); 1847 return task != null && task.hasChild(); 1848 } 1849 1850 /** 1851 * Returns the topmost root task on the display that is compatible with the input windowing 1852 * mode. Null is no compatible root task on the display. 1853 */ 1854 Task getTopRootTaskInWindowingMode(int windowingMode) { 1855 return getRootTask(windowingMode, ACTIVITY_TYPE_UNDEFINED); 1856 } 1857 1858 void moveHomeRootTaskToFront(String reason) { 1859 final Task homeRootTask = getOrCreateRootHomeTask(); 1860 if (homeRootTask != null) { 1861 homeRootTask.moveToFront(reason); 1862 } 1863 } 1864 1865 /** 1866 * Moves the focusable home activity to top. If there is no such activity, the root home task 1867 * will still move to top. 1868 */ 1869 void moveHomeActivityToTop(String reason) { 1870 final ActivityRecord top = getHomeActivity(); 1871 if (top == null) { 1872 moveHomeRootTaskToFront(reason); 1873 return; 1874 } 1875 top.moveFocusableActivityToTop(reason); 1876 } 1877 1878 @Nullable 1879 ActivityRecord getHomeActivity() { 1880 return getHomeActivityForUser(mRootWindowContainer.mCurrentUser); 1881 } 1882 1883 @Nullable 1884 ActivityRecord getHomeActivityForUser(int userId) { 1885 final Task rootHomeTask = getRootHomeTask(); 1886 if (rootHomeTask == null) { 1887 return null; 1888 } 1889 1890 final PooledPredicate p = PooledLambda.obtainPredicate( 1891 TaskDisplayArea::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class), 1892 userId); 1893 final ActivityRecord r = rootHomeTask.getActivity(p); 1894 p.recycle(); 1895 return r; 1896 } 1897 1898 private static boolean isHomeActivityForUser(ActivityRecord r, int userId) { 1899 return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId); 1900 } 1901 1902 /** 1903 * Adjusts the {@param rootTask} behind the last visible rootTask in the display if necessary. 1904 * Generally used in conjunction with {@link #moveRootTaskBehindRootTask}. 1905 */ 1906 // TODO(b/151575894): Remove special root task movement methods. 1907 void moveRootTaskBehindBottomMostVisibleRootTask(Task rootTask) { 1908 if (rootTask.shouldBeVisible(null)) { 1909 // Skip if the root task is already visible 1910 return; 1911 } 1912 1913 // Move the root task to the bottom to not affect the following visibility checks 1914 rootTask.getParent().positionChildAt(POSITION_BOTTOM, rootTask, 1915 false /* includingParents */); 1916 1917 // Find the next position where the root task should be placed 1918 final boolean isRootTask = rootTask.isRootTask(); 1919 final int numRootTasks = 1920 isRootTask ? mChildren.size() : rootTask.getParent().getChildCount(); 1921 for (int rootTaskNdx = 0; rootTaskNdx < numRootTasks; rootTaskNdx++) { 1922 Task s; 1923 if (isRootTask) { 1924 final WindowContainer child = mChildren.get(rootTaskNdx); 1925 if (child.asTaskDisplayArea() != null) { 1926 s = child.asTaskDisplayArea().getBottomMostVisibleRootTask(rootTask); 1927 } else { 1928 s = child.asTask(); 1929 } 1930 } else { 1931 s = rootTask.getParent().getChildAt(rootTaskNdx).asTask(); 1932 } 1933 if (s == rootTask || s == null) { 1934 continue; 1935 } 1936 final int winMode = s.getWindowingMode(); 1937 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN 1938 || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 1939 if (s.shouldBeVisible(null) && isValidWindowingMode) { 1940 // Move the provided root task to behind this root task 1941 final int position = Math.max(0, rootTaskNdx - 1); 1942 rootTask.getParent().positionChildAt(position, rootTask, 1943 false /*includingParents */); 1944 break; 1945 } 1946 } 1947 } 1948 1949 @Nullable 1950 private Task getBottomMostVisibleRootTask(Task excludeRootTask) { 1951 return getRootTask(task -> { 1952 final int winMode = task.getWindowingMode(); 1953 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN 1954 || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 1955 return task.shouldBeVisible(null) && isValidWindowingMode; 1956 }, false /* traverseTopToBottom */); 1957 } 1958 1959 /** 1960 * Moves the {@param rootTask} behind the given {@param behindRootTask} if possible. If 1961 * {@param behindRootTask} is not currently in the display, then then the root task is moved 1962 * to the back. Generally used in conjunction with 1963 * {@link #moveRootTaskBehindBottomMostVisibleRootTask}. 1964 */ 1965 void moveRootTaskBehindRootTask(Task rootTask, Task behindRootTask) { 1966 if (behindRootTask == null || behindRootTask == rootTask) { 1967 return; 1968 } 1969 1970 final WindowContainer parent = rootTask.getParent(); 1971 if (parent == null || parent != behindRootTask.getParent()) { 1972 return; 1973 } 1974 1975 // Note that positionChildAt will first remove the given root task before inserting into the 1976 // list, so we need to adjust the insertion index to account for the removed index 1977 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the 1978 // position internally 1979 final int rootTaskIndex = parent.mChildren.indexOf(rootTask); 1980 final int behindRootTaskIndex = parent.mChildren.indexOf(behindRootTask); 1981 final int insertIndex = rootTaskIndex <= behindRootTaskIndex 1982 ? behindRootTaskIndex - 1 : behindRootTaskIndex; 1983 final int position = Math.max(0, insertIndex); 1984 parent.positionChildAt(position, rootTask, false /* includingParents */); 1985 } 1986 1987 boolean hasPinnedTask() { 1988 return getRootPinnedTask() != null; 1989 } 1990 1991 /** 1992 * @return the root task currently above the {@param rootTask}. Can be null if the 1993 * {@param rootTask} is already top-most. 1994 */ 1995 static Task getRootTaskAbove(Task rootTask) { 1996 final WindowContainer wc = rootTask.getParent(); 1997 final int index = wc.mChildren.indexOf(rootTask) + 1; 1998 return (index < wc.mChildren.size()) ? (Task) wc.mChildren.get(index) : null; 1999 } 2000 2001 /** Returns true if the root task in the windowing mode is visible. */ 2002 boolean isRootTaskVisible(int windowingMode) { 2003 final Task rootTask = getTopRootTaskInWindowingMode(windowingMode); 2004 return rootTask != null && rootTask.isVisible(); 2005 } 2006 2007 void removeRootTask(Task rootTask) { 2008 removeChild(rootTask); 2009 } 2010 2011 int getDisplayId() { 2012 return mDisplayContent.getDisplayId(); 2013 } 2014 2015 boolean isRemoved() { 2016 return mRemoved; 2017 } 2018 2019 /** 2020 * Adds a listener to be notified whenever the root task order in the display changes. Currently 2021 * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the 2022 * current animation when the system state changes. 2023 */ 2024 void registerRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) { 2025 if (!mRootTaskOrderChangedCallbacks.contains(listener)) { 2026 mRootTaskOrderChangedCallbacks.add(listener); 2027 } 2028 } 2029 2030 /** 2031 * Removes a previously registered root task order change listener. 2032 */ 2033 void unregisterRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) { 2034 mRootTaskOrderChangedCallbacks.remove(listener); 2035 } 2036 2037 /** 2038 * Notifies of a root task order change 2039 * 2040 * @param rootTask The root task which triggered the order change 2041 */ 2042 void onRootTaskOrderChanged(Task rootTask) { 2043 for (int i = mRootTaskOrderChangedCallbacks.size() - 1; i >= 0; i--) { 2044 mRootTaskOrderChangedCallbacks.get(i).onRootTaskOrderChanged(rootTask); 2045 } 2046 } 2047 2048 @Override 2049 boolean canCreateRemoteAnimationTarget() { 2050 return true; 2051 } 2052 2053 /** 2054 * Exposes the home task capability of the TaskDisplayArea 2055 */ 2056 boolean canHostHomeTask() { 2057 return mDisplayContent.supportsSystemDecorations() && mCanHostHomeTask; 2058 } 2059 2060 /** 2061 * Callback for when the order of the root tasks in the display changes. 2062 */ 2063 interface OnRootTaskOrderChangedListener { 2064 void onRootTaskOrderChanged(Task rootTask); 2065 } 2066 2067 void ensureActivitiesVisible(ActivityRecord starting, int configChanges, 2068 boolean preserveWindows, boolean notifyClients) { 2069 mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate(); 2070 try { 2071 forAllRootTasks(rootTask -> { 2072 rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows, 2073 notifyClients); 2074 }); 2075 } finally { 2076 mAtmService.mTaskSupervisor.endActivityVisibilityUpdate(); 2077 } 2078 } 2079 2080 /** 2081 * Removes the root tasks in the node applying the content removal node from the display. 2082 * 2083 * @return last reparented root task, or {@code null} if the root tasks had to be destroyed. 2084 */ 2085 Task remove() { 2086 mPreferredTopFocusableRootTask = null; 2087 // TODO(b/153090332): Allow setting content removal mode per task display area 2088 final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove(); 2089 final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 2090 Task lastReparentedRootTask = null; 2091 2092 // Root tasks could be reparented from the removed display area to other display area. After 2093 // reparenting the last root task of the removed display area, the display area becomes 2094 // ready to be released (no more root tasks). But, we cannot release it at that moment 2095 // or the related WindowContainer will also be removed. So, we set display area as removed 2096 // after reparenting root task finished. 2097 // Keep the order from bottom to top. 2098 int numRootTasks = mChildren.size(); 2099 2100 for (int i = 0; i < numRootTasks; i++) { 2101 final WindowContainer child = mChildren.get(i); 2102 if (child.asTaskDisplayArea() != null) { 2103 lastReparentedRootTask = child.asTaskDisplayArea().remove(); 2104 continue; 2105 } 2106 final Task task = mChildren.get(i).asTask(); 2107 // Always finish non-standard type root tasks and root tasks created by a organizer. 2108 // TODO: For root tasks created by organizer, consider reparenting children tasks if 2109 // the use case arises in the future. 2110 if (destroyContentOnRemoval 2111 || !task.isActivityTypeStandardOrUndefined() 2112 || task.mCreatedByOrganizer) { 2113 task.remove(false /* withTransition */, "removeTaskDisplayArea"); 2114 } else { 2115 // Reparent task to corresponding launch root or display area. 2116 final WindowContainer launchRoot = 2117 task.supportsSplitScreenWindowingModeInDisplayArea(toDisplayArea) 2118 ? toDisplayArea.getLaunchRootTask( 2119 task.getWindowingMode(), 2120 task.getActivityType(), 2121 null /* options */, 2122 null /* sourceTask */, 2123 0 /* launchFlags */) 2124 : null; 2125 task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP); 2126 2127 // Set the windowing mode to undefined by default to let the root task inherited the 2128 // windowing mode. 2129 task.setWindowingMode(WINDOWING_MODE_UNDEFINED); 2130 lastReparentedRootTask = task; 2131 } 2132 // Root task may be removed from this display. Ensure each root task will be processed 2133 // and the loop will end. 2134 i -= numRootTasks - mChildren.size(); 2135 numRootTasks = mChildren.size(); 2136 } 2137 2138 if (lastReparentedRootTask != null) { 2139 if (toDisplayArea.isSplitScreenModeActivated() 2140 && !lastReparentedRootTask.supportsSplitScreenWindowingModeInDisplayArea( 2141 toDisplayArea)) { 2142 // Dismiss split screen if the last reparented root task doesn't support split mode. 2143 mAtmService.getTaskChangeNotificationController() 2144 .notifyActivityDismissingDockedRootTask(); 2145 toDisplayArea.onSplitScreenModeDismissed(lastReparentedRootTask); 2146 } else if (!lastReparentedRootTask.isRootTask()) { 2147 // Update focus when the last reparented root task is not a root task anymore. 2148 // (For example, if it has been reparented to a split screen root task, move the 2149 // focus to the split root task) 2150 lastReparentedRootTask.getRootTask().moveToFront("display-removed"); 2151 } 2152 } 2153 2154 mRemoved = true; 2155 2156 return lastReparentedRootTask; 2157 } 2158 2159 /** Whether this task display area can request orientation. */ 2160 boolean canSpecifyOrientation() { 2161 // Only allow to specify orientation if this TDA is not set to ignore orientation request, 2162 // and it is the last focused one on this logical display that can request orientation 2163 // request. 2164 return !mIgnoreOrientationRequest 2165 && mDisplayContent.getOrientationRequestingTaskDisplayArea() == this; 2166 } 2167 2168 void clearPreferredTopFocusableRootTask() { 2169 mPreferredTopFocusableRootTask = null; 2170 } 2171 2172 @Override 2173 TaskDisplayArea getTaskDisplayArea() { 2174 return this; 2175 } 2176 2177 @Override 2178 boolean isTaskDisplayArea() { 2179 return true; 2180 } 2181 2182 @Override 2183 TaskDisplayArea asTaskDisplayArea() { 2184 return this; 2185 } 2186 2187 @Override 2188 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 2189 pw.println(prefix + "TaskDisplayArea " + getName()); 2190 final String doublePrefix = prefix + " "; 2191 super.dump(pw, doublePrefix, dumpAll); 2192 if (mPreferredTopFocusableRootTask != null) { 2193 pw.println(doublePrefix + "mPreferredTopFocusableRootTask=" 2194 + mPreferredTopFocusableRootTask); 2195 } 2196 if (mLastFocusedRootTask != null) { 2197 pw.println(doublePrefix + "mLastFocusedRootTask=" + mLastFocusedRootTask); 2198 } 2199 2200 final String triplePrefix = doublePrefix + " "; 2201 2202 if (mLaunchRootTasks.size() > 0) { 2203 pw.println(doublePrefix + "mLaunchRootTasks:"); 2204 for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { 2205 final LaunchRootTaskDef def = mLaunchRootTasks.get(i); 2206 pw.println(triplePrefix 2207 + Arrays.toString(def.activityTypes) + " " 2208 + Arrays.toString(def.windowingModes) + " " 2209 + " task=" + def.task); 2210 } 2211 } 2212 2213 pw.println(doublePrefix + "Application tokens in top down Z order:"); 2214 for (int index = getChildCount() - 1; index >= 0; --index) { 2215 final WindowContainer child = getChildAt(index); 2216 if (child.asTaskDisplayArea() != null) { 2217 child.dump(pw, doublePrefix, dumpAll); 2218 continue; 2219 } 2220 final Task rootTask = child.asTask(); 2221 pw.println(doublePrefix + "* " + rootTask); 2222 rootTask.dump(pw, triplePrefix, dumpAll); 2223 } 2224 } 2225 } 2226