1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.display; 18 19 20 import static android.hardware.display.DisplayManager.EventsMask; 21 import static android.view.Display.HdrCapabilities.HdrType; 22 23 import android.Manifest; 24 import android.annotation.IntDef; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.RequiresPermission; 28 import android.app.ActivityThread; 29 import android.app.PropertyInvalidatedCache; 30 import android.compat.annotation.UnsupportedAppUsage; 31 import android.content.Context; 32 import android.content.pm.ParceledListSlice; 33 import android.content.res.Resources; 34 import android.graphics.ColorSpace; 35 import android.graphics.Point; 36 import android.hardware.OverlayProperties; 37 import android.hardware.display.DisplayManager.DisplayListener; 38 import android.hardware.graphics.common.DisplayDecorationSupport; 39 import android.media.projection.IMediaProjection; 40 import android.media.projection.MediaProjection; 41 import android.os.Binder; 42 import android.os.Handler; 43 import android.os.HandlerExecutor; 44 import android.os.IBinder; 45 import android.os.Looper; 46 import android.os.RemoteException; 47 import android.os.ServiceManager; 48 import android.os.Trace; 49 import android.sysprop.DisplayProperties; 50 import android.text.TextUtils; 51 import android.util.Log; 52 import android.util.Pair; 53 import android.util.Slog; 54 import android.util.SparseArray; 55 import android.view.Display; 56 import android.view.DisplayAdjustments; 57 import android.view.DisplayInfo; 58 import android.view.Surface; 59 60 import com.android.internal.annotations.VisibleForTesting; 61 62 import java.lang.annotation.Retention; 63 import java.lang.annotation.RetentionPolicy; 64 import java.util.Collections; 65 import java.util.List; 66 import java.util.Objects; 67 import java.util.concurrent.CopyOnWriteArrayList; 68 import java.util.concurrent.Executor; 69 import java.util.concurrent.atomic.AtomicLong; 70 71 /** 72 * Manager communication with the display manager service on behalf of 73 * an application process. You're probably looking for {@link DisplayManager}. 74 * 75 * @hide 76 */ 77 public final class DisplayManagerGlobal { 78 private static final String TAG = "DisplayManager"; 79 80 private static final String EXTRA_LOGGING_PACKAGE_NAME = 81 DisplayProperties.debug_vri_package().orElse(null); 82 private static String sCurrentPackageName = ActivityThread.currentPackageName(); 83 private static boolean sExtraDisplayListenerLogging = initExtraLogging(); 84 85 // To enable these logs, run: 86 // 'adb shell setprop persist.log.tag.DisplayManager DEBUG && adb reboot' 87 private static final boolean DEBUG = DisplayManager.DEBUG || sExtraDisplayListenerLogging; 88 89 // True if display info and display ids should be cached. 90 // 91 // FIXME: The cache is currently disabled because it's unclear whether we have the 92 // necessary guarantees that the caches will always be flushed before clients 93 // attempt to observe their new state. For example, depending on the order 94 // in which the binder transactions take place, we might have a problem where 95 // an application could start processing a configuration change due to a display 96 // orientation change before the display info cache has actually been invalidated. 97 private static final boolean USE_CACHE = false; 98 99 @IntDef(prefix = {"EVENT_DISPLAY_"}, flag = true, value = { 100 EVENT_DISPLAY_ADDED, 101 EVENT_DISPLAY_CHANGED, 102 EVENT_DISPLAY_REMOVED, 103 EVENT_DISPLAY_BRIGHTNESS_CHANGED, 104 EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED, 105 EVENT_DISPLAY_CONNECTED, 106 EVENT_DISPLAY_DISCONNECTED, 107 }) 108 @Retention(RetentionPolicy.SOURCE) 109 public @interface DisplayEvent {} 110 111 public static final int EVENT_DISPLAY_ADDED = 1; 112 public static final int EVENT_DISPLAY_CHANGED = 2; 113 public static final int EVENT_DISPLAY_REMOVED = 3; 114 public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4; 115 public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5; 116 public static final int EVENT_DISPLAY_CONNECTED = 6; 117 public static final int EVENT_DISPLAY_DISCONNECTED = 7; 118 119 @UnsupportedAppUsage 120 private static DisplayManagerGlobal sInstance; 121 122 // Guarded by mLock 123 private boolean mDispatchNativeCallbacks = false; 124 private float mNativeCallbackReportedRefreshRate; 125 private final Object mLock = new Object(); 126 127 @UnsupportedAppUsage 128 private final IDisplayManager mDm; 129 130 private DisplayManagerCallback mCallback; 131 private @EventsMask long mRegisteredEventsMask = 0; 132 private final CopyOnWriteArrayList<DisplayListenerDelegate> mDisplayListeners = 133 new CopyOnWriteArrayList<>(); 134 135 private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>(); 136 private final ColorSpace mWideColorSpace; 137 private final OverlayProperties mOverlayProperties; 138 private int[] mDisplayIdCache; 139 140 private int mWifiDisplayScanNestCount; 141 142 private final Binder mToken = new Binder(); 143 144 @VisibleForTesting DisplayManagerGlobal(IDisplayManager dm)145 public DisplayManagerGlobal(IDisplayManager dm) { 146 mDm = dm; 147 initExtraLogging(); 148 149 try { 150 mWideColorSpace = 151 ColorSpace.get( 152 ColorSpace.Named.values()[mDm.getPreferredWideGamutColorSpaceId()]); 153 mOverlayProperties = mDm.getOverlaySupport(); 154 } catch (RemoteException ex) { 155 throw ex.rethrowFromSystemServer(); 156 } 157 } 158 159 private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache = 160 new PropertyInvalidatedCache<Integer, DisplayInfo>( 161 8, // size of display cache 162 CACHE_KEY_DISPLAY_INFO_PROPERTY) { 163 @Override 164 public DisplayInfo recompute(Integer id) { 165 try { 166 return mDm.getDisplayInfo(id); 167 } catch (RemoteException ex) { 168 throw ex.rethrowFromSystemServer(); 169 } 170 } 171 }; 172 173 /** 174 * Gets an instance of the display manager global singleton. 175 * 176 * @return The display manager instance, may be null early in system startup 177 * before the display manager has been fully initialized. 178 */ 179 @UnsupportedAppUsage getInstance()180 public static DisplayManagerGlobal getInstance() { 181 synchronized (DisplayManagerGlobal.class) { 182 if (sInstance == null) { 183 IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE); 184 if (b != null) { 185 sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b)); 186 } 187 } 188 return sInstance; 189 } 190 } 191 192 /** 193 * Get information about a particular logical display. 194 * 195 * @param displayId The logical display id. 196 * @return Information about the specified display, or null if it does not exist. 197 * This object belongs to an internal cache and should be treated as if it were immutable. 198 */ 199 @UnsupportedAppUsage getDisplayInfo(int displayId)200 public DisplayInfo getDisplayInfo(int displayId) { 201 synchronized (mLock) { 202 return getDisplayInfoLocked(displayId); 203 } 204 } 205 206 /** 207 * Gets information about a particular logical display 208 * See {@link getDisplayInfo}, but assumes that {@link mLock} is held 209 */ getDisplayInfoLocked(int displayId)210 private @Nullable DisplayInfo getDisplayInfoLocked(int displayId) { 211 DisplayInfo info = null; 212 if (mDisplayCache != null) { 213 info = mDisplayCache.query(displayId); 214 } else { 215 try { 216 info = mDm.getDisplayInfo(displayId); 217 } catch (RemoteException ex) { 218 ex.rethrowFromSystemServer(); 219 } 220 } 221 if (info == null) { 222 return null; 223 } 224 225 registerCallbackIfNeededLocked(); 226 227 if (DEBUG) { 228 Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info); 229 } 230 return info; 231 } 232 233 /** 234 * Gets all currently valid logical display ids. 235 * 236 * @return An array containing all display ids. 237 */ 238 @UnsupportedAppUsage getDisplayIds()239 public int[] getDisplayIds() { 240 return getDisplayIds(/* includeDisabled= */ false); 241 } 242 243 /** 244 * Gets all currently valid logical display ids. 245 * 246 * @param includeDisabled True if the returned list of displays includes disabled displays. 247 * @return An array containing all display ids. 248 */ getDisplayIds(boolean includeDisabled)249 public int[] getDisplayIds(boolean includeDisabled) { 250 try { 251 synchronized (mLock) { 252 if (USE_CACHE) { 253 if (mDisplayIdCache != null) { 254 return mDisplayIdCache; 255 } 256 } 257 258 int[] displayIds = mDm.getDisplayIds(includeDisabled); 259 if (USE_CACHE) { 260 mDisplayIdCache = displayIds; 261 } 262 registerCallbackIfNeededLocked(); 263 return displayIds; 264 } 265 } catch (RemoteException ex) { 266 throw ex.rethrowFromSystemServer(); 267 } 268 } 269 270 /** 271 * Check if specified UID's content is present on display and should be granted access to it. 272 * 273 * @param uid UID to be checked. 274 * @param displayId id of the display where presence of the content is checked. 275 * @return {@code true} if UID is present on display, {@code false} otherwise. 276 */ isUidPresentOnDisplay(int uid, int displayId)277 public boolean isUidPresentOnDisplay(int uid, int displayId) { 278 try { 279 return mDm.isUidPresentOnDisplay(uid, displayId); 280 } catch (RemoteException ex) { 281 throw ex.rethrowFromSystemServer(); 282 } 283 } 284 285 /** 286 * Gets information about a logical display. 287 * 288 * The display metrics may be adjusted to provide compatibility 289 * for legacy applications or limited screen areas. 290 * 291 * @param displayId The logical display id. 292 * @param daj The compatibility info and activityToken. 293 * @return The display object, or null if there is no display with the given id. 294 */ getCompatibleDisplay(int displayId, DisplayAdjustments daj)295 public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) { 296 DisplayInfo displayInfo = getDisplayInfo(displayId); 297 if (displayInfo == null) { 298 return null; 299 } 300 return new Display(this, displayId, displayInfo, daj); 301 } 302 303 /** 304 * Gets information about a logical display. 305 * 306 * The display metrics may be adjusted to provide compatibility 307 * for legacy applications or limited screen areas. 308 * 309 * @param displayId The logical display id. 310 * @param resources Resources providing compatibility info. 311 * @return The display object, or null if there is no display with the given id. 312 */ getCompatibleDisplay(int displayId, Resources resources)313 public Display getCompatibleDisplay(int displayId, Resources resources) { 314 DisplayInfo displayInfo = getDisplayInfo(displayId); 315 if (displayInfo == null) { 316 return null; 317 } 318 return new Display(this, displayId, displayInfo, resources); 319 } 320 321 /** 322 * Gets information about a logical display without applying any compatibility metrics. 323 * 324 * @param displayId The logical display id. 325 * @return The display object, or null if there is no display with the given id. 326 */ 327 @UnsupportedAppUsage getRealDisplay(int displayId)328 public Display getRealDisplay(int displayId) { 329 return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); 330 } 331 332 /** 333 * Register a listener for display-related changes. 334 * 335 * @param listener The listener that will be called when display changes occur. 336 * @param handler Handler for the thread that will be receiving the callbacks. May be null. 337 * If null, listener will use the handler for the current thread, and if still null, 338 * the handler for the main thread. 339 * If that is still null, a runtime exception will be thrown. 340 * @param packageName of the calling package. 341 */ registerDisplayListener(@onNull DisplayListener listener, @Nullable Handler handler, @EventsMask long eventsMask, String packageName)342 public void registerDisplayListener(@NonNull DisplayListener listener, 343 @Nullable Handler handler, @EventsMask long eventsMask, String packageName) { 344 Looper looper = getLooperForHandler(handler); 345 Handler springBoard = new Handler(looper); 346 registerDisplayListener(listener, new HandlerExecutor(springBoard), eventsMask, 347 packageName); 348 } 349 350 /** 351 * Register a listener for display-related changes. 352 * 353 * @param listener The listener that will be called when display changes occur. 354 * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null. 355 * @param eventsMask Mask of events to be listened to. 356 * @param packageName of the calling package. 357 */ registerDisplayListener(@onNull DisplayListener listener, @NonNull Executor executor, @EventsMask long eventsMask, String packageName)358 public void registerDisplayListener(@NonNull DisplayListener listener, 359 @NonNull Executor executor, @EventsMask long eventsMask, String packageName) { 360 if (listener == null) { 361 throw new IllegalArgumentException("listener must not be null"); 362 } 363 364 if (eventsMask == 0) { 365 throw new IllegalArgumentException("The set of events to listen to must not be empty."); 366 } 367 368 if (extraLogging()) { 369 Slog.i(TAG, "Registering Display Listener: " 370 + Long.toBinaryString(eventsMask) + ", packageName: " + packageName); 371 } 372 373 synchronized (mLock) { 374 int index = findDisplayListenerLocked(listener); 375 if (index < 0) { 376 mDisplayListeners.add(new DisplayListenerDelegate(listener, executor, eventsMask, 377 packageName)); 378 registerCallbackIfNeededLocked(); 379 } else { 380 mDisplayListeners.get(index).setEventsMask(eventsMask); 381 } 382 updateCallbackIfNeededLocked(); 383 maybeLogAllDisplayListeners(); 384 } 385 } 386 unregisterDisplayListener(DisplayListener listener)387 public void unregisterDisplayListener(DisplayListener listener) { 388 if (listener == null) { 389 throw new IllegalArgumentException("listener must not be null"); 390 } 391 392 if (extraLogging()) { 393 Slog.i(TAG, "Unregistering Display Listener: " + listener); 394 } 395 396 synchronized (mLock) { 397 int index = findDisplayListenerLocked(listener); 398 if (index >= 0) { 399 DisplayListenerDelegate d = mDisplayListeners.get(index); 400 d.clearEvents(); 401 mDisplayListeners.remove(index); 402 updateCallbackIfNeededLocked(); 403 } 404 } 405 maybeLogAllDisplayListeners(); 406 } 407 maybeLogAllDisplayListeners()408 private void maybeLogAllDisplayListeners() { 409 if (!extraLogging()) { 410 return; 411 } 412 413 Slog.i(TAG, "Currently Registered Display Listeners:"); 414 for (int i = 0; i < mDisplayListeners.size(); i++) { 415 Slog.i(TAG, i + ": " + mDisplayListeners.get(i)); 416 } 417 } 418 419 /** 420 * Called when there is a display-related window configuration change. Reroutes the event from 421 * WindowManager to make sure the {@link Display} fields are up-to-date in the last callback. 422 * @param displayId the logical display that was changed. 423 */ handleDisplayChangeFromWindowManager(int displayId)424 public void handleDisplayChangeFromWindowManager(int displayId) { 425 // There can be racing condition between DMS and WMS callbacks, so force triggering the 426 // listener to make sure the client can get the onDisplayChanged callback even if 427 // DisplayInfo is not changed (Display read from both DisplayInfo and WindowConfiguration). 428 handleDisplayEvent(displayId, EVENT_DISPLAY_CHANGED, true /* forceUpdate */); 429 } 430 getLooperForHandler(@ullable Handler handler)431 private static Looper getLooperForHandler(@Nullable Handler handler) { 432 Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); 433 if (looper == null) { 434 looper = Looper.getMainLooper(); 435 } 436 if (looper == null) { 437 throw new RuntimeException("Could not get Looper for the UI thread."); 438 } 439 return looper; 440 } 441 findDisplayListenerLocked(DisplayListener listener)442 private int findDisplayListenerLocked(DisplayListener listener) { 443 final int numListeners = mDisplayListeners.size(); 444 for (int i = 0; i < numListeners; i++) { 445 if (mDisplayListeners.get(i).mListener == listener) { 446 return i; 447 } 448 } 449 return -1; 450 } 451 452 @EventsMask calculateEventsMaskLocked()453 private int calculateEventsMaskLocked() { 454 int mask = 0; 455 final int numListeners = mDisplayListeners.size(); 456 for (int i = 0; i < numListeners; i++) { 457 mask |= mDisplayListeners.get(i).mEventsMask; 458 } 459 if (mDispatchNativeCallbacks) { 460 mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED 461 | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED 462 | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; 463 } 464 return mask; 465 } 466 registerCallbackIfNeededLocked()467 private void registerCallbackIfNeededLocked() { 468 if (mCallback == null) { 469 mCallback = new DisplayManagerCallback(); 470 updateCallbackIfNeededLocked(); 471 } 472 } 473 updateCallbackIfNeededLocked()474 private void updateCallbackIfNeededLocked() { 475 int mask = calculateEventsMaskLocked(); 476 if (DEBUG) { 477 Log.d(TAG, "Mask for listener: " + mask); 478 } 479 if (mask != mRegisteredEventsMask) { 480 try { 481 mDm.registerCallbackWithEventMask(mCallback, mask); 482 mRegisteredEventsMask = mask; 483 } catch (RemoteException ex) { 484 throw ex.rethrowFromSystemServer(); 485 } 486 } 487 } 488 handleDisplayEvent(int displayId, @DisplayEvent int event, boolean forceUpdate)489 private void handleDisplayEvent(int displayId, @DisplayEvent int event, boolean forceUpdate) { 490 final DisplayInfo info; 491 synchronized (mLock) { 492 if (USE_CACHE) { 493 mDisplayInfoCache.remove(displayId); 494 495 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) { 496 mDisplayIdCache = null; 497 } 498 } 499 500 info = getDisplayInfoLocked(displayId); 501 if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { 502 // Choreographer only supports a single display, so only dispatch refresh rate 503 // changes for the default display. 504 if (displayId == Display.DEFAULT_DISPLAY) { 505 // We can likely save a binder hop if we attach the refresh rate onto the 506 // listener. 507 DisplayInfo display = getDisplayInfoLocked(displayId); 508 if (display != null 509 && mNativeCallbackReportedRefreshRate != display.getRefreshRate()) { 510 mNativeCallbackReportedRefreshRate = display.getRefreshRate(); 511 // Signal native callbacks if we ever set a refresh rate. 512 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate); 513 } 514 } 515 } 516 } 517 // Accepting an Executor means the listener may be synchronously invoked, so we must 518 // not be holding mLock when we do so 519 for (DisplayListenerDelegate listener : mDisplayListeners) { 520 listener.sendDisplayEvent(displayId, event, info, forceUpdate); 521 } 522 } 523 524 /** 525 * Enable a connected display that is currently disabled. 526 * @hide 527 */ 528 @RequiresPermission("android.permission.MANAGE_DISPLAYS") enableConnectedDisplay(int displayId)529 public void enableConnectedDisplay(int displayId) { 530 try { 531 mDm.enableConnectedDisplay(displayId); 532 } catch (RemoteException ex) { 533 Log.e(TAG, "Error trying to enable external display", ex); 534 } 535 } 536 537 538 /** 539 * Disable a connected display that is currently enabled. 540 * @hide 541 */ 542 @RequiresPermission("android.permission.MANAGE_DISPLAYS") disableConnectedDisplay(int displayId)543 public void disableConnectedDisplay(int displayId) { 544 try { 545 mDm.disableConnectedDisplay(displayId); 546 } catch (RemoteException ex) { 547 Log.e(TAG, "Error trying to enable external display", ex); 548 } 549 } 550 551 /** 552 * Request to power a display ON or OFF. 553 * @hide 554 */ 555 @RequiresPermission("android.permission.MANAGE_DISPLAYS") requestDisplayPower(int displayId, boolean on)556 public boolean requestDisplayPower(int displayId, boolean on) { 557 try { 558 return mDm.requestDisplayPower(displayId, on); 559 } catch (RemoteException ex) { 560 Log.e(TAG, "Error trying to request display power " + on, ex); 561 return false; 562 } 563 } 564 startWifiDisplayScan()565 public void startWifiDisplayScan() { 566 synchronized (mLock) { 567 if (mWifiDisplayScanNestCount++ == 0) { 568 registerCallbackIfNeededLocked(); 569 try { 570 mDm.startWifiDisplayScan(); 571 } catch (RemoteException ex) { 572 throw ex.rethrowFromSystemServer(); 573 } 574 } 575 } 576 } 577 stopWifiDisplayScan()578 public void stopWifiDisplayScan() { 579 synchronized (mLock) { 580 if (--mWifiDisplayScanNestCount == 0) { 581 try { 582 mDm.stopWifiDisplayScan(); 583 } catch (RemoteException ex) { 584 throw ex.rethrowFromSystemServer(); 585 } 586 } else if (mWifiDisplayScanNestCount < 0) { 587 Log.wtf(TAG, "Wifi display scan nest count became negative: " 588 + mWifiDisplayScanNestCount); 589 mWifiDisplayScanNestCount = 0; 590 } 591 } 592 } 593 connectWifiDisplay(String deviceAddress)594 public void connectWifiDisplay(String deviceAddress) { 595 if (deviceAddress == null) { 596 throw new IllegalArgumentException("deviceAddress must not be null"); 597 } 598 599 try { 600 mDm.connectWifiDisplay(deviceAddress); 601 } catch (RemoteException ex) { 602 throw ex.rethrowFromSystemServer(); 603 } 604 } 605 pauseWifiDisplay()606 public void pauseWifiDisplay() { 607 try { 608 mDm.pauseWifiDisplay(); 609 } catch (RemoteException ex) { 610 throw ex.rethrowFromSystemServer(); 611 } 612 } 613 resumeWifiDisplay()614 public void resumeWifiDisplay() { 615 try { 616 mDm.resumeWifiDisplay(); 617 } catch (RemoteException ex) { 618 throw ex.rethrowFromSystemServer(); 619 } 620 } 621 622 @UnsupportedAppUsage disconnectWifiDisplay()623 public void disconnectWifiDisplay() { 624 try { 625 mDm.disconnectWifiDisplay(); 626 } catch (RemoteException ex) { 627 throw ex.rethrowFromSystemServer(); 628 } 629 } 630 renameWifiDisplay(String deviceAddress, String alias)631 public void renameWifiDisplay(String deviceAddress, String alias) { 632 if (deviceAddress == null) { 633 throw new IllegalArgumentException("deviceAddress must not be null"); 634 } 635 636 try { 637 mDm.renameWifiDisplay(deviceAddress, alias); 638 } catch (RemoteException ex) { 639 throw ex.rethrowFromSystemServer(); 640 } 641 } 642 forgetWifiDisplay(String deviceAddress)643 public void forgetWifiDisplay(String deviceAddress) { 644 if (deviceAddress == null) { 645 throw new IllegalArgumentException("deviceAddress must not be null"); 646 } 647 648 try { 649 mDm.forgetWifiDisplay(deviceAddress); 650 } catch (RemoteException ex) { 651 throw ex.rethrowFromSystemServer(); 652 } 653 } 654 655 @UnsupportedAppUsage getWifiDisplayStatus()656 public WifiDisplayStatus getWifiDisplayStatus() { 657 try { 658 return mDm.getWifiDisplayStatus(); 659 } catch (RemoteException ex) { 660 throw ex.rethrowFromSystemServer(); 661 } 662 } 663 664 /** 665 * Sets the HDR types that have been disabled by user. 666 * @param userDisabledHdrTypes the HDR types to disable. The HDR types are any of 667 */ setUserDisabledHdrTypes(@drType int[] userDisabledHdrTypes)668 public void setUserDisabledHdrTypes(@HdrType int[] userDisabledHdrTypes) { 669 try { 670 mDm.setUserDisabledHdrTypes(userDisabledHdrTypes); 671 } catch (RemoteException ex) { 672 throw ex.rethrowFromSystemServer(); 673 } 674 } 675 676 /** 677 * Sets whether or not the user disabled HDR types are returned from 678 * {@link Display#getHdrCapabilities}. 679 * 680 * @param areUserDisabledHdrTypesAllowed If true, the user-disabled 681 * types are ignored and returned, if the display supports them. If 682 * false, the user-disabled types are taken into consideration and 683 * are never returned, even if the display supports them. 684 */ setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed)685 public void setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed) { 686 try { 687 mDm.setAreUserDisabledHdrTypesAllowed(areUserDisabledHdrTypesAllowed); 688 } catch (RemoteException ex) { 689 throw ex.rethrowFromSystemServer(); 690 } 691 } 692 693 /** 694 * Returns whether or not the user-disabled HDR types are returned from 695 * {@link Display#getHdrCapabilities}. 696 */ areUserDisabledHdrTypesAllowed()697 public boolean areUserDisabledHdrTypesAllowed() { 698 try { 699 return mDm.areUserDisabledHdrTypesAllowed(); 700 } catch (RemoteException ex) { 701 throw ex.rethrowFromSystemServer(); 702 } 703 } 704 705 /** 706 * Returns the HDR formats disabled by the user. 707 * 708 */ getUserDisabledHdrTypes()709 public int[] getUserDisabledHdrTypes() { 710 try { 711 return mDm.getUserDisabledHdrTypes(); 712 } catch (RemoteException ex) { 713 throw ex.rethrowFromSystemServer(); 714 } 715 } 716 717 /** 718 * Overrides HDR modes for a display device. 719 * 720 */ 721 @RequiresPermission(Manifest.permission.ACCESS_SURFACE_FLINGER) overrideHdrTypes(int displayId, int[] modes)722 public void overrideHdrTypes(int displayId, int[] modes) { 723 try { 724 mDm.overrideHdrTypes(displayId, modes); 725 } catch (RemoteException ex) { 726 throw ex.rethrowFromSystemServer(); 727 } 728 } 729 730 requestColorMode(int displayId, int colorMode)731 public void requestColorMode(int displayId, int colorMode) { 732 try { 733 mDm.requestColorMode(displayId, colorMode); 734 } catch (RemoteException ex) { 735 throw ex.rethrowFromSystemServer(); 736 } 737 } 738 createVirtualDisplay(@onNull Context context, MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, @Nullable Executor executor)739 public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection, 740 @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, 741 @Nullable Executor executor) { 742 VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, executor); 743 IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; 744 int displayId; 745 try { 746 displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, 747 projectionToken, context.getPackageName()); 748 } catch (RemoteException ex) { 749 throw ex.rethrowFromSystemServer(); 750 } 751 return createVirtualDisplayWrapper(virtualDisplayConfig, callbackWrapper, 752 displayId); 753 } 754 755 /** 756 * Create a VirtualDisplay wrapper object for a newly created virtual display ; to be called 757 * once the display has been created in system_server. 758 */ 759 @Nullable createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig, IVirtualDisplayCallback callbackWrapper, int displayId)760 public VirtualDisplay createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig, 761 IVirtualDisplayCallback callbackWrapper, int displayId) { 762 if (displayId < 0) { 763 Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName()); 764 return null; 765 } 766 Display display = getRealDisplay(displayId); 767 if (display == null) { 768 Log.wtf(TAG, "Could not obtain display info for newly created " 769 + "virtual display: " + virtualDisplayConfig.getName()); 770 try { 771 mDm.releaseVirtualDisplay(callbackWrapper); 772 } catch (RemoteException ex) { 773 throw ex.rethrowFromSystemServer(); 774 } 775 return null; 776 } 777 return new VirtualDisplay(this, display, callbackWrapper, 778 virtualDisplayConfig.getSurface()); 779 } 780 setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface)781 public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) { 782 try { 783 mDm.setVirtualDisplaySurface(token, surface); 784 setVirtualDisplayState(token, surface != null); 785 } catch (RemoteException ex) { 786 throw ex.rethrowFromSystemServer(); 787 } 788 } 789 resizeVirtualDisplay(IVirtualDisplayCallback token, int width, int height, int densityDpi)790 public void resizeVirtualDisplay(IVirtualDisplayCallback token, 791 int width, int height, int densityDpi) { 792 try { 793 mDm.resizeVirtualDisplay(token, width, height, densityDpi); 794 } catch (RemoteException ex) { 795 throw ex.rethrowFromSystemServer(); 796 } 797 } 798 releaseVirtualDisplay(IVirtualDisplayCallback token)799 public void releaseVirtualDisplay(IVirtualDisplayCallback token) { 800 try { 801 mDm.releaseVirtualDisplay(token); 802 } catch (RemoteException ex) { 803 throw ex.rethrowFromSystemServer(); 804 } 805 } 806 setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn)807 void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) { 808 try { 809 mDm.setVirtualDisplayState(token, isOn); 810 } catch (RemoteException ex) { 811 throw ex.rethrowFromSystemServer(); 812 } 813 } 814 815 /** 816 * Gets the stable device display size, in pixels. 817 */ getStableDisplaySize()818 public Point getStableDisplaySize() { 819 try { 820 return mDm.getStableDisplaySize(); 821 } catch (RemoteException ex) { 822 throw ex.rethrowFromSystemServer(); 823 } 824 } 825 826 /** 827 * Retrieves brightness change events. 828 */ getBrightnessEvents(String callingPackage)829 public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) { 830 try { 831 ParceledListSlice<BrightnessChangeEvent> events = 832 mDm.getBrightnessEvents(callingPackage); 833 if (events == null) { 834 return Collections.emptyList(); 835 } 836 return events.getList(); 837 } catch (RemoteException ex) { 838 throw ex.rethrowFromSystemServer(); 839 } 840 } 841 842 /** 843 * Retrieves Brightness Info for the specified display. 844 */ getBrightnessInfo(int displayId)845 public BrightnessInfo getBrightnessInfo(int displayId) { 846 try { 847 return mDm.getBrightnessInfo(displayId); 848 } catch (RemoteException ex) { 849 throw ex.rethrowFromSystemServer(); 850 } 851 } 852 853 /** 854 * Gets the preferred wide gamut color space for all displays. 855 * The wide gamut color space is returned from composition pipeline 856 * based on hardware capability. 857 * 858 * @hide 859 */ getPreferredWideGamutColorSpace()860 public ColorSpace getPreferredWideGamutColorSpace() { 861 return mWideColorSpace; 862 } 863 864 /** 865 * Gets the overlay properties for all displays. 866 * 867 * @hide 868 */ getOverlaySupport()869 public OverlayProperties getOverlaySupport() { 870 return mOverlayProperties; 871 } 872 873 /** 874 * Sets the global brightness configuration for a given user. 875 * 876 * @hide 877 */ setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, String packageName)878 public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, 879 String packageName) { 880 try { 881 mDm.setBrightnessConfigurationForUser(c, userId, packageName); 882 } catch (RemoteException ex) { 883 throw ex.rethrowFromSystemServer(); 884 } 885 } 886 887 /** 888 * Sets the brightness configuration for a given display. 889 * 890 * @hide 891 */ setBrightnessConfigurationForDisplay(BrightnessConfiguration c, String uniqueDisplayId, int userId, String packageName)892 public void setBrightnessConfigurationForDisplay(BrightnessConfiguration c, 893 String uniqueDisplayId, int userId, String packageName) { 894 try { 895 mDm.setBrightnessConfigurationForDisplay(c, uniqueDisplayId, userId, packageName); 896 } catch (RemoteException ex) { 897 throw ex.rethrowFromSystemServer(); 898 } 899 } 900 901 /** 902 * Gets the brightness configuration for a given display or null if one hasn't been set. 903 * 904 * @hide 905 */ getBrightnessConfigurationForDisplay(String uniqueDisplayId, int userId)906 public BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueDisplayId, 907 int userId) { 908 try { 909 return mDm.getBrightnessConfigurationForDisplay(uniqueDisplayId, userId); 910 } catch (RemoteException ex) { 911 throw ex.rethrowFromSystemServer(); 912 } 913 } 914 915 /** 916 * Gets the global brightness configuration for a given user or null if one hasn't been set. 917 * 918 * @hide 919 */ getBrightnessConfigurationForUser(int userId)920 public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { 921 try { 922 return mDm.getBrightnessConfigurationForUser(userId); 923 } catch (RemoteException ex) { 924 throw ex.rethrowFromSystemServer(); 925 } 926 } 927 928 /** 929 * Gets the default brightness configuration or null if one hasn't been configured. 930 * 931 * @hide 932 */ getDefaultBrightnessConfiguration()933 public BrightnessConfiguration getDefaultBrightnessConfiguration() { 934 try { 935 return mDm.getDefaultBrightnessConfiguration(); 936 } catch (RemoteException ex) { 937 throw ex.rethrowFromSystemServer(); 938 } 939 } 940 941 /** 942 * Gets the last requested minimal post processing setting for the display with displayId. 943 * 944 * @hide 945 */ isMinimalPostProcessingRequested(int displayId)946 public boolean isMinimalPostProcessingRequested(int displayId) { 947 try { 948 return mDm.isMinimalPostProcessingRequested(displayId); 949 } catch (RemoteException ex) { 950 throw ex.rethrowFromSystemServer(); 951 } 952 } 953 954 /** 955 * Temporarily sets the brightness of the display. 956 * <p> 957 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 958 * </p> 959 * 960 * @param brightness The brightness value from 0.0f to 1.0f. 961 * 962 * @hide Requires signature permission. 963 */ setTemporaryBrightness(int displayId, float brightness)964 public void setTemporaryBrightness(int displayId, float brightness) { 965 try { 966 mDm.setTemporaryBrightness(displayId, brightness); 967 } catch (RemoteException ex) { 968 throw ex.rethrowFromSystemServer(); 969 } 970 } 971 972 973 /** 974 * Sets the brightness of the display. 975 * 976 * @param brightness The brightness value from 0.0f to 1.0f. 977 * 978 * @hide 979 */ setBrightness(int displayId, float brightness)980 public void setBrightness(int displayId, float brightness) { 981 try { 982 mDm.setBrightness(displayId, brightness); 983 } catch (RemoteException ex) { 984 throw ex.rethrowFromSystemServer(); 985 } 986 } 987 988 /** 989 * Report whether/how the display supports DISPLAY_DECORATION. 990 * 991 * @param displayId The display whose support is being queried. 992 * 993 * @hide 994 */ getDisplayDecorationSupport(int displayId)995 public DisplayDecorationSupport getDisplayDecorationSupport(int displayId) { 996 try { 997 return mDm.getDisplayDecorationSupport(displayId); 998 } catch (RemoteException ex) { 999 throw ex.rethrowFromSystemServer(); 1000 } 1001 } 1002 1003 /** 1004 * Gets the brightness of the display. 1005 * 1006 * @param displayId The display from which to get the brightness 1007 * 1008 * @hide 1009 */ getBrightness(int displayId)1010 public float getBrightness(int displayId) { 1011 try { 1012 return mDm.getBrightness(displayId); 1013 } catch (RemoteException ex) { 1014 throw ex.rethrowFromSystemServer(); 1015 } 1016 } 1017 1018 /** 1019 * Temporarily sets the auto brightness adjustment factor. 1020 * <p> 1021 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 1022 * </p> 1023 * 1024 * @param adjustment The adjustment factor from -1.0 to 1.0. 1025 * 1026 * @hide Requires signature permission. 1027 */ setTemporaryAutoBrightnessAdjustment(float adjustment)1028 public void setTemporaryAutoBrightnessAdjustment(float adjustment) { 1029 try { 1030 mDm.setTemporaryAutoBrightnessAdjustment(adjustment); 1031 } catch (RemoteException ex) { 1032 throw ex.rethrowFromSystemServer(); 1033 } 1034 } 1035 1036 /** 1037 * Returns the minimum brightness curve, which guarantess that any brightness curve that dips 1038 * below it is rejected by the system. 1039 * This prevent auto-brightness from setting the screen so dark as to prevent the user from 1040 * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable 1041 * in that ambient brightness. 1042 * 1043 * @return The minimum brightness curve (as lux values and their corresponding nits values). 1044 */ getMinimumBrightnessCurve()1045 public Pair<float[], float[]> getMinimumBrightnessCurve() { 1046 try { 1047 Curve curve = mDm.getMinimumBrightnessCurve(); 1048 return Pair.create(curve.getX(), curve.getY()); 1049 } catch (RemoteException ex) { 1050 throw ex.rethrowFromSystemServer(); 1051 } 1052 } 1053 1054 /** 1055 * Retrieves ambient brightness stats. 1056 */ getAmbientBrightnessStats()1057 public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() { 1058 try { 1059 ParceledListSlice<AmbientBrightnessDayStats> stats = mDm.getAmbientBrightnessStats(); 1060 if (stats == null) { 1061 return Collections.emptyList(); 1062 } 1063 return stats.getList(); 1064 } catch (RemoteException ex) { 1065 throw ex.rethrowFromSystemServer(); 1066 } 1067 } 1068 1069 /** 1070 * Sets the default display mode, according to the refresh rate and the resolution chosen by the 1071 * user. 1072 */ setUserPreferredDisplayMode(int displayId, Display.Mode mode)1073 public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) { 1074 try { 1075 mDm.setUserPreferredDisplayMode(displayId, mode); 1076 } catch (RemoteException ex) { 1077 throw ex.rethrowFromSystemServer(); 1078 } 1079 } 1080 1081 /** 1082 * Returns the user preferred display mode. 1083 */ getUserPreferredDisplayMode(int displayId)1084 public Display.Mode getUserPreferredDisplayMode(int displayId) { 1085 try { 1086 return mDm.getUserPreferredDisplayMode(displayId); 1087 } catch (RemoteException ex) { 1088 throw ex.rethrowFromSystemServer(); 1089 } 1090 } 1091 1092 /** 1093 * Returns the system preferred display mode. 1094 */ getSystemPreferredDisplayMode(int displayId)1095 public Display.Mode getSystemPreferredDisplayMode(int displayId) { 1096 try { 1097 return mDm.getSystemPreferredDisplayMode(displayId); 1098 } catch (RemoteException ex) { 1099 throw ex.rethrowFromSystemServer(); 1100 } 1101 } 1102 1103 /** 1104 * Sets the {@link HdrConversionMode} for the device. 1105 */ setHdrConversionMode(@onNull HdrConversionMode hdrConversionMode)1106 public void setHdrConversionMode(@NonNull HdrConversionMode hdrConversionMode) { 1107 try { 1108 mDm.setHdrConversionMode(hdrConversionMode); 1109 } catch (RemoteException ex) { 1110 throw ex.rethrowFromSystemServer(); 1111 } 1112 } 1113 1114 /** 1115 * Returns the {@link HdrConversionMode} of the device, which is set by the user. 1116 * The HDR conversion mode chosen by user is returned irrespective of whether HDR conversion 1117 * is disabled by an app. 1118 */ getHdrConversionModeSetting()1119 public HdrConversionMode getHdrConversionModeSetting() { 1120 try { 1121 return mDm.getHdrConversionModeSetting(); 1122 } catch (RemoteException ex) { 1123 throw ex.rethrowFromSystemServer(); 1124 } 1125 } 1126 1127 /** 1128 * Returns the {@link HdrConversionMode} of the device. 1129 */ getHdrConversionMode()1130 public HdrConversionMode getHdrConversionMode() { 1131 try { 1132 return mDm.getHdrConversionMode(); 1133 } catch (RemoteException ex) { 1134 throw ex.rethrowFromSystemServer(); 1135 } 1136 } 1137 1138 /** 1139 * Returns the HDR output types supported by the device. 1140 */ getSupportedHdrOutputTypes()1141 public @HdrType int[] getSupportedHdrOutputTypes() { 1142 try { 1143 return mDm.getSupportedHdrOutputTypes(); 1144 } catch (RemoteException ex) { 1145 throw ex.rethrowFromSystemServer(); 1146 } 1147 } 1148 1149 /** 1150 * When enabled the app requested display resolution and refresh rate is always selected 1151 * in DisplayModeDirector regardless of user settings and policies for low brightness, low 1152 * battery etc. 1153 */ setShouldAlwaysRespectAppRequestedMode(boolean enabled)1154 public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) { 1155 try { 1156 mDm.setShouldAlwaysRespectAppRequestedMode(enabled); 1157 } catch (RemoteException ex) { 1158 throw ex.rethrowFromSystemServer(); 1159 } 1160 } 1161 1162 /** 1163 * Returns whether DisplayModeDirector is running in a mode which always selects the app 1164 * requested display mode and ignores user settings and policies for low brightness, low 1165 * battery etc. 1166 */ shouldAlwaysRespectAppRequestedMode()1167 public boolean shouldAlwaysRespectAppRequestedMode() { 1168 try { 1169 return mDm.shouldAlwaysRespectAppRequestedMode(); 1170 } catch (RemoteException ex) { 1171 throw ex.rethrowFromSystemServer(); 1172 } 1173 } 1174 1175 /** 1176 * Sets the refresh rate switching type. 1177 * 1178 * @hide 1179 */ setRefreshRateSwitchingType(@isplayManager.SwitchingType int newValue)1180 public void setRefreshRateSwitchingType(@DisplayManager.SwitchingType int newValue) { 1181 try { 1182 mDm.setRefreshRateSwitchingType(newValue); 1183 } catch (RemoteException ex) { 1184 throw ex.rethrowFromSystemServer(); 1185 } 1186 } 1187 1188 /** 1189 * Returns the refresh rate switching type. 1190 * 1191 * @hide 1192 */ 1193 @DisplayManager.SwitchingType getRefreshRateSwitchingType()1194 public int getRefreshRateSwitchingType() { 1195 try { 1196 return mDm.getRefreshRateSwitchingType(); 1197 } catch (RemoteException ex) { 1198 throw ex.rethrowFromSystemServer(); 1199 } 1200 } 1201 1202 /** 1203 * Sets allowed display mode ids 1204 * 1205 * @hide 1206 */ 1207 @RequiresPermission("android.permission.RESTRICT_DISPLAY_MODES") requestDisplayModes(int displayId, @Nullable int[] modeIds)1208 public void requestDisplayModes(int displayId, @Nullable int[] modeIds) { 1209 try { 1210 mDm.requestDisplayModes(mToken, displayId, modeIds); 1211 } catch (RemoteException ex) { 1212 throw ex.rethrowFromSystemServer(); 1213 } 1214 } 1215 1216 private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { 1217 @Override onDisplayEvent(int displayId, @DisplayEvent int event)1218 public void onDisplayEvent(int displayId, @DisplayEvent int event) { 1219 if (DEBUG) { 1220 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString( 1221 event)); 1222 } 1223 handleDisplayEvent(displayId, event, false /* forceUpdate */); 1224 } 1225 } 1226 1227 private static final class DisplayListenerDelegate { 1228 public final DisplayListener mListener; 1229 public volatile long mEventsMask; 1230 1231 private final DisplayInfo mDisplayInfo = new DisplayInfo(); 1232 private final Executor mExecutor; 1233 private AtomicLong mGenerationId = new AtomicLong(1); 1234 private final String mPackageName; 1235 DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor, @EventsMask long eventsMask, String packageName)1236 DisplayListenerDelegate(DisplayListener listener, @NonNull Executor executor, 1237 @EventsMask long eventsMask, String packageName) { 1238 mExecutor = executor; 1239 mListener = listener; 1240 mEventsMask = eventsMask; 1241 mPackageName = packageName; 1242 } 1243 sendDisplayEvent(int displayId, @DisplayEvent int event, @Nullable DisplayInfo info, boolean forceUpdate)1244 void sendDisplayEvent(int displayId, @DisplayEvent int event, @Nullable DisplayInfo info, 1245 boolean forceUpdate) { 1246 if (extraLogging()) { 1247 Slog.i(TAG, "Sending Display Event: " + eventToString(event)); 1248 } 1249 long generationId = mGenerationId.get(); 1250 mExecutor.execute(() -> { 1251 // If the generation id's don't match we were canceled 1252 if (generationId == mGenerationId.get()) { 1253 handleDisplayEventInner(displayId, event, info, forceUpdate); 1254 } 1255 }); 1256 } 1257 clearEvents()1258 void clearEvents() { 1259 mGenerationId.incrementAndGet(); 1260 } 1261 setEventsMask(@ventsMask long newEventsMask)1262 void setEventsMask(@EventsMask long newEventsMask) { 1263 mEventsMask = newEventsMask; 1264 } 1265 handleDisplayEventInner(int displayId, @DisplayEvent int event, @Nullable DisplayInfo info, boolean forceUpdate)1266 private void handleDisplayEventInner(int displayId, @DisplayEvent int event, 1267 @Nullable DisplayInfo info, boolean forceUpdate) { 1268 if (extraLogging()) { 1269 Slog.i(TAG, "DLD(" + eventToString(event) 1270 + ", display=" + displayId 1271 + ", mEventsMask=" + Long.toBinaryString(mEventsMask) 1272 + ", mPackageName=" + mPackageName 1273 + ", displayInfo=" + info 1274 + ", listener=" + mListener.getClass() + ")"); 1275 } 1276 if (DEBUG) { 1277 Trace.beginSection( 1278 TextUtils.trimToSize( 1279 "DLD(" + eventToString(event) 1280 + ", display=" + displayId 1281 + ", listener=" + mListener.getClass() + ")", 127)); 1282 } 1283 switch (event) { 1284 case EVENT_DISPLAY_ADDED: 1285 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { 1286 mListener.onDisplayAdded(displayId); 1287 } 1288 break; 1289 case EVENT_DISPLAY_CHANGED: 1290 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { 1291 if (info != null && (forceUpdate || !info.equals(mDisplayInfo))) { 1292 if (extraLogging()) { 1293 Slog.i(TAG, "Sending onDisplayChanged: Display Changed. Info: " 1294 + info); 1295 } 1296 mDisplayInfo.copyFrom(info); 1297 mListener.onDisplayChanged(displayId); 1298 } 1299 } 1300 break; 1301 case EVENT_DISPLAY_BRIGHTNESS_CHANGED: 1302 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) { 1303 mListener.onDisplayChanged(displayId); 1304 } 1305 break; 1306 case EVENT_DISPLAY_REMOVED: 1307 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { 1308 mListener.onDisplayRemoved(displayId); 1309 } 1310 break; 1311 case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: 1312 if ((mEventsMask & DisplayManager.EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) { 1313 mListener.onDisplayChanged(displayId); 1314 } 1315 break; 1316 case EVENT_DISPLAY_CONNECTED: 1317 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { 1318 mListener.onDisplayConnected(displayId); 1319 } 1320 break; 1321 case EVENT_DISPLAY_DISCONNECTED: 1322 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { 1323 mListener.onDisplayDisconnected(displayId); 1324 } 1325 break; 1326 } 1327 if (DEBUG) { 1328 Trace.endSection(); 1329 } 1330 } 1331 1332 @Override toString()1333 public String toString() { 1334 return "mask: {" + mEventsMask + "}, for " + mListener.getClass(); 1335 } 1336 } 1337 1338 /** 1339 * Assists in dispatching VirtualDisplay lifecycle event callbacks on a given Executor. 1340 */ 1341 public static final class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub { 1342 @Nullable private final VirtualDisplay.Callback mCallback; 1343 @Nullable private final Executor mExecutor; 1344 1345 /** 1346 * Creates a virtual display callback. 1347 * 1348 * @param callback The callback to call for virtual display events, or {@code null} if the 1349 * caller does not wish to receive callback events. 1350 * @param executor The executor to call the {@code callback} on. Must not be {@code null} if 1351 * the callback is not {@code null}. 1352 */ VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor)1353 public VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) { 1354 mCallback = callback; 1355 mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null; 1356 } 1357 1358 // These methods are called from the binder thread, but the AIDL is oneway, so it should be 1359 // safe to call the callback on arbitrary executors directly without risking blocking 1360 // the system. 1361 1362 @Override // Binder call onPaused()1363 public void onPaused() { 1364 if (mCallback != null) { 1365 mExecutor.execute(mCallback::onPaused); 1366 } 1367 } 1368 1369 @Override // Binder call onResumed()1370 public void onResumed() { 1371 if (mCallback != null) { 1372 mExecutor.execute(mCallback::onResumed); 1373 } 1374 } 1375 1376 @Override // Binder call onStopped()1377 public void onStopped() { 1378 if (mCallback != null) { 1379 mExecutor.execute(mCallback::onStopped); 1380 } 1381 } 1382 } 1383 1384 /** 1385 * Name of the property containing a unique token which changes every time we update the 1386 * system's display configuration. 1387 */ 1388 public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY = 1389 "cache_key.display_info"; 1390 1391 /** 1392 * Invalidates the contents of the display info cache for all applications. Can only 1393 * be called by system_server. 1394 */ invalidateLocalDisplayInfoCaches()1395 public static void invalidateLocalDisplayInfoCaches() { 1396 PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY); 1397 } 1398 1399 /** 1400 * Disables the binder call cache. 1401 */ disableLocalDisplayInfoCaches()1402 public void disableLocalDisplayInfoCaches() { 1403 mDisplayCache = null; 1404 } 1405 nSignalNativeCallbacks(float refreshRate)1406 private static native void nSignalNativeCallbacks(float refreshRate); 1407 1408 /** 1409 * Called from AChoreographer via JNI. 1410 * Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. 1411 * Public for unit testing to be able to call this method. 1412 */ 1413 @VisibleForTesting registerNativeChoreographerForRefreshRateCallbacks()1414 public void registerNativeChoreographerForRefreshRateCallbacks() { 1415 synchronized (mLock) { 1416 mDispatchNativeCallbacks = true; 1417 registerCallbackIfNeededLocked(); 1418 updateCallbackIfNeededLocked(); 1419 DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); 1420 if (display != null) { 1421 // We need to tell AChoreographer instances the current refresh rate so that apps 1422 // can get it for free once a callback first registers. 1423 mNativeCallbackReportedRefreshRate = display.getRefreshRate(); 1424 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate); 1425 } 1426 } 1427 } 1428 1429 /** 1430 * Called from AChoreographer via JNI. 1431 * Unregisters AChoreographer from receiving refresh rate callbacks. 1432 * Public for unit testing to be able to call this method. 1433 */ 1434 @VisibleForTesting unregisterNativeChoreographerForRefreshRateCallbacks()1435 public void unregisterNativeChoreographerForRefreshRateCallbacks() { 1436 synchronized (mLock) { 1437 mDispatchNativeCallbacks = false; 1438 updateCallbackIfNeededLocked(); 1439 } 1440 } 1441 eventToString(@isplayEvent int event)1442 private static String eventToString(@DisplayEvent int event) { 1443 switch (event) { 1444 case EVENT_DISPLAY_ADDED: 1445 return "ADDED"; 1446 case EVENT_DISPLAY_CHANGED: 1447 return "CHANGED"; 1448 case EVENT_DISPLAY_REMOVED: 1449 return "REMOVED"; 1450 case EVENT_DISPLAY_BRIGHTNESS_CHANGED: 1451 return "BRIGHTNESS_CHANGED"; 1452 case EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED: 1453 return "HDR_SDR_RATIO_CHANGED"; 1454 case EVENT_DISPLAY_CONNECTED: 1455 return "EVENT_DISPLAY_CONNECTED"; 1456 case EVENT_DISPLAY_DISCONNECTED: 1457 return "EVENT_DISPLAY_DISCONNECTED"; 1458 } 1459 return "UNKNOWN"; 1460 } 1461 1462 initExtraLogging()1463 private static boolean initExtraLogging() { 1464 if (sCurrentPackageName == null) { 1465 sCurrentPackageName = ActivityThread.currentPackageName(); 1466 sExtraDisplayListenerLogging = !TextUtils.isEmpty(EXTRA_LOGGING_PACKAGE_NAME) 1467 && EXTRA_LOGGING_PACKAGE_NAME.equals(sCurrentPackageName); 1468 } 1469 return sExtraDisplayListenerLogging; 1470 } 1471 extraLogging()1472 private static boolean extraLogging() { 1473 return sExtraDisplayListenerLogging; 1474 } 1475 } 1476