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    /** The active color transform. */
173    public int colorTransformId;
174
175    /** The default color transform. */
176    public int defaultColorTransformId;
177
178    /** The list of supported color transforms */
179    public Display.ColorTransform[] supportedColorTransforms = Display.ColorTransform.EMPTY_ARRAY;
180
181    /** The display's HDR capabilities */
182    public Display.HdrCapabilities hdrCapabilities;
183
184    /**
185     * The logical display density which is the basis for density-independent
186     * pixels.
187     */
188    public int logicalDensityDpi;
189
190    /**
191     * The exact physical pixels per inch of the screen in the X dimension.
192     * <p>
193     * The value of this field is indeterminate if the logical display is presented on
194     * more than one physical display.
195     * </p>
196     */
197    public float physicalXDpi;
198
199    /**
200     * The exact physical pixels per inch of the screen in the Y dimension.
201     * <p>
202     * The value of this field is indeterminate if the logical display is presented on
203     * more than one physical display.
204     * </p>
205     */
206    public float physicalYDpi;
207
208    /**
209     * This is a positive value indicating the phase offset of the VSYNC events provided by
210     * Choreographer relative to the display refresh.  For example, if Choreographer reports
211     * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
212     */
213    public long appVsyncOffsetNanos;
214
215    /**
216     * This is how far in advance a buffer must be queued for presentation at
217     * a given time.  If you want a buffer to appear on the screen at
218     * time N, you must submit the buffer before (N - bufferDeadlineNanos).
219     */
220    public long presentationDeadlineNanos;
221
222    /**
223     * The state of the display, such as {@link android.view.Display#STATE_ON}.
224     */
225    public int state;
226
227    /**
228     * The UID of the application that owns this display, or zero if it is owned by the system.
229     * <p>
230     * If the display is private, then only the owner can use it.
231     * </p>
232     */
233    public int ownerUid;
234
235    /**
236     * The package name of the application that owns this display, or null if it is
237     * owned by the system.
238     * <p>
239     * If the display is private, then only the owner can use it.
240     * </p>
241     */
242    public String ownerPackageName;
243
244    public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
245        @Override
246        public DisplayInfo createFromParcel(Parcel source) {
247            return new DisplayInfo(source);
248        }
249
250        @Override
251        public DisplayInfo[] newArray(int size) {
252            return new DisplayInfo[size];
253        }
254    };
255
256    public DisplayInfo() {
257    }
258
259    public DisplayInfo(DisplayInfo other) {
260        copyFrom(other);
261    }
262
263    private DisplayInfo(Parcel source) {
264        readFromParcel(source);
265    }
266
267    @Override
268    public boolean equals(Object o) {
269        return o instanceof DisplayInfo && equals((DisplayInfo)o);
270    }
271
272    public boolean equals(DisplayInfo other) {
273        return other != null
274                && layerStack == other.layerStack
275                && flags == other.flags
276                && type == other.type
277                && Objects.equal(address, other.address)
278                && Objects.equal(uniqueId, other.uniqueId)
279                && appWidth == other.appWidth
280                && appHeight == other.appHeight
281                && smallestNominalAppWidth == other.smallestNominalAppWidth
282                && smallestNominalAppHeight == other.smallestNominalAppHeight
283                && largestNominalAppWidth == other.largestNominalAppWidth
284                && largestNominalAppHeight == other.largestNominalAppHeight
285                && logicalWidth == other.logicalWidth
286                && logicalHeight == other.logicalHeight
287                && overscanLeft == other.overscanLeft
288                && overscanTop == other.overscanTop
289                && overscanRight == other.overscanRight
290                && overscanBottom == other.overscanBottom
291                && rotation == other.rotation
292                && modeId == other.modeId
293                && defaultModeId == other.defaultModeId
294                && colorTransformId == other.colorTransformId
295                && defaultColorTransformId == other.defaultColorTransformId
296                && Objects.equal(hdrCapabilities, other.hdrCapabilities)
297                && logicalDensityDpi == other.logicalDensityDpi
298                && physicalXDpi == other.physicalXDpi
299                && physicalYDpi == other.physicalYDpi
300                && appVsyncOffsetNanos == other.appVsyncOffsetNanos
301                && presentationDeadlineNanos == other.presentationDeadlineNanos
302                && state == other.state
303                && ownerUid == other.ownerUid
304                && Objects.equal(ownerPackageName, other.ownerPackageName);
305    }
306
307    @Override
308    public int hashCode() {
309        return 0; // don't care
310    }
311
312    public void copyFrom(DisplayInfo other) {
313        layerStack = other.layerStack;
314        flags = other.flags;
315        type = other.type;
316        address = other.address;
317        name = other.name;
318        uniqueId = other.uniqueId;
319        appWidth = other.appWidth;
320        appHeight = other.appHeight;
321        smallestNominalAppWidth = other.smallestNominalAppWidth;
322        smallestNominalAppHeight = other.smallestNominalAppHeight;
323        largestNominalAppWidth = other.largestNominalAppWidth;
324        largestNominalAppHeight = other.largestNominalAppHeight;
325        logicalWidth = other.logicalWidth;
326        logicalHeight = other.logicalHeight;
327        overscanLeft = other.overscanLeft;
328        overscanTop = other.overscanTop;
329        overscanRight = other.overscanRight;
330        overscanBottom = other.overscanBottom;
331        rotation = other.rotation;
332        modeId = other.modeId;
333        defaultModeId = other.defaultModeId;
334        supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
335        colorTransformId = other.colorTransformId;
336        defaultColorTransformId = other.defaultColorTransformId;
337        supportedColorTransforms = Arrays.copyOf(
338                other.supportedColorTransforms, other.supportedColorTransforms.length);
339        hdrCapabilities = other.hdrCapabilities;
340        logicalDensityDpi = other.logicalDensityDpi;
341        physicalXDpi = other.physicalXDpi;
342        physicalYDpi = other.physicalYDpi;
343        appVsyncOffsetNanos = other.appVsyncOffsetNanos;
344        presentationDeadlineNanos = other.presentationDeadlineNanos;
345        state = other.state;
346        ownerUid = other.ownerUid;
347        ownerPackageName = other.ownerPackageName;
348    }
349
350    public void readFromParcel(Parcel source) {
351        layerStack = source.readInt();
352        flags = source.readInt();
353        type = source.readInt();
354        address = source.readString();
355        name = source.readString();
356        appWidth = source.readInt();
357        appHeight = source.readInt();
358        smallestNominalAppWidth = source.readInt();
359        smallestNominalAppHeight = source.readInt();
360        largestNominalAppWidth = source.readInt();
361        largestNominalAppHeight = source.readInt();
362        logicalWidth = source.readInt();
363        logicalHeight = source.readInt();
364        overscanLeft = source.readInt();
365        overscanTop = source.readInt();
366        overscanRight = source.readInt();
367        overscanBottom = source.readInt();
368        rotation = source.readInt();
369        modeId = source.readInt();
370        defaultModeId = source.readInt();
371        int nModes = source.readInt();
372        supportedModes = new Display.Mode[nModes];
373        for (int i = 0; i < nModes; i++) {
374            supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
375        }
376        colorTransformId = source.readInt();
377        defaultColorTransformId = source.readInt();
378        int nColorTransforms = source.readInt();
379        supportedColorTransforms = new Display.ColorTransform[nColorTransforms];
380        for (int i = 0; i < nColorTransforms; i++) {
381            supportedColorTransforms[i] = Display.ColorTransform.CREATOR.createFromParcel(source);
382        }
383        hdrCapabilities = source.readParcelable(null);
384        logicalDensityDpi = source.readInt();
385        physicalXDpi = source.readFloat();
386        physicalYDpi = source.readFloat();
387        appVsyncOffsetNanos = source.readLong();
388        presentationDeadlineNanos = source.readLong();
389        state = source.readInt();
390        ownerUid = source.readInt();
391        ownerPackageName = source.readString();
392        uniqueId = source.readString();
393    }
394
395    @Override
396    public void writeToParcel(Parcel dest, int flags) {
397        dest.writeInt(layerStack);
398        dest.writeInt(this.flags);
399        dest.writeInt(type);
400        dest.writeString(address);
401        dest.writeString(name);
402        dest.writeInt(appWidth);
403        dest.writeInt(appHeight);
404        dest.writeInt(smallestNominalAppWidth);
405        dest.writeInt(smallestNominalAppHeight);
406        dest.writeInt(largestNominalAppWidth);
407        dest.writeInt(largestNominalAppHeight);
408        dest.writeInt(logicalWidth);
409        dest.writeInt(logicalHeight);
410        dest.writeInt(overscanLeft);
411        dest.writeInt(overscanTop);
412        dest.writeInt(overscanRight);
413        dest.writeInt(overscanBottom);
414        dest.writeInt(rotation);
415        dest.writeInt(modeId);
416        dest.writeInt(defaultModeId);
417        dest.writeInt(supportedModes.length);
418        for (int i = 0; i < supportedModes.length; i++) {
419            supportedModes[i].writeToParcel(dest, flags);
420        }
421        dest.writeInt(colorTransformId);
422        dest.writeInt(defaultColorTransformId);
423        dest.writeInt(supportedColorTransforms.length);
424        for (int i = 0; i < supportedColorTransforms.length; i++) {
425            supportedColorTransforms[i].writeToParcel(dest, flags);
426        }
427        dest.writeParcelable(hdrCapabilities, flags);
428        dest.writeInt(logicalDensityDpi);
429        dest.writeFloat(physicalXDpi);
430        dest.writeFloat(physicalYDpi);
431        dest.writeLong(appVsyncOffsetNanos);
432        dest.writeLong(presentationDeadlineNanos);
433        dest.writeInt(state);
434        dest.writeInt(ownerUid);
435        dest.writeString(ownerPackageName);
436        dest.writeString(uniqueId);
437    }
438
439    @Override
440    public int describeContents() {
441        return 0;
442    }
443
444    public Display.Mode getMode() {
445        return findMode(modeId);
446    }
447
448    public Display.Mode getDefaultMode() {
449        return findMode(defaultModeId);
450    }
451
452    private Display.Mode findMode(int id) {
453        for (int i = 0; i < supportedModes.length; i++) {
454            if (supportedModes[i].getModeId() == id) {
455                return supportedModes[i];
456            }
457        }
458        throw new IllegalStateException("Unable to locate mode " + id);
459    }
460
461    /**
462     * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable
463     * mode could be found.
464     */
465    public int findDefaultModeByRefreshRate(float refreshRate) {
466        Display.Mode[] modes = supportedModes;
467        Display.Mode defaultMode = getDefaultMode();
468        for (int i = 0; i < modes.length; i++) {
469            if (modes[i].matches(
470                    defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) {
471                return modes[i].getModeId();
472            }
473        }
474        return 0;
475    }
476
477    /**
478     * Returns the list of supported refresh rates in the default mode.
479     */
480    public float[] getDefaultRefreshRates() {
481        Display.Mode[] modes = supportedModes;
482        ArraySet<Float> rates = new ArraySet<>();
483        Display.Mode defaultMode = getDefaultMode();
484        for (int i = 0; i < modes.length; i++) {
485            Display.Mode mode = modes[i];
486            if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth()
487                    && mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) {
488                rates.add(mode.getRefreshRate());
489            }
490        }
491        float[] result = new float[rates.size()];
492        int i = 0;
493        for (Float rate : rates) {
494            result[i++] = rate;
495        }
496        return result;
497    }
498
499    public Display.ColorTransform getColorTransform() {
500        return findColorTransform(colorTransformId);
501    }
502
503    public Display.ColorTransform getDefaultColorTransform() {
504        return findColorTransform(defaultColorTransformId);
505    }
506
507    private Display.ColorTransform findColorTransform(int colorTransformId) {
508        for (int i = 0; i < supportedColorTransforms.length; i++) {
509            Display.ColorTransform colorTransform = supportedColorTransforms[i];
510            if (colorTransform.getId() == colorTransformId) {
511                return colorTransform;
512            }
513        }
514        throw new IllegalStateException("Unable to locate color transform: " + colorTransformId);
515    }
516
517    public void getAppMetrics(DisplayMetrics outMetrics) {
518        getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
519    }
520
521    public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
522        getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
523                displayAdjustments.getConfiguration(), appWidth, appHeight);
524    }
525
526    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
527            Configuration configuration) {
528        getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
529    }
530
531    public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
532            Configuration configuration) {
533        getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
534    }
535
536    public int getNaturalWidth() {
537        return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
538                logicalWidth : logicalHeight;
539    }
540
541    public int getNaturalHeight() {
542        return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
543                logicalHeight : logicalWidth;
544    }
545
546    /**
547     * Returns true if the specified UID has access to this display.
548     */
549    public boolean hasAccess(int uid) {
550        return Display.hasAccess(uid, flags, ownerUid);
551    }
552
553    private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
554            Configuration configuration, int width, int height) {
555        outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
556        outMetrics.density = outMetrics.noncompatDensity =
557                logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
558        outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
559        outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
560        outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
561
562        width = (configuration != null
563                && configuration.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED)
564                ? (int)((configuration.screenWidthDp * outMetrics.density) + 0.5f) : width;
565        height = (configuration != null
566                && configuration.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED)
567                ? (int)((configuration.screenHeightDp * outMetrics.density) + 0.5f) : height;
568
569        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
570        outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
571
572        if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
573            compatInfo.applyToDisplayMetrics(outMetrics);
574        }
575    }
576
577    // For debugging purposes
578    @Override
579    public String toString() {
580        StringBuilder sb = new StringBuilder();
581        sb.append("DisplayInfo{\"");
582        sb.append(name);
583        sb.append("\", uniqueId \"");
584        sb.append(uniqueId);
585        sb.append("\", app ");
586        sb.append(appWidth);
587        sb.append(" x ");
588        sb.append(appHeight);
589        sb.append(", real ");
590        sb.append(logicalWidth);
591        sb.append(" x ");
592        sb.append(logicalHeight);
593        if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) {
594            sb.append(", overscan (");
595            sb.append(overscanLeft);
596            sb.append(",");
597            sb.append(overscanTop);
598            sb.append(",");
599            sb.append(overscanRight);
600            sb.append(",");
601            sb.append(overscanBottom);
602            sb.append(")");
603        }
604        sb.append(", largest app ");
605        sb.append(largestNominalAppWidth);
606        sb.append(" x ");
607        sb.append(largestNominalAppHeight);
608        sb.append(", smallest app ");
609        sb.append(smallestNominalAppWidth);
610        sb.append(" x ");
611        sb.append(smallestNominalAppHeight);
612        sb.append(", mode ");
613        sb.append(modeId);
614        sb.append(", defaultMode ");
615        sb.append(defaultModeId);
616        sb.append(", modes ");
617        sb.append(Arrays.toString(supportedModes));
618        sb.append(", colorTransformId ");
619        sb.append(colorTransformId);
620        sb.append(", defaultColorTransformId ");
621        sb.append(defaultColorTransformId);
622        sb.append(", supportedColorTransforms ");
623        sb.append(Arrays.toString(supportedColorTransforms));
624        sb.append(", hdrCapabilities ");
625        sb.append(hdrCapabilities);
626        sb.append(", rotation ");
627        sb.append(rotation);
628        sb.append(", density ");
629        sb.append(logicalDensityDpi);
630        sb.append(" (");
631        sb.append(physicalXDpi);
632        sb.append(" x ");
633        sb.append(physicalYDpi);
634        sb.append(") dpi, layerStack ");
635        sb.append(layerStack);
636        sb.append(", appVsyncOff ");
637        sb.append(appVsyncOffsetNanos);
638        sb.append(", presDeadline ");
639        sb.append(presentationDeadlineNanos);
640        sb.append(", type ");
641        sb.append(Display.typeToString(type));
642        if (address != null) {
643            sb.append(", address ").append(address);
644        }
645        sb.append(", state ");
646        sb.append(Display.stateToString(state));
647        if (ownerUid != 0 || ownerPackageName != null) {
648            sb.append(", owner ").append(ownerPackageName);
649            sb.append(" (uid ").append(ownerUid).append(")");
650        }
651        sb.append(flagsToString(flags));
652        sb.append("}");
653        return sb.toString();
654    }
655
656    private static String flagsToString(int flags) {
657        StringBuilder result = new StringBuilder();
658        if ((flags & Display.FLAG_SECURE) != 0) {
659            result.append(", FLAG_SECURE");
660        }
661        if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
662            result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
663        }
664        if ((flags & Display.FLAG_PRIVATE) != 0) {
665            result.append(", FLAG_PRIVATE");
666        }
667        if ((flags & Display.FLAG_PRESENTATION) != 0) {
668            result.append(", FLAG_PRESENTATION");
669        }
670        if ((flags & Display.FLAG_SCALING_DISABLED) != 0) {
671            result.append(", FLAG_SCALING_DISABLED");
672        }
673        if ((flags & Display.FLAG_ROUND) != 0) {
674            result.append(", FLAG_ROUND");
675        }
676        return result.toString();
677    }
678}
679