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