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(t -> true); 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.isTopActivityFocusable(); 416 if (isTopFocusableTask) { 417 mPreferredTopFocusableRootTask = 418 child.shouldBeVisible(null /* starting */) ? child : null; 419 } else if (mPreferredTopFocusableRootTask == child) { 420 mPreferredTopFocusableRootTask = null; 421 } 422 423 // Update the top resumed activity because the preferred top focusable task may be changed. 424 mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded("positionChildTaskAt"); 425 426 if (mChildren.indexOf(child) != oldPosition) { 427 onRootTaskOrderChanged(child); 428 } 429 } 430 431 void onLeafTaskRemoved(int taskId) { 432 if (mLastLeafTaskToFrontId == taskId) { 433 mLastLeafTaskToFrontId = INVALID_TASK_ID; 434 } 435 } 436 437 void onLeafTaskMoved(Task t, boolean toTop, boolean toBottom) { 438 if (toBottom) { 439 mAtmService.getTaskChangeNotificationController().notifyTaskMovedToBack( 440 t.getTaskInfo()); 441 } 442 443 if (!toTop) { 444 if (t.mTaskId == mLastLeafTaskToFrontId) { 445 mLastLeafTaskToFrontId = INVALID_TASK_ID; 446 447 // If the previous front-most task is moved to the back, then notify of the new 448 // front-most task. 449 final ActivityRecord topMost = getTopMostActivity(); 450 if (topMost != null) { 451 mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront( 452 topMost.getTask().getTaskInfo()); 453 } 454 } 455 return; 456 } 457 if (t.mTaskId == mLastLeafTaskToFrontId || t.topRunningActivityLocked() == null) { 458 return; 459 } 460 461 mLastLeafTaskToFrontId = t.mTaskId; 462 EventLogTags.writeWmTaskToFront(t.mUserId, t.mTaskId, getDisplayId()); 463 // Notifying only when a leaf task moved to front. Or the listeners would be notified 464 // couple times from the leaf task all the way up to the root task. 465 mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(t.getTaskInfo()); 466 } 467 468 @Override 469 void onChildPositionChanged(WindowContainer child) { 470 super.onChildPositionChanged(child); 471 mRootWindowContainer.invalidateTaskLayers(); 472 } 473 474 @Override 475 boolean forAllTaskDisplayAreas(Predicate<TaskDisplayArea> callback, 476 boolean traverseTopToBottom) { 477 // Apply the callback to all TDAs at or below this container. If the callback returns true, 478 // stop early. 479 if (traverseTopToBottom) { 480 // When it is top to bottom, run on child TDA first as they are on top of the parent. 481 return super.forAllTaskDisplayAreas(callback, traverseTopToBottom) 482 || callback.test(this); 483 } 484 return callback.test(this) || super.forAllTaskDisplayAreas(callback, traverseTopToBottom); 485 } 486 487 @Override 488 void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) { 489 if (traverseTopToBottom) { 490 super.forAllTaskDisplayAreas(callback, traverseTopToBottom); 491 callback.accept(this); 492 } else { 493 callback.accept(this); 494 super.forAllTaskDisplayAreas(callback, traverseTopToBottom); 495 } 496 } 497 498 @Nullable 499 @Override 500 <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, 501 @Nullable R initValue, boolean traverseTopToBottom) { 502 if (traverseTopToBottom) { 503 final R result = 504 super.reduceOnAllTaskDisplayAreas(accumulator, initValue, traverseTopToBottom); 505 return accumulator.apply(this, result); 506 } else { 507 final R result = accumulator.apply(this, initValue); 508 return super.reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom); 509 510 } 511 } 512 513 @Nullable 514 @Override 515 <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, 516 boolean traverseTopToBottom) { 517 if (traverseTopToBottom) { 518 final R item = super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom); 519 return item != null ? item : callback.apply(this); 520 } else { 521 final R item = callback.apply(this); 522 return item != null 523 ? item 524 : super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom); 525 } 526 } 527 528 /** 529 * Assigns a priority number to root task types. This priority defines an order between the 530 * types of root task that are added to the task display area. 531 * 532 * Higher priority number indicates that the root task should have a higher z-order. 533 * 534 * For child {@link TaskDisplayArea}, it will be the priority of its top child. 535 * 536 * @return the priority of the root task 537 */ 538 private int getPriority(WindowContainer child) { 539 final TaskDisplayArea tda = child.asTaskDisplayArea(); 540 if (tda != null) { 541 // Use the top child priority as the TaskDisplayArea priority. 542 return tda.getPriority(tda.getTopChild()); 543 } 544 final Task rootTask = child.asTask(); 545 if (mWmService.mAssistantOnTopOfDream && rootTask.isActivityTypeAssistant()) return 4; 546 if (rootTask.isActivityTypeDream()) return 3; 547 if (rootTask.inPinnedWindowingMode()) return 2; 548 if (rootTask.isAlwaysOnTop()) return 1; 549 return 0; 550 } 551 552 private int findMinPositionForRootTask(Task rootTask) { 553 int minPosition = POSITION_BOTTOM; 554 for (int i = 0; i < mChildren.size(); ++i) { 555 if (getPriority(mChildren.get(i)) < getPriority(rootTask)) { 556 minPosition = i; 557 } else { 558 break; 559 } 560 } 561 562 if (rootTask.isAlwaysOnTop()) { 563 // Since a root task could be repositioned while still being one of the children, we 564 // check if this always-on-top root task already exists and if so, set the minPosition 565 // to its previous position. 566 // Use mChildren.indexOf instead of getTaskIndexOf because we need to place the rootTask 567 // as a direct child. 568 final int currentIndex = mChildren.indexOf(rootTask); 569 if (currentIndex > minPosition) { 570 minPosition = currentIndex; 571 } 572 } 573 return minPosition; 574 } 575 576 private int findMaxPositionForRootTask(Task rootTask) { 577 for (int i = mChildren.size() - 1; i >= 0; --i) { 578 final WindowContainer curr = mChildren.get(i); 579 // Since a root task could be repositioned while still being one of the children, we 580 // check if 'curr' is the same root task and skip it if so 581 final boolean sameRootTask = curr == rootTask; 582 if (getPriority(curr) <= getPriority(rootTask) && !sameRootTask) { 583 return i; 584 } 585 } 586 return 0; 587 } 588 589 /** 590 * When root task is added or repositioned, find a proper position for it. 591 * 592 * The order is defined as: 593 * - Dream is on top of everything 594 * - PiP is directly below the Dream 595 * - always-on-top root tasks are directly below PiP; new always-on-top root tasks are added 596 * above existing ones 597 * - other non-always-on-top root tasks come directly below always-on-top root tasks; new 598 * non-always-on-top root tasks are added directly below always-on-top root tasks and above 599 * existing non-always-on-top root tasks 600 * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything 601 * (including the Dream); otherwise, it is a normal non-always-on-top root task 602 * 603 * @param requestedPosition Position requested by caller. 604 * @param rootTask Root task to be added or positioned. 605 * @param adding Flag indicates whether we're adding a new root task or positioning 606 * an existing. 607 * @return The proper position for the root task. 608 */ 609 private int findPositionForRootTask(int requestedPosition, Task rootTask, boolean adding) { 610 // The max possible position we can insert the root task at. 611 int maxPosition = findMaxPositionForRootTask(rootTask); 612 // The min possible position we can insert the root task at. 613 int minPosition = findMinPositionForRootTask(rootTask); 614 615 // Cap the requested position to something reasonable for the previous position check 616 // below. 617 if (requestedPosition == POSITION_TOP) { 618 requestedPosition = mChildren.size(); 619 } else if (requestedPosition == POSITION_BOTTOM) { 620 requestedPosition = 0; 621 } 622 623 int targetPosition = requestedPosition; 624 targetPosition = Math.min(targetPosition, maxPosition); 625 targetPosition = Math.max(targetPosition, minPosition); 626 627 int prevPosition = mChildren.indexOf(rootTask); 628 // The positions we calculated above (maxPosition, minPosition) do not take into 629 // consideration the following edge cases. 630 // 1) We need to adjust the position depending on the value "adding". 631 // 2) When we are moving a root task to another position, we also need to adjust the 632 // position depending on whether the root task is moving to a higher or lower position. 633 if ((targetPosition != requestedPosition) && (adding || targetPosition < prevPosition)) { 634 targetPosition++; 635 } 636 637 return targetPosition; 638 } 639 640 @Override 641 @ScreenOrientation 642 int getOrientation(@ScreenOrientation int candidate) { 643 final int orientation = super.getOrientation(candidate); 644 if (!canSpecifyOrientation(orientation)) { 645 mLastOrientationSource = null; 646 // We only respect orientation of the focused TDA, which can be a child of this TDA. 647 return reduceOnAllTaskDisplayAreas((taskDisplayArea, taskOrientation) -> { 648 if (taskDisplayArea == this || taskOrientation != SCREEN_ORIENTATION_UNSET) { 649 return taskOrientation; 650 } 651 return taskDisplayArea.getOrientation(candidate); 652 }, SCREEN_ORIENTATION_UNSET); 653 } 654 655 if (orientation != SCREEN_ORIENTATION_UNSET 656 && orientation != SCREEN_ORIENTATION_BEHIND) { 657 ProtoLog.v(WM_DEBUG_ORIENTATION, 658 "App is requesting an orientation, return %d for display id=%d", 659 orientation, mDisplayContent.mDisplayId); 660 return orientation; 661 } 662 663 ProtoLog.v(WM_DEBUG_ORIENTATION, 664 "No app is requesting an orientation, return %d for display id=%d", 665 mDisplayContent.getLastOrientation(), mDisplayContent.mDisplayId); 666 // The next app has not been requested to be visible, so we keep the current orientation 667 // to prevent freezing/unfreezing the display too early. 668 return mDisplayContent.getLastOrientation(); 669 } 670 671 @Override 672 void assignChildLayers(SurfaceControl.Transaction t) { 673 assignRootTaskOrdering(t); 674 675 for (int i = 0; i < mChildren.size(); i++) { 676 mChildren.get(i).assignChildLayers(t); 677 } 678 } 679 680 void assignRootTaskOrdering(SurfaceControl.Transaction t) { 681 if (getParent() == null) { 682 return; 683 } 684 mTmpAlwaysOnTopChildren.clear(); 685 mTmpHomeChildren.clear(); 686 mTmpNormalChildren.clear(); 687 for (int i = 0; i < mChildren.size(); ++i) { 688 final WindowContainer child = mChildren.get(i); 689 final TaskDisplayArea childTda = child.asTaskDisplayArea(); 690 if (childTda != null) { 691 final Task childTdaTopRootTask = childTda.getTopRootTask(); 692 if (childTdaTopRootTask == null) { 693 mTmpNormalChildren.add(childTda); 694 } else if (childTdaTopRootTask.isAlwaysOnTop()) { 695 mTmpAlwaysOnTopChildren.add(childTda); 696 } else if (childTdaTopRootTask.isActivityTypeHome()) { 697 mTmpHomeChildren.add(childTda); 698 } else { 699 mTmpNormalChildren.add(childTda); 700 } 701 continue; 702 } 703 704 final Task childTask = child.asTask(); 705 if (childTask.isAlwaysOnTop()) { 706 mTmpAlwaysOnTopChildren.add(childTask); 707 } else if (childTask.isActivityTypeHome()) { 708 mTmpHomeChildren.add(childTask); 709 } else { 710 mTmpNormalChildren.add(childTask); 711 } 712 } 713 714 int layer = 0; 715 // Place root home tasks to the bottom. 716 layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer); 717 layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer); 718 adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer); 719 } 720 721 /** 722 * Adjusts the layer of the root task which belongs to the same group. 723 * Note that there are three root task groups: home rootTasks, always on top rootTasks, and 724 * normal rootTasks. 725 * 726 * @param startLayer The beginning layer of this group of rootTasks. 727 * @return The adjusted layer value. 728 */ 729 private int adjustRootTaskLayer(SurfaceControl.Transaction t, 730 ArrayList<WindowContainer> children, int startLayer) { 731 mTmpNeedsZBoostIndexes.clear(); 732 final int childCount = children.size(); 733 boolean hasAdjacentTask = false; 734 for (int i = 0; i < childCount; i++) { 735 final WindowContainer child = children.get(i); 736 final TaskDisplayArea childTda = child.asTaskDisplayArea(); 737 final boolean childNeedsZBoost = childTda != null 738 ? childTda.childrenNeedZBoost() 739 : child.needsZBoost(); 740 741 if (childNeedsZBoost) { 742 mTmpNeedsZBoostIndexes.add(i); 743 continue; 744 } 745 746 child.assignLayer(t, startLayer++); 747 } 748 749 final int zBoostSize = mTmpNeedsZBoostIndexes.size(); 750 for (int i = 0; i < zBoostSize; i++) { 751 final WindowContainer child = children.get(mTmpNeedsZBoostIndexes.get(i)); 752 child.assignLayer(t, startLayer++); 753 } 754 return startLayer; 755 } 756 757 private boolean childrenNeedZBoost() { 758 final boolean[] needsZBoost = new boolean[1]; 759 forAllRootTasks(task -> { 760 needsZBoost[0] |= task.needsZBoost(); 761 }); 762 return needsZBoost[0]; 763 } 764 765 @Override 766 RemoteAnimationTarget createRemoteAnimationTarget( 767 RemoteAnimationController.RemoteAnimationRecord record) { 768 final ActivityRecord activity = getTopMostActivity(); 769 return activity != null ? activity.createRemoteAnimationTarget(record) : null; 770 } 771 772 void setBackgroundColor(@ColorInt int colorInt) { 773 setBackgroundColor(colorInt, false /* restore */); 774 } 775 776 void setBackgroundColor(@ColorInt int colorInt, boolean restore) { 777 mBackgroundColor = colorInt; 778 Color color = Color.valueOf(colorInt); 779 780 // We don't want to increment the mColorLayerCounter if we are restoring the background 781 // color after a surface migration because in that case the mColorLayerCounter already 782 // accounts for setting that background color. 783 if (!restore) { 784 mColorLayerCounter++; 785 } 786 787 // Only apply the background color if the TDA is actually attached and has a valid surface 788 // to set the background color on. We still want to keep track of the background color state 789 // even if we are not showing it for when/if the TDA is reattached and gets a valid surface 790 if (mSurfaceControl != null) { 791 getPendingTransaction() 792 .setColor(mSurfaceControl, 793 new float[]{color.red(), color.green(), color.blue()}); 794 scheduleAnimation(); 795 } 796 } 797 798 void clearBackgroundColor() { 799 mColorLayerCounter--; 800 801 // Only clear the color layer if we have received the same amounts of clear as set 802 // requests and TDA has a non null surface control (i.e. is attached) 803 if (mColorLayerCounter == 0 && mSurfaceControl != null) { 804 getPendingTransaction().unsetColor(mSurfaceControl); 805 scheduleAnimation(); 806 } 807 } 808 809 @Override 810 void migrateToNewSurfaceControl(SurfaceControl.Transaction t) { 811 super.migrateToNewSurfaceControl(t); 812 813 if (mColorLayerCounter > 0) { 814 setBackgroundColor(mBackgroundColor, true /* restore */); 815 } 816 817 reassignLayer(t); 818 scheduleAnimation(); 819 } 820 821 void onRootTaskRemoved(Task rootTask) { 822 if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { 823 Slog.v(TAG_ROOT_TASK, "onRootTaskRemoved: detaching " + rootTask + " from displayId=" 824 + mDisplayContent.mDisplayId); 825 } 826 if (mPreferredTopFocusableRootTask == rootTask) { 827 mPreferredTopFocusableRootTask = null; 828 } 829 if (mLaunchAdjacentFlagRootTask == rootTask) { 830 mLaunchAdjacentFlagRootTask = null; 831 } 832 mDisplayContent.releaseSelfIfNeeded(); 833 onRootTaskOrderChanged(rootTask); 834 } 835 836 /** 837 * Moves/reparents `task` to the back of whatever container the root home task is in. This is 838 * for when we just want to move a task to "the back" vs. a specific place. The primary use-case 839 * is to make sure that moved-to-back apps go into secondary split when in split-screen mode. 840 */ 841 void positionTaskBehindHome(Task task) { 842 final Task home = getOrCreateRootHomeTask(); 843 final WindowContainer homeParent = home.getParent(); 844 final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; 845 if (homeParentTask == null) { 846 // reparent throws if parent didn't change... 847 if (task.getParent() == this) { 848 positionChildAt(POSITION_BOTTOM, task, false /*includingParents*/); 849 } else { 850 task.reparent(this, false /* onTop */); 851 } 852 } else if (homeParentTask == task.getParent()) { 853 // Apparently reparent early-outs if same root task, so we have to explicitly reorder. 854 homeParentTask.positionChildAtBottom(task); 855 } else { 856 task.reparent(homeParentTask, false /* toTop */, 857 Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE, false /* animate */, 858 false /* deferResume */, "positionTaskBehindHome"); 859 } 860 } 861 862 /** 863 * Returns an existing root task compatible with the windowing mode and activity type or 864 * creates one if a compatible root task doesn't exist. 865 * 866 * @see #getOrCreateRootTask(int, int, boolean, Task, Task, ActivityOptions, int) 867 */ 868 Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) { 869 return getOrCreateRootTask(windowingMode, activityType, onTop, null /* candidateTask */, 870 null /* sourceTask */, null /* options */, 0 /* intent */); 871 } 872 873 /** 874 * When two level tasks are required for given windowing mode and activity type, returns an 875 * existing compatible root task or creates a new one. 876 * For one level task, the candidate task would be reused to also be the root task or create 877 * a new root task if no candidate task. 878 * 879 * @param windowingMode The windowing mode the root task should be created in. 880 * @param activityType The activityType the root task should be created in. 881 * @param onTop If true the root task will be created at the top of the display, 882 * else at the bottom. 883 * @param candidateTask The possible task the activity might be launched in. Can be null. 884 * @param sourceTask The task requesting to start activity. Used to determine which of the 885 * adjacent roots should be launch root of the new task. Can be null. 886 * @param options The activity options used to the launch. Can be null. 887 * @param launchFlags The launch flags for this launch. 888 * @return The root task to use for the launch. 889 * @see #getRootTask(int, int) 890 */ 891 Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop, 892 @Nullable Task candidateTask, @Nullable Task sourceTask, 893 @Nullable ActivityOptions options, int launchFlags) { 894 final int resolvedWindowingMode = 895 windowingMode == WINDOWING_MODE_UNDEFINED ? getWindowingMode() : windowingMode; 896 // Need to pass in a determined windowing mode to see if a new root task should be created, 897 // so use its parent's windowing mode if it is undefined. 898 if (!alwaysCreateRootTask(resolvedWindowingMode, activityType)) { 899 Task rootTask = getRootTask(resolvedWindowingMode, activityType); 900 if (rootTask != null) { 901 return rootTask; 902 } 903 } else if (candidateTask != null) { 904 final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; 905 final Task launchParentTask = getLaunchRootTask(resolvedWindowingMode, activityType, 906 options, sourceTask, launchFlags, candidateTask); 907 if (launchParentTask != null) { 908 if (candidateTask.getParent() == null) { 909 launchParentTask.addChild(candidateTask, position); 910 } else if (candidateTask.getParent() != launchParentTask) { 911 candidateTask.reparent(launchParentTask, position); 912 } 913 } else if (candidateTask.getDisplayArea() != this 914 || candidateTask.getRootTask().mReparentLeafTaskIfRelaunch) { 915 if (candidateTask.getParent() == null) { 916 addChild(candidateTask, position); 917 } else { 918 candidateTask.reparent(this, onTop); 919 } 920 } 921 // Update windowing mode if necessary, e.g. launch into a different windowing mode. 922 if (windowingMode != WINDOWING_MODE_UNDEFINED && candidateTask.isRootTask() 923 && candidateTask.getWindowingMode() != windowingMode) { 924 candidateTask.mTransitionController.collect(candidateTask); 925 candidateTask.setWindowingMode(windowingMode); 926 } 927 return candidateTask.getRootTask(); 928 } 929 return new Task.Builder(mAtmService) 930 .setWindowingMode(windowingMode) 931 .setActivityType(activityType) 932 .setOnTop(onTop) 933 .setParent(this) 934 .setSourceTask(sourceTask) 935 .setActivityOptions(options) 936 .setLaunchFlags(launchFlags) 937 .build(); 938 } 939 940 /** 941 * Returns an existing root task compatible with the input params or creates one 942 * if a compatible root task doesn't exist. 943 * 944 * @see #getOrCreateRootTask(int, int, boolean) 945 */ 946 Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options, 947 @Nullable Task candidateTask, @Nullable Task sourceTask, 948 @Nullable LaunchParams launchParams, int launchFlags, int activityType, boolean onTop) { 949 int windowingMode = WINDOWING_MODE_UNDEFINED; 950 if (launchParams != null) { 951 // If launchParams isn't null, windowing mode is already resolved. 952 windowingMode = launchParams.mWindowingMode; 953 } else if (options != null) { 954 // If launchParams is null and options isn't let's use the windowing mode in the 955 // options. 956 windowingMode = options.getLaunchWindowingMode(); 957 } 958 // Validate that our desired windowingMode will work under the current conditions. 959 // UNDEFINED windowing mode is a valid result and means that the new root task will inherit 960 // it's display's windowing mode. 961 windowingMode = validateWindowingMode(windowingMode, r, candidateTask); 962 return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask, 963 options, launchFlags); 964 } 965 966 @VisibleForTesting 967 int getNextRootTaskId() { 968 return mAtmService.mTaskSupervisor.getNextTaskIdForUser(); 969 } 970 971 Task createRootTask(int windowingMode, int activityType, boolean onTop) { 972 return createRootTask(windowingMode, activityType, onTop, null /* activityOptions */); 973 } 974 975 /** 976 * A convinenit method of creating a root task by providing windowing mode and activity type 977 * on this display. 978 * 979 * @param windowingMode The windowing mode the root task should be created in. If 980 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the 981 * root task will inherit its parent's windowing mode. 982 * @param activityType The activityType the root task should be created in. If 983 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the 984 * root task will be created in 985 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}. 986 * @param onTop If true the root task will be created at the top of the display, 987 * else at the bottom. 988 * @param opts The activity options. 989 * @return The newly created root task. 990 */ 991 Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityOptions opts) { 992 return new Task.Builder(mAtmService) 993 .setWindowingMode(windowingMode) 994 .setActivityType(activityType) 995 .setParent(this) 996 .setOnTop(onTop) 997 .setActivityOptions(opts) 998 .build(); 999 } 1000 1001 // TODO: Also clear when task is removed from system? 1002 void setLaunchRootTask(Task rootTask, int[] windowingModes, int[] activityTypes) { 1003 if (!rootTask.mCreatedByOrganizer) { 1004 throw new IllegalArgumentException( 1005 "Can't set not mCreatedByOrganizer as launch root tr=" + rootTask); 1006 } 1007 1008 LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask); 1009 if (def != null) { 1010 // Remove so we add to the end of the list. 1011 mLaunchRootTasks.remove(def); 1012 } else { 1013 def = new LaunchRootTaskDef(); 1014 def.task = rootTask; 1015 } 1016 1017 def.activityTypes = activityTypes; 1018 def.windowingModes = windowingModes; 1019 if (!ArrayUtils.isEmpty(windowingModes) || !ArrayUtils.isEmpty(activityTypes)) { 1020 mLaunchRootTasks.add(def); 1021 } 1022 } 1023 1024 void removeLaunchRootTask(Task rootTask) { 1025 LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask); 1026 if (def != null) { 1027 mLaunchRootTasks.remove(def); 1028 } 1029 } 1030 1031 void setLaunchAdjacentFlagRootTask(@Nullable Task adjacentFlagRootTask) { 1032 if (adjacentFlagRootTask != null) { 1033 if (!adjacentFlagRootTask.mCreatedByOrganizer) { 1034 throw new IllegalArgumentException( 1035 "Can't set not mCreatedByOrganizer as launch adjacent flag root tr=" 1036 + adjacentFlagRootTask); 1037 } 1038 1039 if (adjacentFlagRootTask.getAdjacentTaskFragment() == null) { 1040 throw new UnsupportedOperationException( 1041 "Can't set non-adjacent root as launch adjacent flag root tr=" 1042 + adjacentFlagRootTask); 1043 } 1044 } 1045 1046 mLaunchAdjacentFlagRootTask = adjacentFlagRootTask; 1047 } 1048 1049 private @Nullable LaunchRootTaskDef getLaunchRootTaskDef(Task rootTask) { 1050 LaunchRootTaskDef def = null; 1051 for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { 1052 if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue; 1053 def = mLaunchRootTasks.get(i); 1054 break; 1055 } 1056 return def; 1057 } 1058 1059 @Nullable 1060 Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options, 1061 @Nullable Task sourceTask, int launchFlags) { 1062 return getLaunchRootTask(windowingMode, activityType, options, sourceTask, launchFlags, 1063 null /* candidateTask */); 1064 } 1065 1066 @Nullable 1067 Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options, 1068 @Nullable Task sourceTask, int launchFlags, @Nullable Task candidateTask) { 1069 // Try to use the launch root task in options if available. 1070 if (options != null) { 1071 final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask()); 1072 // We only allow this for created by organizer tasks. 1073 if (launchRootTask != null && launchRootTask.mCreatedByOrganizer) { 1074 return launchRootTask; 1075 } 1076 } 1077 1078 // Use launch-adjacent-flag-root if launching with launch-adjacent flag. 1079 if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0 1080 && mLaunchAdjacentFlagRootTask != null) { 1081 if (sourceTask != null && sourceTask == candidateTask) { 1082 // Do nothing when task that is getting opened is same as the source. 1083 } else if (sourceTask != null 1084 && mLaunchAdjacentFlagRootTask.getAdjacentTask() != null 1085 && (sourceTask == mLaunchAdjacentFlagRootTask 1086 || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) { 1087 // If the adjacent launch is coming from the same root, launch to 1088 // adjacent root instead. 1089 return mLaunchAdjacentFlagRootTask.getAdjacentTask(); 1090 } else { 1091 return mLaunchAdjacentFlagRootTask; 1092 } 1093 } 1094 1095 for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { 1096 if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) { 1097 final Task launchRootTask = mLaunchRootTasks.get(i).task; 1098 final Task adjacentRootTask = launchRootTask != null 1099 ? launchRootTask.getAdjacentTask() : null; 1100 if (sourceTask != null && adjacentRootTask != null 1101 && (sourceTask == adjacentRootTask 1102 || sourceTask.isDescendantOf(adjacentRootTask))) { 1103 return adjacentRootTask; 1104 } else { 1105 return launchRootTask; 1106 } 1107 } 1108 } 1109 1110 // If a task is launching from a created-by-organizer task, it should be launched into the 1111 // same created-by-organizer task as well. Unless, the candidate task is already positioned 1112 // in the another adjacent task. 1113 if (sourceTask != null && (candidateTask == null 1114 // A pinned task relaunching should be handled by its task organizer. Skip fallback 1115 // launch target of a pinned task from source task. 1116 || candidateTask.getWindowingMode() != WINDOWING_MODE_PINNED)) { 1117 final Task adjacentTarget = sourceTask.getAdjacentTask(); 1118 if (adjacentTarget != null) { 1119 if (candidateTask != null 1120 && (candidateTask == adjacentTarget 1121 || candidateTask.isDescendantOf(adjacentTarget))) { 1122 return adjacentTarget; 1123 } 1124 return sourceTask.getCreatedByOrganizerTask(); 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 >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; 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 // In the legacy transition system, promoting animation target from TaskFragment to 1779 // TaskDisplayArea prevents running finish animation. See b/194649929. 1780 return WindowManagerService.sEnableShellTransitions; 1781 } 1782 1783 /** 1784 * Exposes the home task capability of the TaskDisplayArea 1785 */ 1786 boolean canHostHomeTask() { 1787 return mDisplayContent.supportsSystemDecorations() && mCanHostHomeTask; 1788 } 1789 1790 /** 1791 * Callback for when the order of the root tasks in the display changes. 1792 */ 1793 interface OnRootTaskOrderChangedListener { 1794 void onRootTaskOrderChanged(Task rootTask); 1795 } 1796 1797 void ensureActivitiesVisible(ActivityRecord starting, int configChanges, 1798 boolean preserveWindows, boolean notifyClients) { 1799 mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate(); 1800 try { 1801 forAllRootTasks(rootTask -> { 1802 rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows, 1803 notifyClients); 1804 }); 1805 } finally { 1806 mAtmService.mTaskSupervisor.endActivityVisibilityUpdate(); 1807 } 1808 } 1809 1810 /** 1811 * Removes the root tasks in the node applying the content removal node from the display. 1812 * 1813 * @return last reparented root task, or {@code null} if the root tasks had to be destroyed. 1814 */ 1815 Task remove() { 1816 mPreferredTopFocusableRootTask = null; 1817 // TODO(b/153090332): Allow setting content removal mode per task display area 1818 final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove(); 1819 final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); 1820 Task lastReparentedRootTask = null; 1821 1822 // Root tasks could be reparented from the removed display area to other display area. After 1823 // reparenting the last root task of the removed display area, the display area becomes 1824 // ready to be released (no more root tasks). But, we cannot release it at that moment 1825 // or the related WindowContainer will also be removed. So, we set display area as removed 1826 // after reparenting root task finished. 1827 // Keep the order from bottom to top. 1828 int numRootTasks = mChildren.size(); 1829 1830 for (int i = 0; i < numRootTasks; i++) { 1831 final WindowContainer child = mChildren.get(i); 1832 if (child.asTaskDisplayArea() != null) { 1833 lastReparentedRootTask = child.asTaskDisplayArea().remove(); 1834 continue; 1835 } 1836 final Task task = mChildren.get(i).asTask(); 1837 // Always finish non-standard type root tasks and root tasks created by a organizer. 1838 // TODO: For root tasks created by organizer, consider reparenting children tasks if 1839 // the use case arises in the future. 1840 if (destroyContentOnRemoval 1841 || !task.isActivityTypeStandardOrUndefined() 1842 || task.mCreatedByOrganizer) { 1843 task.remove(false /* withTransition */, "removeTaskDisplayArea"); 1844 } else { 1845 // Reparent task to corresponding launch root or display area. 1846 final WindowContainer launchRoot = toDisplayArea.getLaunchRootTask( 1847 task.getWindowingMode(), 1848 task.getActivityType(), 1849 null /* options */, 1850 null /* sourceTask */, 1851 0 /* launchFlags */); 1852 task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP); 1853 1854 // Set the windowing mode to undefined by default to let the root task inherited the 1855 // windowing mode. 1856 task.setWindowingMode(WINDOWING_MODE_UNDEFINED); 1857 lastReparentedRootTask = task; 1858 } 1859 // Root task may be removed from this display. Ensure each root task will be processed 1860 // and the loop will end. 1861 i -= numRootTasks - mChildren.size(); 1862 numRootTasks = mChildren.size(); 1863 } 1864 1865 if (lastReparentedRootTask != null && !lastReparentedRootTask.isRootTask()) { 1866 // Update focus when the last reparented root task is not a root task anymore. 1867 // (For example, if it has been reparented to a split screen root task, move the 1868 // focus to the split root task) 1869 lastReparentedRootTask.getRootTask().moveToFront("display-removed"); 1870 } 1871 1872 mRemoved = true; 1873 1874 return lastReparentedRootTask; 1875 } 1876 1877 /** Whether this task display area can request orientation. */ 1878 boolean canSpecifyOrientation(@ScreenOrientation int orientation) { 1879 // Only allow to specify orientation if this TDA is the last focused one on this logical 1880 // display that can request orientation request. 1881 return mDisplayContent.getOrientationRequestingTaskDisplayArea() == this 1882 && !shouldIgnoreOrientationRequest(orientation); 1883 } 1884 1885 void clearPreferredTopFocusableRootTask() { 1886 mPreferredTopFocusableRootTask = null; 1887 } 1888 1889 @Override 1890 public void setWindowingMode(int windowingMode) { 1891 mTempConfiguration.setTo(getRequestedOverrideConfiguration()); 1892 WindowConfiguration tempRequestWindowConfiguration = mTempConfiguration.windowConfiguration; 1893 tempRequestWindowConfiguration.setWindowingMode(windowingMode); 1894 tempRequestWindowConfiguration.setDisplayWindowingMode(windowingMode); 1895 onRequestedOverrideConfigurationChanged(mTempConfiguration); 1896 } 1897 1898 @Override 1899 TaskDisplayArea getTaskDisplayArea() { 1900 return this; 1901 } 1902 1903 @Override 1904 boolean isTaskDisplayArea() { 1905 return true; 1906 } 1907 1908 @Override 1909 TaskDisplayArea asTaskDisplayArea() { 1910 return this; 1911 } 1912 1913 @Override 1914 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 1915 pw.println(prefix + "TaskDisplayArea " + getName()); 1916 final String doublePrefix = prefix + " "; 1917 super.dump(pw, doublePrefix, dumpAll); 1918 if (mPreferredTopFocusableRootTask != null) { 1919 pw.println(doublePrefix + "mPreferredTopFocusableRootTask=" 1920 + mPreferredTopFocusableRootTask); 1921 } 1922 if (mLastFocusedRootTask != null) { 1923 pw.println(doublePrefix + "mLastFocusedRootTask=" + mLastFocusedRootTask); 1924 } 1925 1926 final String triplePrefix = doublePrefix + " "; 1927 1928 if (mLaunchRootTasks.size() > 0) { 1929 pw.println(doublePrefix + "mLaunchRootTasks:"); 1930 for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { 1931 final LaunchRootTaskDef def = mLaunchRootTasks.get(i); 1932 pw.println(triplePrefix 1933 + Arrays.toString(def.activityTypes) + " " 1934 + Arrays.toString(def.windowingModes) + " " 1935 + " task=" + def.task); 1936 } 1937 } 1938 1939 pw.println(doublePrefix + "Application tokens in top down Z order:"); 1940 for (int index = getChildCount() - 1; index >= 0; --index) { 1941 final WindowContainer child = getChildAt(index); 1942 if (child.asTaskDisplayArea() != null) { 1943 child.dump(pw, doublePrefix, dumpAll); 1944 continue; 1945 } 1946 final Task rootTask = child.asTask(); 1947 pw.println(doublePrefix + "* " + rootTask.toFullString()); 1948 rootTask.dump(pw, triplePrefix, dumpAll); 1949 } 1950 } 1951 } 1952