Display.java revision 2ab1b7d9abc1b720b63ae01abcf1df0dc780eed4
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.DisplayManager;
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
53    private final int mDisplayId;
54    private final CompatibilityInfoHolder mCompatibilityInfo;
55    private final DisplayInfo mDisplayInfo = new DisplayInfo();
56
57    // Temporary display metrics structure used for compatibility mode.
58    private final DisplayMetrics mTempMetrics = new DisplayMetrics();
59
60    // We cache the app width and height properties briefly between calls
61    // to getHeight() and getWidth() to ensure that applications perceive
62    // consistent results when the size changes (most of the time).
63    // Applications should now be using getSize() instead.
64    private static final int CACHED_APP_SIZE_DURATION_MILLIS = 20;
65    private long mLastCachedAppSizeUpdate;
66    private int mCachedAppWidthCompat;
67    private int mCachedAppHeightCompat;
68
69    /**
70     * The default Display id.
71     */
72    public static final int DEFAULT_DISPLAY = 0;
73
74    /**
75     * Uninitialized display.
76     * @hide
77     */
78    public static final int NO_DISPLAY = -1;
79
80    /**
81     * Internal method to create a display.
82     * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
83     * to get a display object for the default display.
84     *
85     * @hide
86     */
87    public Display(int displayId, CompatibilityInfoHolder compatibilityInfo) {
88        mDisplayId = displayId;
89        mCompatibilityInfo = compatibilityInfo;
90    }
91
92    /**
93     * Gets the display id.
94     * <p>
95     * Each logical display has a unique id.
96     * The default display has id {@link #DEFAULT_DISPLAY}.
97     * </p>
98     */
99    public int getDisplayId() {
100        return mDisplayId;
101    }
102
103    /**
104     * Gets a full copy of the display information.
105     *
106     * @param outDisplayInfo The object to receive the copy of the display information.
107     * @hide
108     */
109    public void getDisplayInfo(DisplayInfo outDisplayInfo) {
110        synchronized (this) {
111            updateDisplayInfoLocked();
112            outDisplayInfo.copyFrom(mDisplayInfo);
113        }
114    }
115
116    /**
117     * Gets the size of the display, in pixels.
118     * <p>
119     * Note that this value should <em>not</em> be used for computing layouts,
120     * since a device will typically have screen decoration (such as a status bar)
121     * along the edges of the display that reduce the amount of application
122     * space available from the size returned here.  Layouts should instead use
123     * the window size.
124     * </p><p>
125     * The size is adjusted based on the current rotation of the display.
126     * </p><p>
127     * The size returned by this method does not necessarily represent the
128     * actual raw size (native resolution) of the display.  The returned size may
129     * be adjusted to exclude certain system decoration elements that are always visible.
130     * It may also be scaled to provide compatibility with older applications that
131     * were originally designed for smaller displays.
132     * </p>
133     *
134     * @param outSize A {@link Point} object to receive the size information.
135     */
136    public void getSize(Point outSize) {
137        synchronized (this) {
138            updateDisplayInfoLocked();
139            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
140            outSize.x = mTempMetrics.widthPixels;
141            outSize.y = mTempMetrics.heightPixels;
142        }
143    }
144
145    /**
146     * Gets the size of the display as a rectangle, in pixels.
147     *
148     * @param outSize A {@link Rect} object to receive the size information.
149     * @see #getSize(Point)
150     */
151    public void getRectSize(Rect outSize) {
152        synchronized (this) {
153            updateDisplayInfoLocked();
154            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
155            outSize.set(0, 0, mTempMetrics.widthPixels, mTempMetrics.heightPixels);
156        }
157    }
158
159    /**
160     * Return the range of display sizes an application can expect to encounter
161     * under normal operation, as long as there is no physical change in screen
162     * size.  This is basically the sizes you will see as the orientation
163     * changes, taking into account whatever screen decoration there is in
164     * each rotation.  For example, the status bar is always at the top of the
165     * screen, so it will reduce the height both in landscape and portrait, and
166     * the smallest height returned here will be the smaller of the two.
167     *
168     * This is intended for applications to get an idea of the range of sizes
169     * they will encounter while going through device rotations, to provide a
170     * stable UI through rotation.  The sizes here take into account all standard
171     * system decorations that reduce the size actually available to the
172     * application: the status bar, navigation bar, system bar, etc.  It does
173     * <em>not</em> take into account more transient elements like an IME
174     * soft keyboard.
175     *
176     * @param outSmallestSize Filled in with the smallest width and height
177     * that the application will encounter, in pixels (not dp units).  The x
178     * (width) dimension here directly corresponds to
179     * {@link android.content.res.Configuration#smallestScreenWidthDp
180     * Configuration.smallestScreenWidthDp}, except the value here is in raw
181     * screen pixels rather than dp units.  Your application may of course
182     * still get smaller space yet if, for example, a soft keyboard is
183     * being displayed.
184     * @param outLargestSize Filled in with the largest width and height
185     * that the application will encounter, in pixels (not dp units).  Your
186     * application may of course still get larger space than this if,
187     * for example, screen decorations like the status bar are being hidden.
188     */
189    public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) {
190        synchronized (this) {
191            updateDisplayInfoLocked();
192            outSmallestSize.x = mDisplayInfo.smallestNominalAppWidth;
193            outSmallestSize.y = mDisplayInfo.smallestNominalAppHeight;
194            outLargestSize.x = mDisplayInfo.largestNominalAppWidth;
195            outLargestSize.y = mDisplayInfo.largestNominalAppHeight;
196        }
197    }
198
199    /**
200     * Return the maximum screen size dimension that will happen.  This is
201     * mostly for wallpapers.
202     * @hide
203     */
204    public int getMaximumSizeDimension() {
205        synchronized (this) {
206            updateDisplayInfoLocked();
207            return Math.max(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
208        }
209    }
210
211    /**
212     * @deprecated Use {@link #getSize(Point)} instead.
213     */
214    @Deprecated
215    public int getWidth() {
216        synchronized (this) {
217            updateCachedAppSizeIfNeededLocked();
218            return mCachedAppWidthCompat;
219        }
220    }
221
222    /**
223     * @deprecated Use {@link #getSize(Point)} instead.
224     */
225    @Deprecated
226    public int getHeight() {
227        synchronized (this) {
228            updateCachedAppSizeIfNeededLocked();
229            return mCachedAppHeightCompat;
230        }
231    }
232
233    /**
234     * Returns the rotation of the screen from its "natural" orientation.
235     * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
236     * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
237     * {@link Surface#ROTATION_180 Surface.ROTATION_180}, or
238     * {@link Surface#ROTATION_270 Surface.ROTATION_270}.  For
239     * example, if a device has a naturally tall screen, and the user has
240     * turned it on its side to go into a landscape orientation, the value
241     * returned here may be either {@link Surface#ROTATION_90 Surface.ROTATION_90}
242     * or {@link Surface#ROTATION_270 Surface.ROTATION_270} depending on
243     * the direction it was turned.  The angle is the rotation of the drawn
244     * graphics on the screen, which is the opposite direction of the physical
245     * rotation of the device.  For example, if the device is rotated 90
246     * degrees counter-clockwise, to compensate rendering will be rotated by
247     * 90 degrees clockwise and thus the returned value here will be
248     * {@link Surface#ROTATION_90 Surface.ROTATION_90}.
249     */
250    public int getRotation() {
251        synchronized (this) {
252            updateDisplayInfoLocked();
253            return mDisplayInfo.rotation;
254        }
255    }
256
257    /**
258     * @deprecated use {@link #getRotation}
259     * @return orientation of this display.
260     */
261    @Deprecated
262    public int getOrientation() {
263        return getRotation();
264    }
265
266    /**
267     * Gets the pixel format of the display.
268     * @return One of the constants defined in {@link android.graphics.PixelFormat}.
269     *
270     * @deprecated This method is no longer supported.
271     * The result is always {@link PixelFormat#RGBA_8888}.
272     */
273    @Deprecated
274    public int getPixelFormat() {
275        return PixelFormat.RGBA_8888;
276    }
277
278    /**
279     * Gets the refresh rate of this display in frames per second.
280     */
281    public float getRefreshRate() {
282        synchronized (this) {
283            updateDisplayInfoLocked();
284            return mDisplayInfo.refreshRate;
285        }
286    }
287
288    /**
289     * Gets display metrics that describe the size and density of this display.
290     * <p>
291     * The size is adjusted based on the current rotation of the display.
292     * </p><p>
293     * The size returned by this method does not necessarily represent the
294     * actual raw size (native resolution) of the display.  The returned size may
295     * be adjusted to exclude certain system decor elements that are always visible.
296     * It may also be scaled to provide compatibility with older applications that
297     * were originally designed for smaller displays.
298     * </p>
299     *
300     * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
301     */
302    public void getMetrics(DisplayMetrics outMetrics) {
303        synchronized (this) {
304            updateDisplayInfoLocked();
305            mDisplayInfo.getAppMetrics(outMetrics, mCompatibilityInfo);
306        }
307    }
308
309    /**
310     * Gets the real size of the display without subtracting any window decor or
311     * applying any compatibility scale factors.
312     * <p>
313     * The size is adjusted based on the current rotation of the display.
314     * </p><p>
315     * The real size may be smaller than the physical size of the screen when the
316     * window manager is emulating a smaller display (using adb shell am display-size).
317     * </p>
318     *
319     * @param outSize Set to the real size of the display.
320     */
321    public void getRealSize(Point outSize) {
322        synchronized (this) {
323            updateDisplayInfoLocked();
324            outSize.x = mDisplayInfo.logicalWidth;
325            outSize.y = mDisplayInfo.logicalHeight;
326        }
327    }
328
329    /**
330     * Gets display metrics based on the real size of this display.
331     * <p>
332     * The size is adjusted based on the current rotation of the display.
333     * </p><p>
334     * The real size may be smaller than the physical size of the screen when the
335     * window manager is emulating a smaller display (using adb shell am display-size).
336     * </p>
337     *
338     * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
339     */
340    public void getRealMetrics(DisplayMetrics outMetrics) {
341        synchronized (this) {
342            updateDisplayInfoLocked();
343            mDisplayInfo.getLogicalMetrics(outMetrics, null);
344        }
345    }
346
347    private void updateDisplayInfoLocked() {
348        // TODO: only refresh the display information when needed
349        if (!DisplayManager.getInstance().getDisplayInfo(mDisplayId, mDisplayInfo)) {
350            Log.e(TAG, "Could not get information about logical display " + mDisplayId);
351        }
352    }
353
354    private void updateCachedAppSizeIfNeededLocked() {
355        long now = SystemClock.uptimeMillis();
356        if (now > mLastCachedAppSizeUpdate + CACHED_APP_SIZE_DURATION_MILLIS) {
357            updateDisplayInfoLocked();
358            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
359            mCachedAppWidthCompat = mTempMetrics.widthPixels;
360            mCachedAppHeightCompat = mTempMetrics.heightPixels;
361            mLastCachedAppSizeUpdate = now;
362        }
363    }
364}
365
366