1 /*
2  * Copyright (C) 2012 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 com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.hardware.display.DisplayManagerInternal;
27 import android.util.ArraySet;
28 import android.util.SparseArray;
29 import android.view.Display;
30 import android.view.DisplayEventReceiver;
31 import android.view.DisplayInfo;
32 import android.view.Surface;
33 import android.view.SurfaceControl;
34 
35 import com.android.server.wm.utils.InsetUtils;
36 
37 import java.io.PrintWriter;
38 import java.io.StringWriter;
39 import java.util.Arrays;
40 import java.util.Objects;
41 
42 /**
43  * Describes how a logical display is configured.
44  * <p>
45  * At this time, we only support logical displays that are coupled to a particular
46  * primary display device from which the logical display derives its basic properties
47  * such as its size, density and refresh rate.
48  * </p><p>
49  * A logical display may be mirrored onto multiple display devices in addition to its
50  * primary display device.  Note that the contents of a logical display may not
51  * always be visible, even on its primary display device, such as in the case where
52  * the primary display device is currently mirroring content from a different
53  * logical display.
54  * </p><p>
55  * This object is designed to encapsulate as much of the policy of logical
56  * displays as possible.  The idea is to make it easy to implement new kinds of
57  * logical displays mostly by making local changes to this class.
58  * </p><p>
59  * Note: The display manager architecture does not actually require logical displays
60  * to be associated with any individual display device.  Logical displays and
61  * display devices are orthogonal concepts.  Some mapping will exist between
62  * logical displays and display devices but it can be many-to-many and
63  * and some might have no relation at all.
64  * </p><p>
65  * Logical displays are guarded by the {@link DisplayManagerService.SyncRoot} lock.
66  * </p>
67  */
68 final class LogicalDisplay {
69     private static final String TAG = "LogicalDisplay";
70 
71     /**
72      * Phase indicating the logical display's existence is hidden from the rest of the framework.
73      * This can happen if the current layout has specifically requested to keep this display
74      * disabled.
75      */
76     static final int DISPLAY_PHASE_DISABLED = -1;
77 
78     /**
79      * Phase indicating that the logical display is going through a layout transition.
80      * When in this phase, other systems can choose to special case power-state handling of a
81      * display that might be in a transition.
82      */
83     static final int DISPLAY_PHASE_LAYOUT_TRANSITION = 0;
84 
85     /**
86      * The display is exposed to the rest of the system and its power state is determined by a
87      * power-request from PowerManager.
88      */
89     static final int DISPLAY_PHASE_ENABLED = 1;
90 
91     @IntDef(prefix = {"DISPLAY_PHASE" }, value = {
92         DISPLAY_PHASE_DISABLED,
93         DISPLAY_PHASE_LAYOUT_TRANSITION,
94         DISPLAY_PHASE_ENABLED
95     })
96     @interface DisplayPhase {}
97 
98     // The layer stack we use when the display has been blanked to prevent any
99     // of its content from appearing.
100     private static final int BLANK_LAYER_STACK = -1;
101 
102     private static final DisplayInfo EMPTY_DISPLAY_INFO = new DisplayInfo();
103 
104     private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
105     private final int mDisplayId;
106     private final int mLayerStack;
107 
108     private int mDisplayGroupId = Display.INVALID_DISPLAY_GROUP;
109 
110     /**
111      * Override information set by the window manager. Will be reported instead of {@link #mInfo}
112      * if not null.
113      * @see #setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo)
114      * @see #getDisplayInfoLocked()
115      */
116     private DisplayInfo mOverrideDisplayInfo;
117     /**
118      * Current display info. Initialized with {@link #mBaseDisplayInfo}. Set to {@code null} if
119      * needs to be updated.
120      * @see #getDisplayInfoLocked()
121      */
122     private final DisplayInfoProxy mInfo = new DisplayInfoProxy(null);
123 
124     // The display device that this logical display is based on and which
125     // determines the base metrics that it uses.
126     private DisplayDevice mPrimaryDisplayDevice;
127     private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
128 
129     // True if the logical display has unique content.
130     private boolean mHasContent;
131 
132     private int mRequestedColorMode;
133     private boolean mRequestedMinimalPostProcessing;
134 
135     private int[] mUserDisabledHdrTypes = {};
136 
137     private DisplayModeDirector.DesiredDisplayModeSpecs mDesiredDisplayModeSpecs =
138             new DisplayModeDirector.DesiredDisplayModeSpecs();
139 
140     // The display offsets to apply to the display projection.
141     private int mDisplayOffsetX;
142     private int mDisplayOffsetY;
143 
144     /**
145      * The position of the display projection sent to SurfaceFlinger
146      */
147     private final Point mDisplayPosition = new Point();
148 
149     /**
150      * {@code true} if display scaling is disabled, or {@code false} if the default scaling mode
151      * is used.
152      * @see #isDisplayScalingDisabled()
153      * @see #setDisplayScalingDisabledLocked(boolean)
154      */
155     private boolean mDisplayScalingDisabled;
156 
157     // Temporary rectangle used when needed.
158     private final Rect mTempLayerStackRect = new Rect();
159     private final Rect mTempDisplayRect = new Rect();
160 
161     /**
162      * Indicates the current phase of the display. Generally, phases supersede any
163      * requests from PowerManager in DPC's calculation for the display state. Only when the
164      * phase is ENABLED does PowerManager's request for the display take effect.
165      */
166     @DisplayPhase
167     private int mPhase = DISPLAY_PHASE_ENABLED;
168 
169     /**
170      * The UID mappings for refresh rate override
171      */
172     private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides;
173 
174     /**
175      * Holds a set of UIDs that their frame rate override changed and needs to be notified
176      */
177     private ArraySet<Integer> mPendingFrameRateOverrideUids;
178 
179     /**
180      * Temporary frame rate override list, used when needed.
181      */
182     private final SparseArray<Float> mTempFrameRateOverride;
183 
LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice)184     public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
185         mDisplayId = displayId;
186         mLayerStack = layerStack;
187         mPrimaryDisplayDevice = primaryDisplayDevice;
188         mPendingFrameRateOverrideUids = new ArraySet<>();
189         mTempFrameRateOverride = new SparseArray<>();
190     }
191 
192     /**
193      * Gets the logical display id of this logical display.
194      *
195      * @return The logical display id.
196      */
getDisplayIdLocked()197     public int getDisplayIdLocked() {
198         return mDisplayId;
199     }
200 
201     /**
202      * Gets the primary display device associated with this logical display.
203      *
204      * @return The primary display device.
205      */
getPrimaryDisplayDeviceLocked()206     public DisplayDevice getPrimaryDisplayDeviceLocked() {
207         return mPrimaryDisplayDevice;
208     }
209 
210     /**
211      * Gets information about the logical display.
212      *
213      * @return The device info, which should be treated as immutable by the caller.
214      * The logical display should allocate a new display info object whenever
215      * the data changes.
216      */
getDisplayInfoLocked()217     public DisplayInfo getDisplayInfoLocked() {
218         if (mInfo.get() == null) {
219             DisplayInfo info = new DisplayInfo();
220             info.copyFrom(mBaseDisplayInfo);
221             if (mOverrideDisplayInfo != null) {
222                 info.appWidth = mOverrideDisplayInfo.appWidth;
223                 info.appHeight = mOverrideDisplayInfo.appHeight;
224                 info.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth;
225                 info.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight;
226                 info.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth;
227                 info.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
228                 info.logicalWidth = mOverrideDisplayInfo.logicalWidth;
229                 info.logicalHeight = mOverrideDisplayInfo.logicalHeight;
230                 info.rotation = mOverrideDisplayInfo.rotation;
231                 info.displayCutout = mOverrideDisplayInfo.displayCutout;
232                 info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
233                 info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
234                 info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
235                 info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
236             }
237             mInfo.set(info);
238         }
239         return mInfo.get();
240     }
241 
242     /**
243      * Returns the frame rate overrides list
244      */
getFrameRateOverrides()245     public DisplayEventReceiver.FrameRateOverride[] getFrameRateOverrides() {
246         return mFrameRateOverrides;
247     }
248 
249     /**
250      * Returns the list of uids that needs to be updated about their frame rate override
251      */
getPendingFrameRateOverrideUids()252     public ArraySet<Integer> getPendingFrameRateOverrideUids() {
253         return mPendingFrameRateOverrideUids;
254     }
255 
256     /**
257      * Clears the list of uids that needs to be updated about their frame rate override
258      */
clearPendingFrameRateOverrideUids()259     public void clearPendingFrameRateOverrideUids() {
260         mPendingFrameRateOverrideUids = new ArraySet<>();
261     }
262 
263     /**
264      * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo)
265      */
getNonOverrideDisplayInfoLocked(DisplayInfo outInfo)266     void getNonOverrideDisplayInfoLocked(DisplayInfo outInfo) {
267         outInfo.copyFrom(mBaseDisplayInfo);
268     }
269 
270     /**
271      * Sets overridden logical display information from the window manager.
272      * This method can be used to adjust application insets, rotation, and other
273      * properties that the window manager takes care of.
274      *
275      * @param info The logical display information, may be null.
276      */
setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info)277     public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
278         if (info != null) {
279             if (mOverrideDisplayInfo == null) {
280                 mOverrideDisplayInfo = new DisplayInfo(info);
281                 mInfo.set(null);
282                 return true;
283             } else if (!mOverrideDisplayInfo.equals(info)) {
284                 mOverrideDisplayInfo.copyFrom(info);
285                 mInfo.set(null);
286                 return true;
287             }
288         } else if (mOverrideDisplayInfo != null) {
289             mOverrideDisplayInfo = null;
290             mInfo.set(null);
291             return true;
292         }
293         return false;
294     }
295 
296     /**
297      * Returns true if the logical display is in a valid state.
298      * This method should be checked after calling {@link #updateLocked} to handle the
299      * case where a logical display should be removed because all of its associated
300      * display devices are gone or if it is otherwise no longer needed.
301      *
302      * @return True if the logical display is still valid.
303      */
isValidLocked()304     public boolean isValidLocked() {
305         return mPrimaryDisplayDevice != null;
306     }
307 
308     /**
309      * Updates the {@link DisplayGroup} to which the logical display belongs.
310      *
311      * @param groupId Identifier for the {@link DisplayGroup}.
312      */
updateDisplayGroupIdLocked(int groupId)313     public void updateDisplayGroupIdLocked(int groupId) {
314         if (groupId != mDisplayGroupId) {
315             mDisplayGroupId = groupId;
316             mBaseDisplayInfo.displayGroupId = groupId;
317             mInfo.set(null);
318         }
319     }
320 
321     /**
322      * Updates the state of the logical display based on the available display devices.
323      * The logical display might become invalid if it is attached to a display device
324      * that no longer exists.
325      *
326      * @param deviceRepo Repository of active {@link DisplayDevice}s.
327      */
updateLocked(DisplayDeviceRepository deviceRepo)328     public void updateLocked(DisplayDeviceRepository deviceRepo) {
329         // Nothing to update if already invalid.
330         if (mPrimaryDisplayDevice == null) {
331             return;
332         }
333 
334         // Check whether logical display has become invalid.
335         if (!deviceRepo.containsLocked(mPrimaryDisplayDevice)) {
336             setPrimaryDisplayDeviceLocked(null);
337             return;
338         }
339 
340         // Bootstrap the logical display using its associated primary physical display.
341         // We might use more elaborate configurations later.  It's possible that the
342         // configuration of several physical displays might be used to determine the
343         // logical display that they are sharing.  (eg. Adjust size for pixel-perfect
344         // mirroring over HDMI.)
345         DisplayDeviceInfo deviceInfo = mPrimaryDisplayDevice.getDisplayDeviceInfoLocked();
346         if (!Objects.equals(mPrimaryDisplayDeviceInfo, deviceInfo)) {
347             mBaseDisplayInfo.layerStack = mLayerStack;
348             mBaseDisplayInfo.flags = 0;
349             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
350                 mBaseDisplayInfo.flags |= Display.FLAG_SUPPORTS_PROTECTED_BUFFERS;
351             }
352             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SECURE) != 0) {
353                 mBaseDisplayInfo.flags |= Display.FLAG_SECURE;
354             }
355             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0) {
356                 mBaseDisplayInfo.flags |= Display.FLAG_PRIVATE;
357                 // For private displays by default content is destroyed on removal.
358                 mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
359             }
360             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) {
361                 mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
362             }
363             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
364                 mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;
365             }
366             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROUND) != 0) {
367                 mBaseDisplayInfo.flags |= Display.FLAG_ROUND;
368             }
369             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
370                 mBaseDisplayInfo.flags |= Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
371             }
372             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) {
373                 mBaseDisplayInfo.flags |= Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
374             }
375             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TRUSTED) != 0) {
376                 mBaseDisplayInfo.flags |= Display.FLAG_TRUSTED;
377             }
378             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) {
379                 mBaseDisplayInfo.flags |= Display.FLAG_OWN_DISPLAY_GROUP;
380             }
381             Rect maskingInsets = getMaskingInsets(deviceInfo);
382             int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right;
383             int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom;
384 
385             mBaseDisplayInfo.type = deviceInfo.type;
386             mBaseDisplayInfo.address = deviceInfo.address;
387             mBaseDisplayInfo.deviceProductInfo = deviceInfo.deviceProductInfo;
388             mBaseDisplayInfo.name = deviceInfo.name;
389             mBaseDisplayInfo.uniqueId = deviceInfo.uniqueId;
390             mBaseDisplayInfo.appWidth = maskedWidth;
391             mBaseDisplayInfo.appHeight = maskedHeight;
392             mBaseDisplayInfo.logicalWidth = maskedWidth;
393             mBaseDisplayInfo.logicalHeight = maskedHeight;
394             mBaseDisplayInfo.rotation = Surface.ROTATION_0;
395             mBaseDisplayInfo.modeId = deviceInfo.modeId;
396             mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
397             mBaseDisplayInfo.supportedModes = Arrays.copyOf(
398                     deviceInfo.supportedModes, deviceInfo.supportedModes.length);
399             mBaseDisplayInfo.colorMode = deviceInfo.colorMode;
400             mBaseDisplayInfo.supportedColorModes = Arrays.copyOf(
401                     deviceInfo.supportedColorModes,
402                     deviceInfo.supportedColorModes.length);
403             mBaseDisplayInfo.hdrCapabilities = deviceInfo.hdrCapabilities;
404             mBaseDisplayInfo.userDisabledHdrTypes = mUserDisabledHdrTypes;
405             mBaseDisplayInfo.minimalPostProcessingSupported =
406                     deviceInfo.allmSupported || deviceInfo.gameContentTypeSupported;
407             mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
408             mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
409             mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
410             mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
411             mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
412             mBaseDisplayInfo.state = deviceInfo.state;
413             mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth;
414             mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight;
415             mBaseDisplayInfo.largestNominalAppWidth = maskedWidth;
416             mBaseDisplayInfo.largestNominalAppHeight = maskedHeight;
417             mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
418             mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
419             boolean maskCutout =
420                     (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
421             mBaseDisplayInfo.displayCutout = maskCutout ? null : deviceInfo.displayCutout;
422             mBaseDisplayInfo.displayId = mDisplayId;
423             mBaseDisplayInfo.displayGroupId = mDisplayGroupId;
424             updateFrameRateOverrides(deviceInfo);
425             mBaseDisplayInfo.brightnessMinimum = deviceInfo.brightnessMinimum;
426             mBaseDisplayInfo.brightnessMaximum = deviceInfo.brightnessMaximum;
427             mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault;
428             mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
429             mPrimaryDisplayDeviceInfo = deviceInfo;
430             mInfo.set(null);
431         }
432     }
433 
updateFrameRateOverrides(DisplayDeviceInfo deviceInfo)434     private void updateFrameRateOverrides(DisplayDeviceInfo deviceInfo) {
435         mTempFrameRateOverride.clear();
436         if (mFrameRateOverrides != null) {
437             for (DisplayEventReceiver.FrameRateOverride frameRateOverride
438                     : mFrameRateOverrides) {
439                 mTempFrameRateOverride.put(frameRateOverride.uid,
440                         frameRateOverride.frameRateHz);
441             }
442         }
443         mFrameRateOverrides = deviceInfo.frameRateOverrides;
444         if (mFrameRateOverrides != null) {
445             for (DisplayEventReceiver.FrameRateOverride frameRateOverride
446                     : mFrameRateOverrides) {
447                 float refreshRate = mTempFrameRateOverride.get(frameRateOverride.uid, 0f);
448                 if (refreshRate == 0 || frameRateOverride.frameRateHz != refreshRate) {
449                     mTempFrameRateOverride.put(frameRateOverride.uid,
450                             frameRateOverride.frameRateHz);
451                 } else {
452                     mTempFrameRateOverride.delete(frameRateOverride.uid);
453                 }
454             }
455         }
456         for (int i = 0; i < mTempFrameRateOverride.size(); i++) {
457             mPendingFrameRateOverrideUids.add(mTempFrameRateOverride.keyAt(i));
458         }
459     }
460 
461     /**
462      * Return the insets currently applied to the display.
463      *
464      * Note that the base DisplayInfo already takes these insets into account, so if you want to
465      * find out the <b>true</b> size of the display, you need to add them back to the logical
466      * dimensions.
467      */
getInsets()468     public Rect getInsets() {
469         return getMaskingInsets(mPrimaryDisplayDeviceInfo);
470     }
471 
472     /**
473      * Returns insets in ROTATION_0 for areas that are masked.
474      */
getMaskingInsets(DisplayDeviceInfo deviceInfo)475     private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) {
476         boolean maskCutout = (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
477         if (maskCutout && deviceInfo.displayCutout != null) {
478             // getSafeInsets is fixed at creation time and cannot change
479             return deviceInfo.displayCutout.getSafeInsets();
480         } else {
481             return new Rect();
482         }
483     }
484 
485     /**
486      * Returns the position of the display's projection.
487      *
488      * @return The x, y coordinates of the display. The return object must be treated as immutable.
489      */
getDisplayPosition()490     Point getDisplayPosition() {
491         // Allocate a new object to avoid a data race.
492         return new Point(mDisplayPosition);
493     }
494 
495     /**
496      * Applies the layer stack and transformation to the given display device
497      * so that it shows the contents of this logical display.
498      *
499      * We know that the given display device is only ever showing the contents of
500      * a single logical display, so this method is expected to blow away all of its
501      * transformation properties to make it happen regardless of what the
502      * display device was previously showing.
503      *
504      * The caller must have an open Surface transaction.
505      *
506      * The display device may not be the primary display device, in the case
507      * where the display is being mirrored.
508      *
509      * @param device The display device to modify.
510      * @param isBlanked True if the device is being blanked.
511      */
configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device, boolean isBlanked)512     public void configureDisplayLocked(SurfaceControl.Transaction t,
513             DisplayDevice device,
514             boolean isBlanked) {
515         // Set the layer stack.
516         device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);
517         // Also inform whether the device is the same one sent to inputflinger for its layerstack.
518         // TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
519         device.setDisplayFlagsLocked(t,
520                 device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE
521                         ? SurfaceControl.DISPLAY_RECEIVES_INPUT : 0);
522 
523         // Set the color mode and allowed display mode.
524         if (device == mPrimaryDisplayDevice) {
525             device.setDesiredDisplayModeSpecsLocked(mDesiredDisplayModeSpecs);
526             device.setRequestedColorModeLocked(mRequestedColorMode);
527         } else {
528             // Reset to default for non primary displays
529             device.setDesiredDisplayModeSpecsLocked(
530                     new DisplayModeDirector.DesiredDisplayModeSpecs());
531             device.setRequestedColorModeLocked(0);
532         }
533 
534         device.setAutoLowLatencyModeLocked(mRequestedMinimalPostProcessing);
535         device.setGameContentTypeLocked(mRequestedMinimalPostProcessing);
536 
537         // Only grab the display info now as it may have been changed based on the requests above.
538         final DisplayInfo displayInfo = getDisplayInfoLocked();
539         final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
540 
541         // Set the viewport.
542         // This is the area of the logical display that we intend to show on the
543         // display device.  For now, it is always the full size of the logical display.
544         mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
545 
546         // Set the orientation.
547         // The orientation specifies how the physical coordinate system of the display
548         // is rotated when the contents of the logical display are rendered.
549         int orientation = Surface.ROTATION_0;
550         if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
551             orientation = displayInfo.rotation;
552         }
553 
554         // Apply the physical rotation of the display device itself.
555         orientation = (orientation + displayDeviceInfo.rotation) % 4;
556 
557         // Set the frame.
558         // The frame specifies the rotated physical coordinates into which the viewport
559         // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
560         // Currently we maximize the area to fill the display, but we could try to be
561         // more clever and match resolutions.
562         boolean rotated = (orientation == Surface.ROTATION_90
563                 || orientation == Surface.ROTATION_270);
564         int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
565         int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
566 
567         Rect maskingInsets = getMaskingInsets(displayDeviceInfo);
568         InsetUtils.rotateInsets(maskingInsets, orientation);
569         // Don't consider the masked area as available when calculating the scaling below.
570         physWidth -= maskingInsets.left + maskingInsets.right;
571         physHeight -= maskingInsets.top + maskingInsets.bottom;
572 
573         // Determine whether the width or height is more constrained to be scaled.
574         //    physWidth / displayInfo.logicalWidth    => letter box
575         // or physHeight / displayInfo.logicalHeight  => pillar box
576         //
577         // We avoid a division (and possible floating point imprecision) here by
578         // multiplying the fractions by the product of their denominators before
579         // comparing them.
580         int displayRectWidth, displayRectHeight;
581         if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0 || mDisplayScalingDisabled) {
582             displayRectWidth = displayInfo.logicalWidth;
583             displayRectHeight = displayInfo.logicalHeight;
584         } else if (physWidth * displayInfo.logicalHeight
585                 < physHeight * displayInfo.logicalWidth) {
586             // Letter box.
587             displayRectWidth = physWidth;
588             displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
589         } else {
590             // Pillar box.
591             displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
592             displayRectHeight = physHeight;
593         }
594         int displayRectTop = (physHeight - displayRectHeight) / 2;
595         int displayRectLeft = (physWidth - displayRectWidth) / 2;
596         mTempDisplayRect.set(displayRectLeft, displayRectTop,
597                 displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
598 
599         // Now add back the offset for the masked area.
600         mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);
601 
602         if (orientation == Surface.ROTATION_0) {
603             mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY);
604         } else if (orientation == Surface.ROTATION_90) {
605             mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX);
606         } else if (orientation == Surface.ROTATION_180) {
607             mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY);
608         } else {  // Surface.ROTATION_270
609             mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX);
610         }
611 
612         mDisplayPosition.set(mTempDisplayRect.left, mTempDisplayRect.top);
613         device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
614     }
615 
616     /**
617      * Returns true if the logical display has unique content.
618      * <p>
619      * If the display has unique content then we will try to ensure that it is
620      * visible on at least its primary display device.  Otherwise we will ignore the
621      * logical display and perhaps show mirrored content on the primary display device.
622      * </p>
623      *
624      * @return True if the display has unique content.
625      */
hasContentLocked()626     public boolean hasContentLocked() {
627         return mHasContent;
628     }
629 
630     /**
631      * Sets whether the logical display has unique content.
632      *
633      * @param hasContent True if the display has unique content.
634      */
setHasContentLocked(boolean hasContent)635     public void setHasContentLocked(boolean hasContent) {
636         mHasContent = hasContent;
637     }
638 
639     /**
640      * Sets the display configs the system can use.
641      */
setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs specs)642     public void setDesiredDisplayModeSpecsLocked(
643             DisplayModeDirector.DesiredDisplayModeSpecs specs) {
644         mDesiredDisplayModeSpecs = specs;
645     }
646 
647     /**
648      * Returns the display configs the system can choose.
649      */
getDesiredDisplayModeSpecsLocked()650     public DisplayModeDirector.DesiredDisplayModeSpecs getDesiredDisplayModeSpecsLocked() {
651         return mDesiredDisplayModeSpecs;
652     }
653 
654     /**
655      * Requests the given color mode.
656      */
setRequestedColorModeLocked(int colorMode)657     public void setRequestedColorModeLocked(int colorMode) {
658         mRequestedColorMode = colorMode;
659     }
660 
661     /**
662      * Returns the last requested minimal post processing setting.
663      */
getRequestedMinimalPostProcessingLocked()664     public boolean getRequestedMinimalPostProcessingLocked() {
665         return mRequestedMinimalPostProcessing;
666     }
667 
668     /**
669      * Instructs the connected display to do minimal post processing. This is implemented either
670      * via HDMI 2.1 ALLM or HDMI 1.4 ContentType=Game.
671      *
672      * @param on Whether to set minimal post processing on/off on the connected display.
673      */
setRequestedMinimalPostProcessingLocked(boolean on)674     public void setRequestedMinimalPostProcessingLocked(boolean on) {
675         mRequestedMinimalPostProcessing = on;
676     }
677 
678     /** Returns the pending requested color mode. */
getRequestedColorModeLocked()679     public int getRequestedColorModeLocked() {
680         return mRequestedColorMode;
681     }
682 
683     /**
684      * Gets the burn-in offset in X.
685      */
getDisplayOffsetXLocked()686     public int getDisplayOffsetXLocked() {
687         return mDisplayOffsetX;
688     }
689 
690     /**
691      * Gets the burn-in offset in Y.
692      */
getDisplayOffsetYLocked()693     public int getDisplayOffsetYLocked() {
694         return mDisplayOffsetY;
695     }
696 
697     /**
698      * Sets the burn-in offsets.
699      */
setDisplayOffsetsLocked(int x, int y)700     public void setDisplayOffsetsLocked(int x, int y) {
701         mDisplayOffsetX = x;
702         mDisplayOffsetY = y;
703     }
704 
705     /**
706      * @return {@code true} if display scaling is disabled, or {@code false} if the default scaling
707      * mode is used.
708      */
isDisplayScalingDisabled()709     public boolean isDisplayScalingDisabled() {
710         return mDisplayScalingDisabled;
711     }
712 
713     /**
714      * Disables scaling for a display.
715      *
716      * @param disableScaling {@code true} to disable scaling,
717      * {@code false} to use the default scaling behavior of the logical display.
718      */
setDisplayScalingDisabledLocked(boolean disableScaling)719     public void setDisplayScalingDisabledLocked(boolean disableScaling) {
720         mDisplayScalingDisabled = disableScaling;
721     }
722 
setUserDisabledHdrTypes(@onNull int[] userDisabledHdrTypes)723     public void setUserDisabledHdrTypes(@NonNull int[] userDisabledHdrTypes) {
724         if (mUserDisabledHdrTypes != userDisabledHdrTypes) {
725             mUserDisabledHdrTypes = userDisabledHdrTypes;
726             mBaseDisplayInfo.userDisabledHdrTypes = userDisabledHdrTypes;
727             mInfo.set(null);
728         }
729     }
730 
731     /**
732      * Swap the underlying {@link DisplayDevice} with the specified LogicalDisplay.
733      *
734      * @param targetDisplay The display with which to swap display-devices.
735      * @return {@code true} if the displays were swapped, {@code false} otherwise.
736      */
swapDisplaysLocked(@onNull LogicalDisplay targetDisplay)737     public void swapDisplaysLocked(@NonNull LogicalDisplay targetDisplay) {
738         final DisplayDevice oldTargetDevice =
739                 targetDisplay.setPrimaryDisplayDeviceLocked(mPrimaryDisplayDevice);
740         setPrimaryDisplayDeviceLocked(oldTargetDevice);
741     }
742 
743     /**
744      * Sets the primary display device to the specified device.
745      *
746      * @param device The new device to set.
747      * @return The previously set display device.
748      */
setPrimaryDisplayDeviceLocked(@ullable DisplayDevice device)749     public DisplayDevice setPrimaryDisplayDeviceLocked(@Nullable DisplayDevice device) {
750         final DisplayDevice old = mPrimaryDisplayDevice;
751         mPrimaryDisplayDevice = device;
752 
753         // Reset all our display info data
754         mPrimaryDisplayDeviceInfo = null;
755         mBaseDisplayInfo.copyFrom(EMPTY_DISPLAY_INFO);
756         mInfo.set(null);
757 
758         return old;
759     }
760 
setPhase(@isplayPhase int phase)761     public void setPhase(@DisplayPhase int phase) {
762         mPhase = phase;
763     }
764 
765     /**
766      * Returns the currently set phase for this LogicalDisplay. Phases are used when transitioning
767      * from one device state to another. {@see LogicalDisplayMapper}.
768      */
769     @DisplayPhase
getPhase()770     public int getPhase() {
771         return mPhase;
772     }
773 
774     /**
775      * @return {@code true} if the LogicalDisplay is enabled or {@code false}
776      * if disabled indicating that the display should be hidden from the rest of the apps and
777      * framework.
778      */
isEnabled()779     public boolean isEnabled() {
780         // DISPLAY_PHASE_LAYOUT_TRANSITION is still considered an 'enabled' phase.
781         return mPhase == DISPLAY_PHASE_ENABLED || mPhase == DISPLAY_PHASE_LAYOUT_TRANSITION;
782     }
783 
dumpLocked(PrintWriter pw)784     public void dumpLocked(PrintWriter pw) {
785         pw.println("mDisplayId=" + mDisplayId);
786         pw.println("mPhase=" + mPhase);
787         pw.println("mLayerStack=" + mLayerStack);
788         pw.println("mHasContent=" + mHasContent);
789         pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}");
790         pw.println("mRequestedColorMode=" + mRequestedColorMode);
791         pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
792         pw.println("mDisplayScalingDisabled=" + mDisplayScalingDisabled);
793         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
794                 mPrimaryDisplayDevice.getNameLocked() : "null"));
795         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
796         pw.println("mOverrideDisplayInfo=" + mOverrideDisplayInfo);
797         pw.println("mRequestedMinimalPostProcessing=" + mRequestedMinimalPostProcessing);
798         pw.println("mFrameRateOverrides=" + Arrays.toString(mFrameRateOverrides));
799         pw.println("mPendingFrameRateOverrideUids=" + mPendingFrameRateOverrideUids);
800     }
801 
802     @Override
toString()803     public String toString() {
804         StringWriter sw = new StringWriter();
805         dumpLocked(new PrintWriter(sw));
806         return sw.toString();
807     }
808 }
809