Home | History | Annotate | Download | only in util
      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 
     17 package android.util;
     18 
     19 import android.content.res.CompatibilityInfo;
     20 import android.content.res.Configuration;
     21 import 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  */
     31 public 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 
    139         // Note: this assume that configuration is updated before calling
    140         // updateMetrics method.
    141         if (!expandable) {
    142             if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) == 0) {
    143                 expandable = true;
    144                 // the current screen size is compatible with non-resizing apps.
    145                 compatibilityInfo.setExpandable(true);
    146             } else {
    147                 compatibilityInfo.setExpandable(false);
    148             }
    149         }
    150         if (!largeScreens) {
    151             if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
    152                     != Configuration.SCREENLAYOUT_SIZE_LARGE) {
    153                 largeScreens = true;
    154                 // the current screen size is not large.
    155                 compatibilityInfo.setLargeScreens(true);
    156             } else {
    157                 compatibilityInfo.setLargeScreens(false);
    158             }
    159         }
    160 
    161         if (!expandable || !largeScreens) {
    162             // This is a larger screen device and the app is not
    163             // compatible with large screens, so diddle it.
    164 
    165             // Figure out the compatibility width and height of the screen.
    166             int defaultWidth;
    167             int defaultHeight;
    168             switch (orientation) {
    169                 case Configuration.ORIENTATION_LANDSCAPE: {
    170                     defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density +
    171                             0.5f);
    172                     defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density +
    173                             0.5f);
    174                     break;
    175                 }
    176                 case Configuration.ORIENTATION_PORTRAIT:
    177                 case Configuration.ORIENTATION_SQUARE:
    178                 default: {
    179                     defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density +
    180                             0.5f);
    181                     defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density +
    182                             0.5f);
    183                     break;
    184                 }
    185                 case Configuration.ORIENTATION_UNDEFINED: {
    186                     // don't change
    187                     return;
    188                 }
    189             }
    190 
    191             if (defaultWidth < widthPixels) {
    192                 // content/window's x offset in original pixels
    193                 widthPixels = defaultWidth;
    194             }
    195             if (defaultHeight < heightPixels) {
    196                 heightPixels = defaultHeight;
    197             }
    198         }
    199 
    200         if (compatibilityInfo.isScalingRequired()) {
    201             float invertedRatio = compatibilityInfo.applicationInvertedScale;
    202             density *= invertedRatio;
    203             densityDpi = (int)((density*DisplayMetrics.DENSITY_DEFAULT)+.5f);
    204             scaledDensity *= invertedRatio;
    205             xdpi *= invertedRatio;
    206             ydpi *= invertedRatio;
    207             widthPixels = (int) (widthPixels * invertedRatio + 0.5f);
    208             heightPixels = (int) (heightPixels * invertedRatio + 0.5f);
    209         }
    210     }
    211 
    212     @Override
    213     public String toString() {
    214         return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
    215             ", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
    216             ", xdpi=" + xdpi + ", ydpi=" + ydpi + "}";
    217     }
    218 
    219     private static int getDeviceDensity() {
    220         // qemu.sf.lcd_density can be used to override ro.sf.lcd_density
    221         // when running in the emulator, allowing for dynamic configurations.
    222         // The reason for this is that ro.sf.lcd_density is write-once and is
    223         // set by the init process when it parses build.prop before anything else.
    224         return SystemProperties.getInt("qemu.sf.lcd_density",
    225                 SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
    226     }
    227 }
    228