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