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