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 static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE; 20 import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS; 21 22 import android.Manifest; 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.RequiresPermission; 27 import android.annotation.SuppressLint; 28 import android.annotation.TestApi; 29 import android.app.KeyguardManager; 30 import android.app.WindowConfiguration; 31 import android.compat.annotation.UnsupportedAppUsage; 32 import android.content.res.CompatibilityInfo; 33 import android.content.res.Configuration; 34 import android.content.res.Resources; 35 import android.graphics.ColorSpace; 36 import android.graphics.PixelFormat; 37 import android.graphics.Point; 38 import android.graphics.Rect; 39 import android.hardware.OverlayProperties; 40 import android.hardware.display.BrightnessInfo; 41 import android.hardware.display.DeviceProductInfo; 42 import android.hardware.display.DisplayManager; 43 import android.hardware.display.DisplayManagerGlobal; 44 import android.hardware.graphics.common.DisplayDecorationSupport; 45 import android.os.Build; 46 import android.os.Parcel; 47 import android.os.Parcelable; 48 import android.os.Process; 49 import android.os.SystemClock; 50 import android.util.ArraySet; 51 import android.util.DisplayMetrics; 52 import android.util.Log; 53 54 import java.lang.annotation.Retention; 55 import java.lang.annotation.RetentionPolicy; 56 import java.util.ArrayList; 57 import java.util.Arrays; 58 import java.util.List; 59 import java.util.concurrent.Executor; 60 import java.util.function.Consumer; 61 62 /** 63 * Provides information about the size and density of a logical display. 64 * <p> 65 * The display area is described in two different ways. 66 * <ul> 67 * <li>The application display area specifies the part of the display that may contain 68 * an application window, excluding the system decorations. The application display area may 69 * be smaller than the real display area because the system subtracts the space needed 70 * for decor elements such as the status bar. Use {@link WindowMetrics#getBounds()} to query the 71 * application window bounds.</li> 72 * <li>The real display area specifies the part of the display that is accessible to an application 73 * in the current system state. The real display area may be smaller than the physical size of the 74 * display in a few scenarios. Use {@link WindowManager#getCurrentWindowMetrics()} to identify the 75 * current size of the activity window. UI-related work, such as choosing UI layouts, should rely 76 * upon {@link WindowMetrics#getBounds()}. See {@link #getRealSize} / {@link #getRealMetrics} for 77 * details.</li> 78 * </ul> 79 * </p><p> 80 * A logical display does not necessarily represent a particular physical display device 81 * such as the internal display or an external display. The contents of a logical 82 * display may be presented on one or more physical displays according to the devices 83 * that are currently attached and whether mirroring has been enabled. 84 * </p> 85 */ 86 public final class Display { 87 private static final String TAG = "Display"; 88 private static final boolean DEBUG = false; 89 90 private final Object mLock = new Object(); 91 private final DisplayManagerGlobal mGlobal; 92 private final int mDisplayId; 93 private final int mFlags; 94 private final int mType; 95 private final int mOwnerUid; 96 private final String mOwnerPackageName; 97 private final Resources mResources; 98 private DisplayAdjustments mDisplayAdjustments; 99 100 @UnsupportedAppUsage 101 private DisplayInfo mDisplayInfo; // never null 102 private boolean mIsValid; 103 104 // Temporary display metrics structure used for compatibility mode. 105 private final DisplayMetrics mTempMetrics = new DisplayMetrics(); 106 107 // We cache the app width and height properties briefly between calls 108 // to getHeight() and getWidth() to ensure that applications perceive 109 // consistent results when the size changes (most of the time). 110 // Applications should now be using WindowMetrics instead. 111 private static final int CACHED_APP_SIZE_DURATION_MILLIS = 20; 112 private long mLastCachedAppSizeUpdate; 113 private int mCachedAppWidthCompat; 114 private int mCachedAppHeightCompat; 115 116 private ArrayList<HdrSdrRatioListenerWrapper> mHdrSdrRatioListeners = new ArrayList<>(); 117 118 /** 119 * The default Display id, which is the id of the primary display assuming there is one. 120 */ 121 public static final int DEFAULT_DISPLAY = 0; 122 123 /** 124 * Invalid display id. 125 */ 126 public static final int INVALID_DISPLAY = -1; 127 128 /** 129 * Invalid resolution width. 130 * @hide 131 */ 132 public static final int INVALID_DISPLAY_WIDTH = -1; 133 134 /** 135 * Invalid resolution height. 136 * @hide 137 */ 138 public static final int INVALID_DISPLAY_HEIGHT = -1; 139 140 /** 141 * Invalid refresh rate. 142 * @hide 143 */ 144 public static final float INVALID_DISPLAY_REFRESH_RATE = 0.0f; 145 146 /** 147 * The default display group id, which is the display group id of the primary display assuming 148 * there is one. 149 * @hide 150 */ 151 public static final int DEFAULT_DISPLAY_GROUP = 0; 152 153 /** 154 * Invalid display group id. 155 * @hide 156 */ 157 public static final int INVALID_DISPLAY_GROUP = -1; 158 159 /** 160 * Display flag: Indicates that the display supports compositing content 161 * that is stored in protected graphics buffers. 162 * <p> 163 * If this flag is set then the display device supports compositing protected buffers. 164 * </p><p> 165 * If this flag is not set then the display device may not support compositing 166 * protected buffers; the user may see a blank region on the screen instead of 167 * the protected content. 168 * </p><p> 169 * Secure (DRM) video decoders may allocate protected graphics buffers to request that 170 * a hardware-protected path be provided between the video decoder and the external 171 * display sink. If a hardware-protected path is not available, then content stored 172 * in protected graphics buffers may not be composited. 173 * </p><p> 174 * An application can use the absence of this flag as a hint that it should not use protected 175 * buffers for this display because the content may not be visible. For example, 176 * if the flag is not set then the application may choose not to show content on this 177 * display, show an informative error message, select an alternate content stream 178 * or adopt a different strategy for decoding content that does not rely on 179 * protected buffers. 180 * </p> 181 * 182 * @see #getFlags 183 */ 184 public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1 << 0; 185 186 /** 187 * Display flag: Indicates that the display has a secure video output and 188 * supports compositing secure surfaces. 189 * <p> 190 * If this flag is set then the display device has a secure video output 191 * and is capable of showing secure surfaces. It may also be capable of 192 * showing {@link #FLAG_SUPPORTS_PROTECTED_BUFFERS protected buffers}. 193 * </p><p> 194 * If this flag is not set then the display device may not have a secure video 195 * output; the user may see a blank region on the screen instead of 196 * the contents of secure surfaces or protected buffers. 197 * </p><p> 198 * Secure surfaces are used to prevent content rendered into those surfaces 199 * by applications from appearing in screenshots or from being viewed 200 * on non-secure displays. Protected buffers are used by secure video decoders 201 * for a similar purpose. 202 * </p><p> 203 * An application creates a window with a secure surface by specifying the 204 * {@link WindowManager.LayoutParams#FLAG_SECURE} window flag. 205 * Likewise, an application creates a {@link SurfaceView} with a secure surface 206 * by calling {@link SurfaceView#setSecure} before attaching the secure view to 207 * its containing window. 208 * </p><p> 209 * An application can use the absence of this flag as a hint that it should not create 210 * secure surfaces or protected buffers on this display because the content may 211 * not be visible. For example, if the flag is not set then the application may 212 * choose not to show content on this display, show an informative error message, 213 * select an alternate content stream or adopt a different strategy for decoding 214 * content that does not rely on secure surfaces or protected buffers. 215 * </p> 216 * 217 * @see #getFlags 218 */ 219 public static final int FLAG_SECURE = 1 << 1; 220 221 /** 222 * Display flag: Indicates that the display is private. Only the application that 223 * owns the display and apps that are already on the display can create windows on it. 224 * 225 * @see #getFlags 226 */ 227 public static final int FLAG_PRIVATE = 1 << 2; 228 229 /** 230 * Display flag: Indicates that the display is a presentation display. 231 * <p> 232 * This flag identifies secondary displays that are suitable for 233 * use as presentation displays such as external or wireless displays. Applications 234 * may automatically project their content to presentation displays to provide 235 * richer second screen experiences. 236 * </p> 237 * 238 * @see #getFlags 239 */ 240 public static final int FLAG_PRESENTATION = 1 << 3; 241 242 /** 243 * Display flag: Indicates that the display has a round shape. 244 * <p> 245 * This flag identifies displays that are circular, elliptical or otherwise 246 * do not permit the user to see all the way to the logical corners of the display. 247 * </p> 248 * 249 * @see #getFlags 250 */ 251 public static final int FLAG_ROUND = 1 << 4; 252 253 /** 254 * Display flag: Indicates that the display can show its content when non-secure keyguard is 255 * shown. 256 * <p> 257 * This flag identifies secondary displays that will continue showing content if keyguard can be 258 * dismissed without entering credentials. 259 * </p><p> 260 * An example of usage is a virtual display which content is displayed on external hardware 261 * display that is not visible to the system directly. 262 * </p> 263 * 264 * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD 265 * @see KeyguardManager#isDeviceSecure() 266 * @see KeyguardManager#isDeviceLocked() 267 * @see #getFlags 268 * @hide 269 */ 270 // TODO (b/114338689): Remove the flag and use IWindowManager#shouldShowWithInsecureKeyguard 271 public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5; 272 273 /** 274 * Display flag: Indicates that the display should show system decorations. 275 * <p> 276 * This flag identifies secondary displays that should show system decorations, such as status 277 * bar, navigation bar, home activity or IME. 278 * </p> 279 * <p>Note that this flag doesn't work without {@link #FLAG_TRUSTED}</p> 280 * 281 * @see #getFlags() 282 * @hide 283 */ 284 // TODO (b/114338689): Remove the flag and use IWindowManager#setShouldShowSystemDecors 285 public static final int FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 6; 286 287 /** 288 * Flag: The display is trusted to show system decorations and receive inputs without users' 289 * touch. 290 * @see #FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS 291 * 292 * @see #getFlags() 293 * @hide 294 */ 295 @TestApi 296 public static final int FLAG_TRUSTED = 1 << 7; 297 298 /** 299 * Flag: Indicates that the display should not be a part of the default DisplayGroup and 300 * instead be part of a new DisplayGroup. 301 * 302 * @hide 303 * @see #getFlags() 304 */ 305 public static final int FLAG_OWN_DISPLAY_GROUP = 1 << 8; 306 307 /** 308 * Flag: Indicates that the display should always be unlocked. Only valid on virtual displays 309 * that aren't in the default display group. 310 * 311 * @hide 312 * @see #getFlags() 313 */ 314 public static final int FLAG_ALWAYS_UNLOCKED = 1 << 9; 315 316 /** 317 * Flag: Indicates that the display should not play sound effects or perform haptic feedback 318 * when the user touches the screen. 319 * 320 * @hide 321 * @see #getFlags() 322 */ 323 public static final int FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 10; 324 325 /** 326 * Flag: Indicates that the display maintains its own focus and touch mode. 327 * 328 * This flag is similar to {@link com.android.internal.R.bool.config_perDisplayFocusEnabled} in 329 * behavior, but only applies to the specific display instead of system-wide to all displays. 330 * 331 * Note: The display must be trusted in order to have its own focus. 332 * 333 * @see #FLAG_TRUSTED 334 * @hide 335 */ 336 public static final int FLAG_OWN_FOCUS = 1 << 11; 337 338 /** 339 * Flag: Indicates that the display should not become the top focused display by stealing the 340 * top focus from another display. 341 * 342 * <p>The result is that only targeted input events (displayId of input event matches the 343 * displayId of the display) can reach this display. A display with this flag set can still 344 * become the top focused display, if the system consists of only one display or if all 345 * displays have this flag set. In both cases the default display becomes the top focused 346 * display. 347 * 348 * <p>Note: A display only has a focused window if either 349 * - the display is the top focused display or 350 * - the display manages its own focus (via {@link #FLAG_OWN_FOCUS}) 351 * - or all the displays manage their own focus (via {@code config_perDisplayFocusEnabled} flag) 352 * If a display has no focused window, no input event is dispatched to it. Therefore this 353 * flag is only useful together with {@link #FLAG_OWN_FOCUS} and will be 354 * ignored if it is not set. 355 * 356 * <p>Note: The framework only supports IME on the top focused display (b/262520411). Therefore, 357 * Enabling this flag on a display implicitly disables showing any IME. This is not intended 358 * behavior but cannot be fixed until b/262520411 is implemented. If you need IME on display do 359 * not set this flag. 360 * 361 * @hide 362 * @see #getFlags() 363 */ 364 public static final int FLAG_STEAL_TOP_FOCUS_DISABLED = 1 << 12; 365 366 /** 367 * Display flag: Indicates that the display is a rear display. 368 * <p> 369 * This flag identifies complementary displays that are facing away from the user. 370 * </p> 371 * 372 * @hide 373 * @see #getFlags() 374 */ 375 public static final int FLAG_REAR = 1 << 13; 376 377 /** 378 * Display flag: Indicates that the orientation of this display is not fixed and is coupled to 379 * the orientation of its content. 380 * 381 * @hide 382 */ 383 public static final int FLAG_ROTATES_WITH_CONTENT = 1 << 14; 384 385 /** 386 * Display flag: Indicates that the contents of the display should not be scaled 387 * to fit the physical screen dimensions. Used for development only to emulate 388 * devices with smaller physicals screens while preserving density. 389 * 390 * @hide 391 */ 392 public static final int FLAG_SCALING_DISABLED = 1 << 30; 393 394 /** 395 * Display type: Unknown display type. 396 * @hide 397 */ 398 @UnsupportedAppUsage 399 @TestApi 400 public static final int TYPE_UNKNOWN = 0; 401 402 /** 403 * Display type: Physical display connected through an internal port. 404 * @hide 405 */ 406 @TestApi 407 public static final int TYPE_INTERNAL = 1; 408 409 /** 410 * Display type: Physical display connected through an external port. 411 * @hide 412 */ 413 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 414 @TestApi 415 public static final int TYPE_EXTERNAL = 2; 416 417 /** 418 * Display type: WiFi display. 419 * @hide 420 */ 421 @UnsupportedAppUsage 422 @TestApi 423 public static final int TYPE_WIFI = 3; 424 425 /** 426 * Display type: Overlay display. 427 * @hide 428 */ 429 @TestApi 430 public static final int TYPE_OVERLAY = 4; 431 432 /** 433 * Display type: Virtual display. 434 * @hide 435 */ 436 @UnsupportedAppUsage 437 @TestApi 438 public static final int TYPE_VIRTUAL = 5; 439 440 /** 441 * Display state: The display state is unknown. 442 * 443 * @see #getState 444 */ 445 public static final int STATE_UNKNOWN = ViewProtoEnums.DISPLAY_STATE_UNKNOWN; // 0 446 447 /** 448 * Display state: The display is off. 449 * 450 * @see #getState 451 */ 452 public static final int STATE_OFF = ViewProtoEnums.DISPLAY_STATE_OFF; // 1 453 454 /** 455 * Display state: The display is on. 456 * 457 * @see #getState 458 */ 459 public static final int STATE_ON = ViewProtoEnums.DISPLAY_STATE_ON; // 2 460 461 /** 462 * Display state: The display is dozing in a low power state; it is still 463 * on but is optimized for showing system-provided content while the 464 * device is non-interactive. 465 * 466 * @see #getState 467 * @see android.os.PowerManager#isInteractive 468 */ 469 public static final int STATE_DOZE = ViewProtoEnums.DISPLAY_STATE_DOZE; // 3 470 471 /** 472 * Display state: The display is dozing in a suspended low power state; it is still 473 * on but the CPU is not updating it. This may be used in one of two ways: to show 474 * static system-provided content while the device is non-interactive, or to allow 475 * a "Sidekick" compute resource to update the display. For this reason, the 476 * CPU must not control the display in this mode. 477 * 478 * @see #getState 479 * @see android.os.PowerManager#isInteractive 480 */ 481 public static final int STATE_DOZE_SUSPEND = ViewProtoEnums.DISPLAY_STATE_DOZE_SUSPEND; // 4 482 483 /** 484 * Display state: The display is on and optimized for VR mode. 485 * 486 * @see #getState 487 * @see android.os.PowerManager#isInteractive 488 */ 489 public static final int STATE_VR = ViewProtoEnums.DISPLAY_STATE_VR; // 5 490 491 /** 492 * Display state: The display is in a suspended full power state; it is still 493 * on but the CPU is not updating it. This may be used in one of two ways: to show 494 * static system-provided content while the device is non-interactive, or to allow 495 * a "Sidekick" compute resource to update the display. For this reason, the 496 * CPU must not control the display in this mode. 497 * 498 * @see #getState 499 * @see android.os.PowerManager#isInteractive 500 */ 501 public static final int STATE_ON_SUSPEND = ViewProtoEnums.DISPLAY_STATE_ON_SUSPEND; // 6 502 503 /* The color mode constants defined below must be kept in sync with the ones in 504 * system/core/include/system/graphics-base.h */ 505 506 /** 507 * Display color mode: The current color mode is unknown or invalid. 508 * @hide 509 */ 510 public static final int COLOR_MODE_INVALID = -1; 511 512 /** 513 * Display color mode: The default or native gamut of the display. 514 * @hide 515 */ 516 public static final int COLOR_MODE_DEFAULT = 0; 517 518 /** @hide */ 519 public static final int COLOR_MODE_BT601_625 = 1; 520 /** @hide */ 521 public static final int COLOR_MODE_BT601_625_UNADJUSTED = 2; 522 /** @hide */ 523 public static final int COLOR_MODE_BT601_525 = 3; 524 /** @hide */ 525 public static final int COLOR_MODE_BT601_525_UNADJUSTED = 4; 526 /** @hide */ 527 public static final int COLOR_MODE_BT709 = 5; 528 /** @hide */ 529 public static final int COLOR_MODE_DCI_P3 = 6; 530 /** @hide */ 531 public static final int COLOR_MODE_SRGB = 7; 532 /** @hide */ 533 public static final int COLOR_MODE_ADOBE_RGB = 8; 534 /** @hide */ 535 public static final int COLOR_MODE_DISPLAY_P3 = 9; 536 537 /** @hide **/ 538 @IntDef(prefix = {"COLOR_MODE_"}, value = { 539 COLOR_MODE_INVALID, 540 COLOR_MODE_DEFAULT, 541 COLOR_MODE_BT601_625, 542 COLOR_MODE_BT601_625_UNADJUSTED, 543 COLOR_MODE_BT601_525, 544 COLOR_MODE_BT601_525_UNADJUSTED, 545 COLOR_MODE_BT709, 546 COLOR_MODE_DCI_P3, 547 COLOR_MODE_SRGB, 548 COLOR_MODE_ADOBE_RGB, 549 COLOR_MODE_DISPLAY_P3 550 }) 551 @Retention(RetentionPolicy.SOURCE) 552 public @interface ColorMode {} 553 554 /** 555 * Indicates that when display is removed, all its activities will be moved to the primary 556 * display and the topmost activity should become focused. 557 * 558 * @hide 559 */ 560 // TODO (b/114338689): Remove the flag and use WindowManager#REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY 561 public static final int REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY = 0; 562 /** 563 * Indicates that when display is removed, all its stacks and tasks will be removed, all 564 * activities will be destroyed according to the usual lifecycle. 565 * 566 * @hide 567 */ 568 // TODO (b/114338689): Remove the flag and use WindowManager#REMOVE_CONTENT_MODE_DESTROY 569 public static final int REMOVE_MODE_DESTROY_CONTENT = 1; 570 571 /** @hide */ 572 public static final int DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE = 0xFF; 573 574 /** 575 * Internal method to create a display. 576 * The display created with this method will have a static {@link DisplayAdjustments} applied. 577 * Applications should use {@link android.content.Context#getDisplay} with 578 * {@link android.app.Activity} or a context associated with a {@link Display} via 579 * {@link android.content.Context#createDisplayContext(Display)} 580 * to get a display object associated with a {@link android.app.Context}, or 581 * {@link android.hardware.display.DisplayManager#getDisplay} to get a display object by id. 582 * 583 * @see android.content.Context#getDisplay() 584 * @see android.content.Context#createDisplayContext(Display) 585 * @hide 586 */ Display(DisplayManagerGlobal global, int displayId, DisplayInfo displayInfo, DisplayAdjustments daj)587 public Display(DisplayManagerGlobal global, int displayId, /*@NotNull*/ DisplayInfo displayInfo, 588 DisplayAdjustments daj) { 589 this(global, displayId, displayInfo, daj, null /*res*/); 590 } 591 592 /** 593 * Internal method to create a display. 594 * The display created with this method will be adjusted based on the adjustments in the 595 * supplied {@link Resources}. 596 * 597 * @hide 598 */ Display(DisplayManagerGlobal global, int displayId, DisplayInfo displayInfo, Resources res)599 public Display(DisplayManagerGlobal global, int displayId, /*@NotNull*/ DisplayInfo displayInfo, 600 Resources res) { 601 this(global, displayId, displayInfo, null /*daj*/, res); 602 } 603 Display(DisplayManagerGlobal global, int displayId, DisplayInfo displayInfo, DisplayAdjustments daj, Resources res)604 private Display(DisplayManagerGlobal global, int displayId, 605 /*@NotNull*/ DisplayInfo displayInfo, DisplayAdjustments daj, Resources res) { 606 mGlobal = global; 607 mDisplayId = displayId; 608 mDisplayInfo = displayInfo; 609 mResources = res; 610 mDisplayAdjustments = mResources != null 611 ? new DisplayAdjustments(mResources.getConfiguration()) 612 : daj != null ? new DisplayAdjustments(daj) : new DisplayAdjustments(); 613 mIsValid = true; 614 615 // Cache properties that cannot change as long as the display is valid. 616 mFlags = displayInfo.flags; 617 mType = displayInfo.type; 618 mOwnerUid = displayInfo.ownerUid; 619 mOwnerPackageName = displayInfo.ownerPackageName; 620 } 621 622 /** 623 * Gets the display id. 624 * <p> 625 * Each logical display has a unique id. 626 * The default display has id {@link #DEFAULT_DISPLAY}. 627 * </p> 628 */ getDisplayId()629 public int getDisplayId() { 630 return mDisplayId; 631 } 632 633 /** 634 * Gets the display unique id. 635 * <p> 636 * Unique id is different from display id because physical displays have stable unique id across 637 * reboots. 638 * 639 * @see com.android.service.display.DisplayDevice#hasStableUniqueId(). 640 * @hide 641 */ 642 @TestApi getUniqueId()643 public @Nullable String getUniqueId() { 644 return mDisplayInfo.uniqueId; 645 } 646 647 /** 648 * Returns true if this display is still valid, false if the display has been removed. 649 * 650 * If the display is invalid, then the methods of this class will 651 * continue to report the most recently observed display information. 652 * However, it is unwise (and rather fruitless) to continue using a 653 * {@link Display} object after the display's demise. 654 * 655 * It's possible for a display that was previously invalid to become 656 * valid again if a display with the same id is reconnected. 657 * 658 * @return True if the display is still valid. 659 */ isValid()660 public boolean isValid() { 661 synchronized (mLock) { 662 updateDisplayInfoLocked(); 663 return mIsValid; 664 } 665 } 666 667 /** 668 * Gets a full copy of the display information. 669 * 670 * @param outDisplayInfo The object to receive the copy of the display information. 671 * @return True if the display is still valid. 672 * @hide 673 */ 674 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) getDisplayInfo(DisplayInfo outDisplayInfo)675 public boolean getDisplayInfo(DisplayInfo outDisplayInfo) { 676 synchronized (mLock) { 677 updateDisplayInfoLocked(); 678 outDisplayInfo.copyFrom(mDisplayInfo); 679 return mIsValid; 680 } 681 } 682 683 /** 684 * Gets the display's layer stack. 685 * 686 * Each display has its own independent layer stack upon which surfaces 687 * are placed to be managed by surface flinger. 688 * 689 * @return The display's layer stack number. 690 * @hide 691 */ getLayerStack()692 public int getLayerStack() { 693 synchronized (mLock) { 694 updateDisplayInfoLocked(); 695 return mDisplayInfo.layerStack; 696 } 697 } 698 699 /** 700 * Returns a combination of flags that describe the capabilities of the display. 701 * 702 * @return The display flags. 703 * 704 * @see #FLAG_SUPPORTS_PROTECTED_BUFFERS 705 * @see #FLAG_SECURE 706 * @see #FLAG_PRIVATE 707 * @see #FLAG_ROUND 708 */ getFlags()709 public int getFlags() { 710 return mFlags; 711 } 712 713 /** 714 * Gets the display type. 715 * 716 * @return The display type. 717 * 718 * @see #TYPE_UNKNOWN 719 * @see #TYPE_INTERNAL 720 * @see #TYPE_EXTERNAL 721 * @see #TYPE_WIFI 722 * @see #TYPE_OVERLAY 723 * @see #TYPE_VIRTUAL 724 * @hide 725 */ 726 @UnsupportedAppUsage 727 @TestApi getType()728 public int getType() { 729 return mType; 730 } 731 732 /** 733 * Gets the display address, or null if none. 734 * Interpretation varies by display type. 735 * 736 * @return The display address. 737 * @hide 738 */ getAddress()739 public DisplayAddress getAddress() { 740 synchronized (mLock) { 741 updateDisplayInfoLocked(); 742 return mDisplayInfo.address; 743 } 744 } 745 746 /** 747 * Gets the UID of the application that owns this display, or zero if it is 748 * owned by the system. 749 * <p> 750 * If the display is private, then only the owner can use it. 751 * </p> 752 * 753 * @hide 754 */ getOwnerUid()755 public int getOwnerUid() { 756 return mOwnerUid; 757 } 758 759 /** 760 * Gets the package name of the application that owns this display, or null if it is 761 * owned by the system. 762 * <p> 763 * If the display is private, then only the owner can use it. 764 * </p> 765 * 766 * @hide 767 */ 768 @UnsupportedAppUsage getOwnerPackageName()769 public String getOwnerPackageName() { 770 return mOwnerPackageName; 771 } 772 773 /** 774 * Gets the compatibility info used by this display instance. 775 * 776 * @return The display adjustments holder, or null if none is required. 777 * @hide 778 */ 779 @UnsupportedAppUsage getDisplayAdjustments()780 public DisplayAdjustments getDisplayAdjustments() { 781 if (mResources != null) { 782 final DisplayAdjustments currentAdjustments = mResources.getDisplayAdjustments(); 783 if (!mDisplayAdjustments.equals(currentAdjustments)) { 784 mDisplayAdjustments = new DisplayAdjustments(currentAdjustments); 785 } 786 } 787 788 return mDisplayAdjustments; 789 } 790 791 /** 792 * Gets the name of the display. 793 * <p> 794 * Note that some displays may be renamed by the user. 795 * </p> 796 * 797 * @return The display's name. 798 */ getName()799 public String getName() { 800 synchronized (mLock) { 801 updateDisplayInfoLocked(); 802 return mDisplayInfo.name; 803 } 804 } 805 806 /** 807 * Gets the default brightness configured for the display. 808 * 809 * @return Default brightness between 0.0-1.0 810 * @hide 811 */ getBrightnessDefault()812 public float getBrightnessDefault() { 813 synchronized (mLock) { 814 updateDisplayInfoLocked(); 815 return mDisplayInfo.brightnessDefault; 816 } 817 } 818 819 /** 820 * @return Brightness information about the display. 821 * @hide 822 */ 823 @RequiresPermission(CONTROL_DISPLAY_BRIGHTNESS) getBrightnessInfo()824 public @Nullable BrightnessInfo getBrightnessInfo() { 825 return mGlobal.getBrightnessInfo(mDisplayId); 826 } 827 828 /** 829 * Gets the size of the display in pixels. 830 * 831 * <p>The return value does not necessarily represent the actual size (native resolution) of the 832 * display. The returned size might be adjusted to exclude certain system decor elements that 833 * are always visible, or the size might be scaled to provide compatibility with older 834 * applications that were originally designed for smaller displays. 835 * 836 * <p>The returned size can also be different depending on the WindowManager bound to the 837 * display: 838 * <ul> 839 * <li>If size is requested from an activity (either using a WindowManager accessed by 840 * {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the 841 * size of the current app window is returned. As a result, in multi-window mode, the 842 * returned size can be smaller than the size of the device screen. 843 * <li>If size is requested from a non-activity context (for example, the application 844 * context, where the WindowManager is accessed by 845 * {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the 846 * returned size can vary depending on API level: 847 * <ul> 848 * <li>API level 29 and below — The size of the entire display (based on 849 * current rotation) minus system decoration areas is returned. 850 * <li>API level 30 and above — The size of the top running activity in the 851 * current process is returned. If the current process has no running 852 * activities, the size of the device default display, including system 853 * decoration areas, is returned. 854 * </ul> 855 * </ul> 856 * 857 * <p>For layout purposes, apps should make a request from an activity context to obtain the 858 * size of the display area available for app content. 859 * 860 * @param outSize A {@link Point} object which receives the display size information. 861 * 862 * @deprecated Use {@link WindowMetrics} instead. Obtain a {@code WindowMetrics} instance by 863 * calling {@link WindowManager#getCurrentWindowMetrics()}, then call 864 * {@link WindowMetrics#getBounds()} to get the dimensions of the application window. 865 */ 866 @Deprecated getSize(Point outSize)867 public void getSize(Point outSize) { 868 synchronized (mLock) { 869 updateDisplayInfoLocked(); 870 mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); 871 outSize.x = mTempMetrics.widthPixels; 872 outSize.y = mTempMetrics.heightPixels; 873 } 874 } 875 876 /** 877 * Gets the size of the display as a rectangle, in pixels. 878 * 879 * @param outSize A {@link Rect} object to receive the size information. 880 * 881 * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application 882 * window. 883 */ 884 @Deprecated getRectSize(Rect outSize)885 public void getRectSize(Rect outSize) { 886 synchronized (mLock) { 887 updateDisplayInfoLocked(); 888 mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); 889 outSize.set(0, 0, mTempMetrics.widthPixels, mTempMetrics.heightPixels); 890 } 891 } 892 893 /** 894 * Return the range of display sizes an application can expect to encounter 895 * under normal operation, as long as there is no physical change in screen 896 * size. This is basically the sizes you will see as the orientation 897 * changes, taking into account whatever screen decoration there is in 898 * each rotation. For example, the status bar is always at the top of the 899 * screen, so it will reduce the height both in landscape and portrait, and 900 * the smallest height returned here will be the smaller of the two. 901 * 902 * This is intended for applications to get an idea of the range of sizes 903 * they will encounter while going through device rotations, to provide a 904 * stable UI through rotation. The sizes here take into account all standard 905 * system decorations that reduce the size actually available to the 906 * application: the status bar, navigation bar, system bar, etc. It does 907 * <em>not</em> take into account more transient elements like an IME 908 * soft keyboard. 909 * 910 * @param outSmallestSize Filled in with the smallest width and height 911 * that the application will encounter, in pixels (not dp units). The x 912 * (width) dimension here directly corresponds to 913 * {@link android.content.res.Configuration#smallestScreenWidthDp 914 * Configuration.smallestScreenWidthDp}, except the value here is in raw 915 * screen pixels rather than dp units. Your application may of course 916 * still get smaller space yet if, for example, a soft keyboard is 917 * being displayed. 918 * @param outLargestSize Filled in with the largest width and height 919 * that the application will encounter, in pixels (not dp units). Your 920 * application may of course still get larger space than this if, 921 * for example, screen decorations like the status bar are being hidden. 922 */ getCurrentSizeRange(Point outSmallestSize, Point outLargestSize)923 public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) { 924 synchronized (mLock) { 925 updateDisplayInfoLocked(); 926 outSmallestSize.x = mDisplayInfo.smallestNominalAppWidth; 927 outSmallestSize.y = mDisplayInfo.smallestNominalAppHeight; 928 outLargestSize.x = mDisplayInfo.largestNominalAppWidth; 929 outLargestSize.y = mDisplayInfo.largestNominalAppHeight; 930 } 931 } 932 933 /** 934 * Return the maximum screen size dimension that will happen. This is 935 * mostly for wallpapers. 936 * @hide 937 */ 938 @UnsupportedAppUsage getMaximumSizeDimension()939 public int getMaximumSizeDimension() { 940 synchronized (mLock) { 941 updateDisplayInfoLocked(); 942 return Math.max(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); 943 } 944 } 945 946 /** 947 * @deprecated Use {@link WindowMetrics#getBounds#width()} instead. 948 */ 949 @Deprecated getWidth()950 public int getWidth() { 951 synchronized (mLock) { 952 updateCachedAppSizeIfNeededLocked(); 953 return mCachedAppWidthCompat; 954 } 955 } 956 957 /** 958 * @deprecated Use {@link WindowMetrics#getBounds()#height()} instead. 959 */ 960 @Deprecated getHeight()961 public int getHeight() { 962 synchronized (mLock) { 963 updateCachedAppSizeIfNeededLocked(); 964 return mCachedAppHeightCompat; 965 } 966 } 967 968 /** 969 * Returns the rotation of the screen from its "natural" orientation. 970 * The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0} 971 * (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90}, 972 * {@link Surface#ROTATION_180 Surface.ROTATION_180}, or 973 * {@link Surface#ROTATION_270 Surface.ROTATION_270}. For 974 * example, if a device has a naturally tall screen, and the user has 975 * turned it on its side to go into a landscape orientation, the value 976 * returned here may be either {@link Surface#ROTATION_90 Surface.ROTATION_90} 977 * or {@link Surface#ROTATION_270 Surface.ROTATION_270} depending on 978 * the direction it was turned. The angle is the rotation of the drawn 979 * graphics on the screen, which is the opposite direction of the physical 980 * rotation of the device. For example, if the device is rotated 90 981 * degrees counter-clockwise, to compensate rendering will be rotated by 982 * 90 degrees clockwise and thus the returned value here will be 983 * {@link Surface#ROTATION_90 Surface.ROTATION_90}. 984 * 985 * This rotation value will match the results of {@link #getMetrics}: this means that the 986 * rotation value will correspond to the activity if accessed through the activity. 987 */ 988 @Surface.Rotation getRotation()989 public int getRotation() { 990 synchronized (mLock) { 991 updateDisplayInfoLocked(); 992 return getLocalRotation(); 993 } 994 } 995 996 /** 997 * Returns the install orientation of the display. 998 * @hide 999 */ 1000 @Surface.Rotation getInstallOrientation()1001 public int getInstallOrientation() { 1002 synchronized (mLock) { 1003 updateDisplayInfoLocked(); 1004 return mDisplayInfo.installOrientation; 1005 } 1006 } 1007 1008 /** 1009 * @deprecated use {@link #getRotation} 1010 * @return orientation of this display. 1011 */ 1012 @Deprecated 1013 @Surface.Rotation getOrientation()1014 public int getOrientation() { 1015 return getRotation(); 1016 } 1017 1018 1019 /** 1020 * Returns the {@link DisplayCutout}, or {@code null} if there is none. 1021 * 1022 * @see DisplayCutout 1023 */ 1024 @Nullable getCutout()1025 public DisplayCutout getCutout() { 1026 synchronized (mLock) { 1027 updateDisplayInfoLocked(); 1028 if (mResources == null) return mDisplayInfo.displayCutout; 1029 final DisplayCutout localCutout = mDisplayInfo.displayCutout; 1030 if (localCutout == null) return null; 1031 int rotation = getLocalRotation(); 1032 if (rotation != mDisplayInfo.rotation) { 1033 return localCutout.getRotated(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, 1034 mDisplayInfo.rotation, rotation); 1035 } 1036 return localCutout; 1037 } 1038 } 1039 1040 /** 1041 * Returns the {@link RoundedCorner} of the given position if there is one. 1042 * 1043 * @param position the position of the rounded corner on the display. 1044 * 1045 * @return the rounded corner of the given position. Returns {@code null} if there is none. 1046 */ 1047 @SuppressLint("VisiblySynchronized") 1048 @Nullable getRoundedCorner(@oundedCorner.Position int position)1049 public RoundedCorner getRoundedCorner(@RoundedCorner.Position int position) { 1050 synchronized (mLock) { 1051 updateDisplayInfoLocked(); 1052 final RoundedCorners roundedCorners = mDisplayInfo.roundedCorners; 1053 final @Surface.Rotation int rotation = getLocalRotation(); 1054 if (roundedCorners != null && rotation != mDisplayInfo.rotation) { 1055 roundedCorners.rotate(rotation, 1056 mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); 1057 } 1058 return roundedCorners == null ? null : roundedCorners.getRoundedCorner(position); 1059 } 1060 } 1061 1062 /** 1063 * Returns the {@link DisplayShape} which is based on display coordinates. 1064 * 1065 * To get the {@link DisplayShape} based on the window frame, use 1066 * {@link WindowInsets#getDisplayShape()} instead. 1067 * 1068 * @see DisplayShape 1069 */ 1070 @SuppressLint("VisiblySynchronized") 1071 @NonNull getShape()1072 public DisplayShape getShape() { 1073 synchronized (mLock) { 1074 updateDisplayInfoLocked(); 1075 final DisplayShape displayShape = mDisplayInfo.displayShape; 1076 final @Surface.Rotation int rotation = getLocalRotation(); 1077 if (displayShape != null && rotation != mDisplayInfo.rotation) { 1078 return displayShape.setRotation(rotation); 1079 } 1080 return displayShape; 1081 } 1082 } 1083 1084 /** 1085 * Gets the pixel format of the display. 1086 * @return One of the constants defined in {@link android.graphics.PixelFormat}. 1087 * 1088 * @deprecated This method is no longer supported. 1089 * The result is always {@link PixelFormat#RGBA_8888}. 1090 */ 1091 @Deprecated getPixelFormat()1092 public int getPixelFormat() { 1093 return PixelFormat.RGBA_8888; 1094 } 1095 1096 /** 1097 * Gets the refresh rate of this display in frames per second. 1098 */ getRefreshRate()1099 public float getRefreshRate() { 1100 synchronized (mLock) { 1101 updateDisplayInfoLocked(); 1102 return mDisplayInfo.getRefreshRate(); 1103 } 1104 } 1105 1106 /** 1107 * Get the supported refresh rates of this display in frames per second. 1108 * <p> 1109 * This method only returns refresh rates for the display's default modes. For more options, use 1110 * {@link #getSupportedModes()}. 1111 * 1112 * @deprecated use {@link #getSupportedModes()} instead 1113 */ 1114 @Deprecated getSupportedRefreshRates()1115 public float[] getSupportedRefreshRates() { 1116 synchronized (mLock) { 1117 updateDisplayInfoLocked(); 1118 return mDisplayInfo.getDefaultRefreshRates(); 1119 } 1120 } 1121 1122 /** 1123 * Returns the active mode of the display. 1124 */ getMode()1125 public Mode getMode() { 1126 synchronized (mLock) { 1127 updateDisplayInfoLocked(); 1128 return mDisplayInfo.getMode(); 1129 } 1130 } 1131 1132 /** 1133 * Returns the default mode of the display. 1134 * @hide 1135 */ 1136 @TestApi getDefaultMode()1137 public @NonNull Mode getDefaultMode() { 1138 synchronized (mLock) { 1139 updateDisplayInfoLocked(); 1140 return mDisplayInfo.getDefaultMode(); 1141 } 1142 } 1143 1144 /** 1145 * Gets the supported modes of this display. 1146 */ getSupportedModes()1147 public Mode[] getSupportedModes() { 1148 synchronized (mLock) { 1149 updateDisplayInfoLocked(); 1150 final Display.Mode[] modes = mDisplayInfo.supportedModes; 1151 return Arrays.copyOf(modes, modes.length); 1152 } 1153 } 1154 1155 /** 1156 * <p> Returns true if the connected display can be switched into a mode with minimal 1157 * post processing. </p> 1158 * 1159 * <p> If the Display sink is connected via HDMI, this method will return true if the 1160 * display supports either Auto Low Latency Mode or Game Content Type. 1161 * 1162 * <p> If the Display sink has an internal connection or uses some other protocol than 1163 * HDMI, this method will return true if the sink can be switched into an 1164 * implementation-defined low latency image processing mode. </p> 1165 * 1166 * <p> The ability to switch to a mode with minimal post processing may be disabled 1167 * by a user setting in the system settings menu. In that case, this method returns 1168 * false. </p> 1169 * 1170 * @see android.view.Window#setPreferMinimalPostProcessing 1171 */ 1172 @SuppressLint("VisiblySynchronized") isMinimalPostProcessingSupported()1173 public boolean isMinimalPostProcessingSupported() { 1174 synchronized (mLock) { 1175 updateDisplayInfoLocked(); 1176 return mDisplayInfo.minimalPostProcessingSupported; 1177 } 1178 } 1179 1180 /** 1181 * Request the display applies a color mode. 1182 * @hide 1183 */ 1184 @RequiresPermission(CONFIGURE_DISPLAY_COLOR_MODE) requestColorMode(int colorMode)1185 public void requestColorMode(int colorMode) { 1186 mGlobal.requestColorMode(mDisplayId, colorMode); 1187 } 1188 1189 /** 1190 * Returns the active color mode of this display 1191 * @hide 1192 */ getColorMode()1193 public int getColorMode() { 1194 synchronized (mLock) { 1195 updateDisplayInfoLocked(); 1196 return mDisplayInfo.colorMode; 1197 } 1198 } 1199 1200 /** 1201 * @hide 1202 * Get current remove mode of the display - what actions should be performed with the display's 1203 * content when it is removed. Default behavior for public displays in this case is to move all 1204 * activities to the primary display and make it focused. For private display - destroy all 1205 * activities. 1206 * 1207 * @see #REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY 1208 * @see #REMOVE_MODE_DESTROY_CONTENT 1209 */ 1210 // TODO (b/114338689): Remove the method and use IWindowManager#getRemoveContentMode getRemoveMode()1211 public int getRemoveMode() { 1212 return mDisplayInfo.removeMode; 1213 } 1214 1215 /** 1216 * Returns the system's preferred display mode. This mode will be used when the user has not 1217 * specified a display-mode preference. This returns null if the boot display mode feature is 1218 * not supported by system. 1219 * 1220 * @hide 1221 */ 1222 @TestApi 1223 @Nullable getSystemPreferredDisplayMode()1224 public Display.Mode getSystemPreferredDisplayMode() { 1225 return mGlobal.getSystemPreferredDisplayMode(getDisplayId()); 1226 } 1227 1228 /** 1229 * Returns the current display mode's HDR capabilities. 1230 * 1231 * @see #isHdr() 1232 */ getHdrCapabilities()1233 public HdrCapabilities getHdrCapabilities() { 1234 synchronized (mLock) { 1235 updateDisplayInfoLocked(); 1236 if (mDisplayInfo.hdrCapabilities == null) { 1237 return null; 1238 } 1239 int[] supportedHdrTypes; 1240 if (mDisplayInfo.userDisabledHdrTypes.length == 0) { 1241 int[] modeSupportedHdrTypes = getMode().getSupportedHdrTypes(); 1242 supportedHdrTypes = Arrays.copyOf(modeSupportedHdrTypes, 1243 modeSupportedHdrTypes.length); 1244 } else { 1245 ArraySet<Integer> enabledTypesSet = new ArraySet<>(); 1246 for (int supportedType : getMode().getSupportedHdrTypes()) { 1247 if (!contains(mDisplayInfo.userDisabledHdrTypes, supportedType)) { 1248 enabledTypesSet.add(supportedType); 1249 } 1250 } 1251 1252 supportedHdrTypes = new int[enabledTypesSet.size()]; 1253 int index = 0; 1254 for (int enabledType : enabledTypesSet) { 1255 supportedHdrTypes[index++] = enabledType; 1256 } 1257 } 1258 return new HdrCapabilities(supportedHdrTypes, 1259 mDisplayInfo.hdrCapabilities.mMaxLuminance, 1260 mDisplayInfo.hdrCapabilities.mMaxAverageLuminance, 1261 mDisplayInfo.hdrCapabilities.mMinLuminance); 1262 } 1263 } 1264 contains(int[] disabledHdrTypes, int hdrType)1265 private boolean contains(int[] disabledHdrTypes, int hdrType) { 1266 for (Integer disabledHdrFormat : disabledHdrTypes) { 1267 if (disabledHdrFormat == hdrType) { 1268 return true; 1269 } 1270 } 1271 return false; 1272 } 1273 1274 /** 1275 * @hide 1276 * Returns the current mode's supported HDR types. 1277 * 1278 * @see #isHdr() 1279 * @see Mode#getSupportedHdrTypes() 1280 */ 1281 @TestApi 1282 @NonNull getReportedHdrTypes()1283 public int[] getReportedHdrTypes() { 1284 synchronized (mLock) { 1285 updateDisplayInfoLocked(); 1286 return mDisplayInfo.getMode().getSupportedHdrTypes(); 1287 } 1288 } 1289 1290 /** 1291 * Returns whether this display supports any HDR type. 1292 * 1293 * @see #getHdrCapabilities() 1294 * @see HdrCapabilities#getSupportedHdrTypes() 1295 */ isHdr()1296 public boolean isHdr() { 1297 synchronized (mLock) { 1298 updateDisplayInfoLocked(); 1299 HdrCapabilities hdrCapabilities = getHdrCapabilities(); 1300 if (hdrCapabilities == null) { 1301 return false; 1302 } 1303 return !(hdrCapabilities.getSupportedHdrTypes().length == 0); 1304 } 1305 } 1306 1307 /** 1308 * @return Whether the display supports reporting an hdr/sdr ratio. If this is false, 1309 * {@link #getHdrSdrRatio()} will always be 1.0f 1310 */ isHdrSdrRatioAvailable()1311 public boolean isHdrSdrRatioAvailable() { 1312 synchronized (mLock) { 1313 updateDisplayInfoLocked(); 1314 return !Float.isNaN(mDisplayInfo.hdrSdrRatio); 1315 } 1316 } 1317 1318 /** 1319 * @return The current hdr/sdr ratio expressed as the ratio of targetHdrPeakBrightnessInNits / 1320 * targetSdrWhitePointInNits. If {@link #isHdrSdrRatioAvailable()} is false, this 1321 * always returns 1.0f. 1322 */ getHdrSdrRatio()1323 public float getHdrSdrRatio() { 1324 synchronized (mLock) { 1325 updateDisplayInfoLocked(); 1326 return Float.isNaN(mDisplayInfo.hdrSdrRatio) 1327 ? 1.0f : mDisplayInfo.hdrSdrRatio; 1328 } 1329 } 1330 findHdrSdrRatioListenerLocked(Consumer<Display> listener)1331 private int findHdrSdrRatioListenerLocked(Consumer<Display> listener) { 1332 for (int i = 0; i < mHdrSdrRatioListeners.size(); i++) { 1333 final HdrSdrRatioListenerWrapper wrapper = mHdrSdrRatioListeners.get(i); 1334 if (wrapper.mListener == listener) { 1335 return i; 1336 } 1337 } 1338 return -1; 1339 } 1340 1341 /** 1342 * Registers a listener that will be invoked whenever the display's hdr/sdr ratio has changed. 1343 * After receiving the callback on the specified Executor, call {@link #getHdrSdrRatio()} to 1344 * get the updated value. 1345 * If {@link #isHdrSdrRatioAvailable()} is false, then an IllegalStateException will be thrown 1346 * 1347 * @see #unregisterHdrSdrRatioChangedListener(Consumer) 1348 * @param executor The executor to invoke the listener on 1349 * @param listener The listener to invoke when the HDR/SDR ratio changes 1350 * @throws IllegalStateException if {@link #isHdrSdrRatioAvailable()} is false 1351 */ registerHdrSdrRatioChangedListener(@onNull Executor executor, @NonNull Consumer<Display> listener)1352 public void registerHdrSdrRatioChangedListener(@NonNull Executor executor, 1353 @NonNull Consumer<Display> listener) { 1354 if (!isHdrSdrRatioAvailable()) { 1355 throw new IllegalStateException("HDR/SDR ratio changed not available"); 1356 } 1357 HdrSdrRatioListenerWrapper toRegister = null; 1358 synchronized (mLock) { 1359 if (findHdrSdrRatioListenerLocked(listener) == -1) { 1360 toRegister = new HdrSdrRatioListenerWrapper(listener); 1361 mHdrSdrRatioListeners.add(toRegister); 1362 } // else already listening, don't do anything 1363 } 1364 if (toRegister != null) { 1365 // Although we only care about the HDR/SDR ratio changing, that can also come in the 1366 // form of the larger DISPLAY_CHANGED event 1367 mGlobal.registerDisplayListener(toRegister, executor, 1368 DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED 1369 | DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); 1370 } 1371 1372 } 1373 1374 /** 1375 * @param listener The previously 1376 * {@link #registerHdrSdrRatioChangedListener(Executor, Consumer) registered} 1377 * hdr/sdr ratio listener to remove. 1378 * 1379 * @see #registerHdrSdrRatioChangedListener(Executor, Consumer) 1380 */ unregisterHdrSdrRatioChangedListener(@onNull Consumer<Display> listener)1381 public void unregisterHdrSdrRatioChangedListener(@NonNull Consumer<Display> listener) { 1382 HdrSdrRatioListenerWrapper toRemove = null; 1383 synchronized (mLock) { 1384 int index = findHdrSdrRatioListenerLocked(listener); 1385 if (index != -1) { 1386 toRemove = mHdrSdrRatioListeners.remove(index); 1387 } 1388 } 1389 if (toRemove != null) { 1390 mGlobal.unregisterDisplayListener(toRemove); 1391 } 1392 } 1393 1394 /** 1395 * Sets the default {@link Display.Mode} to use for the display. The display mode includes 1396 * preference for resolution and refresh rate. 1397 * If the mode specified is not supported by the display, then no mode change occurs. 1398 * 1399 * @param mode The {@link Display.Mode} to set, which can include resolution and/or 1400 * refresh-rate. It is created using {@link Display.Mode.Builder}. 1401 *` 1402 * @hide 1403 */ 1404 @TestApi 1405 @RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) setUserPreferredDisplayMode(@onNull Display.Mode mode)1406 public void setUserPreferredDisplayMode(@NonNull Display.Mode mode) { 1407 // Create a new object containing default values for the unused fields like mode ID and 1408 // alternative refresh rates. 1409 Display.Mode preferredMode = new Display.Mode(mode.getPhysicalWidth(), 1410 mode.getPhysicalHeight(), mode.getRefreshRate()); 1411 mGlobal.setUserPreferredDisplayMode(mDisplayId, preferredMode); 1412 } 1413 1414 /** 1415 * Removes the display's user preferred display mode. 1416 * 1417 * @hide 1418 */ 1419 @TestApi 1420 @RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) clearUserPreferredDisplayMode()1421 public void clearUserPreferredDisplayMode() { 1422 mGlobal.setUserPreferredDisplayMode(mDisplayId, null); 1423 } 1424 1425 /** 1426 * Returns the display's user preferred display mode. 1427 * 1428 * @hide 1429 */ 1430 @TestApi 1431 @Nullable getUserPreferredDisplayMode()1432 public Display.Mode getUserPreferredDisplayMode() { 1433 return mGlobal.getUserPreferredDisplayMode(mDisplayId); 1434 } 1435 1436 1437 /** 1438 * Returns whether this display can be used to display wide color gamut content. 1439 * This does not necessarily mean the device itself can render wide color gamut 1440 * content. To ensure wide color gamut content can be produced, refer to 1441 * {@link Configuration#isScreenWideColorGamut()}. 1442 */ isWideColorGamut()1443 public boolean isWideColorGamut() { 1444 synchronized (mLock) { 1445 updateDisplayInfoLocked(); 1446 return mDisplayInfo.isWideColorGamut(); 1447 } 1448 } 1449 1450 /** 1451 * Returns the preferred wide color space of the Display. 1452 * The returned wide gamut color space is based on hardware capability and 1453 * is preferred by the composition pipeline. 1454 * Returns null if the display doesn't support wide color gamut. 1455 * {@link Display#isWideColorGamut()}. 1456 */ 1457 @Nullable getPreferredWideGamutColorSpace()1458 public ColorSpace getPreferredWideGamutColorSpace() { 1459 synchronized (mLock) { 1460 updateDisplayInfoLocked(); 1461 if (mDisplayInfo.isWideColorGamut()) { 1462 return mGlobal.getPreferredWideGamutColorSpace(); 1463 } 1464 return null; 1465 } 1466 } 1467 1468 /** 1469 * Returns null if it's virtual display. 1470 * @hide 1471 */ 1472 @Nullable getOverlaySupport()1473 public OverlayProperties getOverlaySupport() { 1474 synchronized (mLock) { 1475 updateDisplayInfoLocked(); 1476 if (mDisplayInfo.type != TYPE_VIRTUAL) { 1477 return mGlobal.getOverlaySupport(); 1478 } 1479 return null; 1480 } 1481 } 1482 1483 /** 1484 * Gets the supported color modes of this device. 1485 * @hide 1486 */ getSupportedColorModes()1487 public int[] getSupportedColorModes() { 1488 synchronized (mLock) { 1489 updateDisplayInfoLocked(); 1490 int[] colorModes = mDisplayInfo.supportedColorModes; 1491 return Arrays.copyOf(colorModes, colorModes.length); 1492 } 1493 } 1494 1495 /** 1496 * Gets the supported wide color gamuts of this device. 1497 * 1498 * @return Supported WCG color spaces. 1499 * @hide 1500 */ 1501 @SuppressLint("VisiblySynchronized") 1502 @NonNull 1503 @TestApi getSupportedWideColorGamut()1504 public @ColorMode ColorSpace[] getSupportedWideColorGamut() { 1505 synchronized (mLock) { 1506 final ColorSpace[] defaultColorSpaces = new ColorSpace[0]; 1507 updateDisplayInfoLocked(); 1508 if (!isWideColorGamut()) { 1509 return defaultColorSpaces; 1510 } 1511 1512 final int[] colorModes = getSupportedColorModes(); 1513 final List<ColorSpace> colorSpaces = new ArrayList<>(); 1514 for (int colorMode : colorModes) { 1515 // Refer to DisplayInfo#isWideColorGamut. 1516 switch (colorMode) { 1517 case COLOR_MODE_DCI_P3: 1518 colorSpaces.add(ColorSpace.get(ColorSpace.Named.DCI_P3)); 1519 break; 1520 case COLOR_MODE_DISPLAY_P3: 1521 colorSpaces.add(ColorSpace.get(ColorSpace.Named.DISPLAY_P3)); 1522 break; 1523 } 1524 } 1525 return colorSpaces.toArray(defaultColorSpaces); 1526 } 1527 } 1528 1529 /** 1530 * Gets the app VSYNC offset, in nanoseconds. This is a positive value indicating 1531 * the phase offset of the VSYNC events provided by Choreographer relative to the 1532 * display refresh. For example, if Choreographer reports that the refresh occurred 1533 * at time N, it actually occurred at (N - appVsyncOffset). 1534 * <p> 1535 * Apps generally do not need to be aware of this. It's only useful for fine-grained 1536 * A/V synchronization. 1537 */ getAppVsyncOffsetNanos()1538 public long getAppVsyncOffsetNanos() { 1539 synchronized (mLock) { 1540 updateDisplayInfoLocked(); 1541 return mDisplayInfo.appVsyncOffsetNanos; 1542 } 1543 } 1544 1545 /** 1546 * This is how far in advance a buffer must be queued for presentation at 1547 * a given time. If you want a buffer to appear on the screen at 1548 * time N, you must submit the buffer before (N - presentationDeadline). 1549 * <p> 1550 * The desired presentation time for GLES rendering may be set with 1551 * {@link android.opengl.EGLExt#eglPresentationTimeANDROID}. For video decoding, use 1552 * {@link android.media.MediaCodec#releaseOutputBuffer(int, long)}. Times are 1553 * expressed in nanoseconds, using the system monotonic clock 1554 * ({@link System#nanoTime}). 1555 */ getPresentationDeadlineNanos()1556 public long getPresentationDeadlineNanos() { 1557 synchronized (mLock) { 1558 updateDisplayInfoLocked(); 1559 return mDisplayInfo.presentationDeadlineNanos; 1560 } 1561 } 1562 1563 /** 1564 * Returns the product-specific information about the display or the directly connected 1565 * device on the display chain. 1566 * For example, if the display is transitively connected, this field may contain product 1567 * information about the intermediate device. 1568 * Returns {@code null} if product information is not available. 1569 */ 1570 @Nullable getDeviceProductInfo()1571 public DeviceProductInfo getDeviceProductInfo() { 1572 synchronized (mLock) { 1573 updateDisplayInfoLocked(); 1574 return mDisplayInfo.deviceProductInfo; 1575 } 1576 } 1577 1578 /** 1579 * Gets the size and density of this display. 1580 * 1581 * <p>The size returned does not necessarily represent the actual size (native resolution) of 1582 * the display. The returned size might be adjusted to exclude certain system decor elements 1583 * that are always visible, or the size might be scaled to provide compatibility with older 1584 * applications that were originally designed for smaller displays. 1585 * 1586 * <p>The returned size can also be different depending on the WindowManager associated with the 1587 * display: 1588 * <ul> 1589 * <li>If metrics are requested from an activity (either using a WindowManager accessed by 1590 * {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the 1591 * returned metrics provide the size of the current app window. As a result, in 1592 * multi-window mode, the returned size can be smaller than the size of the device 1593 * screen. 1594 * <li>If metrics are requested from a non-activity context (for example, the application 1595 * context, where the WindowManager is accessed by 1596 * {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the 1597 * returned size can vary depending on API level: 1598 * <ul> 1599 * <li>API level 29 and below — The returned metrics provide the size of the 1600 * entire display (based on current rotation) minus system decoration areas. 1601 * <li>API level 30 and above — The returned metrics provide the size of the 1602 * top running activity in the current process. If the current process has no 1603 * running activities, the metrics provide the size of the default display of 1604 * the device, including system decoration areas. 1605 * </ul> 1606 * </ul> 1607 * 1608 * @param outMetrics A {@link DisplayMetrics} object which receives the display metrics. 1609 * 1610 * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application 1611 * window. Use {@link WindowMetrics#getDensity()} to get the density of the application 1612 * window. 1613 */ 1614 @Deprecated getMetrics(DisplayMetrics outMetrics)1615 public void getMetrics(DisplayMetrics outMetrics) { 1616 synchronized (mLock) { 1617 updateDisplayInfoLocked(); 1618 mDisplayInfo.getAppMetrics(outMetrics, getDisplayAdjustments()); 1619 } 1620 } 1621 1622 /** 1623 * Gets the size of the largest region of the display accessible to an app in the current system 1624 * state, without subtracting any window decor or applying scaling factors. 1625 * <p> 1626 * The size is adjusted based on the current rotation of the display. 1627 * <p></p> 1628 * The returned size will fall into one of these scenarios: 1629 * <ol> 1630 * <li>The device has no partitions on the display. The returned value is the largest region 1631 * of the display accessible to an app in the current system state, regardless of windowing 1632 * mode.</li> 1633 * <li>The device divides a single display into multiple partitions. An application is 1634 * restricted to a portion of the display. This is common in devices where the display changes 1635 * size, such as foldables or large screens. The returned size will match the portion of 1636 * the display the application is restricted to.</li> 1637 * <li>The window manager is emulating a different display size, using {@code adb shell wm 1638 * size}. The returned size will match the emulated display size.</li> 1639 * </ol> 1640 * </p><p> 1641 * The returned value is <b>unsuitable to use when sizing and placing UI elements</b>, since it 1642 * does not reflect the application window size in any of these scenarios. 1643 * {@link WindowManager#getCurrentWindowMetrics()} is an alternative that returns the size 1644 * of the current application window, even if the window is on a device with a partitioned 1645 * display. This helps prevent UI bugs where UI elements are misaligned or placed beyond the 1646 * bounds of the window. 1647 * <p></p> 1648 * Handling multi-window mode correctly is necessary since applications are not always 1649 * fullscreen. A user on a large screen device, such as a tablet or ChromeOS devices, is more 1650 * likely to use multi-window modes. 1651 * <p></p> 1652 * For example, consider a device with a display partitioned into two halves. The user may have 1653 * a fullscreen application open on the first partition. They may have two applications open in 1654 * split screen (an example of multi-window mode) on the second partition, with each application 1655 * consuming half of the partition. In this case, 1656 * {@link WindowManager#getCurrentWindowMetrics()} reports the fullscreen window is half of the 1657 * screen in size, and each split screen window is a quarter of the screen in size. On the other 1658 * hand, {@link #getRealSize} reports half of the screen size for all windows, since the 1659 * application windows are all restricted to their respective partitions. 1660 * </p> 1661 * 1662 * @param outSize Set to the real size of the display. 1663 * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to identify the current size 1664 * of the activity window. UI-related work, such as choosing UI layouts, should rely 1665 * upon {@link WindowMetrics#getBounds()}. 1666 */ 1667 @Deprecated getRealSize(Point outSize)1668 public void getRealSize(Point outSize) { 1669 synchronized (mLock) { 1670 updateDisplayInfoLocked(); 1671 if (shouldReportMaxBounds()) { 1672 final Rect bounds = mResources.getConfiguration() 1673 .windowConfiguration.getMaxBounds(); 1674 outSize.x = bounds.width(); 1675 outSize.y = bounds.height(); 1676 if (DEBUG) { 1677 Log.d(TAG, "getRealSize determined from max bounds: " + outSize); 1678 } 1679 // Skip adjusting by fixed rotation, since if it is necessary, the configuration 1680 // should already reflect the expected rotation. 1681 return; 1682 } 1683 outSize.x = mDisplayInfo.logicalWidth; 1684 outSize.y = mDisplayInfo.logicalHeight; 1685 final @Surface.Rotation int rotation = getLocalRotation(); 1686 if (rotation != mDisplayInfo.rotation) { 1687 adjustSize(outSize, mDisplayInfo.rotation, rotation); 1688 } 1689 } 1690 } 1691 1692 /** 1693 * Gets the size of the largest region of the display accessible to an app in the current system 1694 * state, without subtracting any window decor or applying scaling factors. 1695 * <p> 1696 * The size is adjusted based on the current rotation of the display. 1697 * <p></p> 1698 * The returned size will fall into one of these scenarios: 1699 * <ol> 1700 * <li>The device has no partitions on the display. The returned value is the largest region 1701 * of the display accessible to an app in the current system state, regardless of windowing 1702 * mode.</li> 1703 * <li>The device divides a single display into multiple partitions. An application is 1704 * restricted to a portion of the display. This is common in devices where the display changes 1705 * size, such as foldables or large screens. The returned size will match the portion of 1706 * the display the application is restricted to.</li> 1707 * <li>The window manager is emulating a different display size, using {@code adb shell wm 1708 * size}. The returned size will match the emulated display size.</li> 1709 * </ol> 1710 * </p><p> 1711 * The returned value is <b>unsuitable to use when sizing and placing UI elements</b>, since it 1712 * does not reflect the application window size in any of these scenarios. 1713 * {@link WindowManager#getCurrentWindowMetrics()} is an alternative that returns the size 1714 * of the current application window, even if the window is on a device with a partitioned 1715 * display. This helps prevent UI bugs where UI elements are misaligned or placed beyond the 1716 * bounds of the window. 1717 * <p></p> 1718 * Handling multi-window mode correctly is necessary since applications are not always 1719 * fullscreen. A user on a large screen device, such as a tablet or ChromeOS devices, is more 1720 * likely to use multi-window modes. 1721 * <p></p> 1722 * For example, consider a device with a display partitioned into two halves. The user may have 1723 * a fullscreen application open on the first partition. They may have two applications open in 1724 * split screen (an example of multi-window mode) on the second partition, with each application 1725 * consuming half of the partition. In this case, 1726 * {@link WindowManager#getCurrentWindowMetrics()} reports the fullscreen window is half of the 1727 * screen in size, and each split screen window is a quarter of the screen in size. On the other 1728 * hand, {@link #getRealMetrics} reports half of the screen size for all windows, since the 1729 * application windows are all restricted to their respective partitions. 1730 * </p> 1731 * 1732 * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. 1733 * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to identify the current size 1734 * of the activity window. UI-related work, such as choosing UI layouts, should rely 1735 * upon {@link WindowMetrics#getBounds()}. Use {@link Configuration#densityDpi} to 1736 * get the current density. 1737 */ 1738 @Deprecated getRealMetrics(DisplayMetrics outMetrics)1739 public void getRealMetrics(DisplayMetrics outMetrics) { 1740 synchronized (mLock) { 1741 updateDisplayInfoLocked(); 1742 if (shouldReportMaxBounds()) { 1743 mDisplayInfo.getMaxBoundsMetrics(outMetrics, 1744 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, 1745 mResources.getConfiguration()); 1746 if (DEBUG) { 1747 Log.d(TAG, "getRealMetrics determined from max bounds: " + outMetrics); 1748 } 1749 // Skip adjusting by fixed rotation, since if it is necessary, the configuration 1750 // should already reflect the expected rotation. 1751 return; 1752 } 1753 mDisplayInfo.getLogicalMetrics(outMetrics, 1754 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); 1755 final @Surface.Rotation int rotation = getLocalRotation(); 1756 if (rotation != mDisplayInfo.rotation) { 1757 adjustMetrics(outMetrics, mDisplayInfo.rotation, rotation); 1758 } 1759 } 1760 } 1761 1762 /** 1763 * Determines if {@link WindowConfiguration#getMaxBounds()} should be reported as the 1764 * display dimensions. The max bounds field may be smaller than the logical dimensions 1765 * when apps need to be sandboxed. 1766 * 1767 * Depends upon {@link WindowConfiguration#getMaxBounds()} being set in 1768 * {@link com.android.server.wm.ConfigurationContainer#providesMaxBounds()}. In most cases, this 1769 * value reflects the size of the current DisplayArea. 1770 * @return {@code true} when max bounds should be applied. 1771 */ shouldReportMaxBounds()1772 private boolean shouldReportMaxBounds() { 1773 if (mResources == null) { 1774 return false; 1775 } 1776 final Configuration config = mResources.getConfiguration(); 1777 return config != null && !config.windowConfiguration.getMaxBounds().isEmpty(); 1778 } 1779 1780 /** 1781 * Gets the state of the display, such as whether it is on or off. 1782 * 1783 * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON}, 1784 * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, {@link #STATE_ON_SUSPEND}, or 1785 * {@link #STATE_UNKNOWN}. 1786 */ getState()1787 public int getState() { 1788 synchronized (mLock) { 1789 updateDisplayInfoLocked(); 1790 return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN; 1791 } 1792 } 1793 1794 /** 1795 * Returns the committed state of the display. 1796 * 1797 * @return The latest committed display state, such as {@link #STATE_ON}. The display state 1798 * {@link Display#getState()} is set as committed only after power state changes finish. 1799 * 1800 * @hide 1801 */ getCommittedState()1802 public int getCommittedState() { 1803 synchronized (mLock) { 1804 updateDisplayInfoLocked(); 1805 return mIsValid ? mDisplayInfo.committedState : STATE_UNKNOWN; 1806 } 1807 } 1808 1809 /** 1810 * Returns true if the specified UID has access to this display. 1811 * @hide 1812 */ 1813 @TestApi hasAccess(int uid)1814 public boolean hasAccess(int uid) { 1815 return hasAccess(uid, mFlags, mOwnerUid, mDisplayId); 1816 } 1817 1818 /** @hide */ hasAccess(int uid, int flags, int ownerUid, int displayId)1819 public static boolean hasAccess(int uid, int flags, int ownerUid, int displayId) { 1820 return (flags & Display.FLAG_PRIVATE) == 0 1821 || uid == ownerUid 1822 || uid == Process.SYSTEM_UID 1823 || uid == 0 1824 // Check if the UID is present on given display. 1825 || DisplayManagerGlobal.getInstance().isUidPresentOnDisplay(uid, displayId); 1826 } 1827 1828 /** 1829 * Returns true if the display is a public presentation display. 1830 * @hide 1831 */ isPublicPresentation()1832 public boolean isPublicPresentation() { 1833 return (mFlags & (Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION)) == 1834 Display.FLAG_PRESENTATION; 1835 } 1836 1837 /** 1838 * @return {@code true} if the display is a trusted display. 1839 * 1840 * @see #FLAG_TRUSTED 1841 * @hide 1842 */ isTrusted()1843 public boolean isTrusted() { 1844 return (mFlags & FLAG_TRUSTED) == FLAG_TRUSTED; 1845 } 1846 1847 /** 1848 * @return {@code true} if the display can steal the top focus from another display. 1849 * 1850 * @see #FLAG_STEAL_TOP_FOCUS_DISABLED 1851 * @hide 1852 */ canStealTopFocus()1853 public boolean canStealTopFocus() { 1854 return (mFlags & FLAG_STEAL_TOP_FOCUS_DISABLED) == 0; 1855 } 1856 updateDisplayInfoLocked()1857 private void updateDisplayInfoLocked() { 1858 // Note: The display manager caches display info objects on our behalf. 1859 DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId); 1860 if (newInfo == null) { 1861 // Preserve the old mDisplayInfo after the display is removed. 1862 if (mIsValid) { 1863 mIsValid = false; 1864 if (DEBUG) { 1865 Log.d(TAG, "Logical display " + mDisplayId + " was removed."); 1866 } 1867 } 1868 } else { 1869 // Use the new display info. (It might be the same object if nothing changed.) 1870 mDisplayInfo = newInfo; 1871 if (!mIsValid) { 1872 mIsValid = true; 1873 if (DEBUG) { 1874 Log.d(TAG, "Logical display " + mDisplayId + " was recreated."); 1875 } 1876 } 1877 } 1878 } 1879 updateCachedAppSizeIfNeededLocked()1880 private void updateCachedAppSizeIfNeededLocked() { 1881 long now = SystemClock.uptimeMillis(); 1882 if (now > mLastCachedAppSizeUpdate + CACHED_APP_SIZE_DURATION_MILLIS) { 1883 updateDisplayInfoLocked(); 1884 mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); 1885 mCachedAppWidthCompat = mTempMetrics.widthPixels; 1886 mCachedAppHeightCompat = mTempMetrics.heightPixels; 1887 mLastCachedAppSizeUpdate = now; 1888 } 1889 } 1890 1891 /** Returns {@code false} if the width and height of display should swap. */ noFlip(@urface.Rotation int realRotation, @Surface.Rotation int localRotation)1892 private static boolean noFlip(@Surface.Rotation int realRotation, 1893 @Surface.Rotation int localRotation) { 1894 // Check if the delta is rotated by 90 degrees. 1895 return (realRotation - localRotation + 4) % 2 == 0; 1896 } 1897 1898 /** 1899 * Adjusts the given size by a rotation offset if necessary. 1900 * @hide 1901 */ adjustSize(@onNull Point size, @Surface.Rotation int realRotation, @Surface.Rotation int localRotation)1902 private void adjustSize(@NonNull Point size, @Surface.Rotation int realRotation, 1903 @Surface.Rotation int localRotation) { 1904 if (noFlip(realRotation, localRotation)) return; 1905 final int w = size.x; 1906 size.x = size.y; 1907 size.y = w; 1908 } 1909 1910 /** 1911 * Adjusts the given metrics by a rotation offset if necessary. 1912 * @hide 1913 */ adjustMetrics(@onNull DisplayMetrics metrics, @Surface.Rotation int realRotation, @Surface.Rotation int localRotation)1914 private void adjustMetrics(@NonNull DisplayMetrics metrics, 1915 @Surface.Rotation int realRotation, @Surface.Rotation int localRotation) { 1916 if (noFlip(realRotation, localRotation)) return; 1917 int w = metrics.widthPixels; 1918 metrics.widthPixels = metrics.heightPixels; 1919 metrics.heightPixels = w; 1920 1921 w = metrics.noncompatWidthPixels; 1922 metrics.noncompatWidthPixels = metrics.noncompatHeightPixels; 1923 metrics.noncompatHeightPixels = w; 1924 } 1925 getLocalRotation()1926 private @Surface.Rotation int getLocalRotation() { 1927 if (mResources == null) return mDisplayInfo.rotation; 1928 final @Surface.Rotation int localRotation = 1929 mResources.getConfiguration().windowConfiguration.getDisplayRotation(); 1930 if (localRotation != WindowConfiguration.ROTATION_UNDEFINED) return localRotation; 1931 return mDisplayInfo.rotation; 1932 } 1933 1934 // For debugging purposes 1935 @Override toString()1936 public String toString() { 1937 synchronized (mLock) { 1938 updateDisplayInfoLocked(); 1939 final DisplayAdjustments adjustments = getDisplayAdjustments(); 1940 mDisplayInfo.getAppMetrics(mTempMetrics, adjustments); 1941 return "Display id " + mDisplayId + ": " + mDisplayInfo + ", " 1942 + mTempMetrics + ", isValid=" + mIsValid; 1943 } 1944 } 1945 1946 /** 1947 * @hide 1948 */ typeToString(int type)1949 public static String typeToString(int type) { 1950 switch (type) { 1951 case TYPE_UNKNOWN: 1952 return "UNKNOWN"; 1953 case TYPE_INTERNAL: 1954 return "INTERNAL"; 1955 case TYPE_EXTERNAL: 1956 return "EXTERNAL"; 1957 case TYPE_WIFI: 1958 return "WIFI"; 1959 case TYPE_OVERLAY: 1960 return "OVERLAY"; 1961 case TYPE_VIRTUAL: 1962 return "VIRTUAL"; 1963 default: 1964 return Integer.toString(type); 1965 } 1966 } 1967 1968 /** 1969 * @hide 1970 */ stateToString(int state)1971 public static String stateToString(int state) { 1972 switch (state) { 1973 case STATE_UNKNOWN: 1974 return "UNKNOWN"; 1975 case STATE_OFF: 1976 return "OFF"; 1977 case STATE_ON: 1978 return "ON"; 1979 case STATE_DOZE: 1980 return "DOZE"; 1981 case STATE_DOZE_SUSPEND: 1982 return "DOZE_SUSPEND"; 1983 case STATE_VR: 1984 return "VR"; 1985 case STATE_ON_SUSPEND: 1986 return "ON_SUSPEND"; 1987 default: 1988 return Integer.toString(state); 1989 } 1990 } 1991 1992 /** 1993 * Returns true if display updates may be suspended while in the specified 1994 * display power state. In SUSPEND states, updates are absolutely forbidden. 1995 * @hide 1996 */ isSuspendedState(int state)1997 public static boolean isSuspendedState(int state) { 1998 return state == STATE_OFF || state == STATE_DOZE_SUSPEND || state == STATE_ON_SUSPEND; 1999 } 2000 2001 /** 2002 * Returns true if the display may be in a reduced operating mode while in the 2003 * specified display power state. 2004 * @hide 2005 */ isDozeState(int state)2006 public static boolean isDozeState(int state) { 2007 return state == STATE_DOZE || state == STATE_DOZE_SUSPEND; 2008 } 2009 2010 /** 2011 * Returns true if the display is in active state such as {@link #STATE_ON} 2012 * or {@link #STATE_VR}. 2013 * @hide 2014 */ isActiveState(int state)2015 public static boolean isActiveState(int state) { 2016 return state == STATE_ON || state == STATE_VR; 2017 } 2018 2019 /** 2020 * Returns true if the display is in an off state such as {@link #STATE_OFF}. 2021 * @hide 2022 */ isOffState(int state)2023 public static boolean isOffState(int state) { 2024 return state == STATE_OFF; 2025 } 2026 2027 /** 2028 * Returns true if the display is in an on state such as {@link #STATE_ON} 2029 * or {@link #STATE_VR} or {@link #STATE_ON_SUSPEND}. 2030 * @hide 2031 */ isOnState(int state)2032 public static boolean isOnState(int state) { 2033 return state == STATE_ON || state == STATE_VR || state == STATE_ON_SUSPEND; 2034 } 2035 2036 /** 2037 * Returns true if the specified width is valid. 2038 * @hide 2039 */ isWidthValid(int width)2040 public static boolean isWidthValid(int width) { 2041 return width > 0; 2042 } 2043 2044 /** 2045 * Returns true if the specified height is valid. 2046 * @hide 2047 */ isHeightValid(int height)2048 public static boolean isHeightValid(int height) { 2049 return height > 0; 2050 } 2051 2052 /** 2053 * Returns true if the specified refresh-rate is valid. 2054 * @hide 2055 */ isRefreshRateValid(float refreshRate)2056 public static boolean isRefreshRateValid(float refreshRate) { 2057 return refreshRate > 0.0f; 2058 } 2059 2060 /** 2061 * Returns whether/how the specified display supports DISPLAY_DECORATION. 2062 * 2063 * Composition.DISPLAY_DECORATION is a special layer type which is used to 2064 * render the screen decorations (i.e. antialiased rounded corners and 2065 * cutouts) while taking advantage of specific hardware. 2066 * 2067 * @hide 2068 */ getDisplayDecorationSupport()2069 public DisplayDecorationSupport getDisplayDecorationSupport() { 2070 return mGlobal.getDisplayDecorationSupport(mDisplayId); 2071 } 2072 2073 /** 2074 * A mode supported by a given display. 2075 * 2076 * @see Display#getSupportedModes() 2077 */ 2078 public static final class Mode implements Parcelable { 2079 /** 2080 * @hide 2081 */ 2082 public static final Mode[] EMPTY_ARRAY = new Mode[0]; 2083 2084 /** 2085 * @hide 2086 */ 2087 public static final int INVALID_MODE_ID = -1; 2088 2089 private final int mModeId; 2090 private final int mWidth; 2091 private final int mHeight; 2092 private final float mRefreshRate; 2093 @NonNull 2094 private final float[] mAlternativeRefreshRates; 2095 @NonNull 2096 @HdrCapabilities.HdrType 2097 private final int[] mSupportedHdrTypes; 2098 2099 /** 2100 * @hide 2101 */ 2102 @TestApi Mode(int width, int height, float refreshRate)2103 public Mode(int width, int height, float refreshRate) { 2104 this(INVALID_MODE_ID, width, height, refreshRate, new float[0], new int[0]); 2105 } 2106 2107 /** 2108 * @hide 2109 */ 2110 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) Mode(int modeId, int width, int height, float refreshRate)2111 public Mode(int modeId, int width, int height, float refreshRate) { 2112 this(modeId, width, height, refreshRate, new float[0], new int[0]); 2113 } 2114 2115 /** 2116 * @hide 2117 */ Mode(int modeId, int width, int height, float refreshRate, float[] alternativeRefreshRates, @HdrCapabilities.HdrType int[] supportedHdrTypes)2118 public Mode(int modeId, int width, int height, float refreshRate, 2119 float[] alternativeRefreshRates, @HdrCapabilities.HdrType int[] supportedHdrTypes) { 2120 mModeId = modeId; 2121 mWidth = width; 2122 mHeight = height; 2123 mRefreshRate = refreshRate; 2124 mAlternativeRefreshRates = 2125 Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length); 2126 Arrays.sort(mAlternativeRefreshRates); 2127 mSupportedHdrTypes = Arrays.copyOf(supportedHdrTypes, supportedHdrTypes.length); 2128 Arrays.sort(mSupportedHdrTypes); 2129 } 2130 2131 /** 2132 * Returns this mode's id. 2133 */ getModeId()2134 public int getModeId() { 2135 return mModeId; 2136 } 2137 2138 /** 2139 * Returns the physical width of the display in pixels when configured in this mode's 2140 * resolution. 2141 * <p> 2142 * Note that due to application UI scaling, the number of pixels made available to 2143 * applications when the mode is active (as reported by {@link Display#getWidth()} may 2144 * differ from the mode's actual resolution (as reported by this function). 2145 * <p> 2146 * For example, applications running on a 4K display may have their UI laid out and rendered 2147 * in 1080p and then scaled up. Applications can take advantage of the extra resolution by 2148 * rendering content through a {@link android.view.SurfaceView} using full size buffers. 2149 */ getPhysicalWidth()2150 public int getPhysicalWidth() { 2151 return mWidth; 2152 } 2153 2154 /** 2155 * Returns the physical height of the display in pixels when configured in this mode's 2156 * resolution. 2157 * <p> 2158 * Note that due to application UI scaling, the number of pixels made available to 2159 * applications when the mode is active (as reported by {@link Display#getHeight()} may 2160 * differ from the mode's actual resolution (as reported by this function). 2161 * <p> 2162 * For example, applications running on a 4K display may have their UI laid out and rendered 2163 * in 1080p and then scaled up. Applications can take advantage of the extra resolution by 2164 * rendering content through a {@link android.view.SurfaceView} using full size buffers. 2165 */ getPhysicalHeight()2166 public int getPhysicalHeight() { 2167 return mHeight; 2168 } 2169 2170 /** 2171 * Returns the refresh rate in frames per second. 2172 */ getRefreshRate()2173 public float getRefreshRate() { 2174 return mRefreshRate; 2175 } 2176 2177 /** 2178 * Returns an array of refresh rates which can be switched to seamlessly. 2179 * <p> 2180 * A seamless switch is one without visual interruptions, such as a black screen for 2181 * a second or two. 2182 * <p> 2183 * Presence in this list does not guarantee a switch will occur to the desired 2184 * refresh rate, but rather, if a switch does occur to a refresh rate in this list, 2185 * it is guaranteed to be seamless. 2186 * <p> 2187 * The binary relation "refresh rate X is alternative to Y" is non-reflexive, 2188 * symmetric and transitive. For example the mode 1920x1080 60Hz, will never have an 2189 * alternative refresh rate of 60Hz. If 1920x1080 60Hz has an alternative of 50Hz 2190 * then 1920x1080 50Hz will have alternative refresh rate of 60Hz. If 1920x1080 60Hz 2191 * has an alternative of 50Hz and 1920x1080 50Hz has an alternative of 24Hz, then 1920x1080 2192 * 60Hz will also have an alternative of 24Hz. 2193 * 2194 * @see Surface#setFrameRate 2195 * @see SurfaceControl.Transaction#setFrameRate 2196 */ 2197 @NonNull getAlternativeRefreshRates()2198 public float[] getAlternativeRefreshRates() { 2199 return Arrays.copyOf(mAlternativeRefreshRates, mAlternativeRefreshRates.length); 2200 } 2201 2202 /** 2203 * Returns the supported {@link HdrCapabilities} HDR_TYPE_* for this specific mode 2204 */ 2205 @NonNull 2206 @HdrCapabilities.HdrType getSupportedHdrTypes()2207 public int[] getSupportedHdrTypes() { 2208 return Arrays.copyOf(mSupportedHdrTypes, mSupportedHdrTypes.length); 2209 } 2210 2211 /** 2212 * Returns {@code true} if this mode matches the given parameters. 2213 * 2214 * @hide 2215 */ 2216 @TestApi matches(int width, int height, float refreshRate)2217 public boolean matches(int width, int height, float refreshRate) { 2218 return mWidth == width && 2219 mHeight == height && 2220 Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate); 2221 } 2222 2223 /** 2224 * Returns {@code true} if this mode matches the given parameters, if those parameters are 2225 * valid.<p> 2226 * If resolution (width and height) is valid and refresh-rate is not, the method matches 2227 * only resolution. 2228 * If refresh-rate is valid and resolution (width and height) is not, the method matches 2229 * only refresh-rate.</p> 2230 * 2231 * @hide 2232 */ matchesIfValid(int width, int height, float refreshRate)2233 public boolean matchesIfValid(int width, int height, float refreshRate) { 2234 if (!isWidthValid(width) && !isHeightValid(height) 2235 && !isRefreshRateValid(refreshRate)) { 2236 return false; 2237 } 2238 if (isWidthValid(width) != isHeightValid(height)) { 2239 return false; 2240 } 2241 return (!isWidthValid(width) || mWidth == width) 2242 && (!isHeightValid(height) || mHeight == height) 2243 && (!isRefreshRateValid(refreshRate) 2244 || Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate)); 2245 } 2246 2247 /** 2248 * Returns {@code true} if this mode equals to the other mode in all parameters except 2249 * the refresh rate. 2250 * 2251 * @hide 2252 */ equalsExceptRefreshRate(@ullable Display.Mode other)2253 public boolean equalsExceptRefreshRate(@Nullable Display.Mode other) { 2254 return mWidth == other.mWidth && mHeight == other.mHeight; 2255 } 2256 2257 /** 2258 * Returns {@code true} if refresh-rate is set for a display mode 2259 * 2260 * @hide 2261 */ isRefreshRateSet()2262 public boolean isRefreshRateSet() { 2263 return mRefreshRate != INVALID_DISPLAY_REFRESH_RATE; 2264 } 2265 2266 /** 2267 * Returns {@code true} if refresh-rate is set for a display mode 2268 * 2269 * @hide 2270 */ isResolutionSet()2271 public boolean isResolutionSet() { 2272 return mWidth != INVALID_DISPLAY_WIDTH && mHeight != INVALID_DISPLAY_HEIGHT; 2273 } 2274 2275 @Override equals(@ullable Object other)2276 public boolean equals(@Nullable Object other) { 2277 if (this == other) { 2278 return true; 2279 } 2280 if (!(other instanceof Mode)) { 2281 return false; 2282 } 2283 Mode that = (Mode) other; 2284 return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate) 2285 && Arrays.equals(mAlternativeRefreshRates, that.mAlternativeRefreshRates) 2286 && Arrays.equals(mSupportedHdrTypes, that.mSupportedHdrTypes); 2287 } 2288 2289 @Override hashCode()2290 public int hashCode() { 2291 int hash = 1; 2292 hash = hash * 17 + mModeId; 2293 hash = hash * 17 + mWidth; 2294 hash = hash * 17 + mHeight; 2295 hash = hash * 17 + Float.floatToIntBits(mRefreshRate); 2296 hash = hash * 17 + Arrays.hashCode(mAlternativeRefreshRates); 2297 hash = hash * 17 + Arrays.hashCode(mSupportedHdrTypes); 2298 return hash; 2299 } 2300 2301 @Override toString()2302 public String toString() { 2303 return new StringBuilder("{") 2304 .append("id=").append(mModeId) 2305 .append(", width=").append(mWidth) 2306 .append(", height=").append(mHeight) 2307 .append(", fps=").append(mRefreshRate) 2308 .append(", alternativeRefreshRates=") 2309 .append(Arrays.toString(mAlternativeRefreshRates)) 2310 .append(", supportedHdrTypes=") 2311 .append(Arrays.toString(mSupportedHdrTypes)) 2312 .append("}") 2313 .toString(); 2314 } 2315 2316 @Override describeContents()2317 public int describeContents() { 2318 return 0; 2319 } 2320 Mode(Parcel in)2321 private Mode(Parcel in) { 2322 this(in.readInt(), in.readInt(), in.readInt(), in.readFloat(), in.createFloatArray(), 2323 in.createIntArray()); 2324 } 2325 2326 @Override writeToParcel(Parcel out, int parcelableFlags)2327 public void writeToParcel(Parcel out, int parcelableFlags) { 2328 out.writeInt(mModeId); 2329 out.writeInt(mWidth); 2330 out.writeInt(mHeight); 2331 out.writeFloat(mRefreshRate); 2332 out.writeFloatArray(mAlternativeRefreshRates); 2333 out.writeIntArray(mSupportedHdrTypes); 2334 } 2335 2336 @SuppressWarnings("hiding") 2337 public static final @android.annotation.NonNull Parcelable.Creator<Mode> CREATOR 2338 = new Parcelable.Creator<Mode>() { 2339 @Override 2340 public Mode createFromParcel(Parcel in) { 2341 return new Mode(in); 2342 } 2343 2344 @Override 2345 public Mode[] newArray(int size) { 2346 return new Mode[size]; 2347 } 2348 }; 2349 2350 /** 2351 * Builder is used to create {@link Display.Mode} objects 2352 * 2353 * @hide 2354 */ 2355 @TestApi 2356 public static final class Builder { 2357 private int mWidth; 2358 private int mHeight; 2359 private float mRefreshRate; 2360 Builder()2361 public Builder() { 2362 mWidth = Display.INVALID_DISPLAY_WIDTH; 2363 mHeight = Display.INVALID_DISPLAY_HEIGHT; 2364 mRefreshRate = Display.INVALID_DISPLAY_REFRESH_RATE; 2365 } 2366 2367 /** 2368 * Sets the resolution (width and height) of a {@link Display.Mode} 2369 * 2370 * @return Instance of {@link Builder} 2371 */ 2372 @NonNull setResolution(int width, int height)2373 public Builder setResolution(int width, int height) { 2374 if (width > 0 && height > 0) { 2375 mWidth = width; 2376 mHeight = height; 2377 } 2378 return this; 2379 } 2380 2381 /** 2382 * Sets the refresh rate of a {@link Display.Mode} 2383 * 2384 * @return Instance of {@link Builder} 2385 */ 2386 @NonNull setRefreshRate(float refreshRate)2387 public Builder setRefreshRate(float refreshRate) { 2388 if (refreshRate > 0.0f) { 2389 mRefreshRate = refreshRate; 2390 } 2391 return this; 2392 } 2393 2394 /** 2395 * Creates the {@link Display.Mode} object. 2396 * 2397 * <p> 2398 * If resolution needs to be set, but refresh-rate doesn't matter, create a mode with 2399 * Builder and call setResolution. 2400 * {@code 2401 * Display.Mode mode = 2402 * new Display.Mode.Builder() 2403 * .setResolution(width, height) 2404 * .build(); 2405 * } 2406 * </p><p> 2407 * If refresh-rate needs to be set, but resolution doesn't matter, create a mode with 2408 * Builder and call setRefreshRate. 2409 * {@code 2410 * Display.Mode mode = 2411 * new Display.Mode.Builder() 2412 * .setRefreshRate(refreshRate) 2413 * .build(); 2414 * } 2415 * </p> 2416 */ 2417 @NonNull build()2418 public Mode build() { 2419 Display.Mode mode = new Mode(mWidth, mHeight, mRefreshRate); 2420 return mode; 2421 } 2422 } 2423 } 2424 2425 /** 2426 * Encapsulates the HDR capabilities of a given display. 2427 * For example, what HDR types it supports and details about the desired luminance data. 2428 * <p>You can get an instance for a given {@link Display} object with 2429 * {@link Display#getHdrCapabilities getHdrCapabilities()}. 2430 */ 2431 public static final class HdrCapabilities implements Parcelable { 2432 /** 2433 * Invalid luminance value. 2434 */ 2435 public static final float INVALID_LUMINANCE = -1; 2436 /** 2437 * Invalid HDR type value. 2438 */ 2439 public static final int HDR_TYPE_INVALID = -1; 2440 /** 2441 * Dolby Vision high dynamic range (HDR) display. 2442 */ 2443 public static final int HDR_TYPE_DOLBY_VISION = 1; 2444 /** 2445 * HDR10 display. 2446 */ 2447 public static final int HDR_TYPE_HDR10 = 2; 2448 /** 2449 * Hybrid Log-Gamma HDR display. 2450 */ 2451 public static final int HDR_TYPE_HLG = 3; 2452 2453 /** 2454 * HDR10+ display. 2455 */ 2456 public static final int HDR_TYPE_HDR10_PLUS = 4; 2457 2458 /** @hide */ 2459 public static final int[] HDR_TYPES = { 2460 HDR_TYPE_DOLBY_VISION, 2461 HDR_TYPE_HDR10, 2462 HDR_TYPE_HLG, 2463 HDR_TYPE_HDR10_PLUS 2464 }; 2465 2466 /** @hide */ 2467 @IntDef(prefix = { "HDR_TYPE_" }, value = { 2468 HDR_TYPE_INVALID, 2469 HDR_TYPE_DOLBY_VISION, 2470 HDR_TYPE_HDR10, 2471 HDR_TYPE_HLG, 2472 HDR_TYPE_HDR10_PLUS, 2473 }) 2474 @Retention(RetentionPolicy.SOURCE) 2475 public @interface HdrType {} 2476 2477 private @HdrType int[] mSupportedHdrTypes = new int[0]; 2478 private float mMaxLuminance = INVALID_LUMINANCE; 2479 private float mMaxAverageLuminance = INVALID_LUMINANCE; 2480 private float mMinLuminance = INVALID_LUMINANCE; 2481 2482 /** 2483 * @hide 2484 */ HdrCapabilities()2485 public HdrCapabilities() { 2486 } 2487 2488 /** 2489 * @hide 2490 */ 2491 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) HdrCapabilities(int[] supportedHdrTypes, float maxLuminance, float maxAverageLuminance, float minLuminance)2492 public HdrCapabilities(int[] supportedHdrTypes, float maxLuminance, 2493 float maxAverageLuminance, float minLuminance) { 2494 mSupportedHdrTypes = supportedHdrTypes; 2495 Arrays.sort(mSupportedHdrTypes); 2496 mMaxLuminance = maxLuminance; 2497 mMaxAverageLuminance = maxAverageLuminance; 2498 mMinLuminance = minLuminance; 2499 } 2500 2501 /** 2502 * Gets the supported HDR types of this display. 2503 * Returns empty array if HDR is not supported by the display. 2504 * 2505 * @deprecated use {@link Display#getMode()} 2506 * and {@link Mode#getSupportedHdrTypes()} instead 2507 */ 2508 @Deprecated 2509 @HdrType getSupportedHdrTypes()2510 public int[] getSupportedHdrTypes() { 2511 return Arrays.copyOf(mSupportedHdrTypes, mSupportedHdrTypes.length); 2512 } 2513 /** 2514 * Returns the desired content max luminance data in cd/m2 for this display. 2515 */ getDesiredMaxLuminance()2516 public float getDesiredMaxLuminance() { 2517 return mMaxLuminance; 2518 } 2519 /** 2520 * Returns the desired content max frame-average luminance data in cd/m2 for this display. 2521 */ getDesiredMaxAverageLuminance()2522 public float getDesiredMaxAverageLuminance() { 2523 return mMaxAverageLuminance; 2524 } 2525 /** 2526 * Returns the desired content min luminance data in cd/m2 for this display. 2527 */ getDesiredMinLuminance()2528 public float getDesiredMinLuminance() { 2529 return mMinLuminance; 2530 } 2531 2532 @Override equals(@ullable Object other)2533 public boolean equals(@Nullable Object other) { 2534 if (this == other) { 2535 return true; 2536 } 2537 2538 if (!(other instanceof HdrCapabilities)) { 2539 return false; 2540 } 2541 HdrCapabilities that = (HdrCapabilities) other; 2542 2543 return Arrays.equals(mSupportedHdrTypes, that.mSupportedHdrTypes) 2544 && mMaxLuminance == that.mMaxLuminance 2545 && mMaxAverageLuminance == that.mMaxAverageLuminance 2546 && mMinLuminance == that.mMinLuminance; 2547 } 2548 2549 @Override hashCode()2550 public int hashCode() { 2551 int hash = 23; 2552 hash = hash * 17 + Arrays.hashCode(mSupportedHdrTypes); 2553 hash = hash * 17 + Float.floatToIntBits(mMaxLuminance); 2554 hash = hash * 17 + Float.floatToIntBits(mMaxAverageLuminance); 2555 hash = hash * 17 + Float.floatToIntBits(mMinLuminance); 2556 return hash; 2557 } 2558 2559 public static final @android.annotation.NonNull Creator<HdrCapabilities> CREATOR = new Creator<HdrCapabilities>() { 2560 @Override 2561 public HdrCapabilities createFromParcel(Parcel source) { 2562 return new HdrCapabilities(source); 2563 } 2564 2565 @Override 2566 public HdrCapabilities[] newArray(int size) { 2567 return new HdrCapabilities[size]; 2568 } 2569 }; 2570 HdrCapabilities(Parcel source)2571 private HdrCapabilities(Parcel source) { 2572 readFromParcel(source); 2573 } 2574 2575 /** 2576 * @hide 2577 */ readFromParcel(Parcel source)2578 public void readFromParcel(Parcel source) { 2579 int types = source.readInt(); 2580 mSupportedHdrTypes = new int[types]; 2581 for (int i = 0; i < types; ++i) { 2582 mSupportedHdrTypes[i] = source.readInt(); 2583 } 2584 mMaxLuminance = source.readFloat(); 2585 mMaxAverageLuminance = source.readFloat(); 2586 mMinLuminance = source.readFloat(); 2587 } 2588 2589 @Override writeToParcel(Parcel dest, int flags)2590 public void writeToParcel(Parcel dest, int flags) { 2591 dest.writeInt(mSupportedHdrTypes.length); 2592 for (int i = 0; i < mSupportedHdrTypes.length; ++i) { 2593 dest.writeInt(mSupportedHdrTypes[i]); 2594 } 2595 dest.writeFloat(mMaxLuminance); 2596 dest.writeFloat(mMaxAverageLuminance); 2597 dest.writeFloat(mMinLuminance); 2598 } 2599 2600 @Override describeContents()2601 public int describeContents() { 2602 return 0; 2603 } 2604 2605 @Override toString()2606 public String toString() { 2607 return "HdrCapabilities{" 2608 + "mSupportedHdrTypes=" + Arrays.toString(mSupportedHdrTypes) 2609 + ", mMaxLuminance=" + mMaxLuminance 2610 + ", mMaxAverageLuminance=" + mMaxAverageLuminance 2611 + ", mMinLuminance=" + mMinLuminance + '}'; 2612 } 2613 2614 /** 2615 * @hide 2616 */ 2617 @NonNull hdrTypeToString(int hdrType)2618 public static String hdrTypeToString(int hdrType) { 2619 switch (hdrType) { 2620 case HDR_TYPE_DOLBY_VISION: 2621 return "HDR_TYPE_DOLBY_VISION"; 2622 case HDR_TYPE_HDR10: 2623 return "HDR_TYPE_HDR10"; 2624 case HDR_TYPE_HLG: 2625 return "HDR_TYPE_HLG"; 2626 case HDR_TYPE_HDR10_PLUS: 2627 return "HDR_TYPE_HDR10_PLUS"; 2628 default: 2629 return "HDR_TYPE_INVALID"; 2630 } 2631 } 2632 } 2633 2634 private class HdrSdrRatioListenerWrapper implements DisplayManager.DisplayListener { 2635 Consumer<Display> mListener; 2636 float mLastReportedRatio = 1.f; 2637 HdrSdrRatioListenerWrapper(Consumer<Display> listener)2638 private HdrSdrRatioListenerWrapper(Consumer<Display> listener) { 2639 mListener = listener; 2640 } 2641 2642 @Override onDisplayAdded(int displayId)2643 public void onDisplayAdded(int displayId) { 2644 // don't care 2645 } 2646 2647 @Override onDisplayRemoved(int displayId)2648 public void onDisplayRemoved(int displayId) { 2649 // don't care 2650 } 2651 2652 @Override onDisplayChanged(int displayId)2653 public void onDisplayChanged(int displayId) { 2654 if (displayId == getDisplayId()) { 2655 float newRatio = getHdrSdrRatio(); 2656 if (newRatio != mLastReportedRatio) { 2657 mListener.accept(Display.this); 2658 } 2659 } 2660 } 2661 } 2662 } 2663