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.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 23 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER; 24 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; 25 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS; 26 27 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; 28 import static com.android.internal.util.Preconditions.checkState; 29 import static com.android.server.wm.DisplayAreaProto.FEATURE_ID; 30 import static com.android.server.wm.DisplayAreaProto.IS_ORGANIZED; 31 import static com.android.server.wm.DisplayAreaProto.IS_ROOT_DISPLAY_AREA; 32 import static com.android.server.wm.DisplayAreaProto.IS_TASK_DISPLAY_AREA; 33 import static com.android.server.wm.DisplayAreaProto.NAME; 34 import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER; 35 import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA; 36 37 import android.annotation.Nullable; 38 import android.content.pm.ActivityInfo; 39 import android.content.pm.ActivityInfo.ScreenOrientation; 40 import android.content.res.Configuration; 41 import android.graphics.Rect; 42 import android.util.proto.ProtoOutputStream; 43 import android.window.DisplayAreaInfo; 44 import android.window.IDisplayAreaOrganizer; 45 46 import com.android.internal.protolog.common.ProtoLog; 47 import com.android.server.policy.WindowManagerPolicy; 48 49 import java.io.PrintWriter; 50 import java.util.Comparator; 51 import java.util.function.BiFunction; 52 import java.util.function.Consumer; 53 import java.util.function.Function; 54 import java.util.function.Predicate; 55 56 /** 57 * Container for grouping WindowContainer below DisplayContent. 58 * 59 * DisplayAreas are managed by a {@link DisplayAreaPolicy}, and can override configurations and 60 * can be leashed. 61 * 62 * DisplayAreas can contain nested DisplayAreas. 63 * 64 * DisplayAreas come in three flavors, to ensure that windows have the right Z-Order: 65 * - BELOW_TASKS: Can only contain BELOW_TASK DisplayAreas and WindowTokens that go below tasks. 66 * - ABOVE_TASKS: Can only contain ABOVE_TASK DisplayAreas and WindowTokens that go above tasks. 67 * - ANY: Can contain any kind of DisplayArea, and any kind of WindowToken or the Task container. 68 * 69 * @param <T> type of the children of the DisplayArea. 70 */ 71 public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { 72 73 protected final Type mType; 74 private final String mName; 75 final int mFeatureId; 76 private final DisplayAreaOrganizerController mOrganizerController; 77 IDisplayAreaOrganizer mOrganizer; 78 private final Configuration mTmpConfiguration = new Configuration(); 79 80 /** 81 * Whether this {@link DisplayArea} should ignore fixed-orientation request. If {@code true}, it 82 * can never specify orientation, but shows the fixed-orientation apps below it in the 83 * letterbox; otherwise, it rotates based on the fixed-orientation request. 84 * 85 * <p>Note: use {@link #getIgnoreOrientationRequest} to access outside of {@link 86 * #setIgnoreOrientationRequest} since the value can be overridden at runtime on a device level. 87 */ 88 protected boolean mSetIgnoreOrientationRequest; 89 DisplayArea(WindowManagerService wms, Type type, String name)90 DisplayArea(WindowManagerService wms, Type type, String name) { 91 this(wms, type, name, FEATURE_UNDEFINED); 92 } 93 DisplayArea(WindowManagerService wms, Type type, String name, int featureId)94 DisplayArea(WindowManagerService wms, Type type, String name, int featureId) { 95 super(wms); 96 // TODO(display-area): move this up to ConfigurationContainer 97 setOverrideOrientation(SCREEN_ORIENTATION_UNSET); 98 mType = type; 99 mName = name; 100 mFeatureId = featureId; 101 mRemoteToken = new RemoteToken(this); 102 mOrganizerController = 103 wms.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController; 104 } 105 106 @Override onChildPositionChanged(WindowContainer child)107 void onChildPositionChanged(WindowContainer child) { 108 super.onChildPositionChanged(child); 109 110 // Verify that we have proper ordering 111 Type.checkChild(mType, Type.typeOf(child)); 112 113 if (child instanceof Task) { 114 // TODO(display-area): ActivityStacks are type ANY, but are allowed to have siblings. 115 // They might need a separate type. 116 return; 117 } 118 119 for (int i = 1; i < getChildCount(); i++) { 120 final WindowContainer top = getChildAt(i - 1); 121 final WindowContainer bottom = getChildAt(i); 122 if (child == top || child == bottom) { 123 Type.checkSiblings(Type.typeOf(top), Type.typeOf(bottom)); 124 } 125 } 126 } 127 128 @Override positionChildAt(int position, T child, boolean includingParents)129 void positionChildAt(int position, T child, boolean includingParents) { 130 if (child.asDisplayArea() == null) { 131 // Reposition other window containers as normal. 132 super.positionChildAt(position, child, includingParents); 133 return; 134 } 135 136 final int targetPosition = findPositionForChildDisplayArea(position, child.asDisplayArea()); 137 super.positionChildAt(targetPosition, child, false /* includingParents */); 138 139 final WindowContainer parent = getParent(); 140 if (includingParents && parent != null 141 && (position == POSITION_TOP || position == POSITION_BOTTOM)) { 142 parent.positionChildAt(position, this /* child */, true /* includingParents */); 143 } 144 } 145 146 @Override 147 @ScreenOrientation getOrientation(int candidate)148 int getOrientation(int candidate) { 149 final int orientation = super.getOrientation(candidate); 150 if (shouldIgnoreOrientationRequest(orientation)) { 151 // In all the other case, mLastOrientationSource will be reassigned to a new value 152 mLastOrientationSource = null; 153 return SCREEN_ORIENTATION_UNSET; 154 } 155 return orientation; 156 } 157 158 @Override handlesOrientationChangeFromDescendant(@creenOrientation int orientation)159 boolean handlesOrientationChangeFromDescendant(@ScreenOrientation int orientation) { 160 return !shouldIgnoreOrientationRequest(orientation) 161 && super.handlesOrientationChangeFromDescendant(orientation); 162 } 163 164 @Override onDescendantOrientationChanged(@ullable WindowContainer requestingContainer)165 boolean onDescendantOrientationChanged(@Nullable WindowContainer requestingContainer) { 166 // If this is set to ignore the orientation request, we don't propagate descendant 167 // orientation request. 168 final int orientation = requestingContainer != null 169 ? requestingContainer.getOverrideOrientation() 170 : SCREEN_ORIENTATION_UNSET; 171 return !shouldIgnoreOrientationRequest(orientation) 172 && super.onDescendantOrientationChanged(requestingContainer); 173 } 174 175 /** 176 * Sets whether this {@link DisplayArea} should ignore fixed-orientation request from apps and 177 * windows below it. 178 * 179 * @return Whether the display orientation changed after calling this method. 180 */ setIgnoreOrientationRequest(boolean ignoreOrientationRequest)181 boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) { 182 if (mSetIgnoreOrientationRequest == ignoreOrientationRequest) { 183 return false; 184 } 185 mSetIgnoreOrientationRequest = ignoreOrientationRequest; 186 187 // Check whether we should notify Display to update orientation. 188 if (mDisplayContent == null) { 189 return false; 190 } 191 192 if (mDisplayContent.mFocusedApp != null) { 193 // We record the last focused TDA that respects orientation request, check if this 194 // change may affect it. 195 mDisplayContent.onLastFocusedTaskDisplayAreaChanged( 196 mDisplayContent.mFocusedApp.getDisplayArea()); 197 } 198 199 // The orientation request from this DA may now be respected. 200 if (!ignoreOrientationRequest) { 201 return mDisplayContent.updateOrientation(); 202 } 203 204 final int lastOrientation = mDisplayContent.getLastOrientation(); 205 final WindowContainer lastOrientationSource = mDisplayContent.getLastOrientationSource(); 206 if (lastOrientation == SCREEN_ORIENTATION_UNSET 207 || lastOrientation == SCREEN_ORIENTATION_UNSPECIFIED) { 208 // Orientation won't be changed. 209 return false; 210 } 211 if (lastOrientationSource == null || lastOrientationSource.isDescendantOf(this)) { 212 // Try update if the orientation may be affected. 213 return mDisplayContent.updateOrientation(); 214 } 215 return false; 216 } 217 218 @Override setAlwaysOnTop(boolean alwaysOnTop)219 public void setAlwaysOnTop(boolean alwaysOnTop) { 220 if (isAlwaysOnTop() == alwaysOnTop) { 221 return; 222 } 223 super.setAlwaysOnTop(alwaysOnTop); 224 // positionChildAtTop() must be called even when always on top gets turned off because 225 // we need to make sure that the display area is moved from among always on top containers 226 // to below other always on top containers. Since the position the display area should be 227 // inserted into is calculated properly in {@link DisplayContent#getTopInsertPosition()} 228 // in both cases, we can just request that the root task is put at top here. 229 if (getParent().asDisplayArea() != null) { 230 getParent().asDisplayArea().positionChildAt(POSITION_TOP, this, 231 false /* includingParents */); 232 } 233 } 234 235 /** 236 * @return {@value true} if we need to ignore the orientation in input. 237 */ shouldIgnoreOrientationRequest(@creenOrientation int orientation)238 boolean shouldIgnoreOrientationRequest(@ScreenOrientation int orientation) { 239 // We always respect orientation request for ActivityInfo.SCREEN_ORIENTATION_LOCKED 240 // ActivityInfo.SCREEN_ORIENTATION_NOSENSOR. 241 // Main use case why this is important is Camera apps that rely on those 242 // properties to ensure that they will be able to determine Camera preview 243 // orientation correctly 244 if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED 245 || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { 246 return false; 247 } 248 return getIgnoreOrientationRequest() 249 && !shouldRespectOrientationRequestDueToPerAppOverride(); 250 } 251 shouldRespectOrientationRequestDueToPerAppOverride()252 private boolean shouldRespectOrientationRequestDueToPerAppOverride() { 253 if (mDisplayContent == null) { 254 return false; 255 } 256 ActivityRecord activity = mDisplayContent.topRunningActivity( 257 /* considerKeyguardState= */ true); 258 return activity != null && activity.getTaskFragment() != null 259 // Checking TaskFragment rather than ActivityRecord to ensure that transition 260 // between fullscreen and PiP would work well. Checking TaskFragment rather than 261 // Task to ensure that Activity Embedding is excluded. 262 && activity.getTaskFragment().getWindowingMode() == WINDOWING_MODE_FULLSCREEN 263 && activity.mLetterboxUiController.isOverrideRespectRequestedOrientationEnabled(); 264 } 265 getIgnoreOrientationRequest()266 boolean getIgnoreOrientationRequest() { 267 // Adding an exception for when ignoreOrientationRequest is overridden at runtime for all 268 // DisplayArea-s. For example, this is needed for the Kids Mode since many Kids apps aren't 269 // optimised to support both orientations and it will be hard for kids to understand the 270 // app compat mode. 271 return mSetIgnoreOrientationRequest && !mWmService.isIgnoreOrientationRequestDisabled(); 272 } 273 274 /** 275 * When a {@link DisplayArea} is repositioned, it should only be moved among its siblings of the 276 * same {@link Type}. 277 * For example, when a {@link DisplayArea} of {@link Type#ANY} is repositioned, it shouldn't be 278 * moved above any {@link Type#ABOVE_TASKS} siblings, or below any {@link Type#BELOW_TASKS} 279 * siblings. 280 */ findPositionForChildDisplayArea(int requestPosition, DisplayArea child)281 private int findPositionForChildDisplayArea(int requestPosition, DisplayArea child) { 282 if (child.getParent() != this) { 283 throw new IllegalArgumentException("positionChildAt: container=" + child.getName() 284 + " is not a child of container=" + getName() 285 + " current parent=" + child.getParent()); 286 } 287 288 // The max possible position we can insert the child at. 289 int maxPosition = findMaxPositionForChildDisplayArea(child); 290 // The min possible position we can insert the child at. 291 int minPosition = findMinPositionForChildDisplayArea(child); 292 293 // Place all non-always-on-top containers below always-on-top ones. 294 int alwaysOnTopCount = 0; 295 for (int i = minPosition; i <= maxPosition; i++) { 296 if (mChildren.get(i).isAlwaysOnTop()) { 297 alwaysOnTopCount++; 298 } 299 } 300 if (child.isAlwaysOnTop()) { 301 minPosition = maxPosition - alwaysOnTopCount + 1; 302 } else { 303 maxPosition -= alwaysOnTopCount; 304 } 305 return Math.max(Math.min(requestPosition, maxPosition), minPosition); 306 } 307 findMaxPositionForChildDisplayArea(DisplayArea child)308 private int findMaxPositionForChildDisplayArea(DisplayArea child) { 309 final Type childType = Type.typeOf(child); 310 for (int i = mChildren.size() - 1; i > 0; i--) { 311 if (Type.typeOf(getChildAt(i)) == childType) { 312 return i; 313 } 314 } 315 return 0; 316 } 317 findMinPositionForChildDisplayArea(DisplayArea child)318 private int findMinPositionForChildDisplayArea(DisplayArea child) { 319 final Type childType = Type.typeOf(child); 320 for (int i = 0; i < mChildren.size(); i++) { 321 if (Type.typeOf(getChildAt(i)) == childType) { 322 return i; 323 } 324 } 325 return mChildren.size() - 1; 326 } 327 328 @Override needsZBoost()329 boolean needsZBoost() { 330 // Z Boost should only happen at or below the ActivityStack level. 331 return false; 332 } 333 334 @Override fillsParent()335 boolean fillsParent() { 336 return true; 337 } 338 339 @Override getName()340 String getName() { 341 return mName; 342 } 343 344 @Override toString()345 public String toString() { 346 return mName + "@" + System.identityHashCode(this); 347 } 348 349 @Override dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel)350 public void dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel) { 351 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { 352 return; 353 } 354 355 final long token = proto.start(fieldId); 356 super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); 357 proto.write(NAME, mName); 358 proto.write(IS_TASK_DISPLAY_AREA, isTaskDisplayArea()); 359 proto.write(IS_ROOT_DISPLAY_AREA, asRootDisplayArea() != null); 360 proto.write(FEATURE_ID, mFeatureId); 361 proto.write(IS_ORGANIZED, isOrganized()); 362 proto.end(token); 363 } 364 365 @Override dump(PrintWriter pw, String prefix, boolean dumpAll)366 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 367 super.dump(pw, prefix, dumpAll); 368 if (mSetIgnoreOrientationRequest) { 369 pw.println(prefix + "mSetIgnoreOrientationRequest=true"); 370 } 371 if (hasRequestedOverrideConfiguration()) { 372 pw.println(prefix + "overrideConfig=" + getRequestedOverrideConfiguration()); 373 } 374 } 375 dumpChildDisplayArea(PrintWriter pw, String prefix, boolean dumpAll)376 void dumpChildDisplayArea(PrintWriter pw, String prefix, boolean dumpAll) { 377 final String doublePrefix = prefix + " "; 378 for (int i = getChildCount() - 1; i >= 0; i--) { 379 final DisplayArea<?> childArea = getChildAt(i).asDisplayArea(); 380 if (childArea == null) { 381 continue; 382 } 383 pw.print(prefix + "* " + childArea.getName()); 384 if (childArea.isOrganized()) { 385 pw.print(" (organized)"); 386 } 387 pw.println(); 388 if (childArea.isTaskDisplayArea()) { 389 // TaskDisplayArea can only contain task. And it is already printed by display. 390 continue; 391 } 392 childArea.dump(pw, doublePrefix, dumpAll); 393 childArea.dumpChildDisplayArea(pw, doublePrefix, dumpAll); 394 } 395 } 396 397 @Override getProtoFieldId()398 long getProtoFieldId() { 399 return DISPLAY_AREA; 400 } 401 402 @Override asDisplayArea()403 final DisplayArea asDisplayArea() { 404 return this; 405 } 406 407 /** Cheap way of doing cast and instanceof. */ asTokens()408 DisplayArea.Tokens asTokens() { 409 return null; 410 } 411 412 @Override forAllDisplayAreas(Consumer<DisplayArea> callback)413 void forAllDisplayAreas(Consumer<DisplayArea> callback) { 414 super.forAllDisplayAreas(callback); 415 callback.accept(this); 416 } 417 418 @Override forAllTaskDisplayAreas(Predicate<TaskDisplayArea> callback, boolean traverseTopToBottom)419 boolean forAllTaskDisplayAreas(Predicate<TaskDisplayArea> callback, 420 boolean traverseTopToBottom) { 421 // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children. 422 if (mType != DisplayArea.Type.ANY) { 423 return false; 424 } 425 426 int childCount = mChildren.size(); 427 int i = traverseTopToBottom ? childCount - 1 : 0; 428 while (i >= 0 && i < childCount) { 429 T child = mChildren.get(i); 430 // Only traverse if the child is a DisplayArea. 431 if (child.asDisplayArea() != null && child.asDisplayArea() 432 .forAllTaskDisplayAreas(callback, traverseTopToBottom)) { 433 return true; 434 } 435 i += traverseTopToBottom ? -1 : 1; 436 } 437 return false; 438 } 439 440 @Override forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom)441 void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) { 442 // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children. 443 if (mType != DisplayArea.Type.ANY) { 444 return; 445 } 446 447 int childCount = mChildren.size(); 448 int i = traverseTopToBottom ? childCount - 1 : 0; 449 while (i >= 0 && i < childCount) { 450 T child = mChildren.get(i); 451 // Only traverse if the child is a DisplayArea. 452 if (child.asDisplayArea() != null) { 453 child.asDisplayArea().forAllTaskDisplayAreas(callback, traverseTopToBottom); 454 } 455 i += traverseTopToBottom ? -1 : 1; 456 } 457 } 458 459 @Nullable 460 @Override reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, @Nullable R initValue, boolean traverseTopToBottom)461 <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, 462 @Nullable R initValue, boolean traverseTopToBottom) { 463 // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children. 464 if (mType != DisplayArea.Type.ANY) { 465 return initValue; 466 } 467 468 int childCount = mChildren.size(); 469 int i = traverseTopToBottom ? childCount - 1 : 0; 470 R result = initValue; 471 while (i >= 0 && i < childCount) { 472 T child = mChildren.get(i); 473 // Only traverse if the child is a DisplayArea. 474 if (child.asDisplayArea() != null) { 475 result = (R) child.asDisplayArea() 476 .reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom); 477 } 478 i += traverseTopToBottom ? -1 : 1; 479 } 480 return result; 481 } 482 483 @Nullable 484 @Override getItemFromDisplayAreas(Function<DisplayArea, R> callback)485 <R> R getItemFromDisplayAreas(Function<DisplayArea, R> callback) { 486 final R item = super.getItemFromDisplayAreas(callback); 487 return item != null ? item : callback.apply(this); 488 } 489 490 @Nullable 491 @Override getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, boolean traverseTopToBottom)492 <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, 493 boolean traverseTopToBottom) { 494 // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children. 495 if (mType != DisplayArea.Type.ANY) { 496 return null; 497 } 498 499 int childCount = mChildren.size(); 500 int i = traverseTopToBottom ? childCount - 1 : 0; 501 while (i >= 0 && i < childCount) { 502 T child = mChildren.get(i); 503 // Only traverse if the child is a DisplayArea. 504 if (child.asDisplayArea() != null) { 505 R result = (R) child.asDisplayArea() 506 .getItemFromTaskDisplayAreas(callback, traverseTopToBottom); 507 if (result != null) { 508 return result; 509 } 510 } 511 i += traverseTopToBottom ? -1 : 1; 512 } 513 return null; 514 } 515 setOrganizer(IDisplayAreaOrganizer organizer)516 void setOrganizer(IDisplayAreaOrganizer organizer) { 517 setOrganizer(organizer, false /* skipDisplayAreaAppeared */); 518 } 519 setOrganizer(IDisplayAreaOrganizer organizer, boolean skipDisplayAreaAppeared)520 void setOrganizer(IDisplayAreaOrganizer organizer, boolean skipDisplayAreaAppeared) { 521 if (mOrganizer == organizer) return; 522 if (mDisplayContent == null || !mDisplayContent.isTrusted()) { 523 throw new IllegalStateException( 524 "Don't organize or trigger events for unavailable or untrusted display."); 525 } 526 IDisplayAreaOrganizer lastOrganizer = mOrganizer; 527 // Update the new display area organizer before calling sendDisplayAreaVanished since it 528 // could result in a new SurfaceControl getting created that would notify the old organizer 529 // about it. 530 mOrganizer = organizer; 531 sendDisplayAreaVanished(lastOrganizer); 532 if (!skipDisplayAreaAppeared) { 533 sendDisplayAreaAppeared(); 534 } 535 } 536 sendDisplayAreaAppeared()537 void sendDisplayAreaAppeared() { 538 if (mOrganizer == null) return; 539 mOrganizerController.onDisplayAreaAppeared(mOrganizer, this); 540 } 541 sendDisplayAreaVanished(IDisplayAreaOrganizer organizer)542 void sendDisplayAreaVanished(IDisplayAreaOrganizer organizer) { 543 if (organizer == null) return; 544 migrateToNewSurfaceControl(getSyncTransaction()); 545 mOrganizerController.onDisplayAreaVanished(organizer, this); 546 } 547 548 @Override onConfigurationChanged(Configuration newParentConfig)549 public void onConfigurationChanged(Configuration newParentConfig) { 550 mTransitionController.collectForDisplayAreaChange(this); 551 mTmpConfiguration.setTo(getConfiguration()); 552 super.onConfigurationChanged(newParentConfig); 553 554 if (mOrganizer != null && getConfiguration().diff(mTmpConfiguration) != 0) { 555 mOrganizerController.onDisplayAreaInfoChanged(mOrganizer, this); 556 } 557 } 558 559 @Override resolveOverrideConfiguration(Configuration newParentConfiguration)560 void resolveOverrideConfiguration(Configuration newParentConfiguration) { 561 super.resolveOverrideConfiguration(newParentConfiguration); 562 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 563 final Rect overrideBounds = resolvedConfig.windowConfiguration.getBounds(); 564 final Rect overrideAppBounds = resolvedConfig.windowConfiguration.getAppBounds(); 565 final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds(); 566 567 // If there is no override of appBounds, restrict appBounds to the override bounds. 568 if (!overrideBounds.isEmpty() && (overrideAppBounds == null || overrideAppBounds.isEmpty()) 569 && parentAppBounds != null && !parentAppBounds.isEmpty()) { 570 final Rect appBounds = new Rect(overrideBounds); 571 appBounds.intersect(parentAppBounds); 572 resolvedConfig.windowConfiguration.setAppBounds(appBounds); 573 } 574 } 575 576 @Override isOrganized()577 boolean isOrganized() { 578 return mOrganizer != null; 579 } 580 581 getDisplayAreaInfo()582 DisplayAreaInfo getDisplayAreaInfo() { 583 final DisplayAreaInfo info = new DisplayAreaInfo(mRemoteToken.toWindowContainerToken(), 584 getDisplayContent().getDisplayId(), mFeatureId); 585 final RootDisplayArea root = getRootDisplayArea(); 586 info.rootDisplayAreaId = root == null ? getDisplayContent().mFeatureId : root.mFeatureId; 587 info.configuration.setTo(getConfiguration()); 588 return info; 589 } 590 591 /** 592 * Gets the stable bounds of the DisplayArea, which is the bounds excluding insets for 593 * navigation bar, cutout, and status bar. 594 */ getStableRect(Rect out)595 void getStableRect(Rect out) { 596 if (mDisplayContent == null) { 597 getBounds(out); 598 return; 599 } 600 601 // Intersect with the display stable bounds to get the DisplayArea stable bounds. 602 mDisplayContent.getStableRect(out); 603 out.intersect(getBounds()); 604 } 605 606 @Override providesMaxBounds()607 public boolean providesMaxBounds() { 608 return true; 609 } 610 isTaskDisplayArea()611 boolean isTaskDisplayArea() { 612 return false; 613 } 614 615 @Override removeImmediately()616 void removeImmediately() { 617 setOrganizer(null); 618 super.removeImmediately(); 619 } 620 621 @Override getDisplayArea()622 DisplayArea getDisplayArea() { 623 return this; 624 } 625 626 /** 627 * DisplayArea that contains WindowTokens, and orders them according to their type. 628 */ 629 public static class Tokens extends DisplayArea<WindowToken> { 630 int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 631 632 private final Comparator<WindowToken> mWindowComparator = 633 Comparator.comparingInt(WindowToken::getWindowLayerFromType); 634 635 private final Predicate<WindowState> mGetOrientingWindow = w -> { 636 if (!w.isVisible() || !w.mLegacyPolicyVisibilityAfterAnim) { 637 return false; 638 } 639 final WindowManagerPolicy policy = mWmService.mPolicy; 640 if (policy.isKeyguardHostWindow(w.mAttrs)) { 641 // Ignore the orientation of keyguard if it is going away or is not showing while 642 // the device is fully awake. In other words, use the orientation of keyguard if 643 // its window is visible while the device is going to sleep or is sleeping. 644 if (!mDisplayContent.isKeyguardLocked() 645 && mDisplayContent.getDisplayPolicy().isAwake() 646 // Device is not going to sleep. 647 && policy.okToAnimate(true /* ignoreScreenOn */)) { 648 return false; 649 } 650 // Consider unoccluding only when all unknown visibilities have been 651 // resolved, as otherwise we just may be starting another occluding activity. 652 final boolean isUnoccluding = 653 mDisplayContent.mAppTransition.isUnoccluding() 654 && mDisplayContent.mUnknownAppVisibilityController.allResolved(); 655 // If keyguard is showing, or we're unoccluding, force the keyguard's orientation, 656 // even if SystemUI hasn't updated the attrs yet. 657 if (policy.isKeyguardShowingAndNotOccluded() || isUnoccluding) { 658 return true; 659 } 660 } 661 final int req = w.mAttrs.screenOrientation; 662 if (req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND 663 || req == SCREEN_ORIENTATION_UNSET) { 664 return false; 665 } 666 return true; 667 }; 668 Tokens(WindowManagerService wms, Type type, String name)669 Tokens(WindowManagerService wms, Type type, String name) { 670 this(wms, type, name, FEATURE_WINDOW_TOKENS); 671 } 672 Tokens(WindowManagerService wms, Type type, String name, int featureId)673 Tokens(WindowManagerService wms, Type type, String name, int featureId) { 674 super(wms, type, name, featureId); 675 } 676 addChild(WindowToken token)677 void addChild(WindowToken token) { 678 addChild(token, mWindowComparator); 679 } 680 681 @Override 682 @ScreenOrientation getOrientation(int candidate)683 int getOrientation(int candidate) { 684 mLastOrientationSource = null; 685 686 // Find a window requesting orientation. 687 final WindowState win = getWindow(mGetOrientingWindow); 688 689 if (win == null) { 690 return candidate; 691 } 692 int req = win.mAttrs.screenOrientation; 693 ProtoLog.v(WM_DEBUG_ORIENTATION, "%s forcing orientation to %d for display id=%d", 694 win, req, mDisplayContent.getDisplayId()); 695 if (mWmService.mPolicy.isKeyguardHostWindow(win.mAttrs)) { 696 // SystemUI controls the Keyguard orientation asynchronously, and mAttrs may be 697 // stale. We record / use the last known override. 698 if (req != SCREEN_ORIENTATION_UNSET && req != SCREEN_ORIENTATION_UNSPECIFIED) { 699 mLastKeyguardForcedOrientation = req; 700 } else { 701 req = mLastKeyguardForcedOrientation; 702 } 703 } 704 mLastOrientationSource = win; 705 return req; 706 } 707 708 @Override asTokens()709 final DisplayArea.Tokens asTokens() { 710 return this; 711 } 712 } 713 714 /** 715 * DisplayArea that can be dimmed. 716 */ 717 static class Dimmable extends DisplayArea<DisplayArea> { 718 private final Dimmer mDimmer = new Dimmer(this); 719 private final Rect mTmpDimBoundsRect = new Rect(); 720 Dimmable(WindowManagerService wms, Type type, String name, int featureId)721 Dimmable(WindowManagerService wms, Type type, String name, int featureId) { 722 super(wms, type, name, featureId); 723 } 724 725 @Override getDimmer()726 Dimmer getDimmer() { 727 return mDimmer; 728 } 729 730 @Override prepareSurfaces()731 void prepareSurfaces() { 732 mDimmer.resetDimStates(); 733 super.prepareSurfaces(); 734 // Bounds need to be relative, as the dim layer is a child. 735 getBounds(mTmpDimBoundsRect); 736 mTmpDimBoundsRect.offsetTo(0 /* newLeft */, 0 /* newTop */); 737 738 // If SystemUI is dragging for recents, we want to reset the dim state so any dim layer 739 // on the display level fades out. 740 if (forAllTasks(task -> !task.canAffectSystemUiFlags())) { 741 mDimmer.resetDimStates(); 742 } 743 744 if (mDimmer.updateDims(getSyncTransaction(), mTmpDimBoundsRect)) { 745 scheduleAnimation(); 746 } 747 } 748 } 749 750 enum Type { 751 /** Can only contain WindowTokens above the APPLICATION_LAYER. */ 752 ABOVE_TASKS, 753 /** Can only contain WindowTokens below the APPLICATION_LAYER. */ 754 BELOW_TASKS, 755 /** Can contain anything. */ 756 ANY; 757 checkSiblings(Type bottom, Type top)758 static void checkSiblings(Type bottom, Type top) { 759 checkState(!(bottom != BELOW_TASKS && top == BELOW_TASKS), 760 bottom + " must be above BELOW_TASKS"); 761 checkState(!(bottom == ABOVE_TASKS && top != ABOVE_TASKS), 762 top + " must be below ABOVE_TASKS"); 763 } 764 checkChild(Type parent, Type child)765 static void checkChild(Type parent, Type child) { 766 switch (parent) { 767 case ABOVE_TASKS: 768 checkState(child == ABOVE_TASKS, "ABOVE_TASKS can only contain ABOVE_TASKS"); 769 break; 770 case BELOW_TASKS: 771 checkState(child == BELOW_TASKS, "BELOW_TASKS can only contain BELOW_TASKS"); 772 break; 773 } 774 } 775 typeOf(WindowContainer c)776 static Type typeOf(WindowContainer c) { 777 if (c.asDisplayArea() != null) { 778 return ((DisplayArea) c).mType; 779 } else if (c instanceof WindowToken && !(c instanceof ActivityRecord)) { 780 return typeOf((WindowToken) c); 781 } else if (c instanceof Task) { 782 return ANY; 783 } else { 784 throw new IllegalArgumentException("Unknown container: " + c); 785 } 786 } 787 typeOf(WindowToken c)788 private static Type typeOf(WindowToken c) { 789 return c.getWindowLayerFromType() < APPLICATION_LAYER ? BELOW_TASKS : ABOVE_TASKS; 790 } 791 } 792 } 793