1 /* 2 * Copyright (C) 2012 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.content.res.Configuration; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.util.ArraySet; 24 import android.util.DisplayMetrics; 25 26 import java.util.Arrays; 27 28 import libcore.util.Objects; 29 30 /** 31 * Describes the characteristics of a particular logical display. 32 * @hide 33 */ 34 public final class DisplayInfo implements Parcelable { 35 /** 36 * The surface flinger layer stack associated with this logical display. 37 */ 38 public int layerStack; 39 40 /** 41 * Display flags. 42 */ 43 public int flags; 44 45 /** 46 * Display type. 47 */ 48 public int type; 49 50 /** 51 * Display address, or null if none. 52 * Interpretation varies by display type. 53 */ 54 public String address; 55 56 /** 57 * The human-readable name of the display. 58 */ 59 public String name; 60 61 /** 62 * Unique identifier for the display. Shouldn't be displayed to the user. 63 */ 64 public String uniqueId; 65 66 /** 67 * The width of the portion of the display that is available to applications, in pixels. 68 * Represents the size of the display minus any system decorations. 69 */ 70 public int appWidth; 71 72 /** 73 * The height of the portion of the display that is available to applications, in pixels. 74 * Represents the size of the display minus any system decorations. 75 */ 76 public int appHeight; 77 78 /** 79 * The smallest value of {@link #appWidth} that an application is likely to encounter, 80 * in pixels, excepting cases where the width may be even smaller due to the presence 81 * of a soft keyboard, for example. 82 */ 83 public int smallestNominalAppWidth; 84 85 /** 86 * The smallest value of {@link #appHeight} that an application is likely to encounter, 87 * in pixels, excepting cases where the height may be even smaller due to the presence 88 * of a soft keyboard, for example. 89 */ 90 public int smallestNominalAppHeight; 91 92 /** 93 * The largest value of {@link #appWidth} that an application is likely to encounter, 94 * in pixels, excepting cases where the width may be even larger due to system decorations 95 * such as the status bar being hidden, for example. 96 */ 97 public int largestNominalAppWidth; 98 99 /** 100 * The largest value of {@link #appHeight} that an application is likely to encounter, 101 * in pixels, excepting cases where the height may be even larger due to system decorations 102 * such as the status bar being hidden, for example. 103 */ 104 public int largestNominalAppHeight; 105 106 /** 107 * The logical width of the display, in pixels. 108 * Represents the usable size of the display which may be smaller than the 109 * physical size when the system is emulating a smaller display. 110 */ 111 public int logicalWidth; 112 113 /** 114 * The logical height of the display, in pixels. 115 * Represents the usable size of the display which may be smaller than the 116 * physical size when the system is emulating a smaller display. 117 */ 118 public int logicalHeight; 119 120 /** 121 * @hide 122 * Number of overscan pixels on the left side of the display. 123 */ 124 public int overscanLeft; 125 126 /** 127 * @hide 128 * Number of overscan pixels on the top side of the display. 129 */ 130 public int overscanTop; 131 132 /** 133 * @hide 134 * Number of overscan pixels on the right side of the display. 135 */ 136 public int overscanRight; 137 138 /** 139 * @hide 140 * Number of overscan pixels on the bottom side of the display. 141 */ 142 public int overscanBottom; 143 144 /** 145 * The rotation of the display relative to its natural orientation. 146 * May be one of {@link android.view.Surface#ROTATION_0}, 147 * {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180}, 148 * {@link android.view.Surface#ROTATION_270}. 149 * <p> 150 * The value of this field is indeterminate if the logical display is presented on 151 * more than one physical display. 152 * </p> 153 */ 154 @Surface.Rotation 155 public int rotation; 156 157 /** 158 * The active display mode. 159 */ 160 public int modeId; 161 162 /** 163 * The default display mode. 164 */ 165 public int defaultModeId; 166 167 /** 168 * The supported modes of this display. 169 */ 170 public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY; 171 172 /** 173 * The logical display density which is the basis for density-independent 174 * pixels. 175 */ 176 public int logicalDensityDpi; 177 178 /** 179 * The exact physical pixels per inch of the screen in the X dimension. 180 * <p> 181 * The value of this field is indeterminate if the logical display is presented on 182 * more than one physical display. 183 * </p> 184 */ 185 public float physicalXDpi; 186 187 /** 188 * The exact physical pixels per inch of the screen in the Y dimension. 189 * <p> 190 * The value of this field is indeterminate if the logical display is presented on 191 * more than one physical display. 192 * </p> 193 */ 194 public float physicalYDpi; 195 196 /** 197 * This is a positive value indicating the phase offset of the VSYNC events provided by 198 * Choreographer relative to the display refresh. For example, if Choreographer reports 199 * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos). 200 */ 201 public long appVsyncOffsetNanos; 202 203 /** 204 * This is how far in advance a buffer must be queued for presentation at 205 * a given time. If you want a buffer to appear on the screen at 206 * time N, you must submit the buffer before (N - bufferDeadlineNanos). 207 */ 208 public long presentationDeadlineNanos; 209 210 /** 211 * The state of the display, such as {@link android.view.Display#STATE_ON}. 212 */ 213 public int state; 214 215 /** 216 * The UID of the application that owns this display, or zero if it is owned by the system. 217 * <p> 218 * If the display is private, then only the owner can use it. 219 * </p> 220 */ 221 public int ownerUid; 222 223 /** 224 * The package name of the application that owns this display, or null if it is 225 * owned by the system. 226 * <p> 227 * If the display is private, then only the owner can use it. 228 * </p> 229 */ 230 public String ownerPackageName; 231 232 public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() { 233 @Override 234 public DisplayInfo createFromParcel(Parcel source) { 235 return new DisplayInfo(source); 236 } 237 238 @Override 239 public DisplayInfo[] newArray(int size) { 240 return new DisplayInfo[size]; 241 } 242 }; 243 DisplayInfo()244 public DisplayInfo() { 245 } 246 DisplayInfo(DisplayInfo other)247 public DisplayInfo(DisplayInfo other) { 248 copyFrom(other); 249 } 250 DisplayInfo(Parcel source)251 private DisplayInfo(Parcel source) { 252 readFromParcel(source); 253 } 254 255 @Override equals(Object o)256 public boolean equals(Object o) { 257 return o instanceof DisplayInfo && equals((DisplayInfo)o); 258 } 259 equals(DisplayInfo other)260 public boolean equals(DisplayInfo other) { 261 return other != null 262 && layerStack == other.layerStack 263 && flags == other.flags 264 && type == other.type 265 && Objects.equal(address, other.address) 266 && Objects.equal(uniqueId, other.uniqueId) 267 && appWidth == other.appWidth 268 && appHeight == other.appHeight 269 && smallestNominalAppWidth == other.smallestNominalAppWidth 270 && smallestNominalAppHeight == other.smallestNominalAppHeight 271 && largestNominalAppWidth == other.largestNominalAppWidth 272 && largestNominalAppHeight == other.largestNominalAppHeight 273 && logicalWidth == other.logicalWidth 274 && logicalHeight == other.logicalHeight 275 && overscanLeft == other.overscanLeft 276 && overscanTop == other.overscanTop 277 && overscanRight == other.overscanRight 278 && overscanBottom == other.overscanBottom 279 && rotation == other.rotation 280 && modeId == other.modeId 281 && defaultModeId == other.defaultModeId 282 && logicalDensityDpi == other.logicalDensityDpi 283 && physicalXDpi == other.physicalXDpi 284 && physicalYDpi == other.physicalYDpi 285 && appVsyncOffsetNanos == other.appVsyncOffsetNanos 286 && presentationDeadlineNanos == other.presentationDeadlineNanos 287 && state == other.state 288 && ownerUid == other.ownerUid 289 && Objects.equal(ownerPackageName, other.ownerPackageName); 290 } 291 292 @Override hashCode()293 public int hashCode() { 294 return 0; // don't care 295 } 296 copyFrom(DisplayInfo other)297 public void copyFrom(DisplayInfo other) { 298 layerStack = other.layerStack; 299 flags = other.flags; 300 type = other.type; 301 address = other.address; 302 name = other.name; 303 uniqueId = other.uniqueId; 304 appWidth = other.appWidth; 305 appHeight = other.appHeight; 306 smallestNominalAppWidth = other.smallestNominalAppWidth; 307 smallestNominalAppHeight = other.smallestNominalAppHeight; 308 largestNominalAppWidth = other.largestNominalAppWidth; 309 largestNominalAppHeight = other.largestNominalAppHeight; 310 logicalWidth = other.logicalWidth; 311 logicalHeight = other.logicalHeight; 312 overscanLeft = other.overscanLeft; 313 overscanTop = other.overscanTop; 314 overscanRight = other.overscanRight; 315 overscanBottom = other.overscanBottom; 316 rotation = other.rotation; 317 modeId = other.modeId; 318 defaultModeId = other.defaultModeId; 319 supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length); 320 logicalDensityDpi = other.logicalDensityDpi; 321 physicalXDpi = other.physicalXDpi; 322 physicalYDpi = other.physicalYDpi; 323 appVsyncOffsetNanos = other.appVsyncOffsetNanos; 324 presentationDeadlineNanos = other.presentationDeadlineNanos; 325 state = other.state; 326 ownerUid = other.ownerUid; 327 ownerPackageName = other.ownerPackageName; 328 } 329 readFromParcel(Parcel source)330 public void readFromParcel(Parcel source) { 331 layerStack = source.readInt(); 332 flags = source.readInt(); 333 type = source.readInt(); 334 address = source.readString(); 335 name = source.readString(); 336 appWidth = source.readInt(); 337 appHeight = source.readInt(); 338 smallestNominalAppWidth = source.readInt(); 339 smallestNominalAppHeight = source.readInt(); 340 largestNominalAppWidth = source.readInt(); 341 largestNominalAppHeight = source.readInt(); 342 logicalWidth = source.readInt(); 343 logicalHeight = source.readInt(); 344 overscanLeft = source.readInt(); 345 overscanTop = source.readInt(); 346 overscanRight = source.readInt(); 347 overscanBottom = source.readInt(); 348 rotation = source.readInt(); 349 modeId = source.readInt(); 350 defaultModeId = source.readInt(); 351 int nModes = source.readInt(); 352 supportedModes = new Display.Mode[nModes]; 353 for (int i = 0; i < nModes; i++) { 354 supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source); 355 } 356 logicalDensityDpi = source.readInt(); 357 physicalXDpi = source.readFloat(); 358 physicalYDpi = source.readFloat(); 359 appVsyncOffsetNanos = source.readLong(); 360 presentationDeadlineNanos = source.readLong(); 361 state = source.readInt(); 362 ownerUid = source.readInt(); 363 ownerPackageName = source.readString(); 364 uniqueId = source.readString(); 365 } 366 367 @Override writeToParcel(Parcel dest, int flags)368 public void writeToParcel(Parcel dest, int flags) { 369 dest.writeInt(layerStack); 370 dest.writeInt(this.flags); 371 dest.writeInt(type); 372 dest.writeString(address); 373 dest.writeString(name); 374 dest.writeInt(appWidth); 375 dest.writeInt(appHeight); 376 dest.writeInt(smallestNominalAppWidth); 377 dest.writeInt(smallestNominalAppHeight); 378 dest.writeInt(largestNominalAppWidth); 379 dest.writeInt(largestNominalAppHeight); 380 dest.writeInt(logicalWidth); 381 dest.writeInt(logicalHeight); 382 dest.writeInt(overscanLeft); 383 dest.writeInt(overscanTop); 384 dest.writeInt(overscanRight); 385 dest.writeInt(overscanBottom); 386 dest.writeInt(rotation); 387 dest.writeInt(modeId); 388 dest.writeInt(defaultModeId); 389 dest.writeInt(supportedModes.length); 390 for (int i = 0; i < supportedModes.length; i++) { 391 supportedModes[i].writeToParcel(dest, flags); 392 } 393 dest.writeInt(logicalDensityDpi); 394 dest.writeFloat(physicalXDpi); 395 dest.writeFloat(physicalYDpi); 396 dest.writeLong(appVsyncOffsetNanos); 397 dest.writeLong(presentationDeadlineNanos); 398 dest.writeInt(state); 399 dest.writeInt(ownerUid); 400 dest.writeString(ownerPackageName); 401 dest.writeString(uniqueId); 402 } 403 404 @Override describeContents()405 public int describeContents() { 406 return 0; 407 } 408 getMode()409 public Display.Mode getMode() { 410 return findMode(modeId); 411 } 412 getDefaultMode()413 public Display.Mode getDefaultMode() { 414 return findMode(defaultModeId); 415 } 416 findMode(int id)417 private Display.Mode findMode(int id) { 418 for (int i = 0; i < supportedModes.length; i++) { 419 if (supportedModes[i].getModeId() == id) { 420 return supportedModes[i]; 421 } 422 } 423 throw new IllegalStateException("Unable to locate mode " + id); 424 } 425 426 /** 427 * Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable 428 * mode could be found. 429 */ findDefaultModeByRefreshRate(float refreshRate)430 public int findDefaultModeByRefreshRate(float refreshRate) { 431 Display.Mode[] modes = supportedModes; 432 Display.Mode defaultMode = getDefaultMode(); 433 for (int i = 0; i < modes.length; i++) { 434 if (modes[i].matches( 435 defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) { 436 return modes[i].getModeId(); 437 } 438 } 439 return 0; 440 } 441 442 /** 443 * Returns the list of supported refresh rates in the default mode. 444 */ getDefaultRefreshRates()445 public float[] getDefaultRefreshRates() { 446 Display.Mode[] modes = supportedModes; 447 ArraySet<Float> rates = new ArraySet<>(); 448 Display.Mode defaultMode = getDefaultMode(); 449 for (int i = 0; i < modes.length; i++) { 450 Display.Mode mode = modes[i]; 451 if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth() 452 && mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) { 453 rates.add(mode.getRefreshRate()); 454 } 455 } 456 float[] result = new float[rates.size()]; 457 int i = 0; 458 for (Float rate : rates) { 459 result[i++] = rate; 460 } 461 return result; 462 } 463 getAppMetrics(DisplayMetrics outMetrics)464 public void getAppMetrics(DisplayMetrics outMetrics) { 465 getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); 466 } 467 getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments)468 public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) { 469 getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(), 470 displayAdjustments.getConfiguration(), appWidth, appHeight); 471 } 472 getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci, Configuration configuration)473 public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci, 474 Configuration configuration) { 475 getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight); 476 } 477 getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration)478 public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, 479 Configuration configuration) { 480 getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight); 481 } 482 getNaturalWidth()483 public int getNaturalWidth() { 484 return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? 485 logicalWidth : logicalHeight; 486 } 487 getNaturalHeight()488 public int getNaturalHeight() { 489 return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? 490 logicalHeight : logicalWidth; 491 } 492 493 /** 494 * Returns true if the specified UID has access to this display. 495 */ hasAccess(int uid)496 public boolean hasAccess(int uid) { 497 return Display.hasAccess(uid, flags, ownerUid); 498 } 499 getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, Configuration configuration, int width, int height)500 private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo, 501 Configuration configuration, int width, int height) { 502 outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi; 503 outMetrics.density = outMetrics.noncompatDensity = 504 logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 505 outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density; 506 outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi; 507 outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi; 508 509 width = (configuration != null 510 && configuration.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) 511 ? (int)((configuration.screenWidthDp * outMetrics.density) + 0.5f) : width; 512 height = (configuration != null 513 && configuration.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) 514 ? (int)((configuration.screenHeightDp * outMetrics.density) + 0.5f) : height; 515 516 outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width; 517 outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height; 518 519 if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) { 520 compatInfo.applyToDisplayMetrics(outMetrics); 521 } 522 } 523 524 // For debugging purposes 525 @Override toString()526 public String toString() { 527 StringBuilder sb = new StringBuilder(); 528 sb.append("DisplayInfo{\""); 529 sb.append(name); 530 sb.append("\", uniqueId \""); 531 sb.append(uniqueId); 532 sb.append("\", app "); 533 sb.append(appWidth); 534 sb.append(" x "); 535 sb.append(appHeight); 536 sb.append(", real "); 537 sb.append(logicalWidth); 538 sb.append(" x "); 539 sb.append(logicalHeight); 540 if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) { 541 sb.append(", overscan ("); 542 sb.append(overscanLeft); 543 sb.append(","); 544 sb.append(overscanTop); 545 sb.append(","); 546 sb.append(overscanRight); 547 sb.append(","); 548 sb.append(overscanBottom); 549 sb.append(")"); 550 } 551 sb.append(", largest app "); 552 sb.append(largestNominalAppWidth); 553 sb.append(" x "); 554 sb.append(largestNominalAppHeight); 555 sb.append(", smallest app "); 556 sb.append(smallestNominalAppWidth); 557 sb.append(" x "); 558 sb.append(smallestNominalAppHeight); 559 sb.append(", mode "); 560 sb.append(modeId); 561 sb.append(", defaultMode "); 562 sb.append(defaultModeId); 563 sb.append(", modes "); 564 sb.append(Arrays.toString(supportedModes)); 565 sb.append(", rotation "); 566 sb.append(rotation); 567 sb.append(", density "); 568 sb.append(logicalDensityDpi); 569 sb.append(" ("); 570 sb.append(physicalXDpi); 571 sb.append(" x "); 572 sb.append(physicalYDpi); 573 sb.append(") dpi, layerStack "); 574 sb.append(layerStack); 575 sb.append(", appVsyncOff "); 576 sb.append(appVsyncOffsetNanos); 577 sb.append(", presDeadline "); 578 sb.append(presentationDeadlineNanos); 579 sb.append(", type "); 580 sb.append(Display.typeToString(type)); 581 if (address != null) { 582 sb.append(", address ").append(address); 583 } 584 sb.append(", state "); 585 sb.append(Display.stateToString(state)); 586 if (ownerUid != 0 || ownerPackageName != null) { 587 sb.append(", owner ").append(ownerPackageName); 588 sb.append(" (uid ").append(ownerUid).append(")"); 589 } 590 sb.append(flagsToString(flags)); 591 sb.append("}"); 592 return sb.toString(); 593 } 594 flagsToString(int flags)595 private static String flagsToString(int flags) { 596 StringBuilder result = new StringBuilder(); 597 if ((flags & Display.FLAG_SECURE) != 0) { 598 result.append(", FLAG_SECURE"); 599 } 600 if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) { 601 result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS"); 602 } 603 if ((flags & Display.FLAG_PRIVATE) != 0) { 604 result.append(", FLAG_PRIVATE"); 605 } 606 if ((flags & Display.FLAG_PRESENTATION) != 0) { 607 result.append(", FLAG_PRESENTATION"); 608 } 609 if ((flags & Display.FLAG_SCALING_DISABLED) != 0) { 610 result.append(", FLAG_SCALING_DISABLED"); 611 } 612 if ((flags & Display.FLAG_ROUND) != 0) { 613 result.append(", FLAG_ROUND"); 614 } 615 return result.toString(); 616 } 617 } 618