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.FLAGS;
22 import static android.view.DisplayInfoProto.LOGICAL_HEIGHT;
23 import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
24 import static android.view.DisplayInfoProto.NAME;
25 
26 import android.annotation.Nullable;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.res.CompatibilityInfo;
29 import android.content.res.Configuration;
30 import android.graphics.Rect;
31 import android.hardware.display.DeviceProductInfo;
32 import android.os.Build;
33 import android.os.Parcel;
34 import android.os.Parcelable;
35 import android.os.Process;
36 import android.util.ArraySet;
37 import android.util.DisplayMetrics;
38 import android.util.proto.ProtoOutputStream;
39 
40 import java.util.Arrays;
41 import java.util.Objects;
42 
43 /**
44  * Describes the characteristics of a particular logical display.
45  * @hide
46  */
47 public final class DisplayInfo implements Parcelable {
48     /**
49      * The surface flinger layer stack associated with this logical display.
50      */
51     public int layerStack;
52 
53     /**
54      * Display flags.
55      */
56     public int flags;
57 
58     /**
59      * Display type.
60      */
61     public int type;
62 
63     /**
64      * Logical display identifier.
65      */
66     public int displayId;
67 
68     /**
69      * Display address, or null if none.
70      * Interpretation varies by display type.
71      */
72     public DisplayAddress address;
73 
74     /**
75      * Product-specific information about the display or the directly connected device on the
76      * display chain. For example, if the display is transitively connected, this field may contain
77      * product information about the intermediate device.
78      */
79     public DeviceProductInfo deviceProductInfo;
80 
81     /**
82      * The human-readable name of the display.
83      */
84     public String name;
85 
86     /**
87      * Unique identifier for the display. Shouldn't be displayed to the user.
88      */
89     public String uniqueId;
90 
91     /**
92      * The width of the portion of the display that is available to applications, in pixels.
93      * Represents the size of the display minus any system decorations.
94      */
95     public int appWidth;
96 
97     /**
98      * The height of the portion of the display that is available to applications, in pixels.
99      * Represents the size of the display minus any system decorations.
100      */
101     public int appHeight;
102 
103     /**
104      * The smallest value of {@link #appWidth} that an application is likely to encounter,
105      * in pixels, excepting cases where the width may be even smaller due to the presence
106      * of a soft keyboard, for example.
107      */
108     public int smallestNominalAppWidth;
109 
110     /**
111      * The smallest value of {@link #appHeight} that an application is likely to encounter,
112      * in pixels, excepting cases where the height may be even smaller due to the presence
113      * of a soft keyboard, for example.
114      */
115     public int smallestNominalAppHeight;
116 
117     /**
118      * The largest value of {@link #appWidth} that an application is likely to encounter,
119      * in pixels, excepting cases where the width may be even larger due to system decorations
120      * such as the status bar being hidden, for example.
121      */
122     public int largestNominalAppWidth;
123 
124     /**
125      * The largest value of {@link #appHeight} that an application is likely to encounter,
126      * in pixels, excepting cases where the height may be even larger due to system decorations
127      * such as the status bar being hidden, for example.
128      */
129     public int largestNominalAppHeight;
130 
131     /**
132      * The logical width of the display, in pixels.
133      * Represents the usable size of the display which may be smaller than the
134      * physical size when the system is emulating a smaller display.
135      */
136     @UnsupportedAppUsage
137     public int logicalWidth;
138 
139     /**
140      * The logical height of the display, in pixels.
141      * Represents the usable size of the display which may be smaller than the
142      * physical size when the system is emulating a smaller display.
143      */
144     @UnsupportedAppUsage
145     public int logicalHeight;
146 
147     /**
148      * The {@link DisplayCutout} if present, otherwise {@code null}.
149      *
150      * @hide
151      */
152     // Remark on @UnsupportedAppUsage: Display.getCutout should be used instead
153     @Nullable
154     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
155     public DisplayCutout displayCutout;
156 
157     /**
158      * The rotation of the display relative to its natural orientation.
159      * May be one of {@link android.view.Surface#ROTATION_0},
160      * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
161      * {@link android.view.Surface#ROTATION_270}.
162      * <p>
163      * The value of this field is indeterminate if the logical display is presented on
164      * more than one physical display.
165      * </p>
166      */
167     @Surface.Rotation
168     @UnsupportedAppUsage
169     public int rotation;
170 
171     /**
172      * The active display mode.
173      */
174     public int modeId;
175 
176     /**
177      * The default display mode.
178      */
179     public int defaultModeId;
180 
181     /**
182      * The supported modes of this display.
183      */
184     public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
185 
186     /** The active color mode. */
187     public int colorMode;
188 
189     /** The list of supported color modes */
190     public int[] supportedColorModes = { Display.COLOR_MODE_DEFAULT };
191 
192     /** The display's HDR capabilities */
193     public Display.HdrCapabilities hdrCapabilities;
194 
195     /**
196      * Indicates whether the display can be switched into a mode with minimal post
197      * processing.
198      *
199      * @see android.view.Display#isMinimalPostProcessingSupported
200      */
201     public boolean minimalPostProcessingSupported;
202 
203     /**
204      * The logical display density which is the basis for density-independent
205      * pixels.
206      */
207     public int logicalDensityDpi;
208 
209     /**
210      * The exact physical pixels per inch of the screen in the X dimension.
211      * <p>
212      * The value of this field is indeterminate if the logical display is presented on
213      * more than one physical display.
214      * </p>
215      */
216     public float physicalXDpi;
217 
218     /**
219      * The exact physical pixels per inch of the screen in the Y dimension.
220      * <p>
221      * The value of this field is indeterminate if the logical display is presented on
222      * more than one physical display.
223      * </p>
224      */
225     public float physicalYDpi;
226 
227     /**
228      * This is a positive value indicating the phase offset of the VSYNC events provided by
229      * Choreographer relative to the display refresh.  For example, if Choreographer reports
230      * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
231      */
232     public long appVsyncOffsetNanos;
233 
234     /**
235      * This is how far in advance a buffer must be queued for presentation at
236      * a given time.  If you want a buffer to appear on the screen at
237      * time N, you must submit the buffer before (N - bufferDeadlineNanos).
238      */
239     public long presentationDeadlineNanos;
240 
241     /**
242      * The state of the display, such as {@link android.view.Display#STATE_ON}.
243      */
244     public int state;
245 
246     /**
247      * The UID of the application that owns this display, or zero if it is owned by the system.
248      * <p>
249      * If the display is private, then only the owner can use it.
250      * </p>
251      */
252     public int ownerUid;
253 
254     /**
255      * The package name of the application that owns this display, or null if it is
256      * owned by the system.
257      * <p>
258      * If the display is private, then only the owner can use it.
259      * </p>
260      */
261     public String ownerPackageName;
262 
263     /**
264      * @hide
265      * Get current remove mode of the display - what actions should be performed with the display's
266      * content when it is removed.
267      *
268      * @see Display#getRemoveMode()
269      */
270     // TODO (b/114338689): Remove the flag and use IWindowManager#getRemoveContentMode
271     public int removeMode = Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY;
272 
273     public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
274         @Override
275         public DisplayInfo createFromParcel(Parcel source) {
276             return new DisplayInfo(source);
277         }
278 
279         @Override
280         public DisplayInfo[] newArray(int size) {
281             return new DisplayInfo[size];
282         }
283     };
284 
285     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769467)
DisplayInfo()286     public DisplayInfo() {
287     }
288 
DisplayInfo(DisplayInfo other)289     public DisplayInfo(DisplayInfo other) {
290         copyFrom(other);
291     }
292 
DisplayInfo(Parcel source)293     private DisplayInfo(Parcel source) {
294         readFromParcel(source);
295     }
296 
297     @Override
equals(Object o)298     public boolean equals(Object o) {
299         return o instanceof DisplayInfo && equals((DisplayInfo)o);
300     }
301 
equals(DisplayInfo other)302     public boolean equals(DisplayInfo other) {
303         return other != null
304                 && layerStack == other.layerStack
305                 && flags == other.flags
306                 && type == other.type
307                 && displayId == other.displayId
308                 && Objects.equals(address, other.address)
309                 && Objects.equals(deviceProductInfo, other.deviceProductInfo)
310                 && Objects.equals(uniqueId, other.uniqueId)
311                 && appWidth == other.appWidth
312                 && appHeight == other.appHeight
313                 && smallestNominalAppWidth == other.smallestNominalAppWidth
314                 && smallestNominalAppHeight == other.smallestNominalAppHeight
315                 && largestNominalAppWidth == other.largestNominalAppWidth
316                 && largestNominalAppHeight == other.largestNominalAppHeight
317                 && logicalWidth == other.logicalWidth
318                 && logicalHeight == other.logicalHeight
319                 && Objects.equals(displayCutout, other.displayCutout)
320                 && rotation == other.rotation
321                 && modeId == other.modeId
322                 && defaultModeId == other.defaultModeId
323                 && colorMode == other.colorMode
324                 && Arrays.equals(supportedColorModes, other.supportedColorModes)
325                 && Objects.equals(hdrCapabilities, other.hdrCapabilities)
326                 && minimalPostProcessingSupported == other.minimalPostProcessingSupported
327                 && logicalDensityDpi == other.logicalDensityDpi
328                 && physicalXDpi == other.physicalXDpi
329                 && physicalYDpi == other.physicalYDpi
330                 && appVsyncOffsetNanos == other.appVsyncOffsetNanos
331                 && presentationDeadlineNanos == other.presentationDeadlineNanos
332                 && state == other.state
333                 && ownerUid == other.ownerUid
334                 && Objects.equals(ownerPackageName, other.ownerPackageName)
335                 && removeMode == other.removeMode;
336     }
337 
338     @Override
hashCode()339     public int hashCode() {
340         return 0; // don't care
341     }
342 
copyFrom(DisplayInfo other)343     public void copyFrom(DisplayInfo other) {
344         layerStack = other.layerStack;
345         flags = other.flags;
346         type = other.type;
347         displayId = other.displayId;
348         address = other.address;
349         deviceProductInfo = other.deviceProductInfo;
350         name = other.name;
351         uniqueId = other.uniqueId;
352         appWidth = other.appWidth;
353         appHeight = other.appHeight;
354         smallestNominalAppWidth = other.smallestNominalAppWidth;
355         smallestNominalAppHeight = other.smallestNominalAppHeight;
356         largestNominalAppWidth = other.largestNominalAppWidth;
357         largestNominalAppHeight = other.largestNominalAppHeight;
358         logicalWidth = other.logicalWidth;
359         logicalHeight = other.logicalHeight;
360         displayCutout = other.displayCutout;
361         rotation = other.rotation;
362         modeId = other.modeId;
363         defaultModeId = other.defaultModeId;
364         supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
365         colorMode = other.colorMode;
366         supportedColorModes = Arrays.copyOf(
367                 other.supportedColorModes, other.supportedColorModes.length);
368         hdrCapabilities = other.hdrCapabilities;
369         minimalPostProcessingSupported = other.minimalPostProcessingSupported;
370         logicalDensityDpi = other.logicalDensityDpi;
371         physicalXDpi = other.physicalXDpi;
372         physicalYDpi = other.physicalYDpi;
373         appVsyncOffsetNanos = other.appVsyncOffsetNanos;
374         presentationDeadlineNanos = other.presentationDeadlineNanos;
375         state = other.state;
376         ownerUid = other.ownerUid;
377         ownerPackageName = other.ownerPackageName;
378         removeMode = other.removeMode;
379     }
380 
readFromParcel(Parcel source)381     public void readFromParcel(Parcel source) {
382         layerStack = source.readInt();
383         flags = source.readInt();
384         type = source.readInt();
385         displayId = source.readInt();
386         address = source.readParcelable(null);
387         deviceProductInfo = source.readParcelable(null);
388         name = source.readString8();
389         appWidth = source.readInt();
390         appHeight = source.readInt();
391         smallestNominalAppWidth = source.readInt();
392         smallestNominalAppHeight = source.readInt();
393         largestNominalAppWidth = source.readInt();
394         largestNominalAppHeight = source.readInt();
395         logicalWidth = source.readInt();
396         logicalHeight = source.readInt();
397         displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
398         rotation = source.readInt();
399         modeId = source.readInt();
400         defaultModeId = source.readInt();
401         int nModes = source.readInt();
402         supportedModes = new Display.Mode[nModes];
403         for (int i = 0; i < nModes; i++) {
404             supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
405         }
406         colorMode = source.readInt();
407         int nColorModes = source.readInt();
408         supportedColorModes = new int[nColorModes];
409         for (int i = 0; i < nColorModes; i++) {
410             supportedColorModes[i] = source.readInt();
411         }
412         hdrCapabilities = source.readParcelable(null);
413         minimalPostProcessingSupported = source.readBoolean();
414         logicalDensityDpi = source.readInt();
415         physicalXDpi = source.readFloat();
416         physicalYDpi = source.readFloat();
417         appVsyncOffsetNanos = source.readLong();
418         presentationDeadlineNanos = source.readLong();
419         state = source.readInt();
420         ownerUid = source.readInt();
421         ownerPackageName = source.readString8();
422         uniqueId = source.readString8();
423         removeMode = source.readInt();
424     }
425 
426     @Override
writeToParcel(Parcel dest, int flags)427     public void writeToParcel(Parcel dest, int flags) {
428         dest.writeInt(layerStack);
429         dest.writeInt(this.flags);
430         dest.writeInt(type);
431         dest.writeInt(displayId);
432         dest.writeParcelable(address, flags);
433         dest.writeParcelable(deviceProductInfo, flags);
434         dest.writeString8(name);
435         dest.writeInt(appWidth);
436         dest.writeInt(appHeight);
437         dest.writeInt(smallestNominalAppWidth);
438         dest.writeInt(smallestNominalAppHeight);
439         dest.writeInt(largestNominalAppWidth);
440         dest.writeInt(largestNominalAppHeight);
441         dest.writeInt(logicalWidth);
442         dest.writeInt(logicalHeight);
443         DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
444         dest.writeInt(rotation);
445         dest.writeInt(modeId);
446         dest.writeInt(defaultModeId);
447         dest.writeInt(supportedModes.length);
448         for (int i = 0; i < supportedModes.length; i++) {
449             supportedModes[i].writeToParcel(dest, flags);
450         }
451         dest.writeInt(colorMode);
452         dest.writeInt(supportedColorModes.length);
453         for (int i = 0; i < supportedColorModes.length; i++) {
454             dest.writeInt(supportedColorModes[i]);
455         }
456         dest.writeParcelable(hdrCapabilities, flags);
457         dest.writeBoolean(minimalPostProcessingSupported);
458         dest.writeInt(logicalDensityDpi);
459         dest.writeFloat(physicalXDpi);
460         dest.writeFloat(physicalYDpi);
461         dest.writeLong(appVsyncOffsetNanos);
462         dest.writeLong(presentationDeadlineNanos);
463         dest.writeInt(state);
464         dest.writeInt(ownerUid);
465         dest.writeString8(ownerPackageName);
466         dest.writeString8(uniqueId);
467         dest.writeInt(removeMode);
468     }
469 
470     @Override
describeContents()471     public int describeContents() {
472         return 0;
473     }
474 
getMode()475     public Display.Mode getMode() {
476         return findMode(modeId);
477     }
478 
getDefaultMode()479     public Display.Mode getDefaultMode() {
480         return findMode(defaultModeId);
481     }
482 
findMode(int id)483     private Display.Mode findMode(int id) {
484         for (int i = 0; i < supportedModes.length; i++) {
485             if (supportedModes[i].getModeId() == id) {
486                 return supportedModes[i];
487             }
488         }
489         throw new IllegalStateException("Unable to locate mode " + id);
490     }
491 
492     /**
493      * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable
494      * mode could be found.
495      */
findDefaultModeByRefreshRate(float refreshRate)496     public int findDefaultModeByRefreshRate(float refreshRate) {
497         Display.Mode[] modes = supportedModes;
498         Display.Mode defaultMode = getDefaultMode();
499         for (int i = 0; i < modes.length; i++) {
500             if (modes[i].matches(
501                     defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) {
502                 return modes[i].getModeId();
503             }
504         }
505         return 0;
506     }
507 
508     /**
509      * Returns the list of supported refresh rates in the default mode.
510      */
getDefaultRefreshRates()511     public float[] getDefaultRefreshRates() {
512         Display.Mode[] modes = supportedModes;
513         ArraySet<Float> rates = new ArraySet<>();
514         Display.Mode defaultMode = getDefaultMode();
515         for (int i = 0; i < modes.length; i++) {
516             Display.Mode mode = modes[i];
517             if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth()
518                     && mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) {
519                 rates.add(mode.getRefreshRate());
520             }
521         }
522         float[] result = new float[rates.size()];
523         int i = 0;
524         for (Float rate : rates) {
525             result[i++] = rate;
526         }
527         return result;
528     }
529 
getAppMetrics(DisplayMetrics outMetrics)530     public void getAppMetrics(DisplayMetrics outMetrics) {
531         getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
532     }
533 
getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments)534     public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
535         getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
536                 displayAdjustments.getConfiguration(), appWidth, appHeight);
537     }
538 
getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci, Configuration configuration)539     public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
540             Configuration configuration) {
541         getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
542     }
543 
getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration)544     public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
545             Configuration configuration) {
546         getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
547     }
548 
getNaturalWidth()549     public int getNaturalWidth() {
550         return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
551                 logicalWidth : logicalHeight;
552     }
553 
getNaturalHeight()554     public int getNaturalHeight() {
555         return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
556                 logicalHeight : logicalWidth;
557     }
558 
isHdr()559     public boolean isHdr() {
560         int[] types = hdrCapabilities != null ? hdrCapabilities.getSupportedHdrTypes() : null;
561         return types != null && types.length > 0;
562     }
563 
isWideColorGamut()564     public boolean isWideColorGamut() {
565         for (int colorMode : supportedColorModes) {
566             if (colorMode == Display.COLOR_MODE_DCI_P3 || colorMode > Display.COLOR_MODE_SRGB) {
567                 return true;
568             }
569         }
570         return false;
571     }
572 
573     /**
574      * Returns true if the specified UID has access to this display.
575      */
hasAccess(int uid)576     public boolean hasAccess(int uid) {
577         return Display.hasAccess(uid, flags, ownerUid, displayId);
578     }
579 
getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration, int width, int height)580     private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
581             Configuration configuration, int width, int height) {
582         outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
583         outMetrics.density = outMetrics.noncompatDensity =
584                 logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
585         outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
586         outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
587         outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
588 
589         final Rect appBounds = configuration != null
590                 ? configuration.windowConfiguration.getAppBounds() : null;
591         width = appBounds != null ? appBounds.width() : width;
592         height = appBounds != null ? appBounds.height() : height;
593 
594         outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
595         outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
596 
597         if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
598             compatInfo.applyToDisplayMetrics(outMetrics);
599         }
600     }
601 
602     // For debugging purposes
603     @Override
toString()604     public String toString() {
605         StringBuilder sb = new StringBuilder();
606         sb.append("DisplayInfo{\"");
607         sb.append(name);
608         sb.append("\", displayId ");
609         sb.append(displayId);
610         sb.append(flagsToString(flags));
611         sb.append(", real ");
612         sb.append(logicalWidth);
613         sb.append(" x ");
614         sb.append(logicalHeight);
615         sb.append(", largest app ");
616         sb.append(largestNominalAppWidth);
617         sb.append(" x ");
618         sb.append(largestNominalAppHeight);
619         sb.append(", smallest app ");
620         sb.append(smallestNominalAppWidth);
621         sb.append(" x ");
622         sb.append(smallestNominalAppHeight);
623         sb.append(", appVsyncOff ");
624         sb.append(appVsyncOffsetNanos);
625         sb.append(", presDeadline ");
626         sb.append(presentationDeadlineNanos);
627         sb.append(", mode ");
628         sb.append(modeId);
629         sb.append(", defaultMode ");
630         sb.append(defaultModeId);
631         sb.append(", modes ");
632         sb.append(Arrays.toString(supportedModes));
633         sb.append(", hdrCapabilities ");
634         sb.append(hdrCapabilities);
635         sb.append(", minimalPostProcessingSupported ");
636         sb.append(minimalPostProcessingSupported);
637         sb.append(", rotation ");
638         sb.append(rotation);
639         sb.append(", state ");
640         sb.append(Display.stateToString(state));
641 
642         if (Process.myUid() != Process.SYSTEM_UID) {
643             sb.append("}");
644             return sb.toString();
645         }
646 
647         sb.append(", type ");
648         sb.append(Display.typeToString(type));
649         sb.append(", uniqueId \"");
650         sb.append(uniqueId);
651         sb.append("\", app ");
652         sb.append(appWidth);
653         sb.append(" x ");
654         sb.append(appHeight);
655         sb.append(", density ");
656         sb.append(logicalDensityDpi);
657         sb.append(" (");
658         sb.append(physicalXDpi);
659         sb.append(" x ");
660         sb.append(physicalYDpi);
661         sb.append(") dpi, layerStack ");
662         sb.append(layerStack);
663         sb.append(", colorMode ");
664         sb.append(colorMode);
665         sb.append(", supportedColorModes ");
666         sb.append(Arrays.toString(supportedColorModes));
667         if (address != null) {
668             sb.append(", address ").append(address);
669         }
670         sb.append(", deviceProductInfo ");
671         sb.append(deviceProductInfo);
672         if (ownerUid != 0 || ownerPackageName != null) {
673             sb.append(", owner ").append(ownerPackageName);
674             sb.append(" (uid ").append(ownerUid).append(")");
675         }
676         sb.append(", removeMode ");
677         sb.append(removeMode);
678         sb.append("}");
679         return sb.toString();
680     }
681 
682     /**
683      * Write to a protocol buffer output stream.
684      * Protocol buffer message definition at {@link android.view.DisplayInfoProto}
685      *
686      * @param protoOutputStream Stream to write the Rect object to.
687      * @param fieldId           Field Id of the DisplayInfoProto as defined in the parent message
688      */
dumpDebug(ProtoOutputStream protoOutputStream, long fieldId)689     public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
690         final long token = protoOutputStream.start(fieldId);
691         protoOutputStream.write(LOGICAL_WIDTH, logicalWidth);
692         protoOutputStream.write(LOGICAL_HEIGHT, logicalHeight);
693         protoOutputStream.write(APP_WIDTH, appWidth);
694         protoOutputStream.write(APP_HEIGHT, appHeight);
695         protoOutputStream.write(NAME, name);
696         protoOutputStream.write(FLAGS, flags);
697         protoOutputStream.end(token);
698     }
699 
flagsToString(int flags)700     private static String flagsToString(int flags) {
701         StringBuilder result = new StringBuilder();
702         if ((flags & Display.FLAG_SECURE) != 0) {
703             result.append(", FLAG_SECURE");
704         }
705         if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
706             result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
707         }
708         if ((flags & Display.FLAG_PRIVATE) != 0) {
709             result.append(", FLAG_PRIVATE");
710         }
711         if ((flags & Display.FLAG_PRESENTATION) != 0) {
712             result.append(", FLAG_PRESENTATION");
713         }
714         if ((flags & Display.FLAG_SCALING_DISABLED) != 0) {
715             result.append(", FLAG_SCALING_DISABLED");
716         }
717         if ((flags & Display.FLAG_ROUND) != 0) {
718             result.append(", FLAG_ROUND");
719         }
720         if ((flags & Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
721             result.append(", FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD");
722         }
723         if ((flags & Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) {
724             result.append(", FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS");
725         }
726         if ((flags & Display.FLAG_TRUSTED) != 0) {
727             result.append(", FLAG_TRUSTED");
728         }
729         return result.toString();
730     }
731 }
732