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