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 android.view;
18 
19 import static android.view.DisplayInfoProto.APP_HEIGHT;
20 import static android.view.DisplayInfoProto.APP_WIDTH;
21 import static android.view.DisplayInfoProto.CUTOUT;
22 import static android.view.DisplayInfoProto.FLAGS;
23 import static android.view.DisplayInfoProto.LOGICAL_HEIGHT;
24 import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
25 import static android.view.DisplayInfoProto.NAME;
26 
27 import android.annotation.NonNull;
28 import android.annotation.Nullable;
29 import android.app.WindowConfiguration;
30 import android.compat.annotation.UnsupportedAppUsage;
31 import android.content.res.CompatibilityInfo;
32 import android.content.res.Configuration;
33 import android.graphics.Rect;
34 import android.hardware.display.DeviceProductInfo;
35 import android.os.Build;
36 import android.os.Parcel;
37 import android.os.Parcelable;
38 import android.os.Process;
39 import android.util.ArraySet;
40 import android.util.DisplayMetrics;
41 import android.util.SparseArray;
42 import android.util.proto.ProtoOutputStream;
43 
44 import com.android.internal.display.BrightnessSynchronizer;
45 
46 import java.util.Arrays;
47 import java.util.Objects;
48 
49 /**
50  * Describes the characteristics of a particular logical display.
51  * @hide
52  */
53 public final class DisplayInfo implements Parcelable {
54     /**
55      * The surface flinger layer stack associated with this logical display.
56      */
57     public int layerStack;
58 
59     /**
60      * Display flags.
61      */
62     public int flags;
63 
64     /**
65      * Display type.
66      */
67     public int type;
68 
69     /**
70      * Logical display identifier.
71      */
72     public int displayId;
73 
74     /**
75      * Display Group identifier.
76      */
77     public int displayGroupId;
78 
79     /**
80      * Display address, or null if none.
81      * Interpretation varies by display type.
82      */
83     public DisplayAddress address;
84 
85     /**
86      * Product-specific information about the display or the directly connected device on the
87      * display chain. For example, if the display is transitively connected, this field may contain
88      * product information about the intermediate device.
89      */
90     public DeviceProductInfo deviceProductInfo;
91 
92     /**
93      * The human-readable name of the display.
94      */
95     public String name;
96 
97     /**
98      * Unique identifier for the display. Shouldn't be displayed to the user.
99      */
100     public String uniqueId;
101 
102     /**
103      * The width of the portion of the display that is available to applications, in pixels.
104      * Represents the size of the display minus any system decorations.
105      */
106     public int appWidth;
107 
108     /**
109      * The height of the portion of the display that is available to applications, in pixels.
110      * Represents the size of the display minus any system decorations.
111      */
112     public int appHeight;
113 
114     /**
115      * The smallest value of {@link #appWidth} that an application is likely to encounter,
116      * in pixels, excepting cases where the width may be even smaller due to the presence
117      * of a soft keyboard, for example.
118      */
119     public int smallestNominalAppWidth;
120 
121     /**
122      * The smallest value of {@link #appHeight} that an application is likely to encounter,
123      * in pixels, excepting cases where the height may be even smaller due to the presence
124      * of a soft keyboard, for example.
125      */
126     public int smallestNominalAppHeight;
127 
128     /**
129      * The largest value of {@link #appWidth} that an application is likely to encounter,
130      * in pixels, excepting cases where the width may be even larger due to system decorations
131      * such as the status bar being hidden, for example.
132      */
133     public int largestNominalAppWidth;
134 
135     /**
136      * The largest value of {@link #appHeight} that an application is likely to encounter,
137      * in pixels, excepting cases where the height may be even larger due to system decorations
138      * such as the status bar being hidden, for example.
139      */
140     public int largestNominalAppHeight;
141 
142     /**
143      * The logical width of the display, in pixels.
144      * Represents the usable size of the display which may be smaller than the
145      * physical size when the system is emulating a smaller display.
146      */
147     @UnsupportedAppUsage
148     public int logicalWidth;
149 
150     /**
151      * The logical height of the display, in pixels.
152      * Represents the usable size of the display which may be smaller than the
153      * physical size when the system is emulating a smaller display.
154      */
155     @UnsupportedAppUsage
156     public int logicalHeight;
157 
158     /**
159      * The {@link DisplayCutout} if present, otherwise {@code null}.
160      *
161      * @hide
162      */
163     // Remark on @UnsupportedAppUsage: Display.getCutout should be used instead
164     @Nullable
165     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
166     public DisplayCutout displayCutout;
167 
168     /**
169      * The rotation of the display relative to its natural orientation.
170      * May be one of {@link android.view.Surface#ROTATION_0},
171      * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
172      * {@link android.view.Surface#ROTATION_270}.
173      * <p>
174      * The value of this field is indeterminate if the logical display is presented on
175      * more than one physical display.
176      * </p>
177      */
178     @Surface.Rotation
179     @UnsupportedAppUsage
180     public int rotation;
181 
182     /**
183      * The active display mode.
184      */
185     public int modeId;
186 
187     /**
188      * The render frame rate this display is scheduled at, which is a divisor of the active mode
189      * refresh rate. This is the rate SurfaceFlinger would consume frames and would be observable
190      * by applications via the cadence of {@link android.view.Choreographer} callbacks and
191      * by backpressure when submitting buffers as fast as possible.
192      * Apps can call {@link android.view.Display#getRefreshRate} to query this value.
193      *
194      */
195     public float renderFrameRate;
196 
197     /**
198      * The default display mode.
199      */
200     public int defaultModeId;
201 
202     /**
203      * The supported modes of this display.
204      */
205     public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
206 
207     /** The active color mode. */
208     public int colorMode;
209 
210     /** The list of supported color modes */
211     public int[] supportedColorModes = { Display.COLOR_MODE_DEFAULT };
212 
213     /** The display's HDR capabilities */
214     public Display.HdrCapabilities hdrCapabilities;
215 
216     /** The formats disabled by user **/
217     public int[] userDisabledHdrTypes = {};
218 
219     /**
220      * Indicates whether the display can be switched into a mode with minimal post
221      * processing.
222      *
223      * @see android.view.Display#isMinimalPostProcessingSupported
224      */
225     public boolean minimalPostProcessingSupported;
226 
227     /**
228      * The logical display density which is the basis for density-independent
229      * pixels.
230      */
231     public int logicalDensityDpi;
232 
233     /**
234      * The exact physical pixels per inch of the screen in the X dimension.
235      * <p>
236      * The value of this field is indeterminate if the logical display is presented on
237      * more than one physical display.
238      * </p>
239      */
240     public float physicalXDpi;
241 
242     /**
243      * The exact physical pixels per inch of the screen in the Y dimension.
244      * <p>
245      * The value of this field is indeterminate if the logical display is presented on
246      * more than one physical display.
247      * </p>
248      */
249     public float physicalYDpi;
250 
251     /**
252      * This is a positive value indicating the phase offset of the VSYNC events provided by
253      * Choreographer relative to the display refresh.  For example, if Choreographer reports
254      * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
255      */
256     public long appVsyncOffsetNanos;
257 
258     /**
259      * This is how far in advance a buffer must be queued for presentation at
260      * a given time.  If you want a buffer to appear on the screen at
261      * time N, you must submit the buffer before (N - bufferDeadlineNanos).
262      */
263     public long presentationDeadlineNanos;
264 
265     /**
266      * The state of the display, such as {@link android.view.Display#STATE_ON}.
267      */
268     public int state;
269 
270     /**
271      * The current committed state of the display. For example, this becomes
272      * {@link android.view.Display#STATE_ON} only after the power state ON is fully committed.
273      */
274     public int committedState;
275 
276     /**
277      * The UID of the application that owns this display, or zero if it is owned by the system.
278      * <p>
279      * If the display is private, then only the owner can use it.
280      * </p>
281      */
282     public int ownerUid;
283 
284     /**
285      * The package name of the application that owns this display, or null if it is
286      * owned by the system.
287      * <p>
288      * If the display is private, then only the owner can use it.
289      * </p>
290      */
291     public String ownerPackageName;
292 
293     /**
294      * The refresh rate override for this app. 0 means no override.
295      */
296     public float refreshRateOverride;
297 
298     /**
299      * @hide
300      * Get current remove mode of the display - what actions should be performed with the display's
301      * content when it is removed.
302      *
303      * @see Display#getRemoveMode()
304      */
305     // TODO (b/114338689): Remove the flag and use IWindowManager#getRemoveContentMode
306     public int removeMode = Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY;
307 
308     /**
309      * @hide
310      * The current minimum brightness constraint of the display. Value between 0.0 and 1.0,
311      * derived from the config constraints of the display device of this logical display.
312      */
313     public float brightnessMinimum;
314 
315     /**
316      * @hide
317      * The current maximum brightness constraint of the display. Value between 0.0 and 1.0,
318      * derived from the config constraints of the display device of this logical display.
319      */
320     public float brightnessMaximum;
321 
322     /**
323      * @hide
324      * The current default brightness of the display. Value between 0.0 and 1.0,
325      * derived from the configuration of the display device of this logical display.
326      */
327     public float brightnessDefault;
328 
329     /**
330      * The {@link RoundedCorners} if present, otherwise {@code null}.
331      */
332     @Nullable
333     public RoundedCorners roundedCorners;
334 
335     /**
336      * Install orientation of the display relative to its natural orientation.
337      */
338     @Surface.Rotation
339     public int installOrientation;
340 
341     @Nullable
342     public DisplayShape displayShape;
343 
344     /**
345      * Refresh rate range limitation based on the current device layout
346      */
347     @Nullable
348     public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate;
349 
350     /**
351      * The current hdr/sdr ratio for the display. If the display doesn't support hdr/sdr ratio
352      * queries then this is NaN
353      */
354     public float hdrSdrRatio = Float.NaN;
355 
356     /**
357      * RefreshRateRange limitation for @Temperature.ThrottlingStatus
358      */
359     @NonNull
360     public SparseArray<SurfaceControl.RefreshRateRange> thermalRefreshRateThrottling =
361             new SparseArray<>();
362 
363     /**
364      * The ID of the brightness throttling data that should be used. This can change e.g. in
365      * concurrent displays mode in which a stricter brightness throttling policy might need to be
366      * used.
367      */
368     @Nullable
369     public String thermalBrightnessThrottlingDataId;
370 
371     public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
372         @Override
373         public DisplayInfo createFromParcel(Parcel source) {
374             return new DisplayInfo(source);
375         }
376 
377         @Override
378         public DisplayInfo[] newArray(int size) {
379             return new DisplayInfo[size];
380         }
381     };
382 
383     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769467)
DisplayInfo()384     public DisplayInfo() {
385     }
386 
DisplayInfo(DisplayInfo other)387     public DisplayInfo(DisplayInfo other) {
388         copyFrom(other);
389     }
390 
DisplayInfo(Parcel source)391     private DisplayInfo(Parcel source) {
392         readFromParcel(source);
393     }
394 
395     @Override
equals(@ullable Object o)396     public boolean equals(@Nullable Object o) {
397         return o instanceof DisplayInfo && equals((DisplayInfo)o);
398     }
399 
equals(DisplayInfo other)400     public boolean equals(DisplayInfo other) {
401         return other != null
402                 && layerStack == other.layerStack
403                 && flags == other.flags
404                 && type == other.type
405                 && displayId == other.displayId
406                 && displayGroupId == other.displayGroupId
407                 && Objects.equals(address, other.address)
408                 && Objects.equals(deviceProductInfo, other.deviceProductInfo)
409                 && Objects.equals(uniqueId, other.uniqueId)
410                 && appWidth == other.appWidth
411                 && appHeight == other.appHeight
412                 && smallestNominalAppWidth == other.smallestNominalAppWidth
413                 && smallestNominalAppHeight == other.smallestNominalAppHeight
414                 && largestNominalAppWidth == other.largestNominalAppWidth
415                 && largestNominalAppHeight == other.largestNominalAppHeight
416                 && logicalWidth == other.logicalWidth
417                 && logicalHeight == other.logicalHeight
418                 && Objects.equals(displayCutout, other.displayCutout)
419                 && rotation == other.rotation
420                 && modeId == other.modeId
421                 && renderFrameRate == other.renderFrameRate
422                 && defaultModeId == other.defaultModeId
423                 && Arrays.equals(supportedModes, other.supportedModes)
424                 && colorMode == other.colorMode
425                 && Arrays.equals(supportedColorModes, other.supportedColorModes)
426                 && Objects.equals(hdrCapabilities, other.hdrCapabilities)
427                 && Arrays.equals(userDisabledHdrTypes, other.userDisabledHdrTypes)
428                 && minimalPostProcessingSupported == other.minimalPostProcessingSupported
429                 && logicalDensityDpi == other.logicalDensityDpi
430                 && physicalXDpi == other.physicalXDpi
431                 && physicalYDpi == other.physicalYDpi
432                 && appVsyncOffsetNanos == other.appVsyncOffsetNanos
433                 && presentationDeadlineNanos == other.presentationDeadlineNanos
434                 && state == other.state
435                 && committedState == other.committedState
436                 && ownerUid == other.ownerUid
437                 && Objects.equals(ownerPackageName, other.ownerPackageName)
438                 && removeMode == other.removeMode
439                 && getRefreshRate() == other.getRefreshRate()
440                 && brightnessMinimum == other.brightnessMinimum
441                 && brightnessMaximum == other.brightnessMaximum
442                 && brightnessDefault == other.brightnessDefault
443                 && Objects.equals(roundedCorners, other.roundedCorners)
444                 && installOrientation == other.installOrientation
445                 && Objects.equals(displayShape, other.displayShape)
446                 && Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
447                 && BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)
448                 && thermalRefreshRateThrottling.contentEquals(other.thermalRefreshRateThrottling)
449                 && Objects.equals(
450                 thermalBrightnessThrottlingDataId, other.thermalBrightnessThrottlingDataId);
451     }
452 
453     @Override
hashCode()454     public int hashCode() {
455         return 0; // don't care
456     }
457 
copyFrom(DisplayInfo other)458     public void copyFrom(DisplayInfo other) {
459         layerStack = other.layerStack;
460         flags = other.flags;
461         type = other.type;
462         displayId = other.displayId;
463         displayGroupId = other.displayGroupId;
464         address = other.address;
465         deviceProductInfo = other.deviceProductInfo;
466         name = other.name;
467         uniqueId = other.uniqueId;
468         appWidth = other.appWidth;
469         appHeight = other.appHeight;
470         smallestNominalAppWidth = other.smallestNominalAppWidth;
471         smallestNominalAppHeight = other.smallestNominalAppHeight;
472         largestNominalAppWidth = other.largestNominalAppWidth;
473         largestNominalAppHeight = other.largestNominalAppHeight;
474         logicalWidth = other.logicalWidth;
475         logicalHeight = other.logicalHeight;
476         displayCutout = other.displayCutout;
477         rotation = other.rotation;
478         modeId = other.modeId;
479         renderFrameRate = other.renderFrameRate;
480         defaultModeId = other.defaultModeId;
481         supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
482         colorMode = other.colorMode;
483         supportedColorModes = Arrays.copyOf(
484                 other.supportedColorModes, other.supportedColorModes.length);
485         hdrCapabilities = other.hdrCapabilities;
486         userDisabledHdrTypes = other.userDisabledHdrTypes;
487         minimalPostProcessingSupported = other.minimalPostProcessingSupported;
488         logicalDensityDpi = other.logicalDensityDpi;
489         physicalXDpi = other.physicalXDpi;
490         physicalYDpi = other.physicalYDpi;
491         appVsyncOffsetNanos = other.appVsyncOffsetNanos;
492         presentationDeadlineNanos = other.presentationDeadlineNanos;
493         state = other.state;
494         committedState = other.committedState;
495         ownerUid = other.ownerUid;
496         ownerPackageName = other.ownerPackageName;
497         removeMode = other.removeMode;
498         refreshRateOverride = other.refreshRateOverride;
499         brightnessMinimum = other.brightnessMinimum;
500         brightnessMaximum = other.brightnessMaximum;
501         brightnessDefault = other.brightnessDefault;
502         roundedCorners = other.roundedCorners;
503         installOrientation = other.installOrientation;
504         displayShape = other.displayShape;
505         layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
506         hdrSdrRatio = other.hdrSdrRatio;
507         thermalRefreshRateThrottling = other.thermalRefreshRateThrottling;
508         thermalBrightnessThrottlingDataId = other.thermalBrightnessThrottlingDataId;
509     }
510 
readFromParcel(Parcel source)511     public void readFromParcel(Parcel source) {
512         layerStack = source.readInt();
513         flags = source.readInt();
514         type = source.readInt();
515         displayId = source.readInt();
516         displayGroupId = source.readInt();
517         address = source.readParcelable(null, android.view.DisplayAddress.class);
518         deviceProductInfo = source.readParcelable(null, android.hardware.display.DeviceProductInfo.class);
519         name = source.readString8();
520         appWidth = source.readInt();
521         appHeight = source.readInt();
522         smallestNominalAppWidth = source.readInt();
523         smallestNominalAppHeight = source.readInt();
524         largestNominalAppWidth = source.readInt();
525         largestNominalAppHeight = source.readInt();
526         logicalWidth = source.readInt();
527         logicalHeight = source.readInt();
528         displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
529         rotation = source.readInt();
530         modeId = source.readInt();
531         renderFrameRate = source.readFloat();
532         defaultModeId = source.readInt();
533         int nModes = source.readInt();
534         supportedModes = new Display.Mode[nModes];
535         for (int i = 0; i < nModes; i++) {
536             supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
537         }
538         colorMode = source.readInt();
539         int nColorModes = source.readInt();
540         supportedColorModes = new int[nColorModes];
541         for (int i = 0; i < nColorModes; i++) {
542             supportedColorModes[i] = source.readInt();
543         }
544         hdrCapabilities = source.readParcelable(null, android.view.Display.HdrCapabilities.class);
545         minimalPostProcessingSupported = source.readBoolean();
546         logicalDensityDpi = source.readInt();
547         physicalXDpi = source.readFloat();
548         physicalYDpi = source.readFloat();
549         appVsyncOffsetNanos = source.readLong();
550         presentationDeadlineNanos = source.readLong();
551         state = source.readInt();
552         committedState = source.readInt();
553         ownerUid = source.readInt();
554         ownerPackageName = source.readString8();
555         uniqueId = source.readString8();
556         removeMode = source.readInt();
557         refreshRateOverride = source.readFloat();
558         brightnessMinimum = source.readFloat();
559         brightnessMaximum = source.readFloat();
560         brightnessDefault = source.readFloat();
561         roundedCorners = source.readTypedObject(RoundedCorners.CREATOR);
562         int numUserDisabledFormats = source.readInt();
563         userDisabledHdrTypes = new int[numUserDisabledFormats];
564         for (int i = 0; i < numUserDisabledFormats; i++) {
565             userDisabledHdrTypes[i] = source.readInt();
566         }
567         installOrientation = source.readInt();
568         displayShape = source.readTypedObject(DisplayShape.CREATOR);
569         layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
570         hdrSdrRatio = source.readFloat();
571         thermalRefreshRateThrottling = source.readSparseArray(null,
572                 SurfaceControl.RefreshRateRange.class);
573         thermalBrightnessThrottlingDataId = source.readString8();
574     }
575 
576     @Override
writeToParcel(Parcel dest, int flags)577     public void writeToParcel(Parcel dest, int flags) {
578         dest.writeInt(layerStack);
579         dest.writeInt(this.flags);
580         dest.writeInt(type);
581         dest.writeInt(displayId);
582         dest.writeInt(displayGroupId);
583         dest.writeParcelable(address, flags);
584         dest.writeParcelable(deviceProductInfo, flags);
585         dest.writeString8(name);
586         dest.writeInt(appWidth);
587         dest.writeInt(appHeight);
588         dest.writeInt(smallestNominalAppWidth);
589         dest.writeInt(smallestNominalAppHeight);
590         dest.writeInt(largestNominalAppWidth);
591         dest.writeInt(largestNominalAppHeight);
592         dest.writeInt(logicalWidth);
593         dest.writeInt(logicalHeight);
594         DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
595         dest.writeInt(rotation);
596         dest.writeInt(modeId);
597         dest.writeFloat(renderFrameRate);
598         dest.writeInt(defaultModeId);
599         dest.writeInt(supportedModes.length);
600         for (int i = 0; i < supportedModes.length; i++) {
601             supportedModes[i].writeToParcel(dest, flags);
602         }
603         dest.writeInt(colorMode);
604         dest.writeInt(supportedColorModes.length);
605         for (int i = 0; i < supportedColorModes.length; i++) {
606             dest.writeInt(supportedColorModes[i]);
607         }
608         dest.writeParcelable(hdrCapabilities, flags);
609         dest.writeBoolean(minimalPostProcessingSupported);
610         dest.writeInt(logicalDensityDpi);
611         dest.writeFloat(physicalXDpi);
612         dest.writeFloat(physicalYDpi);
613         dest.writeLong(appVsyncOffsetNanos);
614         dest.writeLong(presentationDeadlineNanos);
615         dest.writeInt(state);
616         dest.writeInt(committedState);
617         dest.writeInt(ownerUid);
618         dest.writeString8(ownerPackageName);
619         dest.writeString8(uniqueId);
620         dest.writeInt(removeMode);
621         dest.writeFloat(refreshRateOverride);
622         dest.writeFloat(brightnessMinimum);
623         dest.writeFloat(brightnessMaximum);
624         dest.writeFloat(brightnessDefault);
625         dest.writeTypedObject(roundedCorners, flags);
626         dest.writeInt(userDisabledHdrTypes.length);
627         for (int i = 0; i < userDisabledHdrTypes.length; i++) {
628             dest.writeInt(userDisabledHdrTypes[i]);
629         }
630         dest.writeInt(installOrientation);
631         dest.writeTypedObject(displayShape, flags);
632         dest.writeTypedObject(layoutLimitedRefreshRate, flags);
633         dest.writeFloat(hdrSdrRatio);
634         dest.writeSparseArray(thermalRefreshRateThrottling);
635         dest.writeString8(thermalBrightnessThrottlingDataId);
636     }
637 
638     @Override
describeContents()639     public int describeContents() {
640         return 0;
641     }
642 
643     /**
644      * Returns the refresh rate the application would experience.
645      */
getRefreshRate()646     public float getRefreshRate() {
647         if (refreshRateOverride > 0) {
648             return refreshRateOverride;
649         }
650         if (supportedModes.length == 0) {
651             return 0;
652         }
653         return getMode().getRefreshRate();
654     }
655 
getMode()656     public Display.Mode getMode() {
657         return findMode(modeId);
658     }
659 
getDefaultMode()660     public Display.Mode getDefaultMode() {
661         return findMode(defaultModeId);
662     }
663 
findMode(int id)664     private Display.Mode findMode(int id) {
665         for (int i = 0; i < supportedModes.length; i++) {
666             if (supportedModes[i].getModeId() == id) {
667                 return supportedModes[i];
668             }
669         }
670         throw new IllegalStateException(
671                 "Unable to locate mode id=" + id + ",supportedModes=" + Arrays.toString(
672                         supportedModes));
673     }
674 
675     /**
676      * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable
677      * mode could be found.
678      */
679     @Nullable
findDefaultModeByRefreshRate(float refreshRate)680     public Display.Mode findDefaultModeByRefreshRate(float refreshRate) {
681         Display.Mode[] modes = supportedModes;
682         Display.Mode defaultMode = getDefaultMode();
683         for (int i = 0; i < modes.length; i++) {
684             if (modes[i].matches(
685                     defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) {
686                 return modes[i];
687             }
688         }
689         return null;
690     }
691 
692     /**
693      * Returns the list of supported refresh rates in the default mode.
694      */
getDefaultRefreshRates()695     public float[] getDefaultRefreshRates() {
696         Display.Mode[] modes = supportedModes;
697         ArraySet<Float> rates = new ArraySet<>();
698         Display.Mode defaultMode = getDefaultMode();
699         for (int i = 0; i < modes.length; i++) {
700             Display.Mode mode = modes[i];
701             if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth()
702                     && mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) {
703                 rates.add(mode.getRefreshRate());
704             }
705         }
706         float[] result = new float[rates.size()];
707         int i = 0;
708         for (Float rate : rates) {
709             result[i++] = rate;
710         }
711         return result;
712     }
713 
getAppMetrics(DisplayMetrics outMetrics)714     public void getAppMetrics(DisplayMetrics outMetrics) {
715         getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
716     }
717 
getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments)718     public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
719         getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
720                 displayAdjustments.getConfiguration(), appWidth, appHeight);
721     }
722 
getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci, Configuration configuration)723     public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
724             Configuration configuration) {
725         getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
726     }
727 
728     /**
729      * Populates {@code outMetrics} with details of the logical display. Bounds are limited
730      * by the logical size of the display.
731      *
732      * @param outMetrics the {@link DisplayMetrics} to be populated
733      * @param compatInfo the {@link CompatibilityInfo} to be applied
734      * @param configuration the {@link Configuration}
735      */
getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration)736     public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
737             Configuration configuration) {
738         getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
739     }
740 
741     /**
742      * Similar to {@link #getLogicalMetrics}, but the limiting bounds are determined from
743      * {@link WindowConfiguration#getMaxBounds()}
744      */
getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration)745     public void getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
746             Configuration configuration) {
747         Rect bounds = configuration.windowConfiguration.getMaxBounds();
748         // Pass in null configuration to ensure width and height are not overridden to app bounds.
749         getMetricsWithSize(outMetrics, compatInfo, /* configuration= */ null,
750                 bounds.width(), bounds.height());
751     }
752 
getNaturalWidth()753     public int getNaturalWidth() {
754         return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
755                 logicalWidth : logicalHeight;
756     }
757 
getNaturalHeight()758     public int getNaturalHeight() {
759         return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
760                 logicalHeight : logicalWidth;
761     }
762 
isHdr()763     public boolean isHdr() {
764         int[] types = hdrCapabilities != null ? hdrCapabilities.getSupportedHdrTypes() : null;
765         return types != null && types.length > 0;
766     }
767 
isWideColorGamut()768     public boolean isWideColorGamut() {
769         for (int colorMode : supportedColorModes) {
770             if (colorMode == Display.COLOR_MODE_DCI_P3 || colorMode > Display.COLOR_MODE_SRGB) {
771                 return true;
772             }
773         }
774         return false;
775     }
776 
777     /**
778      * Returns true if the specified UID has access to this display.
779      */
hasAccess(int uid)780     public boolean hasAccess(int uid) {
781         return Display.hasAccess(uid, flags, ownerUid, displayId);
782     }
783 
getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration, int width, int height)784     private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
785             Configuration configuration, int width, int height) {
786         outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
787         outMetrics.density = outMetrics.noncompatDensity =
788                 logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
789         outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
790         outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
791         outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
792 
793         final Rect appBounds = configuration != null
794                 ? configuration.windowConfiguration.getAppBounds() : null;
795         width = appBounds != null ? appBounds.width() : width;
796         height = appBounds != null ? appBounds.height() : height;
797 
798         outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
799         outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
800 
801         // Apply to size if the configuration is EMPTY because the size is from real display info.
802         final boolean applyToSize = configuration != null && appBounds == null;
803         compatInfo.applyDisplayMetricsIfNeeded(outMetrics, applyToSize);
804     }
805 
806     // For debugging purposes
807     @Override
toString()808     public String toString() {
809         StringBuilder sb = new StringBuilder();
810         sb.append("DisplayInfo{\"");
811         sb.append(name);
812         sb.append("\", displayId ");
813         sb.append(displayId);
814         sb.append(", displayGroupId ");
815         sb.append(displayGroupId);
816         sb.append(flagsToString(flags));
817         sb.append(", real ");
818         sb.append(logicalWidth);
819         sb.append(" x ");
820         sb.append(logicalHeight);
821         sb.append(", largest app ");
822         sb.append(largestNominalAppWidth);
823         sb.append(" x ");
824         sb.append(largestNominalAppHeight);
825         sb.append(", smallest app ");
826         sb.append(smallestNominalAppWidth);
827         sb.append(" x ");
828         sb.append(smallestNominalAppHeight);
829         sb.append(", appVsyncOff ");
830         sb.append(appVsyncOffsetNanos);
831         sb.append(", presDeadline ");
832         sb.append(presentationDeadlineNanos);
833         sb.append(", mode ");
834         sb.append(modeId);
835         sb.append(renderFrameRate);
836         sb.append(", defaultMode ");
837         sb.append(defaultModeId);
838         sb.append(", modes ");
839         sb.append(Arrays.toString(supportedModes));
840         sb.append(", hdrCapabilities ");
841         sb.append(hdrCapabilities);
842         sb.append(", userDisabledHdrTypes ");
843         sb.append(Arrays.toString(userDisabledHdrTypes));
844         sb.append(", minimalPostProcessingSupported ");
845         sb.append(minimalPostProcessingSupported);
846         sb.append(", rotation ");
847         sb.append(rotation);
848         sb.append(", state ");
849         sb.append(Display.stateToString(state));
850         sb.append(", committedState ");
851         sb.append(Display.stateToString(committedState));
852 
853         if (Process.myUid() != Process.SYSTEM_UID) {
854             sb.append("}");
855             return sb.toString();
856         }
857 
858         sb.append(", type ");
859         sb.append(Display.typeToString(type));
860         sb.append(", uniqueId \"");
861         sb.append(uniqueId);
862         sb.append("\", app ");
863         sb.append(appWidth);
864         sb.append(" x ");
865         sb.append(appHeight);
866         sb.append(", density ");
867         sb.append(logicalDensityDpi);
868         sb.append(" (");
869         sb.append(physicalXDpi);
870         sb.append(" x ");
871         sb.append(physicalYDpi);
872         sb.append(") dpi, layerStack ");
873         sb.append(layerStack);
874         sb.append(", colorMode ");
875         sb.append(colorMode);
876         sb.append(", supportedColorModes ");
877         sb.append(Arrays.toString(supportedColorModes));
878         if (address != null) {
879             sb.append(", address ").append(address);
880         }
881         sb.append(", deviceProductInfo ");
882         sb.append(deviceProductInfo);
883         if (ownerUid != 0 || ownerPackageName != null) {
884             sb.append(", owner ").append(ownerPackageName);
885             sb.append(" (uid ").append(ownerUid).append(")");
886         }
887         sb.append(", removeMode ");
888         sb.append(removeMode);
889         sb.append(", refreshRateOverride ");
890         sb.append(refreshRateOverride);
891         sb.append(", brightnessMinimum ");
892         sb.append(brightnessMinimum);
893         sb.append(", brightnessMaximum ");
894         sb.append(brightnessMaximum);
895         sb.append(", brightnessDefault ");
896         sb.append(brightnessDefault);
897         sb.append(", installOrientation ");
898         sb.append(Surface.rotationToString(installOrientation));
899         sb.append(", layoutLimitedRefreshRate ");
900         sb.append(layoutLimitedRefreshRate);
901         sb.append(", hdrSdrRatio ");
902         if (Float.isNaN(hdrSdrRatio)) {
903             sb.append("not_available");
904         } else {
905             sb.append(hdrSdrRatio);
906         }
907         sb.append(", thermalRefreshRateThrottling ");
908         sb.append(thermalRefreshRateThrottling);
909         sb.append(", thermalBrightnessThrottlingDataId ");
910         sb.append(thermalBrightnessThrottlingDataId);
911         sb.append("}");
912         return sb.toString();
913     }
914 
915     /**
916      * Write to a protocol buffer output stream.
917      * Protocol buffer message definition at {@link android.view.DisplayInfoProto}
918      *
919      * @param protoOutputStream Stream to write the Rect object to.
920      * @param fieldId           Field Id of the DisplayInfoProto as defined in the parent message
921      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId)922     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
923         final long token = protoOutputStream.start(fieldId);
924         protoOutputStream.write(LOGICAL_WIDTH, logicalWidth);
925         protoOutputStream.write(LOGICAL_HEIGHT, logicalHeight);
926         protoOutputStream.write(APP_WIDTH, appWidth);
927         protoOutputStream.write(APP_HEIGHT, appHeight);
928         protoOutputStream.write(NAME, name);
929         protoOutputStream.write(FLAGS, flags);
930         if (displayCutout != null) {
931             displayCutout.dumpDebug(protoOutputStream, CUTOUT);
932         }
933         protoOutputStream.end(token);
934     }
935 
flagsToString(int flags)936     private static String flagsToString(int flags) {
937         StringBuilder result = new StringBuilder();
938         if ((flags & Display.FLAG_SECURE) != 0) {
939             result.append(", FLAG_SECURE");
940         }
941         if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
942             result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
943         }
944         if ((flags & Display.FLAG_PRIVATE) != 0) {
945             result.append(", FLAG_PRIVATE");
946         }
947         if ((flags & Display.FLAG_PRESENTATION) != 0) {
948             result.append(", FLAG_PRESENTATION");
949         }
950         if ((flags & Display.FLAG_SCALING_DISABLED) != 0) {
951             result.append(", FLAG_SCALING_DISABLED");
952         }
953         if ((flags & Display.FLAG_ROUND) != 0) {
954             result.append(", FLAG_ROUND");
955         }
956         if ((flags & Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
957             result.append(", FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD");
958         }
959         if ((flags & Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) {
960             result.append(", FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS");
961         }
962         if ((flags & Display.FLAG_TRUSTED) != 0) {
963             result.append(", FLAG_TRUSTED");
964         }
965         if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) {
966             result.append(", FLAG_OWN_DISPLAY_GROUP");
967         }
968         if ((flags & Display.FLAG_ALWAYS_UNLOCKED) != 0) {
969             result.append(", FLAG_ALWAYS_UNLOCKED");
970         }
971         if ((flags & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
972             result.append(", FLAG_TOUCH_FEEDBACK_DISABLED");
973         }
974         if ((flags & Display.FLAG_REAR) != 0) {
975             result.append(", FLAG_REAR_DISPLAY");
976         }
977         return result.toString();
978     }
979 }
980