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