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.PixelFormat;
     21 import android.graphics.Point;
     22 import android.graphics.Rect;
     23 import android.hardware.display.DisplayManagerGlobal;
     24 import android.os.Process;
     25 import android.os.SystemClock;
     26 import android.util.DisplayMetrics;
     27 import android.util.Log;
     28 
     29 /**
     30  * Provides information about the size and density of a logical display.
     31  * <p>
     32  * The display area is described in two different ways.
     33  * <ul>
     34  * <li>The application display area specifies the part of the display that may contain
     35  * an application window, excluding the system decorations.  The application display area may
     36  * be smaller than the real display area because the system subtracts the space needed
     37  * for decor elements such as the status bar.  Use the following methods to query the
     38  * application display area: {@link #getSize}, {@link #getRectSize} and {@link #getMetrics}.</li>
     39  * <li>The real display area specifies the part of the display that contains content
     40  * including the system decorations.  Even so, the real display area may be smaller than the
     41  * physical size of the display if the window manager is emulating a smaller display
     42  * using (adb shell am display-size).  Use the following methods to query the
     43  * real display area: {@link #getRealSize}, {@link #getRealMetrics}.</li>
     44  * </ul>
     45  * </p><p>
     46  * A logical display does not necessarily represent a particular physical display device
     47  * such as the built-in screen or an external monitor.  The contents of a logical
     48  * display may be presented on one or more physical displays according to the devices
     49  * that are currently attached and whether mirroring has been enabled.
     50  * </p>
     51  */
     52 public final class Display {
     53     private static final String TAG = "Display";
     54     private static final boolean DEBUG = false;
     55 
     56     private final DisplayManagerGlobal mGlobal;
     57     private final int mDisplayId;
     58     private final int mLayerStack;
     59     private final int mFlags;
     60     private final int mType;
     61     private final String mAddress;
     62     private final int mOwnerUid;
     63     private final String mOwnerPackageName;
     64     private final DisplayAdjustments mDisplayAdjustments;
     65 
     66     private DisplayInfo mDisplayInfo; // never null
     67     private boolean mIsValid;
     68 
     69     // Temporary display metrics structure used for compatibility mode.
     70     private final DisplayMetrics mTempMetrics = new DisplayMetrics();
     71 
     72     // We cache the app width and height properties briefly between calls
     73     // to getHeight() and getWidth() to ensure that applications perceive
     74     // consistent results when the size changes (most of the time).
     75     // Applications should now be using getSize() instead.
     76     private static final int CACHED_APP_SIZE_DURATION_MILLIS = 20;
     77     private long mLastCachedAppSizeUpdate;
     78     private int mCachedAppWidthCompat;
     79     private int mCachedAppHeightCompat;
     80 
     81     /**
     82      * The default Display id, which is the id of the built-in primary display
     83      * assuming there is one.
     84      */
     85     public static final int DEFAULT_DISPLAY = 0;
     86 
     87     /**
     88      * Display flag: Indicates that the display supports compositing content
     89      * that is stored in protected graphics buffers.
     90      * <p>
     91      * If this flag is set then the display device supports compositing protected buffers.
     92      * </p><p>
     93      * If this flag is not set then the display device may not support compositing
     94      * protected buffers; the user may see a blank region on the screen instead of
     95      * the protected content.
     96      * </p><p>
     97      * Secure (DRM) video decoders may allocate protected graphics buffers to request that
     98      * a hardware-protected path be provided between the video decoder and the external
     99      * display sink.  If a hardware-protected path is not available, then content stored
    100      * in protected graphics buffers may not be composited.
    101      * </p><p>
    102      * An application can use the absence of this flag as a hint that it should not use protected
    103      * buffers for this display because the content may not be visible.  For example,
    104      * if the flag is not set then the application may choose not to show content on this
    105      * display, show an informative error message, select an alternate content stream
    106      * or adopt a different strategy for decoding content that does not rely on
    107      * protected buffers.
    108      * </p>
    109      *
    110      * @see #getFlags
    111      */
    112     public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1 << 0;
    113 
    114     /**
    115      * Display flag: Indicates that the display has a secure video output and
    116      * supports compositing secure surfaces.
    117      * <p>
    118      * If this flag is set then the display device has a secure video output
    119      * and is capable of showing secure surfaces.  It may also be capable of
    120      * showing {@link #FLAG_SUPPORTS_PROTECTED_BUFFERS protected buffers}.
    121      * </p><p>
    122      * If this flag is not set then the display device may not have a secure video
    123      * output; the user may see a blank region on the screen instead of
    124      * the contents of secure surfaces or protected buffers.
    125      * </p><p>
    126      * Secure surfaces are used to prevent content rendered into those surfaces
    127      * by applications from appearing in screenshots or from being viewed
    128      * on non-secure displays.  Protected buffers are used by secure video decoders
    129      * for a similar purpose.
    130      * </p><p>
    131      * An application creates a window with a secure surface by specifying the
    132      * {@link WindowManager.LayoutParams#FLAG_SECURE} window flag.
    133      * Likewise, an application creates a {@link SurfaceView} with a secure surface
    134      * by calling {@link SurfaceView#setSecure} before attaching the secure view to
    135      * its containing window.
    136      * </p><p>
    137      * An application can use the absence of this flag as a hint that it should not create
    138      * secure surfaces or protected buffers on this display because the content may
    139      * not be visible.  For example, if the flag is not set then the application may
    140      * choose not to show content on this display, show an informative error message,
    141      * select an alternate content stream or adopt a different strategy for decoding
    142      * content that does not rely on secure surfaces or protected buffers.
    143      * </p>
    144      *
    145      * @see #getFlags
    146      */
    147     public static final int FLAG_SECURE = 1 << 1;
    148 
    149     /**
    150      * Display flag: Indicates that the display is private.  Only the application that
    151      * owns the display can create windows on it.
    152      *
    153      * @see #getFlags
    154      */
    155     public static final int FLAG_PRIVATE = 1 << 2;
    156 
    157     /**
    158      * Display flag: Indicates that the display is a presentation display.
    159      * <p>
    160      * This flag identifies secondary displays that are suitable for
    161      * use as presentation displays such as HDMI or Wireless displays.  Applications
    162      * may automatically project their content to presentation displays to provide
    163      * richer second screen experiences.
    164      * </p>
    165      *
    166      * @see #getFlags
    167      */
    168     public static final int FLAG_PRESENTATION = 1 << 3;
    169 
    170     /**
    171      * Display type: Unknown display type.
    172      * @hide
    173      */
    174     public static final int TYPE_UNKNOWN = 0;
    175 
    176     /**
    177      * Display type: Built-in display.
    178      * @hide
    179      */
    180     public static final int TYPE_BUILT_IN = 1;
    181 
    182     /**
    183      * Display type: HDMI display.
    184      * @hide
    185      */
    186     public static final int TYPE_HDMI = 2;
    187 
    188     /**
    189      * Display type: WiFi display.
    190      * @hide
    191      */
    192     public static final int TYPE_WIFI = 3;
    193 
    194     /**
    195      * Display type: Overlay display.
    196      * @hide
    197      */
    198     public static final int TYPE_OVERLAY = 4;
    199 
    200     /**
    201      * Display type: Virtual display.
    202      * @hide
    203      */
    204     public static final int TYPE_VIRTUAL = 5;
    205 
    206     /**
    207      * Internal method to create a display.
    208      * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
    209      * or {@link android.hardware.display.DisplayManager#getDisplay}
    210      * to get a display object.
    211      *
    212      * @hide
    213      */
    214     public Display(DisplayManagerGlobal global,
    215             int displayId, DisplayInfo displayInfo /*not null*/,
    216             DisplayAdjustments daj) {
    217         mGlobal = global;
    218         mDisplayId = displayId;
    219         mDisplayInfo = displayInfo;
    220         mDisplayAdjustments = new DisplayAdjustments(daj);
    221         mIsValid = true;
    222 
    223         // Cache properties that cannot change as long as the display is valid.
    224         mLayerStack = displayInfo.layerStack;
    225         mFlags = displayInfo.flags;
    226         mType = displayInfo.type;
    227         mAddress = displayInfo.address;
    228         mOwnerUid = displayInfo.ownerUid;
    229         mOwnerPackageName = displayInfo.ownerPackageName;
    230     }
    231 
    232     /**
    233      * Gets the display id.
    234      * <p>
    235      * Each logical display has a unique id.
    236      * The default display has id {@link #DEFAULT_DISPLAY}.
    237      * </p>
    238      */
    239     public int getDisplayId() {
    240         return mDisplayId;
    241     }
    242 
    243     /**
    244      * Returns true if this display is still valid, false if the display has been removed.
    245      *
    246      * If the display is invalid, then the methods of this class will
    247      * continue to report the most recently observed display information.
    248      * However, it is unwise (and rather fruitless) to continue using a
    249      * {@link Display} object after the display's demise.
    250      *
    251      * It's possible for a display that was previously invalid to become
    252      * valid again if a display with the same id is reconnected.
    253      *
    254      * @return True if the display is still valid.
    255      */
    256     public boolean isValid() {
    257         synchronized (this) {
    258             updateDisplayInfoLocked();
    259             return mIsValid;
    260         }
    261     }
    262 
    263     /**
    264      * Gets a full copy of the display information.
    265      *
    266      * @param outDisplayInfo The object to receive the copy of the display information.
    267      * @return True if the display is still valid.
    268      * @hide
    269      */
    270     public boolean getDisplayInfo(DisplayInfo outDisplayInfo) {
    271         synchronized (this) {
    272             updateDisplayInfoLocked();
    273             outDisplayInfo.copyFrom(mDisplayInfo);
    274             return mIsValid;
    275         }
    276     }
    277 
    278     /**
    279      * Gets the display's layer stack.
    280      *
    281      * Each display has its own independent layer stack upon which surfaces
    282      * are placed to be managed by surface flinger.
    283      *
    284      * @return The display's layer stack number.
    285      * @hide
    286      */
    287     public int getLayerStack() {
    288         return mLayerStack;
    289     }
    290 
    291     /**
    292      * Returns a combination of flags that describe the capabilities of the display.
    293      *
    294      * @return The display flags.
    295      *
    296      * @see #FLAG_SUPPORTS_PROTECTED_BUFFERS
    297      * @see #FLAG_SECURE
    298      * @see #FLAG_PRIVATE
    299      */
    300     public int getFlags() {
    301         return mFlags;
    302     }
    303 
    304     /**
    305      * Gets the display type.
    306      *
    307      * @return The display type.
    308      *
    309      * @see #TYPE_UNKNOWN
    310      * @see #TYPE_BUILT_IN
    311      * @see #TYPE_HDMI
    312      * @see #TYPE_WIFI
    313      * @see #TYPE_OVERLAY
    314      * @see #TYPE_VIRTUAL
    315      * @hide
    316      */
    317     public int getType() {
    318         return mType;
    319     }
    320 
    321     /**
    322      * Gets the display address, or null if none.
    323      * Interpretation varies by display type.
    324      *
    325      * @return The display address.
    326      * @hide
    327      */
    328     public String getAddress() {
    329         return mAddress;
    330     }
    331 
    332     /**
    333      * Gets the UID of the application that owns this display, or zero if it is
    334      * owned by the system.
    335      * <p>
    336      * If the display is private, then only the owner can use it.
    337      * </p>
    338      *
    339      * @hide
    340      */
    341     public int getOwnerUid() {
    342         return mOwnerUid;
    343     }
    344 
    345     /**
    346      * Gets the package name of the application that owns this display, or null if it is
    347      * owned by the system.
    348      * <p>
    349      * If the display is private, then only the owner can use it.
    350      * </p>
    351      *
    352      * @hide
    353      */
    354     public String getOwnerPackageName() {
    355         return mOwnerPackageName;
    356     }
    357 
    358     /**
    359      * Gets the compatibility info used by this display instance.
    360      *
    361      * @return The display adjustments holder, or null if none is required.
    362      * @hide
    363      */
    364     public DisplayAdjustments getDisplayAdjustments() {
    365         return mDisplayAdjustments;
    366     }
    367 
    368     /**
    369      * Gets the name of the display.
    370      * <p>
    371      * Note that some displays may be renamed by the user.
    372      * </p>
    373      *
    374      * @return The display's name.
    375      */
    376     public String getName() {
    377         synchronized (this) {
    378             updateDisplayInfoLocked();
    379             return mDisplayInfo.name;
    380         }
    381     }
    382 
    383     /**
    384      * Gets the size of the display, in pixels.
    385      * <p>
    386      * Note that this value should <em>not</em> be used for computing layouts,
    387      * since a device will typically have screen decoration (such as a status bar)
    388      * along the edges of the display that reduce the amount of application
    389      * space available from the size returned here.  Layouts should instead use
    390      * the window size.
    391      * </p><p>
    392      * The size is adjusted based on the current rotation of the display.
    393      * </p><p>
    394      * The size returned by this method does not necessarily represent the
    395      * actual raw size (native resolution) of the display.  The returned size may
    396      * be adjusted to exclude certain system decoration elements that are always visible.
    397      * It may also be scaled to provide compatibility with older applications that
    398      * were originally designed for smaller displays.
    399      * </p>
    400      *
    401      * @param outSize A {@link Point} object to receive the size information.
    402      */
    403     public void getSize(Point outSize) {
    404         synchronized (this) {
    405             updateDisplayInfoLocked();
    406             mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
    407             outSize.x = mTempMetrics.widthPixels;
    408             outSize.y = mTempMetrics.heightPixels;
    409         }
    410     }
    411 
    412     /**
    413      * Gets the size of the display as a rectangle, in pixels.
    414      *
    415      * @param outSize A {@link Rect} object to receive the size information.
    416      * @see #getSize(Point)
    417      */
    418     public void getRectSize(Rect outSize) {
    419         synchronized (this) {
    420             updateDisplayInfoLocked();
    421             mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
    422             outSize.set(0, 0, mTempMetrics.widthPixels, mTempMetrics.heightPixels);
    423         }
    424     }
    425 
    426     /**
    427      * Return the range of display sizes an application can expect to encounter
    428      * under normal operation, as long as there is no physical change in screen
    429      * size.  This is basically the sizes you will see as the orientation
    430      * changes, taking into account whatever screen decoration there is in
    431      * each rotation.  For example, the status bar is always at the top of the
    432      * screen, so it will reduce the height both in landscape and portrait, and
    433      * the smallest height returned here will be the smaller of the two.
    434      *
    435      * This is intended for applications to get an idea of the range of sizes
    436      * they will encounter while going through device rotations, to provide a
    437      * stable UI through rotation.  The sizes here take into account all standard
    438      * system decorations that reduce the size actually available to the
    439      * application: the status bar, navigation bar, system bar, etc.  It does
    440      * <em>not</em> take into account more transient elements like an IME
    441      * soft keyboard.
    442      *
    443      * @param outSmallestSize Filled in with the smallest width and height
    444      * that the application will encounter, in pixels (not dp units).  The x
    445      * (width) dimension here directly corresponds to
    446      * {@link android.content.res.Configuration#smallestScreenWidthDp
    447      * Configuration.smallestScreenWidthDp}, except the value here is in raw
    448      * screen pixels rather than dp units.  Your application may of course
    449      * still get smaller space yet if, for example, a soft keyboard is
    450      * being displayed.
    451      * @param outLargestSize Filled in with the largest width and height
    452      * that the application will encounter, in pixels (not dp units).  Your
    453      * application may of course still get larger space than this if,
    454      * for example, screen decorations like the status bar are being hidden.
    455      */
    456     public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) {
    457         synchronized (this) {
    458             updateDisplayInfoLocked();
    459             outSmallestSize.x = mDisplayInfo.smallestNominalAppWidth;
    460             outSmallestSize.y = mDisplayInfo.smallestNominalAppHeight;
    461             outLargestSize.x = mDisplayInfo.largestNominalAppWidth;
    462             outLargestSize.y = mDisplayInfo.largestNominalAppHeight;
    463         }
    464     }
    465 
    466     /**
    467      * Return the maximum screen size dimension that will happen.  This is
    468      * mostly for wallpapers.
    469      * @hide
    470      */
    471     public int getMaximumSizeDimension() {
    472         synchronized (this) {
    473             updateDisplayInfoLocked();
    474             return Math.max(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
    475         }
    476     }
    477 
    478     /**
    479      * @deprecated Use {@link #getSize(Point)} instead.
    480      */
    481     @Deprecated
    482     public int getWidth() {
    483         synchronized (this) {
    484             updateCachedAppSizeIfNeededLocked();
    485             return mCachedAppWidthCompat;
    486         }
    487     }
    488 
    489     /**
    490      * @deprecated Use {@link #getSize(Point)} instead.
    491      */
    492     @Deprecated
    493     public int getHeight() {
    494         synchronized (this) {
    495             updateCachedAppSizeIfNeededLocked();
    496             return mCachedAppHeightCompat;
    497         }
    498     }
    499 
    500     /**
    501      * @hide
    502      * Return a rectangle defining the insets of the overscan region of the display.
    503      * Each field of the rectangle is the number of pixels the overscan area extends
    504      * into the display on that side.
    505      */
    506     public void getOverscanInsets(Rect outRect) {
    507         synchronized (this) {
    508             updateDisplayInfoLocked();
    509             outRect.set(mDisplayInfo.overscanLeft, mDisplayInfo.overscanTop,
    510                     mDisplayInfo.overscanRight, mDisplayInfo.overscanBottom);
    511         }
    512     }
    513 
    514     /**
    515      * Returns the rotation of the screen from its "natural" orientation.
    516      * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
    517      * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
    518      * {@link Surface#ROTATION_180 Surface.ROTATION_180}, or
    519      * {@link Surface#ROTATION_270 Surface.ROTATION_270}.  For
    520      * example, if a device has a naturally tall screen, and the user has
    521      * turned it on its side to go into a landscape orientation, the value
    522      * returned here may be either {@link Surface#ROTATION_90 Surface.ROTATION_90}
    523      * or {@link Surface#ROTATION_270 Surface.ROTATION_270} depending on
    524      * the direction it was turned.  The angle is the rotation of the drawn
    525      * graphics on the screen, which is the opposite direction of the physical
    526      * rotation of the device.  For example, if the device is rotated 90
    527      * degrees counter-clockwise, to compensate rendering will be rotated by
    528      * 90 degrees clockwise and thus the returned value here will be
    529      * {@link Surface#ROTATION_90 Surface.ROTATION_90}.
    530      */
    531     public int getRotation() {
    532         synchronized (this) {
    533             updateDisplayInfoLocked();
    534             return mDisplayInfo.rotation;
    535         }
    536     }
    537 
    538     /**
    539      * @deprecated use {@link #getRotation}
    540      * @return orientation of this display.
    541      */
    542     @Deprecated
    543     public int getOrientation() {
    544         return getRotation();
    545     }
    546 
    547     /**
    548      * Gets the pixel format of the display.
    549      * @return One of the constants defined in {@link android.graphics.PixelFormat}.
    550      *
    551      * @deprecated This method is no longer supported.
    552      * The result is always {@link PixelFormat#RGBA_8888}.
    553      */
    554     @Deprecated
    555     public int getPixelFormat() {
    556         return PixelFormat.RGBA_8888;
    557     }
    558 
    559     /**
    560      * Gets the refresh rate of this display in frames per second.
    561      */
    562     public float getRefreshRate() {
    563         synchronized (this) {
    564             updateDisplayInfoLocked();
    565             return mDisplayInfo.refreshRate;
    566         }
    567     }
    568 
    569     /**
    570      * Gets display metrics that describe the size and density of this display.
    571      * <p>
    572      * The size is adjusted based on the current rotation of the display.
    573      * </p><p>
    574      * The size returned by this method does not necessarily represent the
    575      * actual raw size (native resolution) of the display.  The returned size may
    576      * be adjusted to exclude certain system decor elements that are always visible.
    577      * It may also be scaled to provide compatibility with older applications that
    578      * were originally designed for smaller displays.
    579      * </p>
    580      *
    581      * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
    582      */
    583     public void getMetrics(DisplayMetrics outMetrics) {
    584         synchronized (this) {
    585             updateDisplayInfoLocked();
    586             mDisplayInfo.getAppMetrics(outMetrics, mDisplayAdjustments);
    587         }
    588     }
    589 
    590     /**
    591      * Gets the real size of the display without subtracting any window decor or
    592      * applying any compatibility scale factors.
    593      * <p>
    594      * The size is adjusted based on the current rotation of the display.
    595      * </p><p>
    596      * The real size may be smaller than the physical size of the screen when the
    597      * window manager is emulating a smaller display (using adb shell am display-size).
    598      * </p>
    599      *
    600      * @param outSize Set to the real size of the display.
    601      */
    602     public void getRealSize(Point outSize) {
    603         synchronized (this) {
    604             updateDisplayInfoLocked();
    605             outSize.x = mDisplayInfo.logicalWidth;
    606             outSize.y = mDisplayInfo.logicalHeight;
    607         }
    608     }
    609 
    610     /**
    611      * Gets display metrics based on the real size of this display.
    612      * <p>
    613      * The size is adjusted based on the current rotation of the display.
    614      * </p><p>
    615      * The real size may be smaller than the physical size of the screen when the
    616      * window manager is emulating a smaller display (using adb shell am display-size).
    617      * </p>
    618      *
    619      * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
    620      */
    621     public void getRealMetrics(DisplayMetrics outMetrics) {
    622         synchronized (this) {
    623             updateDisplayInfoLocked();
    624             mDisplayInfo.getLogicalMetrics(outMetrics,
    625                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,
    626                     mDisplayAdjustments.getActivityToken());
    627         }
    628     }
    629 
    630     /**
    631      * Returns true if the specified UID has access to this display.
    632      * @hide
    633      */
    634     public boolean hasAccess(int uid) {
    635         return Display.hasAccess(uid, mFlags, mOwnerUid);
    636     }
    637 
    638     /** @hide */
    639     public static boolean hasAccess(int uid, int flags, int ownerUid) {
    640         return (flags & Display.FLAG_PRIVATE) == 0
    641                 || uid == ownerUid
    642                 || uid == Process.SYSTEM_UID
    643                 || uid == 0;
    644     }
    645 
    646     /**
    647      * Returns true if the display is a public presentation display.
    648      * @hide
    649      */
    650     public boolean isPublicPresentation() {
    651         return (mFlags & (Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION)) ==
    652                 Display.FLAG_PRESENTATION;
    653     }
    654 
    655     private void updateDisplayInfoLocked() {
    656         // Note: The display manager caches display info objects on our behalf.
    657         DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
    658         if (newInfo == null) {
    659             // Preserve the old mDisplayInfo after the display is removed.
    660             if (mIsValid) {
    661                 mIsValid = false;
    662                 if (DEBUG) {
    663                     Log.d(TAG, "Logical display " + mDisplayId + " was removed.");
    664                 }
    665             }
    666         } else {
    667             // Use the new display info.  (It might be the same object if nothing changed.)
    668             mDisplayInfo = newInfo;
    669             if (!mIsValid) {
    670                 mIsValid = true;
    671                 if (DEBUG) {
    672                     Log.d(TAG, "Logical display " + mDisplayId + " was recreated.");
    673                 }
    674             }
    675         }
    676     }
    677 
    678     private void updateCachedAppSizeIfNeededLocked() {
    679         long now = SystemClock.uptimeMillis();
    680         if (now > mLastCachedAppSizeUpdate + CACHED_APP_SIZE_DURATION_MILLIS) {
    681             updateDisplayInfoLocked();
    682             mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
    683             mCachedAppWidthCompat = mTempMetrics.widthPixels;
    684             mCachedAppHeightCompat = mTempMetrics.heightPixels;
    685             mLastCachedAppSizeUpdate = now;
    686         }
    687     }
    688 
    689     // For debugging purposes
    690     @Override
    691     public String toString() {
    692         synchronized (this) {
    693             updateDisplayInfoLocked();
    694             mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);
    695             return "Display id " + mDisplayId + ": " + mDisplayInfo
    696                     + ", " + mTempMetrics + ", isValid=" + mIsValid;
    697         }
    698     }
    699 
    700     /**
    701      * @hide
    702      */
    703     public static String typeToString(int type) {
    704         switch (type) {
    705             case TYPE_UNKNOWN:
    706                 return "UNKNOWN";
    707             case TYPE_BUILT_IN:
    708                 return "BUILT_IN";
    709             case TYPE_HDMI:
    710                 return "HDMI";
    711             case TYPE_WIFI:
    712                 return "WIFI";
    713             case TYPE_OVERLAY:
    714                 return "OVERLAY";
    715             case TYPE_VIRTUAL:
    716                 return "VIRTUAL";
    717             default:
    718                 return Integer.toString(type);
    719         }
    720     }
    721 }
    722 
    723