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     * Returns the rotation of the screen from its "natural" orientation.
441     * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
442     * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
443     * {@link Surface#ROTATION_180 Surface.ROTATION_180}, or
444     * {@link Surface#ROTATION_270 Surface.ROTATION_270}.  For
445     * example, if a device has a naturally tall screen, and the user has
446     * turned it on its side to go into a landscape orientation, the value
447     * returned here may be either {@link Surface#ROTATION_90 Surface.ROTATION_90}
448     * or {@link Surface#ROTATION_270 Surface.ROTATION_270} depending on
449     * the direction it was turned.  The angle is the rotation of the drawn
450     * graphics on the screen, which is the opposite direction of the physical
451     * rotation of the device.  For example, if the device is rotated 90
452     * degrees counter-clockwise, to compensate rendering will be rotated by
453     * 90 degrees clockwise and thus the returned value here will be
454     * {@link Surface#ROTATION_90 Surface.ROTATION_90}.
455     */
456    public int getRotation() {
457        synchronized (this) {
458            updateDisplayInfoLocked();
459            return mDisplayInfo.rotation;
460        }
461    }
462
463    /**
464     * @deprecated use {@link #getRotation}
465     * @return orientation of this display.
466     */
467    @Deprecated
468    public int getOrientation() {
469        return getRotation();
470    }
471
472    /**
473     * Gets the pixel format of the display.
474     * @return One of the constants defined in {@link android.graphics.PixelFormat}.
475     *
476     * @deprecated This method is no longer supported.
477     * The result is always {@link PixelFormat#RGBA_8888}.
478     */
479    @Deprecated
480    public int getPixelFormat() {
481        return PixelFormat.RGBA_8888;
482    }
483
484    /**
485     * Gets the refresh rate of this display in frames per second.
486     */
487    public float getRefreshRate() {
488        synchronized (this) {
489            updateDisplayInfoLocked();
490            return mDisplayInfo.refreshRate;
491        }
492    }
493
494    /**
495     * Gets display metrics that describe the size and density of this display.
496     * <p>
497     * The size is adjusted based on the current rotation of the display.
498     * </p><p>
499     * The size returned by this method does not necessarily represent the
500     * actual raw size (native resolution) of the display.  The returned size may
501     * be adjusted to exclude certain system decor elements that are always visible.
502     * It may also be scaled to provide compatibility with older applications that
503     * were originally designed for smaller displays.
504     * </p>
505     *
506     * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
507     */
508    public void getMetrics(DisplayMetrics outMetrics) {
509        synchronized (this) {
510            updateDisplayInfoLocked();
511            mDisplayInfo.getAppMetrics(outMetrics, mCompatibilityInfo);
512        }
513    }
514
515    /**
516     * Gets the real size of the display without subtracting any window decor or
517     * applying any compatibility scale factors.
518     * <p>
519     * The size is adjusted based on the current rotation of the display.
520     * </p><p>
521     * The real size may be smaller than the physical size of the screen when the
522     * window manager is emulating a smaller display (using adb shell am display-size).
523     * </p>
524     *
525     * @param outSize Set to the real size of the display.
526     */
527    public void getRealSize(Point outSize) {
528        synchronized (this) {
529            updateDisplayInfoLocked();
530            outSize.x = mDisplayInfo.logicalWidth;
531            outSize.y = mDisplayInfo.logicalHeight;
532        }
533    }
534
535    /**
536     * Gets display metrics based on the real size of this display.
537     * <p>
538     * The size is adjusted based on the current rotation of the display.
539     * </p><p>
540     * The real size may be smaller than the physical size of the screen when the
541     * window manager is emulating a smaller display (using adb shell am display-size).
542     * </p>
543     *
544     * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
545     */
546    public void getRealMetrics(DisplayMetrics outMetrics) {
547        synchronized (this) {
548            updateDisplayInfoLocked();
549            mDisplayInfo.getLogicalMetrics(outMetrics, null);
550        }
551    }
552
553    private void updateDisplayInfoLocked() {
554        // Note: The display manager caches display info objects on our behalf.
555        DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
556        if (newInfo == null) {
557            // Preserve the old mDisplayInfo after the display is removed.
558            if (mIsValid) {
559                mIsValid = false;
560                if (DEBUG) {
561                    Log.d(TAG, "Logical display " + mDisplayId + " was removed.");
562                }
563            }
564        } else {
565            // Use the new display info.  (It might be the same object if nothing changed.)
566            mDisplayInfo = newInfo;
567            if (!mIsValid) {
568                mIsValid = true;
569                if (DEBUG) {
570                    Log.d(TAG, "Logical display " + mDisplayId + " was recreated.");
571                }
572            }
573        }
574    }
575
576    private void updateCachedAppSizeIfNeededLocked() {
577        long now = SystemClock.uptimeMillis();
578        if (now > mLastCachedAppSizeUpdate + CACHED_APP_SIZE_DURATION_MILLIS) {
579            updateDisplayInfoLocked();
580            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
581            mCachedAppWidthCompat = mTempMetrics.widthPixels;
582            mCachedAppHeightCompat = mTempMetrics.heightPixels;
583            mLastCachedAppSizeUpdate = now;
584        }
585    }
586
587    // For debugging purposes
588    @Override
589    public String toString() {
590        synchronized (this) {
591            updateDisplayInfoLocked();
592            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
593            return "Display id " + mDisplayId + ": " + mDisplayInfo
594                    + ", " + mTempMetrics + ", isValid=" + mIsValid;
595        }
596    }
597
598    /**
599     * @hide
600     */
601    public static String typeToString(int type) {
602        switch (type) {
603            case TYPE_UNKNOWN:
604                return "UNKNOWN";
605            case TYPE_BUILT_IN:
606                return "BUILT_IN";
607            case TYPE_HDMI:
608                return "HDMI";
609            case TYPE_WIFI:
610                return "WIFI";
611            case TYPE_OVERLAY:
612                return "OVERLAY";
613            default:
614                return Integer.toString(type);
615        }
616    }
617}
618
619