DisplayMetrics.java revision 14cee9f688c32d63d8521188e7422811629bb7c2
1/*
2 * Copyright (C) 2006 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.util;
18
19import android.content.res.CompatibilityInfo;
20import android.content.res.Configuration;
21import android.os.*;
22
23
24/**
25 * A structure describing general information about a display, such as its
26 * size, density, and font scaling.
27 * <p>To access the DisplayMetrics members, initialize an object like this:</p>
28 * <pre> DisplayMetrics metrics = new DisplayMetrics();
29 * getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
30 */
31public class DisplayMetrics {
32    /**
33     * Standard quantized DPI for low-density screens.
34     */
35    public static final int DENSITY_LOW = 120;
36
37    /**
38     * Standard quantized DPI for medium-density screens.
39     */
40    public static final int DENSITY_MEDIUM = 160;
41
42    /**
43     * Standard quantized DPI for high-density screens.
44     */
45    public static final int DENSITY_HIGH = 240;
46
47    /**
48     * The reference density used throughout the system.
49     */
50    public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;
51
52    /**
53     * The device's density.
54     * @hide becase eventually this should be able to change while
55     * running, so shouldn't be a constant.
56     */
57    public static final int DENSITY_DEVICE = getDeviceDensity();
58
59    /**
60     * The absolute width of the display in pixels.
61     */
62    public int widthPixels;
63    /**
64     * The absolute height of the display in pixels.
65     */
66    public int heightPixels;
67    /**
68     * The logical density of the display.  This is a scaling factor for the
69     * Density Independent Pixel unit, where one DIP is one pixel on an
70     * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen),
71     * providing the baseline of the system's display. Thus on a 160dpi screen
72     * this density value will be 1; on a 120 dpi screen it would be .75; etc.
73     *
74     * <p>This value does not exactly follow the real screen size (as given by
75     * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
76     * the overall UI in steps based on gross changes in the display dpi.  For
77     * example, a 240x320 screen will have a density of 1 even if its width is
78     * 1.8", 1.3", etc. However, if the screen resolution is increased to
79     * 320x480 but the screen size remained 1.5"x2" then the density would be
80     * increased (probably to 1.5).
81     *
82     * @see #DENSITY_DEFAULT
83     */
84    public float density;
85    /**
86     * The screen density expressed as dots-per-inch.  May be either
87     * {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}.
88     */
89    public int densityDpi;
90    /**
91     * A scaling factor for fonts displayed on the display.  This is the same
92     * as {@link #density}, except that it may be adjusted in smaller
93     * increments at runtime based on a user preference for the font size.
94     */
95    public float scaledDensity;
96    /**
97     * The exact physical pixels per inch of the screen in the X dimension.
98     */
99    public float xdpi;
100    /**
101     * The exact physical pixels per inch of the screen in the Y dimension.
102     */
103    public float ydpi;
104
105    public DisplayMetrics() {
106    }
107
108    public void setTo(DisplayMetrics o) {
109        widthPixels = o.widthPixels;
110        heightPixels = o.heightPixels;
111        density = o.density;
112        densityDpi = o.densityDpi;
113        scaledDensity = o.scaledDensity;
114        xdpi = o.xdpi;
115        ydpi = o.ydpi;
116    }
117
118    public void setToDefaults() {
119        widthPixels = 0;
120        heightPixels = 0;
121        density = DENSITY_DEVICE / (float) DENSITY_DEFAULT;
122        densityDpi = DENSITY_DEVICE;
123        scaledDensity = density;
124        xdpi = DENSITY_DEVICE;
125        ydpi = DENSITY_DEVICE;
126    }
127
128    /**
129     * Update the display metrics based on the compatibility info and orientation
130     * NOTE: DO NOT EXPOSE THIS API!  It is introducing a circular dependency
131     * with the higher-level android.res package.
132     * {@hide}
133     */
134    public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation,
135            int screenLayout) {
136        boolean expandable = compatibilityInfo.isConfiguredExpandable();
137        boolean largeScreens = compatibilityInfo.isConfiguredLargeScreens();
138        boolean xlargeScreens = compatibilityInfo.isConfiguredXLargeScreens();
139
140        // Note: this assume that configuration is updated before calling
141        // updateMetrics method.
142        if (!expandable) {
143            if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) == 0) {
144                expandable = true;
145                // the current screen size is compatible with non-resizing apps.
146                compatibilityInfo.setExpandable(true);
147            } else {
148                compatibilityInfo.setExpandable(false);
149            }
150        }
151        if (!largeScreens) {
152            if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
153                    != Configuration.SCREENLAYOUT_SIZE_LARGE) {
154                largeScreens = true;
155                // the current screen size is not large.
156                compatibilityInfo.setLargeScreens(true);
157            } else {
158                compatibilityInfo.setLargeScreens(false);
159            }
160        }
161        if (!xlargeScreens) {
162            if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
163                    != Configuration.SCREENLAYOUT_SIZE_XLARGE) {
164                xlargeScreens = true;
165                // the current screen size is not large.
166                compatibilityInfo.setXLargeScreens(true);
167            } else {
168                compatibilityInfo.setXLargeScreens(false);
169            }
170        }
171
172        if (!expandable || (!largeScreens && !xlargeScreens)) {
173            // This is a larger screen device and the app is not
174            // compatible with large screens, so diddle it.
175
176            // Figure out the compatibility width and height of the screen.
177            int defaultWidth;
178            int defaultHeight;
179            switch (orientation) {
180                case Configuration.ORIENTATION_LANDSCAPE: {
181                    defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density +
182                            0.5f);
183                    defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density +
184                            0.5f);
185                    break;
186                }
187                case Configuration.ORIENTATION_PORTRAIT:
188                case Configuration.ORIENTATION_SQUARE:
189                default: {
190                    defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density +
191                            0.5f);
192                    defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density +
193                            0.5f);
194                    break;
195                }
196                case Configuration.ORIENTATION_UNDEFINED: {
197                    // don't change
198                    return;
199                }
200            }
201
202            if (defaultWidth < widthPixels) {
203                // content/window's x offset in original pixels
204                widthPixels = defaultWidth;
205            }
206            if (defaultHeight < heightPixels) {
207                heightPixels = defaultHeight;
208            }
209        }
210
211        if (compatibilityInfo.isScalingRequired()) {
212            float invertedRatio = compatibilityInfo.applicationInvertedScale;
213            density *= invertedRatio;
214            densityDpi = (int)((density*DisplayMetrics.DENSITY_DEFAULT)+.5f);
215            scaledDensity *= invertedRatio;
216            xdpi *= invertedRatio;
217            ydpi *= invertedRatio;
218            widthPixels = (int) (widthPixels * invertedRatio + 0.5f);
219            heightPixels = (int) (heightPixels * invertedRatio + 0.5f);
220        }
221    }
222
223    @Override
224    public String toString() {
225        return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
226            ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
227            ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
228    }
229
230    private static int getDeviceDensity() {
231        // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
232        // when running in the emulator, allowing for dynamic configurations.
233        // The reason for this is that ro.sf.lcd_density is write-once and is
234        // set by the init process when it parses build.prop before anything else.
235        return SystemProperties.getInt("qemu.sf.lcd_density",
236                SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
237    }
238}
239