1 /* 2 * Copyright (C) 2017 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.am; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 28 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 29 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 30 import static android.view.Display.DEFAULT_DISPLAY; 31 import static android.view.Display.FLAG_PRIVATE; 32 import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT; 33 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK; 34 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK; 35 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 36 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 37 import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER; 38 import static com.android.server.am.ActivityDisplayProto.STACKS; 39 import static com.android.server.am.ActivityDisplayProto.ID; 40 41 import android.annotation.Nullable; 42 import android.app.ActivityManagerInternal; 43 import android.app.ActivityOptions; 44 import android.app.WindowConfiguration; 45 import android.graphics.Point; 46 import android.util.IntArray; 47 import android.util.Slog; 48 import android.util.proto.ProtoOutputStream; 49 import android.view.Display; 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.server.wm.ConfigurationContainer; 52 import com.android.server.wm.DisplayWindowController; 53 54 import com.android.server.wm.WindowContainerListener; 55 import java.io.PrintWriter; 56 import java.util.ArrayList; 57 58 /** 59 * Exactly one of these classes per Display in the system. Capable of holding zero or more 60 * attached {@link ActivityStack}s. 61 */ 62 class ActivityDisplay extends ConfigurationContainer<ActivityStack> 63 implements WindowContainerListener { 64 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM; 65 private static final String TAG_STACK = TAG + POSTFIX_STACK; 66 67 static final int POSITION_TOP = Integer.MAX_VALUE; 68 static final int POSITION_BOTTOM = Integer.MIN_VALUE; 69 70 71 /** 72 * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays. 73 */ 74 private static int sNextFreeStackId = 0; 75 76 private ActivityStackSupervisor mSupervisor; 77 /** Actual Display this object tracks. */ 78 int mDisplayId; 79 Display mDisplay; 80 81 /** 82 * All of the stacks on this display. Order matters, topmost stack is in front of all other 83 * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls 84 * changing the list should also call {@link #onStackOrderChanged()}. 85 */ 86 private final ArrayList<ActivityStack> mStacks = new ArrayList<>(); 87 private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>(); 88 89 /** Array of all UIDs that are present on the display. */ 90 private IntArray mDisplayAccessUIDs = new IntArray(); 91 92 /** All tokens used to put activities on this stack to sleep (including mOffToken) */ 93 final ArrayList<ActivityManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>(); 94 /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */ 95 ActivityManagerInternal.SleepToken mOffToken; 96 97 private boolean mSleeping; 98 99 // Cached reference to some special stacks we tend to get a lot so we don't need to loop 100 // through the list to find them. 101 private ActivityStack mHomeStack = null; 102 private ActivityStack mRecentsStack = null; 103 private ActivityStack mPinnedStack = null; 104 private ActivityStack mSplitScreenPrimaryStack = null; 105 106 // Used in updating the display size 107 private Point mTmpDisplaySize = new Point(); 108 109 private DisplayWindowController mWindowContainerController; 110 111 @VisibleForTesting ActivityDisplay(ActivityStackSupervisor supervisor, int displayId)112 ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) { 113 this(supervisor, supervisor.mDisplayManager.getDisplay(displayId)); 114 } 115 ActivityDisplay(ActivityStackSupervisor supervisor, Display display)116 ActivityDisplay(ActivityStackSupervisor supervisor, Display display) { 117 mSupervisor = supervisor; 118 mDisplayId = display.getDisplayId(); 119 mDisplay = display; 120 mWindowContainerController = createWindowContainerController(); 121 updateBounds(); 122 } 123 createWindowContainerController()124 protected DisplayWindowController createWindowContainerController() { 125 return new DisplayWindowController(mDisplay, this); 126 } 127 updateBounds()128 void updateBounds() { 129 mDisplay.getSize(mTmpDisplaySize); 130 setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y); 131 } 132 addChild(ActivityStack stack, int position)133 void addChild(ActivityStack stack, int position) { 134 if (position == POSITION_BOTTOM) { 135 position = 0; 136 } else if (position == POSITION_TOP) { 137 position = mStacks.size(); 138 } 139 if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack 140 + " to displayId=" + mDisplayId + " position=" + position); 141 addStackReferenceIfNeeded(stack); 142 positionChildAt(stack, position); 143 mSupervisor.mService.updateSleepIfNeededLocked(); 144 } 145 removeChild(ActivityStack stack)146 void removeChild(ActivityStack stack) { 147 if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack 148 + " from displayId=" + mDisplayId); 149 mStacks.remove(stack); 150 removeStackReferenceIfNeeded(stack); 151 mSupervisor.mService.updateSleepIfNeededLocked(); 152 onStackOrderChanged(); 153 } 154 positionChildAtTop(ActivityStack stack)155 void positionChildAtTop(ActivityStack stack) { 156 positionChildAt(stack, mStacks.size()); 157 } 158 positionChildAtBottom(ActivityStack stack)159 void positionChildAtBottom(ActivityStack stack) { 160 positionChildAt(stack, 0); 161 } 162 positionChildAt(ActivityStack stack, int position)163 private void positionChildAt(ActivityStack stack, int position) { 164 // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust 165 // the position internally, also update the logic here 166 mStacks.remove(stack); 167 final int insertPosition = getTopInsertPosition(stack, position); 168 mStacks.add(insertPosition, stack); 169 mWindowContainerController.positionChildAt(stack.getWindowContainerController(), 170 insertPosition); 171 onStackOrderChanged(); 172 } 173 getTopInsertPosition(ActivityStack stack, int candidatePosition)174 private int getTopInsertPosition(ActivityStack stack, int candidatePosition) { 175 int position = mStacks.size(); 176 if (position > 0) { 177 final ActivityStack topStack = mStacks.get(position - 1); 178 if (topStack.getWindowConfiguration().isAlwaysOnTop() && topStack != stack) { 179 // If the top stack is always on top, we move this stack just below it. 180 position--; 181 } 182 } 183 return Math.min(position, candidatePosition); 184 } 185 getStack(int stackId)186 <T extends ActivityStack> T getStack(int stackId) { 187 for (int i = mStacks.size() - 1; i >= 0; --i) { 188 final ActivityStack stack = mStacks.get(i); 189 if (stack.mStackId == stackId) { 190 return (T) stack; 191 } 192 } 193 return null; 194 } 195 196 /** 197 * @return the topmost stack on the display that is compatible with the input windowing mode and 198 * activity type. {@code null} means no compatible stack on the display. 199 * @see ConfigurationContainer#isCompatible(int, int) 200 */ getStack(int windowingMode, int activityType)201 <T extends ActivityStack> T getStack(int windowingMode, int activityType) { 202 if (activityType == ACTIVITY_TYPE_HOME) { 203 return (T) mHomeStack; 204 } else if (activityType == ACTIVITY_TYPE_RECENTS) { 205 return (T) mRecentsStack; 206 } 207 if (windowingMode == WINDOWING_MODE_PINNED) { 208 return (T) mPinnedStack; 209 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 210 return (T) mSplitScreenPrimaryStack; 211 } 212 213 for (int i = mStacks.size() - 1; i >= 0; --i) { 214 final ActivityStack stack = mStacks.get(i); 215 if (stack.isCompatible(windowingMode, activityType)) { 216 return (T) stack; 217 } 218 } 219 return null; 220 } 221 alwaysCreateStack(int windowingMode, int activityType)222 private boolean alwaysCreateStack(int windowingMode, int activityType) { 223 // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing 224 // modes so that we can manage visual ordering and return types correctly. 225 return activityType == ACTIVITY_TYPE_STANDARD 226 && (windowingMode == WINDOWING_MODE_FULLSCREEN 227 || windowingMode == WINDOWING_MODE_FREEFORM 228 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); 229 } 230 231 /** 232 * Returns an existing stack compatible with the windowing mode and activity type or creates one 233 * if a compatible stack doesn't exist. 234 * @see #getStack(int, int) 235 * @see #createStack(int, int, boolean) 236 */ getOrCreateStack(int windowingMode, int activityType, boolean onTop)237 <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType, 238 boolean onTop) { 239 if (!alwaysCreateStack(windowingMode, activityType)) { 240 T stack = getStack(windowingMode, activityType); 241 if (stack != null) { 242 return stack; 243 } 244 } 245 return createStack(windowingMode, activityType, onTop); 246 } 247 248 /** 249 * Returns an existing stack compatible with the input params or creates one 250 * if a compatible stack doesn't exist. 251 * @see #getOrCreateStack(int, int, boolean) 252 */ getOrCreateStack(@ullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType, boolean onTop)253 <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r, 254 @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType, 255 boolean onTop) { 256 final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType); 257 return getOrCreateStack(windowingMode, activityType, onTop); 258 } 259 getNextStackId()260 private int getNextStackId() { 261 return sNextFreeStackId++; 262 } 263 264 /** 265 * Creates a stack matching the input windowing mode and activity type on this display. 266 * @param windowingMode The windowing mode the stack should be created in. If 267 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will 268 * be created in {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}. 269 * @param activityType The activityType the stack should be created in. If 270 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will 271 * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}. 272 * @param onTop If true the stack will be created at the top of the display, else at the bottom. 273 * @return The newly created stack. 274 */ createStack(int windowingMode, int activityType, boolean onTop)275 <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) { 276 277 if (activityType == ACTIVITY_TYPE_UNDEFINED) { 278 // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants 279 // anything else should be passing it in anyways... 280 activityType = ACTIVITY_TYPE_STANDARD; 281 } 282 283 if (activityType != ACTIVITY_TYPE_STANDARD) { 284 // For now there can be only one stack of a particular non-standard activity type on a 285 // display. So, get that ignoring whatever windowing mode it is currently in. 286 T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); 287 if (stack != null) { 288 throw new IllegalArgumentException("Stack=" + stack + " of activityType=" 289 + activityType + " already on display=" + this + ". Can't have multiple."); 290 } 291 } 292 293 final ActivityManagerService service = mSupervisor.mService; 294 if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow, 295 service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement, 296 service.mSupportsPictureInPicture, activityType)) { 297 throw new IllegalArgumentException("Can't create stack for unsupported windowingMode=" 298 + windowingMode); 299 } 300 301 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 302 // TODO: Should be okay to have stacks with with undefined windowing mode long term, but 303 // have to set them to something for now due to logic that depending on them. 304 windowingMode = getWindowingMode(); // Put in current display's windowing mode 305 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 306 // Else fullscreen for now... 307 windowingMode = WINDOWING_MODE_FULLSCREEN; 308 } 309 } 310 311 final int stackId = getNextStackId(); 312 return createStackUnchecked(windowingMode, activityType, stackId, onTop); 313 } 314 315 @VisibleForTesting createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop)316 <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, 317 int stackId, boolean onTop) { 318 if (windowingMode == WINDOWING_MODE_PINNED) { 319 return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop); 320 } 321 return (T) new ActivityStack( 322 this, stackId, mSupervisor, windowingMode, activityType, onTop); 323 } 324 325 /** 326 * Removes stacks in the input windowing modes from the system if they are of activity type 327 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED 328 */ removeStacksInWindowingModes(int... windowingModes)329 void removeStacksInWindowingModes(int... windowingModes) { 330 if (windowingModes == null || windowingModes.length == 0) { 331 return; 332 } 333 334 for (int j = windowingModes.length - 1 ; j >= 0; --j) { 335 final int windowingMode = windowingModes[j]; 336 for (int i = mStacks.size() - 1; i >= 0; --i) { 337 final ActivityStack stack = mStacks.get(i); 338 if (!stack.isActivityTypeStandardOrUndefined()) { 339 continue; 340 } 341 if (stack.getWindowingMode() != windowingMode) { 342 continue; 343 } 344 mSupervisor.removeStack(stack); 345 } 346 } 347 } 348 removeStacksWithActivityTypes(int... activityTypes)349 void removeStacksWithActivityTypes(int... activityTypes) { 350 if (activityTypes == null || activityTypes.length == 0) { 351 return; 352 } 353 354 for (int j = activityTypes.length - 1 ; j >= 0; --j) { 355 final int activityType = activityTypes[j]; 356 for (int i = mStacks.size() - 1; i >= 0; --i) { 357 final ActivityStack stack = mStacks.get(i); 358 if (stack.getActivityType() == activityType) { 359 mSupervisor.removeStack(stack); 360 } 361 } 362 } 363 } 364 onStackWindowingModeChanged(ActivityStack stack)365 void onStackWindowingModeChanged(ActivityStack stack) { 366 removeStackReferenceIfNeeded(stack); 367 addStackReferenceIfNeeded(stack); 368 } 369 addStackReferenceIfNeeded(ActivityStack stack)370 private void addStackReferenceIfNeeded(ActivityStack stack) { 371 final int activityType = stack.getActivityType(); 372 final int windowingMode = stack.getWindowingMode(); 373 374 if (activityType == ACTIVITY_TYPE_HOME) { 375 if (mHomeStack != null && mHomeStack != stack) { 376 throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" 377 + mHomeStack + " already exist on display=" + this + " stack=" + stack); 378 } 379 mHomeStack = stack; 380 } else if (activityType == ACTIVITY_TYPE_RECENTS) { 381 if (mRecentsStack != null && mRecentsStack != stack) { 382 throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack=" 383 + mRecentsStack + " already exist on display=" + this + " stack=" + stack); 384 } 385 mRecentsStack = stack; 386 } 387 if (windowingMode == WINDOWING_MODE_PINNED) { 388 if (mPinnedStack != null && mPinnedStack != stack) { 389 throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack=" 390 + mPinnedStack + " already exist on display=" + this 391 + " stack=" + stack); 392 } 393 mPinnedStack = stack; 394 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 395 if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) { 396 throw new IllegalArgumentException("addStackReferenceIfNeeded:" 397 + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack 398 + " already exist on display=" + this + " stack=" + stack); 399 } 400 mSplitScreenPrimaryStack = stack; 401 onSplitScreenModeActivated(); 402 } 403 } 404 removeStackReferenceIfNeeded(ActivityStack stack)405 private void removeStackReferenceIfNeeded(ActivityStack stack) { 406 if (stack == mHomeStack) { 407 mHomeStack = null; 408 } else if (stack == mRecentsStack) { 409 mRecentsStack = null; 410 } else if (stack == mPinnedStack) { 411 mPinnedStack = null; 412 } else if (stack == mSplitScreenPrimaryStack) { 413 mSplitScreenPrimaryStack = null; 414 // Inform the reset of the system that split-screen mode was dismissed so things like 415 // resizing all the other stacks can take place. 416 onSplitScreenModeDismissed(); 417 } 418 } 419 onSplitScreenModeDismissed()420 private void onSplitScreenModeDismissed() { 421 mSupervisor.mWindowManager.deferSurfaceLayout(); 422 try { 423 // Adjust the windowing mode of any stack in secondary split-screen to fullscreen. 424 for (int i = mStacks.size() - 1; i >= 0; --i) { 425 final ActivityStack otherStack = mStacks.get(i); 426 if (!otherStack.inSplitScreenSecondaryWindowingMode()) { 427 continue; 428 } 429 otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN, false /* animate */, 430 false /* showRecents */, false /* enteringSplitScreenMode */, 431 true /* deferEnsuringVisibility */); 432 } 433 } finally { 434 final ActivityStack topFullscreenStack = 435 getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); 436 if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) { 437 // Whenever split-screen is dismissed we want the home stack directly behind the 438 // current top fullscreen stack so it shows up when the top stack is finished. 439 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however 440 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch 441 // once we have that. 442 mHomeStack.moveToFront("onSplitScreenModeDismissed"); 443 topFullscreenStack.moveToFront("onSplitScreenModeDismissed"); 444 } 445 mSupervisor.mWindowManager.continueSurfaceLayout(); 446 } 447 } 448 onSplitScreenModeActivated()449 private void onSplitScreenModeActivated() { 450 mSupervisor.mWindowManager.deferSurfaceLayout(); 451 try { 452 // Adjust the windowing mode of any affected by split-screen to split-screen secondary. 453 for (int i = mStacks.size() - 1; i >= 0; --i) { 454 final ActivityStack otherStack = mStacks.get(i); 455 if (otherStack == mSplitScreenPrimaryStack 456 || !otherStack.affectedBySplitScreenResize()) { 457 continue; 458 } 459 otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, 460 false /* animate */, false /* showRecents */, 461 true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */); 462 } 463 } finally { 464 mSupervisor.mWindowManager.continueSurfaceLayout(); 465 } 466 } 467 468 /** 469 * Returns true if the {@param windowingMode} is supported based on other parameters passed in. 470 * @param windowingMode The windowing mode we are checking support for. 471 * @param supportsMultiWindow If we should consider support for multi-window mode in general. 472 * @param supportsSplitScreen If we should consider support for split-screen multi-window. 473 * @param supportsFreeform If we should consider support for freeform multi-window. 474 * @param supportsPip If we should consider support for picture-in-picture mutli-window. 475 * @param activityType The activity type under consideration. 476 * @return true if the windowing mode is supported. 477 */ isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, int activityType)478 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, 479 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, 480 int activityType) { 481 482 if (windowingMode == WINDOWING_MODE_UNDEFINED 483 || windowingMode == WINDOWING_MODE_FULLSCREEN) { 484 return true; 485 } 486 if (!supportsMultiWindow) { 487 return false; 488 } 489 490 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 491 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { 492 return supportsSplitScreen 493 && WindowConfiguration.supportSplitScreenWindowingMode(activityType); 494 } 495 496 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) { 497 return false; 498 } 499 500 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) { 501 return false; 502 } 503 return true; 504 } 505 resolveWindowingMode(@ullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task, int activityType)506 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, 507 @Nullable TaskRecord task, int activityType) { 508 509 // First preference if the windowing mode in the activity options if set. 510 int windowingMode = (options != null) 511 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED; 512 513 // If windowing mode is unset, then next preference is the candidate task, then the 514 // activity record. 515 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 516 if (task != null) { 517 windowingMode = task.getWindowingMode(); 518 } 519 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) { 520 windowingMode = r.getWindowingMode(); 521 } 522 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 523 // Use the display's windowing mode. 524 windowingMode = getWindowingMode(); 525 } 526 } 527 528 // Make sure the windowing mode we are trying to use makes sense for what is supported. 529 final ActivityManagerService service = mSupervisor.mService; 530 boolean supportsMultiWindow = service.mSupportsMultiWindow; 531 boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow; 532 boolean supportsFreeform = service.mSupportsFreeformWindowManagement; 533 boolean supportsPip = service.mSupportsPictureInPicture; 534 if (supportsMultiWindow) { 535 if (task != null) { 536 supportsMultiWindow = task.isResizeable(); 537 supportsSplitScreen = task.supportsSplitScreenWindowingMode(); 538 // TODO: Do we need to check for freeform and Pip support here? 539 } else if (r != null) { 540 supportsMultiWindow = r.isResizeable(); 541 supportsSplitScreen = r.supportsSplitScreenWindowingMode(); 542 supportsFreeform = r.supportsFreeform(); 543 supportsPip = r.supportsPictureInPicture(); 544 } 545 } 546 547 final boolean inSplitScreenMode = hasSplitScreenPrimaryStack(); 548 if (!inSplitScreenMode 549 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { 550 // Switch to fullscreen windowing mode if we are not in split-screen mode and we are 551 // trying to launch in split-screen secondary. 552 windowingMode = WINDOWING_MODE_FULLSCREEN; 553 } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN 554 && supportsSplitScreen) { 555 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 556 } 557 558 if (windowingMode != WINDOWING_MODE_UNDEFINED 559 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen, 560 supportsFreeform, supportsPip, activityType)) { 561 return windowingMode; 562 } 563 // Try to use the display's windowing mode otherwise fallback to fullscreen. 564 windowingMode = getWindowingMode(); 565 return windowingMode != WINDOWING_MODE_UNDEFINED 566 ? windowingMode : WINDOWING_MODE_FULLSCREEN; 567 } 568 569 /** 570 * Get the topmost stack on the display. It may be different from focused stack, because 571 * focus may be on another display. 572 */ getTopStack()573 ActivityStack getTopStack() { 574 return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1); 575 } 576 isTopStack(ActivityStack stack)577 boolean isTopStack(ActivityStack stack) { 578 return stack == getTopStack(); 579 } 580 isTopNotPinnedStack(ActivityStack stack)581 boolean isTopNotPinnedStack(ActivityStack stack) { 582 for (int i = mStacks.size() - 1; i >= 0; --i) { 583 final ActivityStack current = mStacks.get(i); 584 if (!current.inPinnedWindowingMode()) { 585 return current == stack; 586 } 587 } 588 return false; 589 } 590 getTopStackInWindowingMode(int windowingMode)591 ActivityStack getTopStackInWindowingMode(int windowingMode) { 592 for (int i = mStacks.size() - 1; i >= 0; --i) { 593 final ActivityStack current = mStacks.get(i); 594 if (windowingMode == current.getWindowingMode()) { 595 return current; 596 } 597 } 598 return null; 599 } 600 getIndexOf(ActivityStack stack)601 int getIndexOf(ActivityStack stack) { 602 return mStacks.indexOf(stack); 603 } 604 onLockTaskPackagesUpdated()605 void onLockTaskPackagesUpdated() { 606 for (int i = mStacks.size() - 1; i >= 0; --i) { 607 mStacks.get(i).onLockTaskPackagesUpdated(); 608 } 609 } 610 611 /** We are in the process of exiting split-screen mode. */ onExitingSplitScreenMode()612 void onExitingSplitScreenMode() { 613 // Remove reference to the primary-split-screen stack so it no longer has any effect on the 614 // display. For example, we want to be able to create fullscreen stack for standard activity 615 // types when exiting split-screen mode. 616 mSplitScreenPrimaryStack = null; 617 } 618 getSplitScreenPrimaryStack()619 ActivityStack getSplitScreenPrimaryStack() { 620 return mSplitScreenPrimaryStack; 621 } 622 hasSplitScreenPrimaryStack()623 boolean hasSplitScreenPrimaryStack() { 624 return mSplitScreenPrimaryStack != null; 625 } 626 getPinnedStack()627 PinnedActivityStack getPinnedStack() { 628 return (PinnedActivityStack) mPinnedStack; 629 } 630 hasPinnedStack()631 boolean hasPinnedStack() { 632 return mPinnedStack != null; 633 } 634 635 @Override toString()636 public String toString() { 637 return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; 638 } 639 640 @Override getChildCount()641 protected int getChildCount() { 642 return mStacks.size(); 643 } 644 645 @Override getChildAt(int index)646 protected ActivityStack getChildAt(int index) { 647 return mStacks.get(index); 648 } 649 650 @Override getParent()651 protected ConfigurationContainer getParent() { 652 return mSupervisor; 653 } 654 isPrivate()655 boolean isPrivate() { 656 return (mDisplay.getFlags() & FLAG_PRIVATE) != 0; 657 } 658 isUidPresent(int uid)659 boolean isUidPresent(int uid) { 660 for (ActivityStack stack : mStacks) { 661 if (stack.isUidPresent(uid)) { 662 return true; 663 } 664 } 665 return false; 666 } 667 remove()668 void remove() { 669 final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove(); 670 while (getChildCount() > 0) { 671 final ActivityStack stack = getChildAt(0); 672 if (destroyContentOnRemoval) { 673 // Override the stack configuration to make it equal to the current applied one, so 674 // that we don't accidentally report configuration change to activities that are 675 // going to be finished. 676 stack.onOverrideConfigurationChanged(stack.getConfiguration()); 677 mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, 678 false /* onTop */); 679 stack.finishAllActivitiesLocked(true /* immediately */); 680 } else { 681 // Moving all tasks to fullscreen stack, because it's guaranteed to be 682 // a valid launch stack for all activities. This way the task history from 683 // external display will be preserved on primary after move. 684 mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */); 685 } 686 } 687 688 mWindowContainerController.removeContainer(); 689 mWindowContainerController = null; 690 } 691 692 /** Update and get all UIDs that are present on the display and have access to it. */ getPresentUIDs()693 IntArray getPresentUIDs() { 694 mDisplayAccessUIDs.clear(); 695 for (ActivityStack stack : mStacks) { 696 stack.getPresentUIDs(mDisplayAccessUIDs); 697 } 698 return mDisplayAccessUIDs; 699 } 700 shouldDestroyContentOnRemove()701 private boolean shouldDestroyContentOnRemove() { 702 return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT; 703 } 704 shouldSleep()705 boolean shouldSleep() { 706 return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty()) 707 && (mSupervisor.mService.mRunningVoice == null); 708 } 709 710 /** 711 * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is 712 * already top-most. 713 */ getStackAbove(ActivityStack stack)714 ActivityStack getStackAbove(ActivityStack stack) { 715 final int stackIndex = mStacks.indexOf(stack) + 1; 716 return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null; 717 } 718 719 /** 720 * Adjusts the {@param stack} behind the last visible stack in the display if necessary. 721 * Generally used in conjunction with {@link #moveStackBehindStack}. 722 */ moveStackBehindBottomMostVisibleStack(ActivityStack stack)723 void moveStackBehindBottomMostVisibleStack(ActivityStack stack) { 724 if (stack.shouldBeVisible(null)) { 725 // Skip if the stack is already visible 726 return; 727 } 728 729 // Move the stack to the bottom to not affect the following visibility checks 730 positionChildAtBottom(stack); 731 732 // Find the next position where the stack should be placed 733 final int numStacks = mStacks.size(); 734 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) { 735 final ActivityStack s = mStacks.get(stackNdx); 736 if (s == stack) { 737 continue; 738 } 739 final int winMode = s.getWindowingMode(); 740 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN || 741 winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 742 if (s.shouldBeVisible(null) && isValidWindowingMode) { 743 // Move the provided stack to behind this stack 744 positionChildAt(stack, Math.max(0, stackNdx - 1)); 745 break; 746 } 747 } 748 } 749 750 /** 751 * Moves the {@param stack} behind the given {@param behindStack} if possible. If 752 * {@param behindStack} is not currently in the display, then then the stack is moved to the 753 * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}. 754 */ moveStackBehindStack(ActivityStack stack, ActivityStack behindStack)755 void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) { 756 if (behindStack == null || behindStack == stack) { 757 return; 758 } 759 760 // Note that positionChildAt will first remove the given stack before inserting into the 761 // list, so we need to adjust the insertion index to account for the removed index 762 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the 763 // position internally 764 final int stackIndex = mStacks.indexOf(stack); 765 final int behindStackIndex = mStacks.indexOf(behindStack); 766 final int insertIndex = stackIndex <= behindStackIndex 767 ? behindStackIndex - 1 : behindStackIndex; 768 positionChildAt(stack, Math.max(0, insertIndex)); 769 } 770 isSleeping()771 boolean isSleeping() { 772 return mSleeping; 773 } 774 setIsSleeping(boolean asleep)775 void setIsSleeping(boolean asleep) { 776 mSleeping = asleep; 777 } 778 779 /** 780 * Adds a listener to be notified whenever the stack order in the display changes. Currently 781 * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the 782 * current animation when the system state changes. 783 */ registerStackOrderChangedListener(OnStackOrderChangedListener listener)784 void registerStackOrderChangedListener(OnStackOrderChangedListener listener) { 785 if (!mStackOrderChangedCallbacks.contains(listener)) { 786 mStackOrderChangedCallbacks.add(listener); 787 } 788 } 789 790 /** 791 * Removes a previously registered stack order change listener. 792 */ unregisterStackOrderChangedListener(OnStackOrderChangedListener listener)793 void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) { 794 mStackOrderChangedCallbacks.remove(listener); 795 } 796 onStackOrderChanged()797 private void onStackOrderChanged() { 798 for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) { 799 mStackOrderChangedCallbacks.get(i).onStackOrderChanged(); 800 } 801 } 802 803 /** 804 * See {@link DisplayWindowController#deferUpdateImeTarget()} 805 */ deferUpdateImeTarget()806 public void deferUpdateImeTarget() { 807 mWindowContainerController.deferUpdateImeTarget(); 808 } 809 810 /** 811 * See {@link DisplayWindowController#deferUpdateImeTarget()} 812 */ continueUpdateImeTarget()813 public void continueUpdateImeTarget() { 814 mWindowContainerController.continueUpdateImeTarget(); 815 } 816 dump(PrintWriter pw, String prefix)817 public void dump(PrintWriter pw, String prefix) { 818 pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()); 819 final String myPrefix = prefix + " "; 820 if (mHomeStack != null) { 821 pw.println(myPrefix + "mHomeStack=" + mHomeStack); 822 } 823 if (mRecentsStack != null) { 824 pw.println(myPrefix + "mRecentsStack=" + mRecentsStack); 825 } 826 if (mPinnedStack != null) { 827 pw.println(myPrefix + "mPinnedStack=" + mPinnedStack); 828 } 829 if (mSplitScreenPrimaryStack != null) { 830 pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack); 831 } 832 } 833 dumpStacks(PrintWriter pw)834 public void dumpStacks(PrintWriter pw) { 835 for (int i = mStacks.size() - 1; i >= 0; --i) { 836 pw.print(mStacks.get(i).mStackId); 837 if (i > 0) { 838 pw.print(","); 839 } 840 } 841 } 842 writeToProto(ProtoOutputStream proto, long fieldId)843 public void writeToProto(ProtoOutputStream proto, long fieldId) { 844 final long token = proto.start(fieldId); 845 super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */); 846 proto.write(ID, mDisplayId); 847 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { 848 final ActivityStack stack = mStacks.get(stackNdx); 849 stack.writeToProto(proto, STACKS); 850 } 851 proto.end(token); 852 } 853 854 /** 855 * Callback for when the order of the stacks in the display changes. 856 */ 857 interface OnStackOrderChangedListener { onStackOrderChanged()858 void onStackOrderChanged(); 859 } 860 } 861