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.display; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.content.Context; 24 import android.hardware.devicestate.DeviceStateManager; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.PowerManager; 29 import android.os.SystemClock; 30 import android.os.SystemProperties; 31 import android.text.TextUtils; 32 import android.util.ArrayMap; 33 import android.util.IndentingPrintWriter; 34 import android.util.Slog; 35 import android.util.SparseArray; 36 import android.util.SparseBooleanArray; 37 import android.util.SparseIntArray; 38 import android.view.Display; 39 import android.view.DisplayAddress; 40 import android.view.DisplayInfo; 41 42 import com.android.internal.annotations.VisibleForTesting; 43 import com.android.internal.foldables.FoldGracePeriodProvider; 44 import com.android.server.LocalServices; 45 import com.android.server.display.feature.DisplayManagerFlags; 46 import com.android.server.display.layout.DisplayIdProducer; 47 import com.android.server.display.layout.Layout; 48 import com.android.server.display.mode.SyntheticModeManager; 49 import com.android.server.display.utils.DebugUtils; 50 import com.android.server.policy.WindowManagerPolicy; 51 import com.android.server.utils.FoldSettingProvider; 52 53 import java.io.PrintWriter; 54 import java.util.Arrays; 55 import java.util.function.Consumer; 56 57 /** 58 * Responsible for creating {@link LogicalDisplay}s and associating them to the 59 * {@link DisplayDevice} objects supplied through {@link DisplayAdapter.Listener}. 60 * 61 * Additionally this class will keep track of which {@link DisplayGroup} each 62 * {@link LogicalDisplay} belongs to. 63 * 64 * For devices with a single internal display, the mapping is done once and left 65 * alone. For devices with multiple built-in displays, such as foldable devices, 66 * {@link LogicalDisplay}s can be remapped to different {@link DisplayDevice}s. 67 */ 68 class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { 69 private static final String TAG = "LogicalDisplayMapper"; 70 71 // To enable these logs, run: 72 // 'adb shell setprop persist.log.tag.LogicalDisplayMapper DEBUG && adb reboot' 73 private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); 74 75 public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1; 76 public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2; 77 public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3; 78 public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4; 79 public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5; 80 public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6; 81 public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 7; 82 public static final int LOGICAL_DISPLAY_EVENT_CONNECTED = 8; 83 public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 9; 84 85 public static final int DISPLAY_GROUP_EVENT_ADDED = 1; 86 public static final int DISPLAY_GROUP_EVENT_CHANGED = 2; 87 public static final int DISPLAY_GROUP_EVENT_REMOVED = 3; 88 89 private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 500; 90 91 private static final int MSG_TRANSITION_TO_PENDING_DEVICE_STATE = 1; 92 93 private static final int UPDATE_STATE_NEW = 0; 94 private static final int UPDATE_STATE_TRANSITION = 1; 95 private static final int UPDATE_STATE_UPDATED = 2; 96 97 private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1; 98 99 /** 100 * Temporary display info, used for comparing display configurations. 101 */ 102 private final DisplayInfo mTempDisplayInfo = new DisplayInfo(); 103 private final DisplayInfo mTempNonOverrideDisplayInfo = new DisplayInfo(); 104 105 /** 106 * True if the display mapper service should pretend there is only one display 107 * and only tell applications about the existence of the default logical display. 108 * The display manager can still mirror content to secondary displays but applications 109 * cannot present unique content on those displays. 110 * Used for demonstration purposes only. 111 */ 112 private final boolean mSingleDisplayDemoMode; 113 114 /** 115 * True if the device can have more than one internal display on at a time. 116 */ 117 private final boolean mSupportsConcurrentInternalDisplays; 118 119 /** 120 * Wake the device when transitioning into these device state. 121 */ 122 private final SparseBooleanArray mDeviceStatesOnWhichToWakeUp; 123 124 /** 125 * Sleep the device when transitioning into these device state. 126 */ 127 private final SparseBooleanArray mDeviceStatesOnWhichToSelectiveSleep; 128 129 /** 130 * Map of all logical displays indexed by logical display id. 131 * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache. 132 * TODO: multi-display - Move the aforementioned comment? 133 */ 134 private final SparseArray<LogicalDisplay> mLogicalDisplays = 135 new SparseArray<LogicalDisplay>(); 136 137 // Cache whether or not the display was enabled on the last update. 138 private final SparseBooleanArray mDisplaysEnabledCache = new SparseBooleanArray(); 139 140 /** Map of all display groups indexed by display group id. */ 141 private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>(); 142 143 /** 144 * Map of display groups which are linked to virtual devices (all displays in the group are 145 * linked to that device). Keyed by virtual device unique id. 146 */ 147 private final SparseIntArray mDeviceDisplayGroupIds = new SparseIntArray(); 148 149 /** 150 * Map of display group ids indexed by display group name. 151 */ 152 private final ArrayMap<String, Integer> mDisplayGroupIdsByName = new ArrayMap<>(); 153 154 private final DisplayDeviceRepository mDisplayDeviceRepo; 155 private final DeviceStateToLayoutMap mDeviceStateToLayoutMap; 156 private final Listener mListener; 157 private final DisplayManagerService.SyncRoot mSyncRoot; 158 private final LogicalDisplayMapperHandler mHandler; 159 private final FoldSettingProvider mFoldSettingProvider; 160 private final FoldGracePeriodProvider mFoldGracePeriodProvider; 161 private final PowerManager mPowerManager; 162 163 /** 164 * Has an entry for every logical display that the rest of the system has been notified about. 165 * Any entry in here requires us to send a {@link LOGICAL_DISPLAY_EVENT_REMOVED} event when it 166 * is deleted or {@link LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed. The values are any 167 * of the {@code UPDATE_STATE_*} constant types. 168 */ 169 private final SparseIntArray mUpdatedLogicalDisplays = new SparseIntArray(); 170 171 /** 172 * Keeps track of all the display groups that we already told other people about. IOW, if a 173 * display group is in this array, then we *must* send change and remove notifications for it 174 * because other components know about them. Also, what this array stores is a change counter 175 * for each group, so we know if the group itself has changes since we last sent out a 176 * notification. See {@link DisplayGroup#getChangeCountLocked}. 177 */ 178 private final SparseIntArray mUpdatedDisplayGroups = new SparseIntArray(); 179 180 /** 181 * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out. 182 */ 183 private final SparseIntArray mLogicalDisplaysToUpdate = new SparseIntArray(); 184 185 /** 186 * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out. 187 */ 188 private final SparseIntArray mDisplayGroupsToUpdate = new SparseIntArray(); 189 190 /** 191 * ArrayMap of display device unique ID to virtual device ID. Used in {@link 192 * #updateLogicalDisplaysLocked} to establish which Virtual Devices own which Virtual Displays. 193 */ 194 private final ArrayMap<String, Integer> mVirtualDeviceDisplayMapping = new ArrayMap<>(); 195 private WindowManagerPolicy mWindowManagerPolicy; 196 197 private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; 198 private final DisplayIdProducer mIdProducer = (isDefault) -> 199 isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++; 200 private Layout mCurrentLayout = null; 201 private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; 202 private int mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; 203 private int mDeviceStateToBeAppliedAfterBoot = 204 DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; 205 private boolean mBootCompleted = false; 206 private boolean mInteractive; 207 private final DisplayManagerFlags mFlags; 208 private final SyntheticModeManager mSyntheticModeManager; 209 LogicalDisplayMapper(@onNull Context context, FoldSettingProvider foldSettingProvider, FoldGracePeriodProvider foldGracePeriodProvider, @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Handler handler, DisplayManagerFlags flags)210 LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, 211 FoldGracePeriodProvider foldGracePeriodProvider, 212 @NonNull DisplayDeviceRepository repo, 213 @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, 214 @NonNull Handler handler, DisplayManagerFlags flags) { 215 this(context, foldSettingProvider, foldGracePeriodProvider, repo, listener, syncRoot, 216 handler, 217 new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY 218 : sNextNonDefaultDisplayId++, flags), flags, 219 new SyntheticModeManager(flags)); 220 } 221 LogicalDisplayMapper(@onNull Context context, FoldSettingProvider foldSettingProvider, FoldGracePeriodProvider foldGracePeriodProvider, @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap, DisplayManagerFlags flags, SyntheticModeManager syntheticModeManager)222 LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, 223 FoldGracePeriodProvider foldGracePeriodProvider, 224 @NonNull DisplayDeviceRepository repo, 225 @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, 226 @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap, 227 DisplayManagerFlags flags, SyntheticModeManager syntheticModeManager) { 228 mSyncRoot = syncRoot; 229 mPowerManager = context.getSystemService(PowerManager.class); 230 mInteractive = mPowerManager.isInteractive(); 231 mHandler = new LogicalDisplayMapperHandler(handler.getLooper()); 232 mDisplayDeviceRepo = repo; 233 mListener = listener; 234 mFoldSettingProvider = foldSettingProvider; 235 mFoldGracePeriodProvider = foldGracePeriodProvider; 236 mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); 237 mSupportsConcurrentInternalDisplays = context.getResources().getBoolean( 238 com.android.internal.R.bool.config_supportsConcurrentInternalDisplays); 239 mDeviceStatesOnWhichToWakeUp = toSparseBooleanArray(context.getResources().getIntArray( 240 com.android.internal.R.array.config_deviceStatesOnWhichToWakeUp)); 241 mDeviceStatesOnWhichToSelectiveSleep = toSparseBooleanArray( 242 context.getResources().getIntArray( 243 com.android.internal.R.array.config_deviceStatesOnWhichToSleep)); 244 mDisplayDeviceRepo.addListener(this); 245 mDeviceStateToLayoutMap = deviceStateToLayoutMap; 246 mFlags = flags; 247 mSyntheticModeManager = syntheticModeManager; 248 } 249 250 @Override onDisplayDeviceEventLocked(DisplayDevice device, int event)251 public void onDisplayDeviceEventLocked(DisplayDevice device, int event) { 252 switch (event) { 253 case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED: 254 if (DEBUG) { 255 Slog.d(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked()); 256 } 257 handleDisplayDeviceAddedLocked(device); 258 break; 259 260 case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED: 261 if (DEBUG) { 262 Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); 263 } 264 handleDisplayDeviceRemovedLocked(device); 265 updateLogicalDisplaysLocked(); 266 break; 267 } 268 } 269 270 @Override onDisplayDeviceChangedLocked(DisplayDevice device, int diff)271 public void onDisplayDeviceChangedLocked(DisplayDevice device, int diff) { 272 if (DEBUG) { 273 Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); 274 } 275 finishStateTransitionLocked(false /*force*/); 276 updateLogicalDisplaysLocked(diff); 277 } 278 279 @Override onTraversalRequested()280 public void onTraversalRequested() { 281 mListener.onTraversalRequested(); 282 } 283 onWindowManagerReady()284 public void onWindowManagerReady() { 285 mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class); 286 } 287 getDisplayLocked(int displayId)288 public LogicalDisplay getDisplayLocked(int displayId) { 289 return getDisplayLocked(displayId, /* includeDisabled= */ true); 290 } 291 getDisplayLocked(int displayId, boolean includeDisabled)292 public LogicalDisplay getDisplayLocked(int displayId, boolean includeDisabled) { 293 LogicalDisplay display = mLogicalDisplays.get(displayId); 294 if (display == null || display.isEnabledLocked() || includeDisabled) { 295 return display; 296 } 297 return null; 298 } 299 getDisplayLocked(DisplayDevice device)300 public LogicalDisplay getDisplayLocked(DisplayDevice device) { 301 return getDisplayLocked(device, /* includeDisabled= */ true); 302 } 303 getDisplayLocked(DisplayDevice device, boolean includeDisabled)304 public LogicalDisplay getDisplayLocked(DisplayDevice device, boolean includeDisabled) { 305 if (device == null) { 306 return null; 307 } 308 final int count = mLogicalDisplays.size(); 309 for (int i = 0; i < count; i++) { 310 final LogicalDisplay display = mLogicalDisplays.valueAt(i); 311 if (display.getPrimaryDisplayDeviceLocked() == device) { 312 if (display.isEnabledLocked() || includeDisabled) { 313 return display; 314 } 315 return null; 316 } 317 } 318 return null; 319 } 320 getDisplayIdsLocked(int callingUid, boolean includeDisabled)321 public int[] getDisplayIdsLocked(int callingUid, boolean includeDisabled) { 322 final int count = mLogicalDisplays.size(); 323 int[] displayIds = new int[count]; 324 int n = 0; 325 for (int i = 0; i < count; i++) { 326 LogicalDisplay display = mLogicalDisplays.valueAt(i); 327 if (display.isEnabledLocked() || includeDisabled) { 328 DisplayInfo info = display.getDisplayInfoLocked(); 329 if (info.hasAccess(callingUid)) { 330 displayIds[n++] = mLogicalDisplays.keyAt(i); 331 } 332 } 333 } 334 if (n != count) { 335 displayIds = Arrays.copyOfRange(displayIds, 0, n); 336 } 337 return displayIds; 338 } 339 forEachLocked(Consumer<LogicalDisplay> consumer)340 public void forEachLocked(Consumer<LogicalDisplay> consumer) { 341 forEachLocked(consumer, /* includeDisabled= */ true); 342 } 343 forEachLocked(Consumer<LogicalDisplay> consumer, boolean includeDisabled)344 public void forEachLocked(Consumer<LogicalDisplay> consumer, boolean includeDisabled) { 345 final int count = mLogicalDisplays.size(); 346 for (int i = 0; i < count; i++) { 347 LogicalDisplay display = mLogicalDisplays.valueAt(i); 348 if (display.isEnabledLocked() || includeDisabled) { 349 consumer.accept(display); 350 } 351 } 352 } 353 354 @VisibleForTesting getDisplayGroupIdFromDisplayIdLocked(int displayId)355 public int getDisplayGroupIdFromDisplayIdLocked(int displayId) { 356 final LogicalDisplay display = getDisplayLocked(displayId); 357 if (display == null) { 358 return Display.INVALID_DISPLAY_GROUP; 359 } 360 361 final int size = mDisplayGroups.size(); 362 for (int i = 0; i < size; i++) { 363 final DisplayGroup displayGroup = mDisplayGroups.valueAt(i); 364 if (displayGroup.containsLocked(display)) { 365 return mDisplayGroups.keyAt(i); 366 } 367 } 368 369 return Display.INVALID_DISPLAY_GROUP; 370 } 371 getDisplayGroupLocked(int groupId)372 public DisplayGroup getDisplayGroupLocked(int groupId) { 373 return mDisplayGroups.get(groupId); 374 } 375 376 /** 377 * Returns the {@link DisplayInfo} for this device state, indicated by the given display id. The 378 * DisplayInfo represents the attributes of the indicated display in the layout associated with 379 * this state. This is used to get display information for various displays in various states; 380 * e.g. to help apps preload resources for the possible display states. 381 * 382 * @param deviceState the state to query possible layouts for 383 * @param displayId the display id to retrieve 384 * @return {@code null} if no corresponding {@link DisplayInfo} could be found, or the 385 * {@link DisplayInfo} with a matching display id. 386 */ 387 @Nullable getDisplayInfoForStateLocked(int deviceState, int displayId)388 public DisplayInfo getDisplayInfoForStateLocked(int deviceState, int displayId) { 389 // Retrieve the layout for this particular state. 390 final Layout layout = mDeviceStateToLayoutMap.get(deviceState); 391 if (layout == null) { 392 // TODO(b/352019542): remove the log once b/345960547 is fixed. 393 Slog.d(TAG, "Cannot get layout for given state:" + deviceState); 394 return null; 395 } 396 // Retrieve the details of the given display within this layout. 397 Layout.Display display = layout.getById(displayId); 398 if (display == null) { 399 // TODO(b/352019542): remove the log once b/345960547 is fixed. 400 Slog.d(TAG, "Cannot get display for given layout:" + layout); 401 return null; 402 } 403 // Retrieve the display info for the display that matches the display id. 404 final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(display.getAddress()); 405 if (device == null) { 406 Slog.w(TAG, "The display device (" + display.getAddress() + "), is not available" 407 + " for the display state " + mDeviceState); 408 return null; 409 } 410 LogicalDisplay logicalDisplay = getDisplayLocked(device, /* includeDisabled= */ true); 411 if (logicalDisplay == null) { 412 Slog.w(TAG, "The logical display associated with address (" + display.getAddress() 413 + "), is not available for the display state " + mDeviceState); 414 return null; 415 } 416 DisplayInfo displayInfo = new DisplayInfo(logicalDisplay.getDisplayInfoLocked()); 417 displayInfo.displayId = displayId; 418 return displayInfo; 419 } 420 dumpLocked(PrintWriter pw)421 public void dumpLocked(PrintWriter pw) { 422 pw.println("LogicalDisplayMapper:"); 423 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 424 ipw.increaseIndent(); 425 426 ipw.println("mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); 427 ipw.println("mCurrentLayout=" + mCurrentLayout); 428 ipw.println("mDeviceStatesOnWhichToWakeUp=" + mDeviceStatesOnWhichToWakeUp); 429 ipw.println("mDeviceStatesOnWhichSelectiveSleep=" + mDeviceStatesOnWhichToSelectiveSleep); 430 ipw.println("mInteractive=" + mInteractive); 431 ipw.println("mBootCompleted=" + mBootCompleted); 432 433 ipw.println(); 434 ipw.println("mDeviceState=" + mDeviceState); 435 ipw.println("mPendingDeviceState=" + mPendingDeviceState); 436 ipw.println("mDeviceStateToBeAppliedAfterBoot=" + mDeviceStateToBeAppliedAfterBoot); 437 438 final int logicalDisplayCount = mLogicalDisplays.size(); 439 ipw.println(); 440 ipw.println("Logical Displays: size=" + logicalDisplayCount); 441 for (int i = 0; i < logicalDisplayCount; i++) { 442 int displayId = mLogicalDisplays.keyAt(i); 443 LogicalDisplay display = mLogicalDisplays.valueAt(i); 444 ipw.println("Display " + displayId + ":"); 445 ipw.increaseIndent(); 446 display.dumpLocked(ipw); 447 ipw.decreaseIndent(); 448 ipw.println(); 449 } 450 mDeviceStateToLayoutMap.dumpLocked(ipw); 451 } 452 453 /** 454 * Creates an association between a displayDevice and a virtual device. Any displays associated 455 * with this virtual device will be grouped together in a single {@link DisplayGroup} unless 456 * created with {@link Display.FLAG_OWN_DISPLAY_GROUP}. 457 * 458 * @param displayDevice the displayDevice to be linked 459 * @param virtualDeviceUniqueId the unique ID of the virtual device. 460 */ associateDisplayDeviceWithVirtualDevice( DisplayDevice displayDevice, int virtualDeviceUniqueId)461 void associateDisplayDeviceWithVirtualDevice( 462 DisplayDevice displayDevice, int virtualDeviceUniqueId) { 463 mVirtualDeviceDisplayMapping.put(displayDevice.getUniqueId(), virtualDeviceUniqueId); 464 } 465 setDeviceStateLocked(int state)466 void setDeviceStateLocked(int state) { 467 if (!mBootCompleted) { 468 // The boot animation might still be in progress, we do not want to switch states now 469 // as the boot animation would end up with an incorrect size. 470 if (DEBUG) { 471 Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState 472 + " until boot is completed"); 473 } 474 mDeviceStateToBeAppliedAfterBoot = state; 475 return; 476 } 477 478 Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState 479 + ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted); 480 // As part of a state transition, we may need to turn off some displays temporarily so that 481 // the transition is smooth. Plus, on some devices, only one internal displays can be 482 // on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be 483 // temporarily turned off. 484 resetLayoutLocked(mDeviceState, state, /* transitionValue= */ true); 485 mPendingDeviceState = state; 486 mDeviceStateToBeAppliedAfterBoot = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; 487 final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, 488 mInteractive, mBootCompleted); 489 final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState, 490 mInteractive, mBootCompleted); 491 492 // If all displays are off already, we can just transition here, unless we are trying to 493 // wake or sleep the device as part of this transition. In that case defer the final 494 // transition until later once the device is awake/asleep. 495 if (areAllTransitioningDisplaysOffLocked() && !wakeDevice && !sleepDevice) { 496 transitionToPendingStateLocked(); 497 return; 498 } 499 500 if (DEBUG) { 501 Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState); 502 } 503 // Send the transitioning phase updates to DisplayManager so that the displays can 504 // start turning OFF in preparation for the new layout. 505 updateLogicalDisplaysLocked(); 506 507 if (wakeDevice || sleepDevice) { 508 if (wakeDevice) { 509 // We already told the displays to turn off, now we need to wake the device as 510 // we transition to this new state. We do it here so that the waking happens 511 // between the transition from one layout to another. 512 mHandler.post(() -> { 513 mPowerManager.wakeUp(SystemClock.uptimeMillis(), 514 PowerManager.WAKE_REASON_UNFOLD_DEVICE, "server.display:unfold"); 515 }); 516 } else if (sleepDevice) { 517 // Send the device to sleep when required. 518 int goToSleepFlag = 519 mFoldSettingProvider.shouldSleepOnFold() ? 0 520 : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP; 521 mHandler.post(() -> { 522 mPowerManager.goToSleep(SystemClock.uptimeMillis(), 523 PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD, 524 goToSleepFlag); 525 }); 526 } 527 } 528 529 mHandler.sendEmptyMessageDelayed(MSG_TRANSITION_TO_PENDING_DEVICE_STATE, 530 TIMEOUT_STATE_TRANSITION_MILLIS); 531 } 532 onBootCompleted()533 void onBootCompleted() { 534 synchronized (mSyncRoot) { 535 mBootCompleted = true; 536 if (mDeviceStateToBeAppliedAfterBoot 537 != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER) { 538 setDeviceStateLocked(mDeviceStateToBeAppliedAfterBoot); 539 } 540 } 541 } 542 onEarlyInteractivityChange(boolean interactive)543 void onEarlyInteractivityChange(boolean interactive) { 544 synchronized (mSyncRoot) { 545 if (mInteractive != interactive) { 546 mInteractive = interactive; 547 finishStateTransitionLocked(false /*force*/); 548 } 549 } 550 } 551 552 /** 553 * Returns if the device should be woken up or not. Called to check if the device state we are 554 * moving to is one that should awake the device, as well as if we are moving from a device 555 * state that shouldn't have been already woken from. 556 * 557 * @param pendingState device state we are moving to 558 * @param currentState device state we are currently in 559 * @param isInteractive if the device is in an interactive state 560 * @param isBootCompleted is the device fully booted 561 * 562 * @see #shouldDeviceBePutToSleep 563 * @see #setDeviceStateLocked 564 */ 565 @VisibleForTesting shouldDeviceBeWoken(int pendingState, int currentState, boolean isInteractive, boolean isBootCompleted)566 boolean shouldDeviceBeWoken(int pendingState, int currentState, boolean isInteractive, 567 boolean isBootCompleted) { 568 return mDeviceStatesOnWhichToWakeUp.get(pendingState) 569 && !mDeviceStatesOnWhichToWakeUp.get(currentState) 570 && !isInteractive && isBootCompleted; 571 } 572 573 /** 574 * Returns if the device should be put to sleep or not. 575 * 576 * Includes a check to verify that the device state that we are moving to, {@code pendingState}, 577 * is the same as the physical state of the device, {@code baseState}. Also if the 578 * 'Stay Awake On Fold' is not enabled. Different values for these parameters indicate a device 579 * state override is active, and we shouldn't put the device to sleep to provide a better user 580 * experience. 581 * 582 * @param pendingState device state we are moving to 583 * @param currentState device state we are currently in 584 * @param isInteractive if the device is in an interactive state 585 * @param isBootCompleted is the device fully booted 586 * 587 * @see #shouldDeviceBeWoken 588 * @see #setDeviceStateLocked 589 */ 590 @VisibleForTesting shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isInteractive, boolean isBootCompleted)591 boolean shouldDeviceBePutToSleep(int pendingState, int currentState, boolean isInteractive, 592 boolean isBootCompleted) { 593 return currentState != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER 594 && mDeviceStatesOnWhichToSelectiveSleep.get(pendingState) 595 && !mDeviceStatesOnWhichToSelectiveSleep.get(currentState) 596 && isInteractive 597 && isBootCompleted 598 && !mFoldSettingProvider.shouldStayAwakeOnFold(); 599 } 600 areAllTransitioningDisplaysOffLocked()601 private boolean areAllTransitioningDisplaysOffLocked() { 602 final int count = mLogicalDisplays.size(); 603 for (int i = 0; i < count; i++) { 604 final LogicalDisplay display = mLogicalDisplays.valueAt(i); 605 if (!display.isInTransitionLocked()) { 606 continue; 607 } 608 609 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); 610 if (device != null) { 611 final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 612 if (info.state != Display.STATE_OFF) { 613 return false; 614 } 615 } 616 } 617 return true; 618 } 619 transitionToPendingStateLocked()620 private void transitionToPendingStateLocked() { 621 resetLayoutLocked(mDeviceState, mPendingDeviceState, /* transitionValue= */ false); 622 mDeviceState = mPendingDeviceState; 623 mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; 624 applyLayoutLocked(); 625 updateLogicalDisplaysLocked(); 626 } 627 finishStateTransitionLocked(boolean force)628 private void finishStateTransitionLocked(boolean force) { 629 if (mPendingDeviceState == DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER) { 630 return; 631 } 632 633 final boolean waitingToWakeDevice = mDeviceStatesOnWhichToWakeUp.get(mPendingDeviceState) 634 && !mDeviceStatesOnWhichToWakeUp.get(mDeviceState) 635 && !mInteractive && mBootCompleted; 636 // The device should only wait for sleep if #shouldStayAwakeOnFold method returns false. 637 // If not, device should be marked ready for transition immediately. 638 final boolean waitingToSleepDevice = mDeviceStatesOnWhichToSelectiveSleep.get( 639 mPendingDeviceState) 640 && !mDeviceStatesOnWhichToSelectiveSleep.get(mDeviceState) 641 && mInteractive && mBootCompleted && !shouldStayAwakeOnFold(); 642 643 final boolean displaysOff = areAllTransitioningDisplaysOffLocked(); 644 final boolean isReadyToTransition = displaysOff && !waitingToWakeDevice 645 && !waitingToSleepDevice; 646 647 if (isReadyToTransition || force) { 648 transitionToPendingStateLocked(); 649 mHandler.removeMessages(MSG_TRANSITION_TO_PENDING_DEVICE_STATE); 650 } else if (DEBUG) { 651 Slog.d(TAG, "Not yet ready to transition to state=" + mPendingDeviceState 652 + " with displays-off=" + displaysOff + ", force=" + force 653 + ", mInteractive=" + mInteractive + ", isReady=" + isReadyToTransition); 654 } 655 } 656 handleDisplayDeviceAddedLocked(DisplayDevice device)657 private void handleDisplayDeviceAddedLocked(DisplayDevice device) { 658 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); 659 // The default Display needs to have additional initialization. 660 // This initializes a default dynamic display layout for the default 661 // device, which is used as a fallback in case no static layout definitions 662 // exist or cannot be loaded. 663 if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) { 664 initializeDefaultDisplayDeviceLocked(device); 665 } 666 667 // Create a logical display for the new display device 668 LogicalDisplay display = createNewLogicalDisplayLocked( 669 device, mIdProducer.getId(/* isDefault= */ false)); 670 671 applyLayoutLocked(); 672 updateLogicalDisplaysLocked(); 673 } 674 handleDisplayDeviceRemovedLocked(DisplayDevice device)675 private void handleDisplayDeviceRemovedLocked(DisplayDevice device) { 676 final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); 677 Layout.Display layoutDisplay = layout.getById(DEFAULT_DISPLAY); 678 if (layoutDisplay == null) { 679 return; 680 } 681 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); 682 683 // Remove any virtual device mapping which exists for the display. 684 mVirtualDeviceDisplayMapping.remove(device.getUniqueId()); 685 686 if (layoutDisplay.getAddress().equals(deviceInfo.address)) { 687 layout.removeDisplayLocked(DEFAULT_DISPLAY); 688 689 // Need to find another local display and make it default 690 for (int i = 0; i < mLogicalDisplays.size(); i++) { 691 LogicalDisplay nextDisplay = mLogicalDisplays.valueAt(i); 692 DisplayDevice nextDevice = nextDisplay.getPrimaryDisplayDeviceLocked(); 693 if (nextDevice == null) { 694 continue; 695 } 696 DisplayDeviceInfo nextDeviceInfo = nextDevice.getDisplayDeviceInfoLocked(); 697 698 if ((nextDeviceInfo.flags 699 & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0 700 && !nextDeviceInfo.address.equals(deviceInfo.address)) { 701 layout.createDefaultDisplayLocked(nextDeviceInfo.address, mIdProducer); 702 applyLayoutLocked(); 703 return; 704 } 705 } 706 } 707 } 708 709 @VisibleForTesting updateLogicalDisplays()710 void updateLogicalDisplays() { 711 synchronized (mSyncRoot) { 712 updateLogicalDisplaysLocked(); 713 } 714 } 715 updateLogicalDisplaysLocked()716 void updateLogicalDisplaysLocked() { 717 updateLogicalDisplaysLocked(DisplayDeviceInfo.DIFF_EVERYTHING); 718 } 719 updateLogicalDisplaysLocked(int diff)720 private void updateLogicalDisplaysLocked(int diff) { 721 updateLogicalDisplaysLocked(diff, /* isSecondLoop= */ false); 722 } 723 724 /** 725 * Updates the rest of the display system once all the changes are applied for display 726 * devices and logical displays. The includes releasing invalid/empty LogicalDisplays, 727 * creating/adjusting/removing DisplayGroups, and notifying the rest of the system of the 728 * relevant changes. 729 * 730 * @param diff The DisplayDeviceInfo.DIFF_* of what actually changed to enable finer-grained 731 * display update listeners 732 * @param isSecondLoop If true, this is the second time this is called for the same change. 733 */ updateLogicalDisplaysLocked(int diff, boolean isSecondLoop)734 private void updateLogicalDisplaysLocked(int diff, boolean isSecondLoop) { 735 boolean reloop = false; 736 // Go through all the displays and figure out if they need to be updated. 737 // Loops in reverse so that displays can be removed during the loop without affecting the 738 // rest of the loop. 739 for (int i = mLogicalDisplays.size() - 1; i >= 0; i--) { 740 final int displayId = mLogicalDisplays.keyAt(i); 741 LogicalDisplay display = mLogicalDisplays.valueAt(i); 742 assignDisplayGroupLocked(display); 743 744 boolean wasDirty = display.isDirtyLocked(); 745 mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); 746 display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo); 747 748 display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); 749 final DisplayInfo newDisplayInfo = display.getDisplayInfoLocked(); 750 final int updateState = mUpdatedLogicalDisplays.get(displayId, UPDATE_STATE_NEW); 751 final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW; 752 final boolean wasPreviouslyEnabled = mDisplaysEnabledCache.get(displayId); 753 final boolean isCurrentlyEnabled = display.isEnabledLocked(); 754 755 // The display is no longer valid and needs to be removed. 756 if (!display.isValidLocked()) { 757 // Remove from group 758 final DisplayGroup displayGroup = getDisplayGroupLocked( 759 getDisplayGroupIdFromDisplayIdLocked(displayId)); 760 if (displayGroup != null) { 761 displayGroup.removeDisplayLocked(display); 762 } 763 764 if (wasPreviouslyUpdated) { 765 // The display isn't actually removed from our internal data structures until 766 // after the notification is sent; see {@link #sendUpdatesForDisplaysLocked}. 767 if (mFlags.isConnectedDisplayManagementEnabled()) { 768 if (mDisplaysEnabledCache.get(displayId)) { 769 // We still need to send LOGICAL_DISPLAY_EVENT_DISCONNECTED 770 reloop = true; 771 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED); 772 } else { 773 mUpdatedLogicalDisplays.delete(displayId); 774 mLogicalDisplaysToUpdate.put(displayId, 775 LOGICAL_DISPLAY_EVENT_DISCONNECTED); 776 } 777 } else { 778 mUpdatedLogicalDisplays.delete(displayId); 779 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED); 780 } 781 } else { 782 // This display never left this class, safe to remove without notification 783 mLogicalDisplays.removeAt(i); 784 } 785 continue; 786 787 // The display is new. 788 } else if (!wasPreviouslyUpdated) { 789 if (mFlags.isConnectedDisplayManagementEnabled()) { 790 // We still need to send LOGICAL_DISPLAY_EVENT_ADDED 791 reloop = true; 792 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CONNECTED); 793 } else { 794 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED); 795 } 796 // Underlying displays device has changed to a different one. 797 } else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) { 798 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_SWAPPED); 799 800 // Something about the display device has changed. 801 } else if (mFlags.isConnectedDisplayManagementEnabled() 802 && wasPreviouslyEnabled != isCurrentlyEnabled) { 803 int event = isCurrentlyEnabled ? LOGICAL_DISPLAY_EVENT_ADDED : 804 LOGICAL_DISPLAY_EVENT_REMOVED; 805 mLogicalDisplaysToUpdate.put(displayId, event); 806 } else if (wasDirty || !mTempDisplayInfo.equals(newDisplayInfo)) { 807 // If only the hdr/sdr ratio changed, then send just the event for that case 808 if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) { 809 mLogicalDisplaysToUpdate.put(displayId, 810 LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED); 811 } else { 812 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED); 813 } 814 815 // The display is involved in a display layout transition 816 } else if (updateState == UPDATE_STATE_TRANSITION) { 817 mLogicalDisplaysToUpdate.put(displayId, 818 LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); 819 820 // Display frame rate overrides changed. 821 } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) { 822 mLogicalDisplaysToUpdate.put( 823 displayId, LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); 824 825 // Non-override display values changed. 826 } else { 827 // While application shouldn't know nor care about the non-overridden info, we 828 // still need to let WindowManager know so it can update its own internal state for 829 // things like display cutouts. 830 display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo); 831 if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) { 832 mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED); 833 } 834 } 835 836 mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED); 837 } 838 839 // Go through the groups and do the same thing. We do this after displays since group 840 // information can change in the previous loop. 841 // Loops in reverse so that groups can be removed during the loop without affecting the 842 // rest of the loop. 843 for (int i = mDisplayGroups.size() - 1; i >= 0; i--) { 844 final int groupId = mDisplayGroups.keyAt(i); 845 final DisplayGroup group = mDisplayGroups.valueAt(i); 846 final boolean wasPreviouslyUpdated = mUpdatedDisplayGroups.indexOfKey(groupId) > -1; 847 final int changeCount = group.getChangeCountLocked(); 848 849 if (group.isEmptyLocked()) { 850 mUpdatedDisplayGroups.delete(groupId); 851 if (wasPreviouslyUpdated) { 852 mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_REMOVED); 853 } 854 continue; 855 } else if (!wasPreviouslyUpdated) { 856 mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_ADDED); 857 } else if (mUpdatedDisplayGroups.get(groupId) != changeCount) { 858 mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_CHANGED); 859 } 860 mUpdatedDisplayGroups.put(groupId, changeCount); 861 } 862 863 // Send the display and display group updates in order by message type. This is important 864 // to ensure that addition and removal notifications happen in the right order. 865 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); 866 sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED); 867 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED); 868 if (mFlags.isConnectedDisplayManagementEnabled()) { 869 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED); 870 } 871 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED); 872 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); 873 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED); 874 if (mFlags.isConnectedDisplayManagementEnabled()) { 875 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CONNECTED); 876 } 877 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED); 878 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED); 879 sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED); 880 sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED); 881 882 mLogicalDisplaysToUpdate.clear(); 883 mDisplayGroupsToUpdate.clear(); 884 885 if (reloop) { 886 if (isSecondLoop) { 887 Slog.wtf(TAG, "Trying to loop a third time"); 888 return; 889 } 890 updateLogicalDisplaysLocked(diff, /* isSecondLoop= */ true); 891 } 892 } 893 894 /** 895 * Send the specified message for all relevant displays in the specified display-to-message map. 896 */ sendUpdatesForDisplaysLocked(int msg)897 private void sendUpdatesForDisplaysLocked(int msg) { 898 for (int i = mLogicalDisplaysToUpdate.size() - 1; i >= 0; --i) { 899 final int currMsg = mLogicalDisplaysToUpdate.valueAt(i); 900 if (currMsg != msg) { 901 continue; 902 } 903 904 final int id = mLogicalDisplaysToUpdate.keyAt(i); 905 final LogicalDisplay display = getDisplayLocked(id); 906 if (DEBUG) { 907 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); 908 final String uniqueId = device == null ? "null" : device.getUniqueId(); 909 Slog.d(TAG, "Sending " + displayEventToString(msg) + " for display=" + id 910 + " with device=" + uniqueId); 911 } 912 913 if (mFlags.isConnectedDisplayManagementEnabled()) { 914 if (msg == LOGICAL_DISPLAY_EVENT_ADDED) { 915 mDisplaysEnabledCache.put(id, true); 916 } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) { 917 mDisplaysEnabledCache.delete(id); 918 } 919 } 920 921 mListener.onLogicalDisplayEventLocked(display, msg); 922 923 if (mFlags.isConnectedDisplayManagementEnabled()) { 924 if (msg == LOGICAL_DISPLAY_EVENT_DISCONNECTED) { 925 mLogicalDisplays.delete(id); 926 } 927 } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) { 928 // We wait until we sent the EVENT_REMOVED event before actually removing the 929 // display. 930 mLogicalDisplays.delete(id); 931 } 932 } 933 } 934 935 /** 936 * Send the specified message for all relevant display groups in the specified message map. 937 */ sendUpdatesForGroupsLocked(int msg)938 private void sendUpdatesForGroupsLocked(int msg) { 939 for (int i = mDisplayGroupsToUpdate.size() - 1; i >= 0; --i) { 940 final int currMsg = mDisplayGroupsToUpdate.valueAt(i); 941 if (currMsg != msg) { 942 continue; 943 } 944 945 final int id = mDisplayGroupsToUpdate.keyAt(i); 946 mListener.onDisplayGroupEventLocked(id, msg); 947 if (msg == DISPLAY_GROUP_EVENT_REMOVED) { 948 // We wait until we sent the EVENT_REMOVED event before actually removing the 949 // group. 950 mDisplayGroups.delete(id); 951 // Remove possible reference to the removed group. 952 int deviceIndex = mDeviceDisplayGroupIds.indexOfValue(id); 953 if (deviceIndex >= 0) { 954 mDeviceDisplayGroupIds.removeAt(deviceIndex); 955 } 956 } 957 } 958 } 959 960 /** This method should be called before LogicalDisplay.updateLocked, 961 * DisplayInfo in LogicalDisplay (display.getDisplayInfoLocked()) is not updated yet, 962 * and should not be used directly or indirectly in this method */ assignDisplayGroupLocked(LogicalDisplay display)963 private void assignDisplayGroupLocked(LogicalDisplay display) { 964 if (!display.isValidLocked()) { // null check for display.mPrimaryDisplayDevice 965 return; 966 } 967 // updated primary device directly from LogicalDisplay (not from DisplayInfo) 968 final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked(); 969 // final in LogicalDisplay 970 final int displayId = display.getDisplayIdLocked(); 971 final String primaryDisplayUniqueId = displayDevice.getUniqueId(); 972 final Integer linkedDeviceUniqueId = 973 mVirtualDeviceDisplayMapping.get(primaryDisplayUniqueId); 974 975 // Get current display group data 976 int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId); 977 Integer deviceDisplayGroupId = null; 978 if (linkedDeviceUniqueId != null 979 && mDeviceDisplayGroupIds.indexOfKey(linkedDeviceUniqueId) > 0) { 980 deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); 981 } 982 final DisplayGroup oldGroup = getDisplayGroupLocked(groupId); 983 984 // groupName directly from LogicalDisplay (not from DisplayInfo) 985 final String groupName = display.getDisplayGroupNameLocked(); 986 // DisplayDeviceInfo is safe to use, it is updated earlier 987 final DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); 988 // Get the new display group if a change is needed, if display group name is empty and 989 // {@code DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP} is not set, the display is assigned 990 // to the default display group. 991 final boolean needsOwnDisplayGroup = 992 (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0 993 || !TextUtils.isEmpty(groupName); 994 995 final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP; 996 final boolean needsDeviceDisplayGroup = 997 !needsOwnDisplayGroup && linkedDeviceUniqueId != null; 998 final boolean hasDeviceDisplayGroup = 999 deviceDisplayGroupId != null && groupId == deviceDisplayGroupId; 1000 if (groupId == Display.INVALID_DISPLAY_GROUP 1001 || hasOwnDisplayGroup != needsOwnDisplayGroup 1002 || hasDeviceDisplayGroup != needsDeviceDisplayGroup) { 1003 groupId = 1004 assignDisplayGroupIdLocked(needsOwnDisplayGroup, 1005 display.getDisplayGroupNameLocked(), needsDeviceDisplayGroup, 1006 linkedDeviceUniqueId); 1007 } 1008 1009 // Create a new group if needed 1010 DisplayGroup newGroup = getDisplayGroupLocked(groupId); 1011 if (newGroup == null) { 1012 newGroup = new DisplayGroup(groupId); 1013 mDisplayGroups.append(groupId, newGroup); 1014 } 1015 if (oldGroup != newGroup) { 1016 if (oldGroup != null) { 1017 oldGroup.removeDisplayLocked(display); 1018 } 1019 newGroup.addDisplayLocked(display); 1020 display.updateDisplayGroupIdLocked(groupId); 1021 Slog.i(TAG, "Setting new display group " + groupId + " for display " 1022 + displayId + ", from previous group: " 1023 + (oldGroup != null ? oldGroup.getGroupId() : "null")); 1024 } 1025 } 1026 1027 /** 1028 * Goes through all the displays used in the layouts for the specified {@code fromState} and 1029 * {@code toState} and un/marks them for transition. When a new layout is requested, we 1030 * mark the displays that will change into a transitional phase so that they can all be turned 1031 * OFF. Once all are confirmed OFF, then this method gets called again to reset transition 1032 * marker. This helps to ensure that all display-OFF requests are made before 1033 * display-ON which in turn hides any resizing-jank windows might incur when switching displays. 1034 * 1035 * @param fromState The state we are switching from. 1036 * @param toState The state we are switching to. 1037 * @param transitionValue The value to mark the transition state: true == transitioning. 1038 */ resetLayoutLocked(int fromState, int toState, boolean transitionValue)1039 private void resetLayoutLocked(int fromState, int toState, boolean transitionValue) { 1040 final Layout fromLayout = mDeviceStateToLayoutMap.get(fromState); 1041 final Layout toLayout = mDeviceStateToLayoutMap.get(toState); 1042 1043 final int count = mLogicalDisplays.size(); 1044 for (int i = 0; i < count; i++) { 1045 final LogicalDisplay logicalDisplay = mLogicalDisplays.valueAt(i); 1046 final int displayId = logicalDisplay.getDisplayIdLocked(); 1047 final DisplayDevice device = logicalDisplay.getPrimaryDisplayDeviceLocked(); 1048 if (device == null) { 1049 // If there's no device, then the logical display is due to be removed. Ignore it. 1050 continue; 1051 } 1052 1053 // Grab the display associations this display-device has in the old layout and the 1054 // new layout. 1055 final DisplayAddress address = device.getDisplayDeviceInfoLocked().address; 1056 1057 // Virtual displays do not have addresses, so account for nulls. 1058 final Layout.Display fromDisplay = 1059 address != null ? fromLayout.getByAddress(address) : null; 1060 final Layout.Display toDisplay = 1061 address != null ? toLayout.getByAddress(address) : null; 1062 1063 // If the display is in one of the layouts but not the other, then the content will 1064 // change, so in this case we also want to blank the displays to avoid jank. 1065 final boolean displayNotInBothLayouts = (fromDisplay == null) != (toDisplay == null); 1066 1067 // If a layout doesn't mention a display-device at all, then the display-device defaults 1068 // to enabled. This is why we treat null as "enabled" in the code below. 1069 final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled(); 1070 final boolean willBeEnabled = toDisplay == null || toDisplay.isEnabled(); 1071 1072 final boolean deviceHasNewLogicalDisplayId = fromDisplay != null && toDisplay != null 1073 && fromDisplay.getLogicalDisplayId() != toDisplay.getLogicalDisplayId(); 1074 1075 // We consider a display-device as changing/transition if 1076 // 1) It's already marked as transitioning 1077 // 2) It's going from enabled to disabled, or vice versa 1078 // 3) It's enabled, but it's mapped to a new logical display ID. To the user this 1079 // would look like apps moving from one screen to another since task-stacks stay 1080 // with the logical display [ID]. 1081 // 4) It's in one layout but not the other, so the content will change. 1082 final boolean isTransitioning = 1083 logicalDisplay.isInTransitionLocked() 1084 || (wasEnabled != willBeEnabled) 1085 || deviceHasNewLogicalDisplayId 1086 || displayNotInBothLayouts; 1087 1088 if (isTransitioning) { 1089 if (transitionValue != logicalDisplay.isInTransitionLocked()) { 1090 Slog.i(TAG, "Set isInTransition on display " + displayId + ": " 1091 + transitionValue); 1092 } 1093 // This will either mark the display as "transitioning" if we are starting to change 1094 // the device state, or remove the transitioning marker if the state change is 1095 // ending. 1096 logicalDisplay.setIsInTransitionLocked(transitionValue); 1097 mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION); 1098 } 1099 } 1100 } 1101 1102 /** 1103 * Apply (or reapply) the currently selected display layout. 1104 */ applyLayoutLocked()1105 private void applyLayoutLocked() { 1106 final Layout oldLayout = mCurrentLayout; 1107 mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState); 1108 Slog.i(TAG, "Applying layout: " + mCurrentLayout + ", Previous layout: " + oldLayout); 1109 1110 // Go through each of the displays in the current layout set. 1111 final int size = mCurrentLayout.size(); 1112 for (int i = 0; i < size; i++) { 1113 final Layout.Display displayLayout = mCurrentLayout.getAt(i); 1114 1115 // If the underlying display-device we want to use for this display 1116 // doesn't exist, then skip it. This can happen at startup as display-devices 1117 // trickle in one at a time. When the new display finally shows up, the layout is 1118 // recalculated so that the display is properly added to the current layout. 1119 final DisplayAddress address = displayLayout.getAddress(); 1120 final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address); 1121 if (device == null) { 1122 Slog.w(TAG, "applyLayoutLocked: The display device (" + address + "), is not " 1123 + "available for the display state " + mDeviceState); 1124 continue; 1125 } 1126 1127 // Now that we have a display-device, we need a LogicalDisplay to map it to. Find the 1128 // right one, if it doesn't exist, create a new one. 1129 final int logicalDisplayId = displayLayout.getLogicalDisplayId(); 1130 1131 LogicalDisplay newDisplay = getDisplayLocked(logicalDisplayId); 1132 boolean newDisplayCreated = false; 1133 if (newDisplay == null) { 1134 newDisplay = createNewLogicalDisplayLocked( 1135 null /*displayDevice*/, logicalDisplayId); 1136 newDisplayCreated = true; 1137 } 1138 1139 // Now swap the underlying display devices between the old display and the new display 1140 final LogicalDisplay oldDisplay = getDisplayLocked(device); 1141 if (newDisplay != oldDisplay) { 1142 // Display is swapping, notify WindowManager, so it can prepare for 1143 // the display switch 1144 if (!newDisplayCreated && mWindowManagerPolicy != null) { 1145 mWindowManagerPolicy.onDisplaySwitchStart(newDisplay.getDisplayIdLocked()); 1146 } 1147 1148 newDisplay.swapDisplaysLocked(oldDisplay); 1149 } 1150 DisplayDeviceConfig config = device.getDisplayDeviceConfig(); 1151 1152 newDisplay.setDevicePositionLocked(displayLayout.getPosition()); 1153 newDisplay.setLeadDisplayLocked(displayLayout.getLeadDisplayId()); 1154 newDisplay.updateLayoutLimitedRefreshRateLocked( 1155 config.getRefreshRange(displayLayout.getRefreshRateZoneId()) 1156 ); 1157 newDisplay.updateThermalRefreshRateThrottling( 1158 config.getThermalRefreshRateThrottlingData( 1159 displayLayout.getRefreshRateThermalThrottlingMapId() 1160 ) 1161 ); 1162 setEnabledLocked(newDisplay, displayLayout.isEnabled()); 1163 newDisplay.setThermalBrightnessThrottlingDataIdLocked( 1164 displayLayout.getThermalBrightnessThrottlingMapId() == null 1165 ? DisplayDeviceConfig.DEFAULT_ID 1166 : displayLayout.getThermalBrightnessThrottlingMapId()); 1167 newDisplay.setPowerThrottlingDataIdLocked( 1168 displayLayout.getPowerThrottlingMapId() == null 1169 ? DisplayDeviceConfig.DEFAULT_ID 1170 : displayLayout.getPowerThrottlingMapId()); 1171 newDisplay.setDisplayGroupNameLocked(displayLayout.getDisplayGroupName()); 1172 } 1173 } 1174 1175 /** 1176 * Creates a new logical display for the specified device and display Id and adds it to the list 1177 * of logical displays. 1178 * 1179 * @param device The device to associate with the LogicalDisplay. 1180 * @param displayId The display ID to give the new display. If invalid, a new ID is assigned. 1181 * @return The new logical display if created, null otherwise. 1182 */ createNewLogicalDisplayLocked(DisplayDevice device, int displayId)1183 private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) { 1184 final int layerStack = assignLayerStackLocked(displayId); 1185 final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device, 1186 mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled(), 1187 mFlags.isAlwaysRotateDisplayDeviceEnabled()); 1188 display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); 1189 1190 final DisplayInfo info = display.getDisplayInfoLocked(); 1191 if (info.type == Display.TYPE_INTERNAL && mDeviceStateToLayoutMap.size() > 1) { 1192 // If this is an internal display and the device uses a display layout configuration, 1193 // the display should be disabled as later we will receive a device state update, which 1194 // will tell us which internal displays should be enabled and which should be disabled. 1195 display.setEnabledLocked(false); 1196 } 1197 1198 mLogicalDisplays.put(displayId, display); 1199 return display; 1200 } 1201 setEnabledLocked(LogicalDisplay display, boolean isEnabled)1202 void setEnabledLocked(LogicalDisplay display, boolean isEnabled) { 1203 final int displayId = display.getDisplayIdLocked(); 1204 final DisplayInfo info = display.getDisplayInfoLocked(); 1205 1206 final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode 1207 && (info.type != Display.TYPE_INTERNAL); 1208 if (isEnabled && disallowSecondaryDisplay) { 1209 Slog.i(TAG, "Not creating a logical display for a secondary display because single" 1210 + " display demo mode is enabled: " + display.getDisplayInfoLocked()); 1211 isEnabled = false; 1212 } 1213 1214 if (display.isEnabledLocked() != isEnabled) { 1215 Slog.i(TAG, "SetEnabled on display " + displayId + ": " + isEnabled); 1216 display.setEnabledLocked(isEnabled); 1217 } 1218 } 1219 assignDisplayGroupIdLocked(boolean isOwnDisplayGroup, String displayGroupName, boolean isDeviceDisplayGroup, Integer linkedDeviceUniqueId)1220 private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup, String displayGroupName, 1221 boolean isDeviceDisplayGroup, Integer linkedDeviceUniqueId) { 1222 if (isDeviceDisplayGroup && linkedDeviceUniqueId != null) { 1223 int deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); 1224 // A value of 0 indicates that no device display group was found. 1225 if (deviceDisplayGroupId == 0) { 1226 deviceDisplayGroupId = mNextNonDefaultGroupId++; 1227 mDeviceDisplayGroupIds.put(linkedDeviceUniqueId, deviceDisplayGroupId); 1228 } 1229 return deviceDisplayGroupId; 1230 } 1231 if (!isOwnDisplayGroup) return Display.DEFAULT_DISPLAY_GROUP; 1232 Integer displayGroupId = mDisplayGroupIdsByName.get(displayGroupName); 1233 if (displayGroupId == null) { 1234 displayGroupId = Integer.valueOf(mNextNonDefaultGroupId++); 1235 mDisplayGroupIdsByName.put(displayGroupName, displayGroupId); 1236 } 1237 return displayGroupId; 1238 } 1239 initializeDefaultDisplayDeviceLocked(DisplayDevice device)1240 private void initializeDefaultDisplayDeviceLocked(DisplayDevice device) { 1241 // We always want to make sure that our default layout creates a logical 1242 // display for the default display device that is found. 1243 // To that end, when we are notified of a new default display, we add it to 1244 // the default layout definition if it is not already there. 1245 final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); 1246 if (layout.getById(DEFAULT_DISPLAY) != null) { 1247 // The layout should only have one default display 1248 return; 1249 } 1250 final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 1251 layout.createDefaultDisplayLocked(info.address, mIdProducer); 1252 } 1253 assignLayerStackLocked(int displayId)1254 private int assignLayerStackLocked(int displayId) { 1255 // Currently layer stacks and display ids are the same. 1256 // This need not be the case. 1257 return displayId; 1258 } 1259 toSparseBooleanArray(int[] input)1260 private SparseBooleanArray toSparseBooleanArray(int[] input) { 1261 final SparseBooleanArray retval = new SparseBooleanArray(2); 1262 for (int i = 0; input != null && i < input.length; i++) { 1263 retval.put(input[i], true); 1264 } 1265 return retval; 1266 } 1267 1268 /** 1269 * Returns true if the device would definitely have outer display ON/Stay Awake on fold based on 1270 * the value of `Continue using app on fold` setting 1271 */ shouldStayAwakeOnFold()1272 private boolean shouldStayAwakeOnFold() { 1273 return mFoldSettingProvider.shouldStayAwakeOnFold() || ( 1274 mFoldSettingProvider.shouldSelectiveStayAwakeOnFold() 1275 && mFoldGracePeriodProvider.isEnabled()); 1276 } 1277 displayEventToString(int msg)1278 private String displayEventToString(int msg) { 1279 switch(msg) { 1280 case LOGICAL_DISPLAY_EVENT_ADDED: 1281 return "added"; 1282 case LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION: 1283 return "transition"; 1284 case LOGICAL_DISPLAY_EVENT_CHANGED: 1285 return "changed"; 1286 case LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED: 1287 return "framerate_override"; 1288 case LOGICAL_DISPLAY_EVENT_SWAPPED: 1289 return "swapped"; 1290 case LOGICAL_DISPLAY_EVENT_REMOVED: 1291 return "removed"; 1292 case LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED: 1293 return "hdr_sdr_ratio_changed"; 1294 case LOGICAL_DISPLAY_EVENT_CONNECTED: 1295 return "connected"; 1296 case LOGICAL_DISPLAY_EVENT_DISCONNECTED: 1297 return "disconnected"; 1298 } 1299 return null; 1300 } 1301 setDisplayEnabledLocked(@onNull LogicalDisplay display, boolean enabled)1302 void setDisplayEnabledLocked(@NonNull LogicalDisplay display, boolean enabled) { 1303 boolean isEnabled = display.isEnabledLocked(); 1304 if (isEnabled == enabled) { 1305 Slog.w(TAG, "Display is already " + (isEnabled ? "enabled" : "disabled") + ": " 1306 + display.getDisplayIdLocked()); 1307 return; 1308 } 1309 setEnabledLocked(display, enabled); 1310 updateLogicalDisplaysLocked(); 1311 } 1312 1313 public interface Listener { onLogicalDisplayEventLocked(LogicalDisplay display, int event)1314 void onLogicalDisplayEventLocked(LogicalDisplay display, int event); onDisplayGroupEventLocked(int groupId, int event)1315 void onDisplayGroupEventLocked(int groupId, int event); onTraversalRequested()1316 void onTraversalRequested(); 1317 } 1318 1319 private class LogicalDisplayMapperHandler extends Handler { LogicalDisplayMapperHandler(Looper looper)1320 LogicalDisplayMapperHandler(Looper looper) { 1321 super(looper, null, true /*async*/); 1322 } 1323 1324 @Override handleMessage(Message msg)1325 public void handleMessage(Message msg) { 1326 switch (msg.what) { 1327 case MSG_TRANSITION_TO_PENDING_DEVICE_STATE: 1328 synchronized (mSyncRoot) { 1329 finishStateTransitionLocked(true /*force*/); 1330 } 1331 break; 1332 } 1333 } 1334 } 1335 } 1336