DisplayInfo.java revision b3b9eb3cfc5b3b3609a5d01258315798b38a5cf9
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
17package android.view;
18
19import android.content.res.CompatibilityInfo;
20import android.content.res.Configuration;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.util.ArraySet;
24import android.util.DisplayMetrics;
25
26import java.util.Arrays;
27
28import libcore.util.Objects;
29
30/**
31 * Describes the characteristics of a particular logical display.
32 * @hide
33 */
34public 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
244    public DisplayInfo() {
245    }
246
247    public DisplayInfo(DisplayInfo other) {
248        copyFrom(other);
249    }
250
251    private DisplayInfo(Parcel source) {
252        readFromParcel(source);
253    }
254
255    @Override
256    public boolean equals(Object o) {
257        return o instanceof DisplayInfo && equals((DisplayInfo)o);
258    }
259
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
293    public int hashCode() {
294        return 0; // don't care
295    }
296
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
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
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
405    public int describeContents() {
406        return 0;
407    }
408
409    public Display.Mode getMode() {
410        return findMode(modeId);
411    }
412
413    public Display.Mode getDefaultMode() {
414        return findMode(defaultModeId);
415    }
416
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     */
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     */
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
464    public void getAppMetrics(DisplayMetrics outMetrics) {
465        getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
466    }
467
468    public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
469        getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
470                displayAdjustments.getConfiguration(), appWidth, appHeight);
471    }
472
473    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
474            Configuration configuration) {
475        getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
476    }
477
478    public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
479            Configuration configuration) {
480        getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
481    }
482
483    public int getNaturalWidth() {
484        return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
485                logicalWidth : logicalHeight;
486    }
487
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     */
496    public boolean hasAccess(int uid) {
497        return Display.hasAccess(uid, flags, ownerUid);
498    }
499
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
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
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        return result.toString();
613    }
614}
615