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