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