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 org.robolectric.android.internal; 18 19 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 20 import static android.os.Build.VERSION_CODES.KITKAT; 21 import static android.os.Build.VERSION_CODES.LOLLIPOP; 22 import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; 23 import static android.os.Build.VERSION_CODES.M; 24 import static android.os.Build.VERSION_CODES.N; 25 import static android.os.Build.VERSION_CODES.N_MR1; 26 import static android.os.Build.VERSION_CODES.O; 27 28 import android.util.ArraySet; 29 import android.view.Display; 30 import android.view.DisplayInfo; 31 import android.view.Surface; 32 import java.util.Arrays; 33 import java.util.Objects; 34 import org.robolectric.RuntimeEnvironment; 35 36 /** 37 * Describes the characteristics of a particular logical display. 38 * 39 * Robolectric internal (for now), do not use. 40 */ 41 public final class DisplayConfig { 42 /** 43 * The surface flinger layer stack associated with this logical display. 44 */ 45 public int layerStack; 46 47 /** 48 * Display flags. 49 */ 50 public int flags; 51 52 /** 53 * Display type. 54 */ 55 public int type; 56 57 /** 58 * Display address, or null if none. 59 * Interpretation varies by display type. 60 */ 61 public String address; 62 63 /** 64 * The human-readable name of the display. 65 */ 66 public String name; 67 68 /** 69 * Unique identifier for the display. Shouldn't be displayed to the user. 70 */ 71 public String uniqueId; 72 73 /** 74 * The width of the portion of the display that is available to applications, in pixels. 75 * Represents the size of the display minus any system decorations. 76 */ 77 public int appWidth; 78 79 /** 80 * The height of the portion of the display that is available to applications, in pixels. 81 * Represents the size of the display minus any system decorations. 82 */ 83 public int appHeight; 84 85 /** 86 * The smallest value of {@link #appWidth} that an application is likely to encounter, 87 * in pixels, excepting cases where the width may be even smaller due to the presence 88 * of a soft keyboard, for example. 89 */ 90 public int smallestNominalAppWidth; 91 92 /** 93 * The smallest value of {@link #appHeight} that an application is likely to encounter, 94 * in pixels, excepting cases where the height may be even smaller due to the presence 95 * of a soft keyboard, for example. 96 */ 97 public int smallestNominalAppHeight; 98 99 /** 100 * The largest value of {@link #appWidth} that an application is likely to encounter, 101 * in pixels, excepting cases where the width may be even larger due to system decorations 102 * such as the status bar being hidden, for example. 103 */ 104 public int largestNominalAppWidth; 105 106 /** 107 * The largest value of {@link #appHeight} that an application is likely to encounter, 108 * in pixels, excepting cases where the height may be even larger due to system decorations 109 * such as the status bar being hidden, for example. 110 */ 111 public int largestNominalAppHeight; 112 113 /** 114 * The logical width 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 logicalWidth; 119 120 /** 121 * The logical height of the display, in pixels. 122 * Represents the usable size of the display which may be smaller than the 123 * physical size when the system is emulating a smaller display. 124 */ 125 public int logicalHeight; 126 127 /** 128 * @hide 129 * Number of overscan pixels on the left side of the display. 130 */ 131 public int overscanLeft; 132 133 /** 134 * @hide 135 * Number of overscan pixels on the top side of the display. 136 */ 137 public int overscanTop; 138 139 /** 140 * @hide 141 * Number of overscan pixels on the right side of the display. 142 */ 143 public int overscanRight; 144 145 /** 146 * @hide 147 * Number of overscan pixels on the bottom side of the display. 148 */ 149 public int overscanBottom; 150 151 /** 152 * The rotation of the display relative to its natural orientation. 153 * May be one of {@link Surface#ROTATION_0}, 154 * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180}, 155 * {@link Surface#ROTATION_270}. 156 * <p> 157 * The value of this field is indeterminate if the logical display is presented on 158 * more than one physical display. 159 * </p> 160 */ 161 @Surface.Rotation 162 public int rotation; 163 164 /** 165 * The active display mode. 166 */ 167 public int modeId; 168 169 /** 170 * The default display mode. 171 */ 172 public int defaultModeId; 173 174 /** 175 * The supported modes of this display. 176 */ 177 public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY; 178 179 /** The active color mode. */ 180 public int colorMode; 181 182 /** The list of supported color modes */ 183 public int[] supportedColorModes = { Display.COLOR_MODE_DEFAULT }; 184 185 /** The display's HDR capabilities */ 186 public Display.HdrCapabilities hdrCapabilities; 187 188 /** 189 * The logical display density which is the basis for density-independent 190 * pixels. 191 */ 192 public int logicalDensityDpi; 193 194 /** 195 * The exact physical pixels per inch of the screen in the X dimension. 196 * <p> 197 * The value of this field is indeterminate if the logical display is presented on 198 * more than one physical display. 199 * </p> 200 */ 201 public float physicalXDpi; 202 203 /** 204 * The exact physical pixels per inch of the screen in the Y dimension. 205 * <p> 206 * The value of this field is indeterminate if the logical display is presented on 207 * more than one physical display. 208 * </p> 209 */ 210 public float physicalYDpi; 211 212 /** 213 * This is a positive value indicating the phase offset of the VSYNC events provided by 214 * Choreographer relative to the display refresh. For example, if Choreographer reports 215 * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos). 216 */ 217 public long appVsyncOffsetNanos; 218 219 /** 220 * This is how far in advance a buffer must be queued for presentation at 221 * a given time. If you want a buffer to appear on the screen at 222 * time N, you must submit the buffer before (N - bufferDeadlineNanos). 223 */ 224 public long presentationDeadlineNanos; 225 226 /** 227 * The state of the display, such as {@link Display#STATE_ON}. 228 */ 229 public int state; 230 231 /** 232 * The UID of the application that owns this display, or zero if it is owned by the system. 233 * <p> 234 * If the display is private, then only the owner can use it. 235 * </p> 236 */ 237 public int ownerUid; 238 239 /** 240 * The package name of the application that owns this display, or null if it is 241 * owned by the system. 242 * <p> 243 * If the display is private, then only the owner can use it. 244 * </p> 245 */ 246 public String ownerPackageName; 247 248 /** 249 * @hide 250 * Get current remove mode of the display - what actions should be performed with the display's 251 * content when it is removed. 252 * 253 * @see Display#getRemoveMode() 254 */ 255 public int removeMode = Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY; 256 257 public DisplayConfig() { 258 } 259 260 public DisplayConfig(DisplayConfig other) { 261 copyFrom(other); 262 } 263 264 public DisplayConfig(DisplayInfo other) { 265 layerStack = other.layerStack; 266 flags = other.flags; 267 type = other.type; 268 address = other.address; 269 name = other.name; 270 if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP_MR1) { 271 uniqueId = other.uniqueId; 272 } 273 appWidth = other.appWidth; 274 appHeight = other.appHeight; 275 smallestNominalAppWidth = other.smallestNominalAppWidth; 276 smallestNominalAppHeight = other.smallestNominalAppHeight; 277 largestNominalAppWidth = other.largestNominalAppWidth; 278 largestNominalAppHeight = other.largestNominalAppHeight; 279 logicalWidth = other.logicalWidth; 280 logicalHeight = other.logicalHeight; 281 if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR2) { 282 overscanLeft = other.overscanLeft; 283 overscanTop = other.overscanTop; 284 overscanRight = other.overscanRight; 285 overscanBottom = other.overscanBottom; 286 } 287 rotation = other.rotation; 288 if (RuntimeEnvironment.getApiLevel() >= M) { 289 modeId = other.modeId; 290 defaultModeId = other.defaultModeId; 291 supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length); 292 } 293 if (RuntimeEnvironment.getApiLevel() >= N_MR1) { 294 colorMode = other.colorMode; 295 supportedColorModes = Arrays.copyOf( 296 other.supportedColorModes, other.supportedColorModes.length); 297 } 298 if (RuntimeEnvironment.getApiLevel() >= N) { 299 hdrCapabilities = other.hdrCapabilities; 300 } 301 logicalDensityDpi = other.logicalDensityDpi; 302 physicalXDpi = other.physicalXDpi; 303 physicalYDpi = other.physicalYDpi; 304 if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) { 305 appVsyncOffsetNanos = other.appVsyncOffsetNanos; 306 presentationDeadlineNanos = other.presentationDeadlineNanos; 307 state = other.state; 308 } 309 if (RuntimeEnvironment.getApiLevel() >= KITKAT) { 310 ownerUid = other.ownerUid; 311 ownerPackageName = other.ownerPackageName; 312 } 313 if (RuntimeEnvironment.getApiLevel() >= O) { 314 removeMode = other.removeMode; 315 } 316 } 317 318 @Override 319 public boolean equals(Object o) { 320 return o instanceof DisplayConfig && equals((DisplayConfig)o); 321 } 322 323 public boolean equals(DisplayConfig other) { 324 return other != null 325 && layerStack == other.layerStack 326 && flags == other.flags 327 && type == other.type 328 && Objects.equals(address, other.address) 329 && Objects.equals(uniqueId, other.uniqueId) 330 && appWidth == other.appWidth 331 && appHeight == other.appHeight 332 && smallestNominalAppWidth == other.smallestNominalAppWidth 333 && smallestNominalAppHeight == other.smallestNominalAppHeight 334 && largestNominalAppWidth == other.largestNominalAppWidth 335 && largestNominalAppHeight == other.largestNominalAppHeight 336 && logicalWidth == other.logicalWidth 337 && logicalHeight == other.logicalHeight 338 && overscanLeft == other.overscanLeft 339 && overscanTop == other.overscanTop 340 && overscanRight == other.overscanRight 341 && overscanBottom == other.overscanBottom 342 && rotation == other.rotation 343 && modeId == other.modeId 344 && defaultModeId == other.defaultModeId 345 && colorMode == other.colorMode 346 && Arrays.equals(supportedColorModes, other.supportedColorModes) 347 && Objects.equals(hdrCapabilities, other.hdrCapabilities) 348 && logicalDensityDpi == other.logicalDensityDpi 349 && physicalXDpi == other.physicalXDpi 350 && physicalYDpi == other.physicalYDpi 351 && appVsyncOffsetNanos == other.appVsyncOffsetNanos 352 && presentationDeadlineNanos == other.presentationDeadlineNanos 353 && state == other.state 354 && ownerUid == other.ownerUid 355 && Objects.equals(ownerPackageName, other.ownerPackageName) 356 && removeMode == other.removeMode; 357 } 358 359 @Override 360 public int hashCode() { 361 return 0; // don't care 362 } 363 364 public void copyFrom(DisplayConfig other) { 365 layerStack = other.layerStack; 366 flags = other.flags; 367 type = other.type; 368 address = other.address; 369 name = other.name; 370 uniqueId = other.uniqueId; 371 appWidth = other.appWidth; 372 appHeight = other.appHeight; 373 smallestNominalAppWidth = other.smallestNominalAppWidth; 374 smallestNominalAppHeight = other.smallestNominalAppHeight; 375 largestNominalAppWidth = other.largestNominalAppWidth; 376 largestNominalAppHeight = other.largestNominalAppHeight; 377 logicalWidth = other.logicalWidth; 378 logicalHeight = other.logicalHeight; 379 overscanLeft = other.overscanLeft; 380 overscanTop = other.overscanTop; 381 overscanRight = other.overscanRight; 382 overscanBottom = other.overscanBottom; 383 rotation = other.rotation; 384 modeId = other.modeId; 385 defaultModeId = other.defaultModeId; 386 supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length); 387 colorMode = other.colorMode; 388 supportedColorModes = Arrays.copyOf( 389 other.supportedColorModes, other.supportedColorModes.length); 390 hdrCapabilities = other.hdrCapabilities; 391 logicalDensityDpi = other.logicalDensityDpi; 392 physicalXDpi = other.physicalXDpi; 393 physicalYDpi = other.physicalYDpi; 394 appVsyncOffsetNanos = other.appVsyncOffsetNanos; 395 presentationDeadlineNanos = other.presentationDeadlineNanos; 396 state = other.state; 397 ownerUid = other.ownerUid; 398 ownerPackageName = other.ownerPackageName; 399 removeMode = other.removeMode; 400 } 401 402 public void copyTo(DisplayInfo other) { 403 other.layerStack = layerStack; 404 other.flags = flags; 405 other.type = type; 406 other.address = address; 407 other.name = name; 408 if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP_MR1) { 409 other.uniqueId = uniqueId; 410 } 411 other.appWidth = appWidth; 412 other.appHeight = appHeight; 413 other.smallestNominalAppWidth = smallestNominalAppWidth; 414 other.smallestNominalAppHeight = smallestNominalAppHeight; 415 other.largestNominalAppWidth = largestNominalAppWidth; 416 other.largestNominalAppHeight = largestNominalAppHeight; 417 other.logicalWidth = logicalWidth; 418 other.logicalHeight = logicalHeight; 419 if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR2) { 420 other.overscanLeft = overscanLeft; 421 other.overscanTop = overscanTop; 422 other.overscanRight = overscanRight; 423 other.overscanBottom = overscanBottom; 424 } 425 other.rotation = rotation; 426 if (RuntimeEnvironment.getApiLevel() >= M) { 427 other.modeId = modeId; 428 other.defaultModeId = defaultModeId; 429 other.supportedModes = Arrays.copyOf(supportedModes, supportedModes.length); 430 } 431 if (RuntimeEnvironment.getApiLevel() >= N_MR1) { 432 other.colorMode = colorMode; 433 other.supportedColorModes = Arrays.copyOf( 434 supportedColorModes, supportedColorModes.length); 435 } 436 if (RuntimeEnvironment.getApiLevel() >= N) { 437 other.hdrCapabilities = hdrCapabilities; 438 } 439 other.logicalDensityDpi = logicalDensityDpi; 440 other.physicalXDpi = physicalXDpi; 441 other.physicalYDpi = physicalYDpi; 442 if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP) { 443 other.appVsyncOffsetNanos = appVsyncOffsetNanos; 444 other.presentationDeadlineNanos = presentationDeadlineNanos; 445 other.state = state; 446 } 447 if (RuntimeEnvironment.getApiLevel() >= KITKAT) { 448 other.ownerUid = ownerUid; 449 other.ownerPackageName = ownerPackageName; 450 } 451 if (RuntimeEnvironment.getApiLevel() >= O) { 452 other.removeMode = removeMode; 453 } 454 } 455 456 // For debugging purposes 457 @Override 458 public String toString() { 459 StringBuilder sb = new StringBuilder(); 460 sb.append("DisplayConfig{\""); 461 sb.append(name); 462 sb.append("\", uniqueId \""); 463 sb.append(uniqueId); 464 sb.append("\", app "); 465 sb.append(appWidth); 466 sb.append(" x "); 467 sb.append(appHeight); 468 sb.append(", real "); 469 sb.append(logicalWidth); 470 sb.append(" x "); 471 sb.append(logicalHeight); 472 if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) { 473 sb.append(", overscan ("); 474 sb.append(overscanLeft); 475 sb.append(","); 476 sb.append(overscanTop); 477 sb.append(","); 478 sb.append(overscanRight); 479 sb.append(","); 480 sb.append(overscanBottom); 481 sb.append(")"); 482 } 483 sb.append(", largest app "); 484 sb.append(largestNominalAppWidth); 485 sb.append(" x "); 486 sb.append(largestNominalAppHeight); 487 sb.append(", smallest app "); 488 sb.append(smallestNominalAppWidth); 489 sb.append(" x "); 490 sb.append(smallestNominalAppHeight); 491 sb.append(", mode "); 492 sb.append(modeId); 493 sb.append(", defaultMode "); 494 sb.append(defaultModeId); 495 sb.append(", modes "); 496 sb.append(Arrays.toString(supportedModes)); 497 sb.append(", colorMode "); 498 sb.append(colorMode); 499 sb.append(", supportedColorModes "); 500 sb.append(Arrays.toString(supportedColorModes)); 501 sb.append(", hdrCapabilities "); 502 sb.append(hdrCapabilities); 503 sb.append(", rotation "); 504 sb.append(rotation); 505 sb.append(", density "); 506 sb.append(logicalDensityDpi); 507 sb.append(" ("); 508 sb.append(physicalXDpi); 509 sb.append(" x "); 510 sb.append(physicalYDpi); 511 sb.append(") dpi, layerStack "); 512 sb.append(layerStack); 513 sb.append(", appVsyncOff "); 514 sb.append(appVsyncOffsetNanos); 515 sb.append(", presDeadline "); 516 sb.append(presentationDeadlineNanos); 517 sb.append(", type "); 518 sb.append(Display.typeToString(type)); 519 if (address != null) { 520 sb.append(", address ").append(address); 521 } 522 sb.append(", state "); 523 sb.append(Display.stateToString(state)); 524 if (ownerUid != 0 || ownerPackageName != null) { 525 sb.append(", owner ").append(ownerPackageName); 526 sb.append(" (uid ").append(ownerUid).append(")"); 527 } 528 sb.append(flagsToString(flags)); 529 sb.append(", removeMode "); 530 sb.append(removeMode); 531 sb.append("}"); 532 return sb.toString(); 533 } 534 535 private static String flagsToString(int flags) { 536 StringBuilder result = new StringBuilder(); 537 if ((flags & Display.FLAG_SECURE) != 0) { 538 result.append(", FLAG_SECURE"); 539 } 540 if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) { 541 result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS"); 542 } 543 if ((flags & Display.FLAG_PRIVATE) != 0) { 544 result.append(", FLAG_PRIVATE"); 545 } 546 if ((flags & Display.FLAG_PRESENTATION) != 0) { 547 result.append(", FLAG_PRESENTATION"); 548 } 549 if ((flags & Display.FLAG_SCALING_DISABLED) != 0) { 550 result.append(", FLAG_SCALING_DISABLED"); 551 } 552 if ((flags & Display.FLAG_ROUND) != 0) { 553 result.append(", FLAG_ROUND"); 554 } 555 return result.toString(); 556 } 557 } 558