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.os.Parcel;
21import android.os.Parcelable;
22import android.util.DisplayMetrics;
23
24import libcore.util.Objects;
25
26/**
27 * Describes the characteristics of a particular logical display.
28 * @hide
29 */
30public final class DisplayInfo implements Parcelable {
31    /**
32     * The surface flinger layer stack associated with this logical display.
33     */
34    public int layerStack;
35
36    /**
37     * Display flags.
38     */
39    public int flags;
40
41    /**
42     * Display type.
43     */
44    public int type;
45
46    /**
47     * Display address, or null if none.
48     * Interpretation varies by display type.
49     */
50    public String address;
51
52    /**
53     * The human-readable name of the display.
54     */
55    public String name;
56
57    /**
58     * The width of the portion of the display that is available to applications, in pixels.
59     * Represents the size of the display minus any system decorations.
60     */
61    public int appWidth;
62
63    /**
64     * The height of the portion of the display that is available to applications, in pixels.
65     * Represents the size of the display minus any system decorations.
66     */
67    public int appHeight;
68
69    /**
70     * The smallest value of {@link #appWidth} that an application is likely to encounter,
71     * in pixels, excepting cases where the width may be even smaller due to the presence
72     * of a soft keyboard, for example.
73     */
74    public int smallestNominalAppWidth;
75
76    /**
77     * The smallest value of {@link #appHeight} that an application is likely to encounter,
78     * in pixels, excepting cases where the height may be even smaller due to the presence
79     * of a soft keyboard, for example.
80     */
81    public int smallestNominalAppHeight;
82
83    /**
84     * The largest value of {@link #appWidth} that an application is likely to encounter,
85     * in pixels, excepting cases where the width may be even larger due to system decorations
86     * such as the status bar being hidden, for example.
87     */
88    public int largestNominalAppWidth;
89
90    /**
91     * The largest value of {@link #appHeight} that an application is likely to encounter,
92     * in pixels, excepting cases where the height may be even larger due to system decorations
93     * such as the status bar being hidden, for example.
94     */
95    public int largestNominalAppHeight;
96
97    /**
98     * The logical width of the display, in pixels.
99     * Represents the usable size of the display which may be smaller than the
100     * physical size when the system is emulating a smaller display.
101     */
102    public int logicalWidth;
103
104    /**
105     * The logical height of the display, in pixels.
106     * Represents the usable size of the display which may be smaller than the
107     * physical size when the system is emulating a smaller display.
108     */
109    public int logicalHeight;
110
111    /**
112     * The rotation of the display relative to its natural orientation.
113     * May be one of {@link android.view.Surface#ROTATION_0},
114     * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
115     * {@link android.view.Surface#ROTATION_270}.
116     * <p>
117     * The value of this field is indeterminate if the logical display is presented on
118     * more than one physical display.
119     * </p>
120     */
121    public int rotation;
122
123    /**
124     * The refresh rate of this display in frames per second.
125     * <p>
126     * The value of this field is indeterminate if the logical display is presented on
127     * more than one physical display.
128     * </p>
129     */
130    public float refreshRate;
131
132    /**
133     * The logical display density which is the basis for density-independent
134     * pixels.
135     */
136    public int logicalDensityDpi;
137
138    /**
139     * The exact physical pixels per inch of the screen in the X dimension.
140     * <p>
141     * The value of this field is indeterminate if the logical display is presented on
142     * more than one physical display.
143     * </p>
144     */
145    public float physicalXDpi;
146
147    /**
148     * The exact physical pixels per inch of the screen in the Y dimension.
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    public float physicalYDpi;
155
156    public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
157        @Override
158        public DisplayInfo createFromParcel(Parcel source) {
159            return new DisplayInfo(source);
160        }
161
162        @Override
163        public DisplayInfo[] newArray(int size) {
164            return new DisplayInfo[size];
165        }
166    };
167
168    public DisplayInfo() {
169    }
170
171    public DisplayInfo(DisplayInfo other) {
172        copyFrom(other);
173    }
174
175    private DisplayInfo(Parcel source) {
176        readFromParcel(source);
177    }
178
179    @Override
180    public boolean equals(Object o) {
181        return o instanceof DisplayInfo && equals((DisplayInfo)o);
182    }
183
184    public boolean equals(DisplayInfo other) {
185        return other != null
186                && layerStack == other.layerStack
187                && flags == other.flags
188                && type == other.type
189                && Objects.equal(address, other.address)
190                && Objects.equal(name, other.name)
191                && appWidth == other.appWidth
192                && appHeight == other.appHeight
193                && smallestNominalAppWidth == other.smallestNominalAppWidth
194                && smallestNominalAppHeight == other.smallestNominalAppHeight
195                && largestNominalAppWidth == other.largestNominalAppWidth
196                && largestNominalAppHeight == other.largestNominalAppHeight
197                && logicalWidth == other.logicalWidth
198                && logicalHeight == other.logicalHeight
199                && rotation == other.rotation
200                && refreshRate == other.refreshRate
201                && logicalDensityDpi == other.logicalDensityDpi
202                && physicalXDpi == other.physicalXDpi
203                && physicalYDpi == other.physicalYDpi;
204    }
205
206    @Override
207    public int hashCode() {
208        return 0; // don't care
209    }
210
211    public void copyFrom(DisplayInfo other) {
212        layerStack = other.layerStack;
213        flags = other.flags;
214        type = other.type;
215        address = other.address;
216        name = other.name;
217        appWidth = other.appWidth;
218        appHeight = other.appHeight;
219        smallestNominalAppWidth = other.smallestNominalAppWidth;
220        smallestNominalAppHeight = other.smallestNominalAppHeight;
221        largestNominalAppWidth = other.largestNominalAppWidth;
222        largestNominalAppHeight = other.largestNominalAppHeight;
223        logicalWidth = other.logicalWidth;
224        logicalHeight = other.logicalHeight;
225        rotation = other.rotation;
226        refreshRate = other.refreshRate;
227        logicalDensityDpi = other.logicalDensityDpi;
228        physicalXDpi = other.physicalXDpi;
229        physicalYDpi = other.physicalYDpi;
230    }
231
232    public void readFromParcel(Parcel source) {
233        layerStack = source.readInt();
234        flags = source.readInt();
235        type = source.readInt();
236        address = source.readString();
237        name = source.readString();
238        appWidth = source.readInt();
239        appHeight = source.readInt();
240        smallestNominalAppWidth = source.readInt();
241        smallestNominalAppHeight = source.readInt();
242        largestNominalAppWidth = source.readInt();
243        largestNominalAppHeight = source.readInt();
244        logicalWidth = source.readInt();
245        logicalHeight = source.readInt();
246        rotation = source.readInt();
247        refreshRate = source.readFloat();
248        logicalDensityDpi = source.readInt();
249        physicalXDpi = source.readFloat();
250        physicalYDpi = source.readFloat();
251    }
252
253    @Override
254    public void writeToParcel(Parcel dest, int flags) {
255        dest.writeInt(layerStack);
256        dest.writeInt(this.flags);
257        dest.writeInt(type);
258        dest.writeString(address);
259        dest.writeString(name);
260        dest.writeInt(appWidth);
261        dest.writeInt(appHeight);
262        dest.writeInt(smallestNominalAppWidth);
263        dest.writeInt(smallestNominalAppHeight);
264        dest.writeInt(largestNominalAppWidth);
265        dest.writeInt(largestNominalAppHeight);
266        dest.writeInt(logicalWidth);
267        dest.writeInt(logicalHeight);
268        dest.writeInt(rotation);
269        dest.writeFloat(refreshRate);
270        dest.writeInt(logicalDensityDpi);
271        dest.writeFloat(physicalXDpi);
272        dest.writeFloat(physicalYDpi);
273    }
274
275    @Override
276    public int describeContents() {
277        return 0;
278    }
279
280    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfoHolder cih) {
281        getMetricsWithSize(outMetrics, cih, appWidth, appHeight);
282    }
283
284    public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfoHolder cih) {
285        getMetricsWithSize(outMetrics, cih, logicalWidth, logicalHeight);
286    }
287
288    private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfoHolder cih,
289            int width, int height) {
290        outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
291        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
292        outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
293
294        outMetrics.density = outMetrics.noncompatDensity =
295                logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
296        outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
297        outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
298        outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
299
300        if (cih != null) {
301            CompatibilityInfo ci = cih.getIfNeeded();
302            if (ci != null) {
303                ci.applyToDisplayMetrics(outMetrics);
304            }
305        }
306    }
307
308    // For debugging purposes
309    @Override
310    public String toString() {
311        return "DisplayInfo{\"" + name + "\", app " + appWidth + " x " + appHeight
312                + ", real " + logicalWidth + " x " + logicalHeight
313                + ", largest app " + largestNominalAppWidth + " x " + largestNominalAppHeight
314                + ", smallest app " + smallestNominalAppWidth + " x " + smallestNominalAppHeight
315                + ", " + refreshRate + " fps"
316                + ", rotation " + rotation
317                + ", density " + logicalDensityDpi
318                + ", " + physicalXDpi + " x " + physicalYDpi + " dpi"
319                + ", layerStack " + layerStack
320                + ", type " + Display.typeToString(type)
321                + ", address " + address
322                + flagsToString(flags) + "}";
323    }
324
325    private static String flagsToString(int flags) {
326        StringBuilder result = new StringBuilder();
327        if ((flags & Display.FLAG_SECURE) != 0) {
328            result.append(", FLAG_SECURE");
329        }
330        if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
331            result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
332        }
333        return result.toString();
334    }
335}
336