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