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