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