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