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