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.Point; 21 import android.graphics.Rect; 22 import android.os.RemoteException; 23 import android.os.ServiceManager; 24 import android.os.SystemClock; 25 import android.util.DisplayMetrics; 26 import android.util.Slog; 27 28 /** 29 * Provides information about the display size and density. 30 */ 31 public 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 range of display sizes an application can expect to encounter 147 * under normal operation, as long as there is no physical change in screen 148 * size. This is basically the sizes you will see as the orientation 149 * changes, taking into account whatever screen decoration there is in 150 * each rotation. For example, the status bar is always at the top of the 151 * screen, so it will reduce the height both in landscape and portrait, and 152 * the smallest height returned here will be the smaller of the two. 153 * 154 * This is intended for applications to get an idea of the range of sizes 155 * they will encounter while going through device rotations, to provide a 156 * stable UI through rotation. The sizes here take into account all standard 157 * system decorations that reduce the size actually available to the 158 * application: the status bar, navigation bar, system bar, etc. It does 159 * <em>not</em> take into account more transient elements like an IME 160 * soft keyboard. 161 * 162 * @param outSmallestSize Filled in with the smallest width and height 163 * that the application will encounter, in pixels (not dp units). The x 164 * (width) dimension here directly corresponds to 165 * {@link android.content.res.Configuration#smallestScreenWidthDp 166 * Configuration.smallestScreenWidthDp}, except the value here is in raw 167 * screen pixels rather than dp units. Your application may of course 168 * still get smaller space yet if, for example, a soft keyboard is 169 * being displayed. 170 * @param outLargestSize Filled in with the largest width and height 171 * that the application will encounter, in pixels (not dp units). Your 172 * application may of course still get larger space than this if, 173 * for example, screen decorations like the status bar are being hidden. 174 */ 175 public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) { 176 try { 177 IWindowManager wm = getWindowManager(); 178 wm.getCurrentSizeRange(outSmallestSize, outLargestSize); 179 } catch (RemoteException e) { 180 Slog.w("Display", "Unable to get display size range", e); 181 outSmallestSize.x = 0; 182 outSmallestSize.y = 0; 183 outLargestSize.x = 0; 184 outLargestSize.y = 0; 185 } 186 } 187 188 /** 189 * Return the maximum screen size dimension that will happen. This is 190 * mostly for wallpapers. 191 * @hide 192 */ 193 public int getMaximumSizeDimension() { 194 try { 195 IWindowManager wm = getWindowManager(); 196 return wm.getMaximumSizeDimension(); 197 } catch (RemoteException e) { 198 Slog.w("Display", "Unable to get display maximum size dimension", e); 199 return 0; 200 } 201 } 202 203 /** 204 * @deprecated Use {@link #getSize(Point)} instead. 205 */ 206 @Deprecated 207 public int getWidth() { 208 synchronized (mTmpPoint) { 209 long now = SystemClock.uptimeMillis(); 210 if (now > (mLastGetTime+20)) { 211 getSizeInternal(mTmpPoint, true); 212 mLastGetTime = now; 213 } 214 return mTmpPoint.x; 215 } 216 } 217 218 /** 219 * @deprecated Use {@link #getSize(Point)} instead. 220 */ 221 @Deprecated 222 public int getHeight() { 223 synchronized (mTmpPoint) { 224 long now = SystemClock.uptimeMillis(); 225 if (now > (mLastGetTime+20)) { 226 getSizeInternal(mTmpPoint, true); 227 mLastGetTime = now; 228 } 229 return mTmpPoint.y; 230 } 231 } 232 233 /** 234 * Gets the real size of the display without subtracting any window decor or 235 * applying any compatibility scale factors. 236 * <p> 237 * The real size may be smaller than the raw size when the window manager 238 * is emulating a smaller display (using adb shell am display-size). 239 * </p><p> 240 * The size is adjusted based on the current rotation of the display. 241 * </p> 242 * @hide 243 */ 244 public void getRealSize(Point outSize) { 245 try { 246 IWindowManager wm = getWindowManager(); 247 if (wm != null) { 248 wm.getRealDisplaySize(outSize); 249 } else { 250 // This is just for boot-strapping, initializing the 251 // system process before the window manager is up. 252 outSize.x = getRawWidth(); 253 outSize.y = getRawHeight(); 254 } 255 if (DEBUG_DISPLAY_SIZE) Slog.v( 256 TAG, "Returning real display size: " + outSize); 257 } catch (RemoteException e) { 258 Slog.w("Display", "Unable to get real display size", e); 259 } 260 } 261 262 /** 263 * Gets the raw width of the display, in pixels. 264 * <p> 265 * The size is adjusted based on the current rotation of the display. 266 * </p> 267 * @hide 268 */ 269 public int getRawWidth() { 270 int w = getRawWidthNative(); 271 if (DEBUG_DISPLAY_SIZE) Slog.v( 272 TAG, "Returning raw display width: " + w); 273 return w; 274 } 275 private native int getRawWidthNative(); 276 277 /** 278 * Gets the raw height of the display, in pixels. 279 * <p> 280 * The size is adjusted based on the current rotation of the display. 281 * </p> 282 * @hide 283 */ 284 public int getRawHeight() { 285 int h = getRawHeightNative(); 286 if (DEBUG_DISPLAY_SIZE) Slog.v( 287 TAG, "Returning raw display height: " + h); 288 return h; 289 } 290 private native int getRawHeightNative(); 291 292 /** 293 * Returns the rotation of the screen from its "natural" orientation. 294 * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0} 295 * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90}, 296 * {@link Surface#ROTATION_180 Surface.ROTATION_180}, or 297 * {@link Surface#ROTATION_270 Surface.ROTATION_270}. For 298 * example, if a device has a naturally tall screen, and the user has 299 * turned it on its side to go into a landscape orientation, the value 300 * returned here may be either {@link Surface#ROTATION_90 Surface.ROTATION_90} 301 * or {@link Surface#ROTATION_270 Surface.ROTATION_270} depending on 302 * the direction it was turned. The angle is the rotation of the drawn 303 * graphics on the screen, which is the opposite direction of the physical 304 * rotation of the device. For example, if the device is rotated 90 305 * degrees counter-clockwise, to compensate rendering will be rotated by 306 * 90 degrees clockwise and thus the returned value here will be 307 * {@link Surface#ROTATION_90 Surface.ROTATION_90}. 308 */ 309 public int getRotation() { 310 return getOrientation(); 311 } 312 313 /** 314 * @deprecated use {@link #getRotation} 315 * @return orientation of this display. 316 */ 317 @Deprecated native public int getOrientation(); 318 319 /** 320 * Return the native pixel format of the display. The returned value 321 * may be one of the constants int {@link android.graphics.PixelFormat}. 322 */ 323 public int getPixelFormat() { 324 return mPixelFormat; 325 } 326 327 /** 328 * Return the refresh rate of this display in frames per second. 329 */ 330 public float getRefreshRate() { 331 return mRefreshRate; 332 } 333 334 /** 335 * Gets display metrics that describe the size and density of this display. 336 * <p> 337 * The size is adjusted based on the current rotation of the display. 338 * </p><p> 339 * The size returned by this method does not necessarily represent the 340 * actual raw size (native resolution) of the display. The returned size may 341 * be adjusted to exclude certain system decor elements that are always visible. 342 * It may also be scaled to provide compatibility with older applications that 343 * were originally designed for smaller displays. 344 * </p> 345 * 346 * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. 347 */ 348 public void getMetrics(DisplayMetrics outMetrics) { 349 synchronized (mTmpPoint) { 350 getSizeInternal(mTmpPoint, false); 351 getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y); 352 } 353 354 CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded(); 355 if (ci != null) { 356 ci.applyToDisplayMetrics(outMetrics); 357 } 358 359 if (DEBUG_DISPLAY_SIZE) Slog.v(TAG, "Returning DisplayMetrics: " 360 + outMetrics.widthPixels + "x" + outMetrics.heightPixels 361 + " " + outMetrics.density); 362 } 363 364 /** 365 * Gets display metrics based on the real size of this display. 366 * @hide 367 */ 368 public void getRealMetrics(DisplayMetrics outMetrics) { 369 synchronized (mTmpPoint) { 370 getRealSize(mTmpPoint); 371 getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y); 372 } 373 } 374 375 /** 376 * If the display is mirrored to an external HDMI display, returns the 377 * width of that display. 378 * @hide 379 */ 380 public int getRawExternalWidth() { 381 return 1280; 382 } 383 384 /** 385 * If the display is mirrored to an external HDMI display, returns the 386 * height of that display. 387 * @hide 388 */ 389 public int getRawExternalHeight() { 390 return 720; 391 } 392 393 /** 394 * If the display is mirrored to an external HDMI display, returns the 395 * rotation of that display relative to its natural orientation. 396 * @hide 397 */ 398 public int getExternalRotation() { 399 return Surface.ROTATION_0; 400 } 401 402 /** 403 * Gets display metrics based on an explicit assumed display size. 404 * @hide 405 */ 406 public void getMetricsWithSize(DisplayMetrics outMetrics, 407 int width, int height) { 408 outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f); 409 410 outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width; 411 outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height; 412 413 outMetrics.density = outMetrics.noncompatDensity = mDensity; 414 outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density; 415 outMetrics.xdpi = outMetrics.noncompatXdpi = mDpiX; 416 outMetrics.ydpi = outMetrics.noncompatYdpi = mDpiY; 417 } 418 419 static IWindowManager getWindowManager() { 420 synchronized (sStaticInit) { 421 if (sWindowManager == null) { 422 sWindowManager = IWindowManager.Stub.asInterface( 423 ServiceManager.getService("window")); 424 } 425 return sWindowManager; 426 } 427 } 428 429 /* 430 * We use a class initializer to allow the native code to cache some 431 * field offsets. 432 */ 433 native private static void nativeClassInit(); 434 435 private native void init(int display); 436 437 private final CompatibilityInfoHolder mCompatibilityInfo; 438 private final int mDisplay; 439 // Following fields are initialized from native code 440 private int mPixelFormat; 441 private float mRefreshRate; 442 /*package*/ float mDensity; 443 /*package*/ float mDpiX; 444 /*package*/ float mDpiY; 445 446 private final Point mTmpPoint = new Point(); 447 private final DisplayMetrics mTmpMetrics = new DisplayMetrics(); 448 private float mLastGetTime; 449 450 private static final Object sStaticInit = new Object(); 451 private static boolean sInitialized = false; 452 private static IWindowManager sWindowManager; 453 454 /** 455 * Returns a display object which uses the metric's width/height instead. 456 * @hide 457 */ 458 public static Display createCompatibleDisplay(int displayId, CompatibilityInfoHolder compat) { 459 return new Display(displayId, compat); 460 } 461 } 462 463