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