Home | History | Annotate | Download | only in view
      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.view;
     18 
     19 import android.content.res.CompatibilityInfo;
     20 import android.graphics.Point;
     21 import android.graphics.Rect;
     22 import android.os.RemoteException;
     23 import android.os.ServiceManager;
     24 import android.os.SystemClock;
     25 import android.util.DisplayMetrics;
     26 import android.util.Slog;
     27 
     28 /**
     29  * Provides information about the display size and density.
     30  */
     31 public class Display {
     32     static final String TAG = "Display";
     33     static final boolean DEBUG_DISPLAY_SIZE = false;
     34 
     35     /**
     36      * The default Display id.
     37      */
     38     public static final int DEFAULT_DISPLAY = 0;
     39 
     40     /**
     41      * Use {@link android.view.WindowManager#getDefaultDisplay()
     42      * WindowManager.getDefaultDisplay()} to create a Display object.
     43      * Display gives you access to some information about a particular display
     44      * connected to the device.
     45      */
     46     Display(int display, CompatibilityInfoHolder compatInfo) {
     47         // initalize the statics when this class is first instansiated. This is
     48         // done here instead of in the static block because Zygote
     49         synchronized (sStaticInit) {
     50             if (!sInitialized) {
     51                 nativeClassInit();
     52                 sInitialized = true;
     53             }
     54         }
     55         mCompatibilityInfo = compatInfo != null ? compatInfo : new CompatibilityInfoHolder();
     56         mDisplay = display;
     57         init(display);
     58     }
     59 
     60     /**
     61      * Returns the index of this display.  This is currently undefined; do
     62      * not use.
     63      */
     64     public int getDisplayId() {
     65         return mDisplay;
     66     }
     67 
     68     /**
     69      * Returns the number of displays connected to the device.  This is
     70      * currently undefined; do not use.
     71      */
     72     native static int getDisplayCount();
     73 
     74     /**
     75      * Gets the size of the display, in pixels.
     76      * <p>
     77      * Note that this value should <em>not</em> be used for computing layouts,
     78      * since a device will typically have screen decoration (such as a status bar)
     79      * along the edges of the display that reduce the amount of application
     80      * space available from the size returned here.  Layouts should instead use
     81      * the window size.
     82      * </p><p>
     83      * The size is adjusted based on the current rotation of the display.
     84      * </p><p>
     85      * The size returned by this method does not necessarily represent the
     86      * actual raw size (native resolution) of the display.  The returned size may
     87      * be adjusted to exclude certain system decor elements that are always visible.
     88      * It may also be scaled to provide compatibility with older applications that
     89      * were originally designed for smaller displays.
     90      * </p>
     91      *
     92      * @param outSize A {@link Point} object to receive the size information.
     93      */
     94     public void getSize(Point outSize) {
     95         getSizeInternal(outSize, true);
     96     }
     97 
     98     private void getSizeInternal(Point outSize, boolean doCompat) {
     99         try {
    100             IWindowManager wm = getWindowManager();
    101             if (wm != null) {
    102                 wm.getDisplaySize(outSize);
    103                 CompatibilityInfo ci;
    104                 if (doCompat && (ci=mCompatibilityInfo.getIfNeeded()) != null) {
    105                     synchronized (mTmpMetrics) {
    106                         mTmpMetrics.noncompatWidthPixels = outSize.x;
    107                         mTmpMetrics.noncompatHeightPixels = outSize.y;
    108                         mTmpMetrics.density = mDensity;
    109                         ci.applyToDisplayMetrics(mTmpMetrics);
    110                         outSize.x = mTmpMetrics.widthPixels;
    111                         outSize.y = mTmpMetrics.heightPixels;
    112                     }
    113                 }
    114             } else {
    115                 // This is just for boot-strapping, initializing the
    116                 // system process before the window manager is up.
    117                 outSize.x = getRawWidth();
    118                 outSize.y = getRawHeight();
    119             }
    120             if (false) {
    121                 RuntimeException here = new RuntimeException("here");
    122                 here.fillInStackTrace();
    123                 Slog.v(TAG, "Returning display size: " + outSize, here);
    124             }
    125             if (DEBUG_DISPLAY_SIZE && doCompat) Slog.v(
    126                     TAG, "Returning display size: " + outSize);
    127         } catch (RemoteException e) {
    128             Slog.w("Display", "Unable to get display size", e);
    129         }
    130     }
    131 
    132     /**
    133      * Gets the size of the display as a rectangle, in pixels.
    134      *
    135      * @param outSize A {@link Rect} object to receive the size information.
    136      * @see #getSize(Point)
    137      */
    138     public void getRectSize(Rect outSize) {
    139         synchronized (mTmpPoint) {
    140             getSizeInternal(mTmpPoint, true);
    141             outSize.set(0, 0, mTmpPoint.x, mTmpPoint.y);
    142         }
    143     }
    144 
    145     /**
    146      * Return the range of display sizes an application can expect to encounter
    147      * under normal operation, as long as there is no physical change in screen
    148      * size.  This is basically the sizes you will see as the orientation
    149      * changes, taking into account whatever screen decoration there is in
    150      * each rotation.  For example, the status bar is always at the top of the
    151      * screen, so it will reduce the height both in landscape and portrait, and
    152      * the smallest height returned here will be the smaller of the two.
    153      *
    154      * This is intended for applications to get an idea of the range of sizes
    155      * they will encounter while going through device rotations, to provide a
    156      * stable UI through rotation.  The sizes here take into account all standard
    157      * system decorations that reduce the size actually available to the
    158      * application: the status bar, navigation bar, system bar, etc.  It does
    159      * <em>not</em> take into account more transient elements like an IME
    160      * soft keyboard.
    161      *
    162      * @param outSmallestSize Filled in with the smallest width and height
    163      * that the application will encounter, in pixels (not dp units).  The x
    164      * (width) dimension here directly corresponds to
    165      * {@link android.content.res.Configuration#smallestScreenWidthDp
    166      * Configuration.smallestScreenWidthDp}, except the value here is in raw
    167      * screen pixels rather than dp units.  Your application may of course
    168      * still get smaller space yet if, for example, a soft keyboard is
    169      * being displayed.
    170      * @param outLargestSize Filled in with the largest width and height
    171      * that the application will encounter, in pixels (not dp units).  Your
    172      * application may of course still get larger space than this if,
    173      * for example, screen decorations like the status bar are being hidden.
    174      */
    175     public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) {
    176         try {
    177             IWindowManager wm = getWindowManager();
    178             wm.getCurrentSizeRange(outSmallestSize, outLargestSize);
    179         } catch (RemoteException e) {
    180             Slog.w("Display", "Unable to get display size range", e);
    181             outSmallestSize.x = 0;
    182             outSmallestSize.y = 0;
    183             outLargestSize.x = 0;
    184             outLargestSize.y = 0;
    185         }
    186     }
    187 
    188     /**
    189      * Return the maximum screen size dimension that will happen.  This is
    190      * mostly for wallpapers.
    191      * @hide
    192      */
    193     public int getMaximumSizeDimension() {
    194         try {
    195             IWindowManager wm = getWindowManager();
    196             return wm.getMaximumSizeDimension();
    197         } catch (RemoteException e) {
    198             Slog.w("Display", "Unable to get display maximum size dimension", e);
    199             return 0;
    200         }
    201     }
    202 
    203     /**
    204      * @deprecated Use {@link #getSize(Point)} instead.
    205      */
    206     @Deprecated
    207     public int getWidth() {
    208         synchronized (mTmpPoint) {
    209             long now = SystemClock.uptimeMillis();
    210             if (now > (mLastGetTime+20)) {
    211                 getSizeInternal(mTmpPoint, true);
    212                 mLastGetTime = now;
    213             }
    214             return mTmpPoint.x;
    215         }
    216     }
    217 
    218     /**
    219      * @deprecated Use {@link #getSize(Point)} instead.
    220      */
    221     @Deprecated
    222     public int getHeight() {
    223         synchronized (mTmpPoint) {
    224             long now = SystemClock.uptimeMillis();
    225             if (now > (mLastGetTime+20)) {
    226                 getSizeInternal(mTmpPoint, true);
    227                 mLastGetTime = now;
    228             }
    229             return mTmpPoint.y;
    230         }
    231     }
    232 
    233     /**
    234      * Gets the real size of the display without subtracting any window decor or
    235      * applying any compatibility scale factors.
    236      * <p>
    237      * The real size may be smaller than the raw size when the window manager
    238      * is emulating a smaller display (using adb shell am display-size).
    239      * </p><p>
    240      * The size is adjusted based on the current rotation of the display.
    241      * </p>
    242      * @hide
    243      */
    244     public void getRealSize(Point outSize) {
    245         try {
    246             IWindowManager wm = getWindowManager();
    247             if (wm != null) {
    248                 wm.getRealDisplaySize(outSize);
    249             } else {
    250                 // This is just for boot-strapping, initializing the
    251                 // system process before the window manager is up.
    252                 outSize.x = getRawWidth();
    253                 outSize.y = getRawHeight();
    254             }
    255             if (DEBUG_DISPLAY_SIZE) Slog.v(
    256                     TAG, "Returning real display size: " + outSize);
    257         } catch (RemoteException e) {
    258             Slog.w("Display", "Unable to get real display size", e);
    259         }
    260     }
    261 
    262     /**
    263      * Gets the raw width of the display, in pixels.
    264      * <p>
    265      * The size is adjusted based on the current rotation of the display.
    266      * </p>
    267      * @hide
    268      */
    269     public int getRawWidth() {
    270         int w = getRawWidthNative();
    271         if (DEBUG_DISPLAY_SIZE) Slog.v(
    272                 TAG, "Returning raw display width: " + w);
    273         return w;
    274     }
    275     private native int getRawWidthNative();
    276 
    277     /**
    278      * Gets the raw height of the display, in pixels.
    279      * <p>
    280      * The size is adjusted based on the current rotation of the display.
    281      * </p>
    282      * @hide
    283      */
    284     public int getRawHeight() {
    285         int h = getRawHeightNative();
    286         if (DEBUG_DISPLAY_SIZE) Slog.v(
    287                 TAG, "Returning raw display height: " + h);
    288         return h;
    289     }
    290     private native int getRawHeightNative();
    291 
    292     /**
    293      * Returns the rotation of the screen from its "natural" orientation.
    294      * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
    295      * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
    296      * {@link Surface#ROTATION_180 Surface.ROTATION_180}, or
    297      * {@link Surface#ROTATION_270 Surface.ROTATION_270}.  For
    298      * example, if a device has a naturally tall screen, and the user has
    299      * turned it on its side to go into a landscape orientation, the value
    300      * returned here may be either {@link Surface#ROTATION_90 Surface.ROTATION_90}
    301      * or {@link Surface#ROTATION_270 Surface.ROTATION_270} depending on
    302      * the direction it was turned.  The angle is the rotation of the drawn
    303      * graphics on the screen, which is the opposite direction of the physical
    304      * rotation of the device.  For example, if the device is rotated 90
    305      * degrees counter-clockwise, to compensate rendering will be rotated by
    306      * 90 degrees clockwise and thus the returned value here will be
    307      * {@link Surface#ROTATION_90 Surface.ROTATION_90}.
    308      */
    309     public int getRotation() {
    310         return getOrientation();
    311     }
    312 
    313     /**
    314      * @deprecated use {@link #getRotation}
    315      * @return orientation of this display.
    316      */
    317     @Deprecated native public int getOrientation();
    318 
    319     /**
    320      * Return the native pixel format of the display.  The returned value
    321      * may be one of the constants int {@link android.graphics.PixelFormat}.
    322      */
    323     public int getPixelFormat() {
    324         return mPixelFormat;
    325     }
    326 
    327     /**
    328      * Return the refresh rate of this display in frames per second.
    329      */
    330     public float getRefreshRate() {
    331         return mRefreshRate;
    332     }
    333 
    334     /**
    335      * Gets display metrics that describe the size and density of this display.
    336      * <p>
    337      * The size is adjusted based on the current rotation of the display.
    338      * </p><p>
    339      * The size returned by this method does not necessarily represent the
    340      * actual raw size (native resolution) of the display.  The returned size may
    341      * be adjusted to exclude certain system decor elements that are always visible.
    342      * It may also be scaled to provide compatibility with older applications that
    343      * were originally designed for smaller displays.
    344      * </p>
    345      *
    346      * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
    347      */
    348     public void getMetrics(DisplayMetrics outMetrics) {
    349         synchronized (mTmpPoint) {
    350             getSizeInternal(mTmpPoint, false);
    351             getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y);
    352         }
    353 
    354         CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
    355         if (ci != null) {
    356             ci.applyToDisplayMetrics(outMetrics);
    357         }
    358 
    359         if (DEBUG_DISPLAY_SIZE) Slog.v(TAG, "Returning DisplayMetrics: "
    360                 + outMetrics.widthPixels + "x" + outMetrics.heightPixels
    361                 + " " + outMetrics.density);
    362     }
    363 
    364     /**
    365      * Gets display metrics based on the real size of this display.
    366      * @hide
    367      */
    368     public void getRealMetrics(DisplayMetrics outMetrics) {
    369         synchronized (mTmpPoint) {
    370             getRealSize(mTmpPoint);
    371             getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y);
    372         }
    373     }
    374 
    375     /**
    376      * If the display is mirrored to an external HDMI display, returns the
    377      * width of that display.
    378      * @hide
    379      */
    380     public int getRawExternalWidth() {
    381         return 1280;
    382     }
    383 
    384     /**
    385      * If the display is mirrored to an external HDMI display, returns the
    386      * height of that display.
    387      * @hide
    388      */
    389     public int getRawExternalHeight() {
    390         return 720;
    391     }
    392 
    393     /**
    394      * If the display is mirrored to an external HDMI display, returns the
    395      * rotation of that display relative to its natural orientation.
    396      * @hide
    397      */
    398     public int getExternalRotation() {
    399         return Surface.ROTATION_0;
    400     }
    401 
    402     /**
    403      * Gets display metrics based on an explicit assumed display size.
    404      * @hide
    405      */
    406     public void getMetricsWithSize(DisplayMetrics outMetrics,
    407             int width, int height) {
    408         outMetrics.densityDpi   = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f);
    409 
    410         outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
    411         outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
    412 
    413         outMetrics.density = outMetrics.noncompatDensity = mDensity;
    414         outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
    415         outMetrics.xdpi = outMetrics.noncompatXdpi = mDpiX;
    416         outMetrics.ydpi = outMetrics.noncompatYdpi = mDpiY;
    417     }
    418 
    419     static IWindowManager getWindowManager() {
    420         synchronized (sStaticInit) {
    421             if (sWindowManager == null) {
    422                 sWindowManager = IWindowManager.Stub.asInterface(
    423                         ServiceManager.getService("window"));
    424             }
    425             return sWindowManager;
    426         }
    427     }
    428 
    429     /*
    430      * We use a class initializer to allow the native code to cache some
    431      * field offsets.
    432      */
    433     native private static void nativeClassInit();
    434 
    435     private native void init(int display);
    436 
    437     private final CompatibilityInfoHolder mCompatibilityInfo;
    438     private final int   mDisplay;
    439     // Following fields are initialized from native code
    440     private int         mPixelFormat;
    441     private float       mRefreshRate;
    442     /*package*/ float   mDensity;
    443     /*package*/ float   mDpiX;
    444     /*package*/ float   mDpiY;
    445 
    446     private final Point mTmpPoint = new Point();
    447     private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
    448     private float mLastGetTime;
    449 
    450     private static final Object sStaticInit = new Object();
    451     private static boolean sInitialized = false;
    452     private static IWindowManager sWindowManager;
    453 
    454     /**
    455      * Returns a display object which uses the metric's width/height instead.
    456      * @hide
    457      */
    458     public static Display createCompatibleDisplay(int displayId, CompatibilityInfoHolder compat) {
    459         return new Display(displayId, compat);
    460     }
    461 }
    462 
    463