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