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