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