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.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.PropertyInvalidatedCache; 27 import android.compat.annotation.UnsupportedAppUsage; 28 import android.content.Context; 29 import android.content.pm.ParceledListSlice; 30 import android.content.res.Resources; 31 import android.graphics.ColorSpace; 32 import android.graphics.Point; 33 import android.hardware.display.DisplayManager.DisplayListener; 34 import android.hardware.graphics.common.DisplayDecorationSupport; 35 import android.media.projection.IMediaProjection; 36 import android.media.projection.MediaProjection; 37 import android.os.Handler; 38 import android.os.IBinder; 39 import android.os.Looper; 40 import android.os.Message; 41 import android.os.RemoteException; 42 import android.os.ServiceManager; 43 import android.os.Trace; 44 import android.util.Log; 45 import android.util.Pair; 46 import android.util.SparseArray; 47 import android.view.Display; 48 import android.view.DisplayAdjustments; 49 import android.view.DisplayInfo; 50 import android.view.Surface; 51 52 import com.android.internal.annotations.VisibleForTesting; 53 54 import java.lang.annotation.Retention; 55 import java.lang.annotation.RetentionPolicy; 56 import java.util.ArrayList; 57 import java.util.Collections; 58 import java.util.List; 59 import java.util.Objects; 60 import java.util.concurrent.Executor; 61 62 /** 63 * Manager communication with the display manager service on behalf of 64 * an application process. You're probably looking for {@link DisplayManager}. 65 * 66 * @hide 67 */ 68 public final class DisplayManagerGlobal { 69 private static final String TAG = "DisplayManager"; 70 private static final boolean DEBUG = false; 71 72 // True if display info and display ids should be cached. 73 // 74 // FIXME: The cache is currently disabled because it's unclear whether we have the 75 // necessary guarantees that the caches will always be flushed before clients 76 // attempt to observe their new state. For example, depending on the order 77 // in which the binder transactions take place, we might have a problem where 78 // an application could start processing a configuration change due to a display 79 // orientation change before the display info cache has actually been invalidated. 80 private static final boolean USE_CACHE = false; 81 82 @IntDef(prefix = {"SWITCHING_TYPE_"}, value = { 83 EVENT_DISPLAY_ADDED, 84 EVENT_DISPLAY_CHANGED, 85 EVENT_DISPLAY_REMOVED, 86 EVENT_DISPLAY_BRIGHTNESS_CHANGED 87 }) 88 @Retention(RetentionPolicy.SOURCE) 89 public @interface DisplayEvent {} 90 91 public static final int EVENT_DISPLAY_ADDED = 1; 92 public static final int EVENT_DISPLAY_CHANGED = 2; 93 public static final int EVENT_DISPLAY_REMOVED = 3; 94 public static final int EVENT_DISPLAY_BRIGHTNESS_CHANGED = 4; 95 96 @UnsupportedAppUsage 97 private static DisplayManagerGlobal sInstance; 98 99 // Guarded by mLock 100 private boolean mDispatchNativeCallbacks = false; 101 private float mNativeCallbackReportedRefreshRate; 102 private final Object mLock = new Object(); 103 104 @UnsupportedAppUsage 105 private final IDisplayManager mDm; 106 107 private DisplayManagerCallback mCallback; 108 private @EventsMask long mRegisteredEventsMask = 0; 109 private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>(); 110 111 private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>(); 112 private final ColorSpace mWideColorSpace; 113 private int[] mDisplayIdCache; 114 115 private int mWifiDisplayScanNestCount; 116 117 @VisibleForTesting DisplayManagerGlobal(IDisplayManager dm)118 public DisplayManagerGlobal(IDisplayManager dm) { 119 mDm = dm; 120 try { 121 mWideColorSpace = 122 ColorSpace.get( 123 ColorSpace.Named.values()[mDm.getPreferredWideGamutColorSpaceId()]); 124 } catch (RemoteException ex) { 125 throw ex.rethrowFromSystemServer(); 126 } 127 } 128 129 private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache = 130 new PropertyInvalidatedCache<Integer, DisplayInfo>( 131 8, // size of display cache 132 CACHE_KEY_DISPLAY_INFO_PROPERTY) { 133 @Override 134 public DisplayInfo recompute(Integer id) { 135 try { 136 return mDm.getDisplayInfo(id); 137 } catch (RemoteException ex) { 138 throw ex.rethrowFromSystemServer(); 139 } 140 } 141 }; 142 143 /** 144 * Gets an instance of the display manager global singleton. 145 * 146 * @return The display manager instance, may be null early in system startup 147 * before the display manager has been fully initialized. 148 */ 149 @UnsupportedAppUsage getInstance()150 public static DisplayManagerGlobal getInstance() { 151 synchronized (DisplayManagerGlobal.class) { 152 if (sInstance == null) { 153 IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE); 154 if (b != null) { 155 sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b)); 156 } 157 } 158 return sInstance; 159 } 160 } 161 162 /** 163 * Get information about a particular logical display. 164 * 165 * @param displayId The logical display id. 166 * @return Information about the specified display, or null if it does not exist. 167 * This object belongs to an internal cache and should be treated as if it were immutable. 168 */ 169 @UnsupportedAppUsage getDisplayInfo(int displayId)170 public DisplayInfo getDisplayInfo(int displayId) { 171 synchronized (mLock) { 172 return getDisplayInfoLocked(displayId); 173 } 174 } 175 176 /** 177 * Gets information about a particular logical display 178 * See {@link getDisplayInfo}, but assumes that {@link mLock} is held 179 */ getDisplayInfoLocked(int displayId)180 private @Nullable DisplayInfo getDisplayInfoLocked(int displayId) { 181 DisplayInfo info = null; 182 if (mDisplayCache != null) { 183 info = mDisplayCache.query(displayId); 184 } else { 185 try { 186 info = mDm.getDisplayInfo(displayId); 187 } catch (RemoteException ex) { 188 ex.rethrowFromSystemServer(); 189 } 190 } 191 if (info == null) { 192 return null; 193 } 194 195 registerCallbackIfNeededLocked(); 196 197 if (DEBUG) { 198 Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info); 199 } 200 return info; 201 } 202 203 /** 204 * Gets all currently valid logical display ids. 205 * 206 * @return An array containing all display ids. 207 */ 208 @UnsupportedAppUsage getDisplayIds()209 public int[] getDisplayIds() { 210 return getDisplayIds(/* includeDisabled= */ false); 211 } 212 213 /** 214 * Gets all currently valid logical display ids. 215 * 216 * @param includeDisabled True if the returned list of displays includes disabled displays. 217 * @return An array containing all display ids. 218 */ getDisplayIds(boolean includeDisabled)219 public int[] getDisplayIds(boolean includeDisabled) { 220 try { 221 synchronized (mLock) { 222 if (USE_CACHE) { 223 if (mDisplayIdCache != null) { 224 return mDisplayIdCache; 225 } 226 } 227 228 int[] displayIds = mDm.getDisplayIds(includeDisabled); 229 if (USE_CACHE) { 230 mDisplayIdCache = displayIds; 231 } 232 registerCallbackIfNeededLocked(); 233 return displayIds; 234 } 235 } catch (RemoteException ex) { 236 throw ex.rethrowFromSystemServer(); 237 } 238 } 239 240 /** 241 * Check if specified UID's content is present on display and should be granted access to it. 242 * 243 * @param uid UID to be checked. 244 * @param displayId id of the display where presence of the content is checked. 245 * @return {@code true} if UID is present on display, {@code false} otherwise. 246 */ isUidPresentOnDisplay(int uid, int displayId)247 public boolean isUidPresentOnDisplay(int uid, int displayId) { 248 try { 249 return mDm.isUidPresentOnDisplay(uid, displayId); 250 } catch (RemoteException ex) { 251 throw ex.rethrowFromSystemServer(); 252 } 253 } 254 255 /** 256 * Gets information about a logical display. 257 * 258 * The display metrics may be adjusted to provide compatibility 259 * for legacy applications or limited screen areas. 260 * 261 * @param displayId The logical display id. 262 * @param daj The compatibility info and activityToken. 263 * @return The display object, or null if there is no display with the given id. 264 */ getCompatibleDisplay(int displayId, DisplayAdjustments daj)265 public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) { 266 DisplayInfo displayInfo = getDisplayInfo(displayId); 267 if (displayInfo == null) { 268 return null; 269 } 270 return new Display(this, displayId, displayInfo, daj); 271 } 272 273 /** 274 * Gets information about a logical display. 275 * 276 * The display metrics may be adjusted to provide compatibility 277 * for legacy applications or limited screen areas. 278 * 279 * @param displayId The logical display id. 280 * @param resources Resources providing compatibility info. 281 * @return The display object, or null if there is no display with the given id. 282 */ getCompatibleDisplay(int displayId, Resources resources)283 public Display getCompatibleDisplay(int displayId, Resources resources) { 284 DisplayInfo displayInfo = getDisplayInfo(displayId); 285 if (displayInfo == null) { 286 return null; 287 } 288 return new Display(this, displayId, displayInfo, resources); 289 } 290 291 /** 292 * Gets information about a logical display without applying any compatibility metrics. 293 * 294 * @param displayId The logical display id. 295 * @return The display object, or null if there is no display with the given id. 296 */ 297 @UnsupportedAppUsage getRealDisplay(int displayId)298 public Display getRealDisplay(int displayId) { 299 return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); 300 } 301 302 /** 303 * Register a listener for display-related changes. 304 * 305 * @param listener The listener that will be called when display changes occur. 306 * @param handler Handler for the thread that will be receiving the callbacks. May be null. 307 * If null, listener will use the handler for the current thread, and if still null, 308 * the handler for the main thread. 309 * If that is still null, a runtime exception will be thrown. 310 */ registerDisplayListener(@onNull DisplayListener listener, @Nullable Handler handler, @EventsMask long eventsMask)311 public void registerDisplayListener(@NonNull DisplayListener listener, 312 @Nullable Handler handler, @EventsMask long eventsMask) { 313 if (listener == null) { 314 throw new IllegalArgumentException("listener must not be null"); 315 } 316 317 if (eventsMask == 0) { 318 throw new IllegalArgumentException("The set of events to listen to must not be empty."); 319 } 320 321 synchronized (mLock) { 322 int index = findDisplayListenerLocked(listener); 323 if (index < 0) { 324 Looper looper = getLooperForHandler(handler); 325 mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask)); 326 registerCallbackIfNeededLocked(); 327 } else { 328 mDisplayListeners.get(index).setEventsMask(eventsMask); 329 } 330 updateCallbackIfNeededLocked(); 331 } 332 } 333 unregisterDisplayListener(DisplayListener listener)334 public void unregisterDisplayListener(DisplayListener listener) { 335 if (listener == null) { 336 throw new IllegalArgumentException("listener must not be null"); 337 } 338 339 synchronized (mLock) { 340 int index = findDisplayListenerLocked(listener); 341 if (index >= 0) { 342 DisplayListenerDelegate d = mDisplayListeners.get(index); 343 d.clearEvents(); 344 mDisplayListeners.remove(index); 345 updateCallbackIfNeededLocked(); 346 } 347 } 348 } 349 getLooperForHandler(@ullable Handler handler)350 private static Looper getLooperForHandler(@Nullable Handler handler) { 351 Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); 352 if (looper == null) { 353 looper = Looper.getMainLooper(); 354 } 355 if (looper == null) { 356 throw new RuntimeException("Could not get Looper for the UI thread."); 357 } 358 return looper; 359 } 360 findDisplayListenerLocked(DisplayListener listener)361 private int findDisplayListenerLocked(DisplayListener listener) { 362 final int numListeners = mDisplayListeners.size(); 363 for (int i = 0; i < numListeners; i++) { 364 if (mDisplayListeners.get(i).mListener == listener) { 365 return i; 366 } 367 } 368 return -1; 369 } 370 371 @EventsMask calculateEventsMaskLocked()372 private int calculateEventsMaskLocked() { 373 int mask = 0; 374 final int numListeners = mDisplayListeners.size(); 375 for (int i = 0; i < numListeners; i++) { 376 mask |= mDisplayListeners.get(i).mEventsMask; 377 } 378 if (mDispatchNativeCallbacks) { 379 mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED 380 | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED 381 | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED; 382 } 383 return mask; 384 } 385 registerCallbackIfNeededLocked()386 private void registerCallbackIfNeededLocked() { 387 if (mCallback == null) { 388 mCallback = new DisplayManagerCallback(); 389 updateCallbackIfNeededLocked(); 390 } 391 } 392 updateCallbackIfNeededLocked()393 private void updateCallbackIfNeededLocked() { 394 int mask = calculateEventsMaskLocked(); 395 if (mask != mRegisteredEventsMask) { 396 try { 397 mDm.registerCallbackWithEventMask(mCallback, mask); 398 mRegisteredEventsMask = mask; 399 } catch (RemoteException ex) { 400 throw ex.rethrowFromSystemServer(); 401 } 402 } 403 } 404 handleDisplayEvent(int displayId, @DisplayEvent int event)405 private void handleDisplayEvent(int displayId, @DisplayEvent int event) { 406 synchronized (mLock) { 407 if (USE_CACHE) { 408 mDisplayInfoCache.remove(displayId); 409 410 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) { 411 mDisplayIdCache = null; 412 } 413 } 414 415 final int numListeners = mDisplayListeners.size(); 416 DisplayInfo info = getDisplayInfo(displayId); 417 for (int i = 0; i < numListeners; i++) { 418 mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info); 419 } 420 if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { 421 // Choreographer only supports a single display, so only dispatch refresh rate 422 // changes for the default display. 423 if (displayId == Display.DEFAULT_DISPLAY) { 424 // We can likely save a binder hop if we attach the refresh rate onto the 425 // listener. 426 DisplayInfo display = getDisplayInfoLocked(displayId); 427 if (display != null 428 && mNativeCallbackReportedRefreshRate != display.getRefreshRate()) { 429 mNativeCallbackReportedRefreshRate = display.getRefreshRate(); 430 // Signal native callbacks if we ever set a refresh rate. 431 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate); 432 } 433 } 434 } 435 } 436 } 437 startWifiDisplayScan()438 public void startWifiDisplayScan() { 439 synchronized (mLock) { 440 if (mWifiDisplayScanNestCount++ == 0) { 441 registerCallbackIfNeededLocked(); 442 try { 443 mDm.startWifiDisplayScan(); 444 } catch (RemoteException ex) { 445 throw ex.rethrowFromSystemServer(); 446 } 447 } 448 } 449 } 450 stopWifiDisplayScan()451 public void stopWifiDisplayScan() { 452 synchronized (mLock) { 453 if (--mWifiDisplayScanNestCount == 0) { 454 try { 455 mDm.stopWifiDisplayScan(); 456 } catch (RemoteException ex) { 457 throw ex.rethrowFromSystemServer(); 458 } 459 } else if (mWifiDisplayScanNestCount < 0) { 460 Log.wtf(TAG, "Wifi display scan nest count became negative: " 461 + mWifiDisplayScanNestCount); 462 mWifiDisplayScanNestCount = 0; 463 } 464 } 465 } 466 connectWifiDisplay(String deviceAddress)467 public void connectWifiDisplay(String deviceAddress) { 468 if (deviceAddress == null) { 469 throw new IllegalArgumentException("deviceAddress must not be null"); 470 } 471 472 try { 473 mDm.connectWifiDisplay(deviceAddress); 474 } catch (RemoteException ex) { 475 throw ex.rethrowFromSystemServer(); 476 } 477 } 478 pauseWifiDisplay()479 public void pauseWifiDisplay() { 480 try { 481 mDm.pauseWifiDisplay(); 482 } catch (RemoteException ex) { 483 throw ex.rethrowFromSystemServer(); 484 } 485 } 486 resumeWifiDisplay()487 public void resumeWifiDisplay() { 488 try { 489 mDm.resumeWifiDisplay(); 490 } catch (RemoteException ex) { 491 throw ex.rethrowFromSystemServer(); 492 } 493 } 494 495 @UnsupportedAppUsage disconnectWifiDisplay()496 public void disconnectWifiDisplay() { 497 try { 498 mDm.disconnectWifiDisplay(); 499 } catch (RemoteException ex) { 500 throw ex.rethrowFromSystemServer(); 501 } 502 } 503 renameWifiDisplay(String deviceAddress, String alias)504 public void renameWifiDisplay(String deviceAddress, String alias) { 505 if (deviceAddress == null) { 506 throw new IllegalArgumentException("deviceAddress must not be null"); 507 } 508 509 try { 510 mDm.renameWifiDisplay(deviceAddress, alias); 511 } catch (RemoteException ex) { 512 throw ex.rethrowFromSystemServer(); 513 } 514 } 515 forgetWifiDisplay(String deviceAddress)516 public void forgetWifiDisplay(String deviceAddress) { 517 if (deviceAddress == null) { 518 throw new IllegalArgumentException("deviceAddress must not be null"); 519 } 520 521 try { 522 mDm.forgetWifiDisplay(deviceAddress); 523 } catch (RemoteException ex) { 524 throw ex.rethrowFromSystemServer(); 525 } 526 } 527 528 @UnsupportedAppUsage getWifiDisplayStatus()529 public WifiDisplayStatus getWifiDisplayStatus() { 530 try { 531 return mDm.getWifiDisplayStatus(); 532 } catch (RemoteException ex) { 533 throw ex.rethrowFromSystemServer(); 534 } 535 } 536 537 /** 538 * Sets the HDR types that have been disabled by user. 539 * @param userDisabledHdrTypes the HDR types to disable. The HDR types are any of 540 */ setUserDisabledHdrTypes(@drType int[] userDisabledHdrTypes)541 public void setUserDisabledHdrTypes(@HdrType int[] userDisabledHdrTypes) { 542 try { 543 mDm.setUserDisabledHdrTypes(userDisabledHdrTypes); 544 } catch (RemoteException ex) { 545 throw ex.rethrowFromSystemServer(); 546 } 547 } 548 549 /** 550 * Sets whether or not the user disabled HDR types are returned from 551 * {@link Display#getHdrCapabilities}. 552 * 553 * @param areUserDisabledHdrTypesAllowed If true, the user-disabled 554 * types are ignored and returned, if the display supports them. If 555 * false, the user-disabled types are taken into consideration and 556 * are never returned, even if the display supports them. 557 */ setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed)558 public void setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed) { 559 try { 560 mDm.setAreUserDisabledHdrTypesAllowed(areUserDisabledHdrTypesAllowed); 561 } catch (RemoteException ex) { 562 throw ex.rethrowFromSystemServer(); 563 } 564 } 565 566 /** 567 * Returns whether or not the user-disabled HDR types are returned from 568 * {@link Display#getHdrCapabilities}. 569 */ areUserDisabledHdrTypesAllowed()570 public boolean areUserDisabledHdrTypesAllowed() { 571 try { 572 return mDm.areUserDisabledHdrTypesAllowed(); 573 } catch (RemoteException ex) { 574 throw ex.rethrowFromSystemServer(); 575 } 576 } 577 578 /** 579 * Returns the HDR formats disabled by the user. 580 * 581 */ getUserDisabledHdrTypes()582 public int[] getUserDisabledHdrTypes() { 583 try { 584 return mDm.getUserDisabledHdrTypes(); 585 } catch (RemoteException ex) { 586 throw ex.rethrowFromSystemServer(); 587 } 588 } 589 requestColorMode(int displayId, int colorMode)590 public void requestColorMode(int displayId, int colorMode) { 591 try { 592 mDm.requestColorMode(displayId, colorMode); 593 } catch (RemoteException ex) { 594 throw ex.rethrowFromSystemServer(); 595 } 596 } 597 createVirtualDisplay(@onNull Context context, MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, @Nullable Executor executor, @Nullable Context windowContext)598 public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection, 599 @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, 600 @Nullable Executor executor, @Nullable Context windowContext) { 601 VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, executor); 602 IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; 603 int displayId; 604 try { 605 displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, 606 projectionToken, context.getPackageName()); 607 } catch (RemoteException ex) { 608 throw ex.rethrowFromSystemServer(); 609 } 610 return createVirtualDisplayWrapper(virtualDisplayConfig, windowContext, callbackWrapper, 611 displayId); 612 } 613 614 /** 615 * Create a VirtualDisplay wrapper object for a newly created virtual display ; to be called 616 * once the display has been created in system_server. 617 */ 618 @Nullable createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig, Context windowContext, IVirtualDisplayCallback callbackWrapper, int displayId)619 public VirtualDisplay createVirtualDisplayWrapper(VirtualDisplayConfig virtualDisplayConfig, 620 Context windowContext, IVirtualDisplayCallback callbackWrapper, int displayId) { 621 if (displayId < 0) { 622 Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName()); 623 return null; 624 } 625 Display display = getRealDisplay(displayId); 626 if (display == null) { 627 Log.wtf(TAG, "Could not obtain display info for newly created " 628 + "virtual display: " + virtualDisplayConfig.getName()); 629 try { 630 mDm.releaseVirtualDisplay(callbackWrapper); 631 } catch (RemoteException ex) { 632 throw ex.rethrowFromSystemServer(); 633 } 634 return null; 635 } 636 return new VirtualDisplay(this, display, callbackWrapper, 637 virtualDisplayConfig.getSurface(), windowContext); 638 } 639 setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface)640 public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) { 641 try { 642 mDm.setVirtualDisplaySurface(token, surface); 643 setVirtualDisplayState(token, surface != null); 644 } catch (RemoteException ex) { 645 throw ex.rethrowFromSystemServer(); 646 } 647 } 648 resizeVirtualDisplay(IVirtualDisplayCallback token, int width, int height, int densityDpi)649 public void resizeVirtualDisplay(IVirtualDisplayCallback token, 650 int width, int height, int densityDpi) { 651 try { 652 mDm.resizeVirtualDisplay(token, width, height, densityDpi); 653 } catch (RemoteException ex) { 654 throw ex.rethrowFromSystemServer(); 655 } 656 } 657 releaseVirtualDisplay(IVirtualDisplayCallback token)658 public void releaseVirtualDisplay(IVirtualDisplayCallback token) { 659 try { 660 mDm.releaseVirtualDisplay(token); 661 } catch (RemoteException ex) { 662 throw ex.rethrowFromSystemServer(); 663 } 664 } 665 setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn)666 void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) { 667 try { 668 mDm.setVirtualDisplayState(token, isOn); 669 } catch (RemoteException ex) { 670 throw ex.rethrowFromSystemServer(); 671 } 672 } 673 674 /** 675 * Gets the stable device display size, in pixels. 676 */ getStableDisplaySize()677 public Point getStableDisplaySize() { 678 try { 679 return mDm.getStableDisplaySize(); 680 } catch (RemoteException ex) { 681 throw ex.rethrowFromSystemServer(); 682 } 683 } 684 685 /** 686 * Retrieves brightness change events. 687 */ getBrightnessEvents(String callingPackage)688 public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) { 689 try { 690 ParceledListSlice<BrightnessChangeEvent> events = 691 mDm.getBrightnessEvents(callingPackage); 692 if (events == null) { 693 return Collections.emptyList(); 694 } 695 return events.getList(); 696 } catch (RemoteException ex) { 697 throw ex.rethrowFromSystemServer(); 698 } 699 } 700 701 /** 702 * Retrieves Brightness Info for the specified display. 703 */ getBrightnessInfo(int displayId)704 public BrightnessInfo getBrightnessInfo(int displayId) { 705 try { 706 return mDm.getBrightnessInfo(displayId); 707 } catch (RemoteException ex) { 708 throw ex.rethrowFromSystemServer(); 709 } 710 } 711 712 /** 713 * Gets the preferred wide gamut color space for all displays. 714 * The wide gamut color space is returned from composition pipeline 715 * based on hardware capability. 716 * 717 * @hide 718 */ getPreferredWideGamutColorSpace()719 public ColorSpace getPreferredWideGamutColorSpace() { 720 return mWideColorSpace; 721 } 722 723 /** 724 * Sets the global brightness configuration for a given user. 725 * 726 * @hide 727 */ setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, String packageName)728 public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, 729 String packageName) { 730 try { 731 mDm.setBrightnessConfigurationForUser(c, userId, packageName); 732 } catch (RemoteException ex) { 733 throw ex.rethrowFromSystemServer(); 734 } 735 } 736 737 /** 738 * Sets the brightness configuration for a given display. 739 * 740 * @hide 741 */ setBrightnessConfigurationForDisplay(BrightnessConfiguration c, String uniqueDisplayId, int userId, String packageName)742 public void setBrightnessConfigurationForDisplay(BrightnessConfiguration c, 743 String uniqueDisplayId, int userId, String packageName) { 744 try { 745 mDm.setBrightnessConfigurationForDisplay(c, uniqueDisplayId, userId, packageName); 746 } catch (RemoteException ex) { 747 throw ex.rethrowFromSystemServer(); 748 } 749 } 750 751 /** 752 * Gets the brightness configuration for a given display or null if one hasn't been set. 753 * 754 * @hide 755 */ getBrightnessConfigurationForDisplay(String uniqueDisplayId, int userId)756 public BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueDisplayId, 757 int userId) { 758 try { 759 return mDm.getBrightnessConfigurationForDisplay(uniqueDisplayId, userId); 760 } catch (RemoteException ex) { 761 throw ex.rethrowFromSystemServer(); 762 } 763 } 764 765 /** 766 * Gets the global brightness configuration for a given user or null if one hasn't been set. 767 * 768 * @hide 769 */ getBrightnessConfigurationForUser(int userId)770 public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { 771 try { 772 return mDm.getBrightnessConfigurationForUser(userId); 773 } catch (RemoteException ex) { 774 throw ex.rethrowFromSystemServer(); 775 } 776 } 777 778 /** 779 * Gets the default brightness configuration or null if one hasn't been configured. 780 * 781 * @hide 782 */ getDefaultBrightnessConfiguration()783 public BrightnessConfiguration getDefaultBrightnessConfiguration() { 784 try { 785 return mDm.getDefaultBrightnessConfiguration(); 786 } catch (RemoteException ex) { 787 throw ex.rethrowFromSystemServer(); 788 } 789 } 790 791 /** 792 * Gets the last requested minimal post processing setting for the display with displayId. 793 * 794 * @hide 795 */ isMinimalPostProcessingRequested(int displayId)796 public boolean isMinimalPostProcessingRequested(int displayId) { 797 try { 798 return mDm.isMinimalPostProcessingRequested(displayId); 799 } catch (RemoteException ex) { 800 throw ex.rethrowFromSystemServer(); 801 } 802 } 803 804 /** 805 * Temporarily sets the brightness of the display. 806 * <p> 807 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 808 * </p> 809 * 810 * @param brightness The brightness value from 0.0f to 1.0f. 811 * 812 * @hide Requires signature permission. 813 */ setTemporaryBrightness(int displayId, float brightness)814 public void setTemporaryBrightness(int displayId, float brightness) { 815 try { 816 mDm.setTemporaryBrightness(displayId, brightness); 817 } catch (RemoteException ex) { 818 throw ex.rethrowFromSystemServer(); 819 } 820 } 821 822 823 /** 824 * Sets the brightness of the display. 825 * 826 * @param brightness The brightness value from 0.0f to 1.0f. 827 * 828 * @hide 829 */ setBrightness(int displayId, float brightness)830 public void setBrightness(int displayId, float brightness) { 831 try { 832 mDm.setBrightness(displayId, brightness); 833 } catch (RemoteException ex) { 834 throw ex.rethrowFromSystemServer(); 835 } 836 } 837 838 /** 839 * Report whether/how the display supports DISPLAY_DECORATION. 840 * 841 * @param displayId The display whose support is being queried. 842 * 843 * @hide 844 */ getDisplayDecorationSupport(int displayId)845 public DisplayDecorationSupport getDisplayDecorationSupport(int displayId) { 846 try { 847 return mDm.getDisplayDecorationSupport(displayId); 848 } catch (RemoteException ex) { 849 throw ex.rethrowFromSystemServer(); 850 } 851 } 852 853 /** 854 * Gets the brightness of the display. 855 * 856 * @param displayId The display from which to get the brightness 857 * 858 * @hide 859 */ getBrightness(int displayId)860 public float getBrightness(int displayId) { 861 try { 862 return mDm.getBrightness(displayId); 863 } catch (RemoteException ex) { 864 throw ex.rethrowFromSystemServer(); 865 } 866 } 867 868 /** 869 * Temporarily sets the auto brightness adjustment factor. 870 * <p> 871 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 872 * </p> 873 * 874 * @param adjustment The adjustment factor from -1.0 to 1.0. 875 * 876 * @hide Requires signature permission. 877 */ setTemporaryAutoBrightnessAdjustment(float adjustment)878 public void setTemporaryAutoBrightnessAdjustment(float adjustment) { 879 try { 880 mDm.setTemporaryAutoBrightnessAdjustment(adjustment); 881 } catch (RemoteException ex) { 882 throw ex.rethrowFromSystemServer(); 883 } 884 } 885 886 /** 887 * Returns the minimum brightness curve, which guarantess that any brightness curve that dips 888 * below it is rejected by the system. 889 * This prevent auto-brightness from setting the screen so dark as to prevent the user from 890 * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable 891 * in that ambient brightness. 892 * 893 * @return The minimum brightness curve (as lux values and their corresponding nits values). 894 */ getMinimumBrightnessCurve()895 public Pair<float[], float[]> getMinimumBrightnessCurve() { 896 try { 897 Curve curve = mDm.getMinimumBrightnessCurve(); 898 return Pair.create(curve.getX(), curve.getY()); 899 } catch (RemoteException ex) { 900 throw ex.rethrowFromSystemServer(); 901 } 902 } 903 904 /** 905 * Retrieves ambient brightness stats. 906 */ getAmbientBrightnessStats()907 public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() { 908 try { 909 ParceledListSlice<AmbientBrightnessDayStats> stats = mDm.getAmbientBrightnessStats(); 910 if (stats == null) { 911 return Collections.emptyList(); 912 } 913 return stats.getList(); 914 } catch (RemoteException ex) { 915 throw ex.rethrowFromSystemServer(); 916 } 917 } 918 919 /** 920 * Sets the default display mode, according to the refresh rate and the resolution chosen by the 921 * user. 922 */ setUserPreferredDisplayMode(int displayId, Display.Mode mode)923 public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) { 924 try { 925 mDm.setUserPreferredDisplayMode(displayId, mode); 926 } catch (RemoteException ex) { 927 throw ex.rethrowFromSystemServer(); 928 } 929 } 930 931 /** 932 * Returns the user preferred display mode. 933 */ getUserPreferredDisplayMode(int displayId)934 public Display.Mode getUserPreferredDisplayMode(int displayId) { 935 try { 936 return mDm.getUserPreferredDisplayMode(displayId); 937 } catch (RemoteException ex) { 938 throw ex.rethrowFromSystemServer(); 939 } 940 } 941 942 /** 943 * Returns the system preferred display mode. 944 */ getSystemPreferredDisplayMode(int displayId)945 public Display.Mode getSystemPreferredDisplayMode(int displayId) { 946 try { 947 return mDm.getSystemPreferredDisplayMode(displayId); 948 } catch (RemoteException ex) { 949 throw ex.rethrowFromSystemServer(); 950 } 951 } 952 953 /** 954 * When enabled the app requested display resolution and refresh rate is always selected 955 * in DisplayModeDirector regardless of user settings and policies for low brightness, low 956 * battery etc. 957 */ setShouldAlwaysRespectAppRequestedMode(boolean enabled)958 public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) { 959 try { 960 mDm.setShouldAlwaysRespectAppRequestedMode(enabled); 961 } catch (RemoteException ex) { 962 throw ex.rethrowFromSystemServer(); 963 } 964 } 965 966 /** 967 * Returns whether DisplayModeDirector is running in a mode which always selects the app 968 * requested display mode and ignores user settings and policies for low brightness, low 969 * battery etc. 970 */ shouldAlwaysRespectAppRequestedMode()971 public boolean shouldAlwaysRespectAppRequestedMode() { 972 try { 973 return mDm.shouldAlwaysRespectAppRequestedMode(); 974 } catch (RemoteException ex) { 975 throw ex.rethrowFromSystemServer(); 976 } 977 } 978 979 /** 980 * Sets the refresh rate switching type. 981 * 982 * @hide 983 */ setRefreshRateSwitchingType(@isplayManager.SwitchingType int newValue)984 public void setRefreshRateSwitchingType(@DisplayManager.SwitchingType int newValue) { 985 try { 986 mDm.setRefreshRateSwitchingType(newValue); 987 } catch (RemoteException ex) { 988 throw ex.rethrowFromSystemServer(); 989 } 990 } 991 992 /** 993 * Returns the refresh rate switching type. 994 * 995 * @hide 996 */ 997 @DisplayManager.SwitchingType getRefreshRateSwitchingType()998 public int getRefreshRateSwitchingType() { 999 try { 1000 return mDm.getRefreshRateSwitchingType(); 1001 } catch (RemoteException ex) { 1002 throw ex.rethrowFromSystemServer(); 1003 } 1004 } 1005 1006 private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { 1007 @Override onDisplayEvent(int displayId, @DisplayEvent int event)1008 public void onDisplayEvent(int displayId, @DisplayEvent int event) { 1009 if (DEBUG) { 1010 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + eventToString( 1011 event)); 1012 } 1013 handleDisplayEvent(displayId, event); 1014 } 1015 } 1016 1017 private static final class DisplayListenerDelegate extends Handler { 1018 public final DisplayListener mListener; 1019 public volatile long mEventsMask; 1020 1021 private final DisplayInfo mDisplayInfo = new DisplayInfo(); 1022 DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, @EventsMask long eventsMask)1023 DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, 1024 @EventsMask long eventsMask) { 1025 super(looper, null, true /*async*/); 1026 mListener = listener; 1027 mEventsMask = eventsMask; 1028 } 1029 sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info)1030 public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) { 1031 Message msg = obtainMessage(event, displayId, 0, info); 1032 sendMessage(msg); 1033 } 1034 clearEvents()1035 public void clearEvents() { 1036 removeCallbacksAndMessages(null); 1037 } 1038 setEventsMask(@ventsMask long newEventsMask)1039 public void setEventsMask(@EventsMask long newEventsMask) { 1040 mEventsMask = newEventsMask; 1041 } 1042 1043 @Override handleMessage(Message msg)1044 public void handleMessage(Message msg) { 1045 if (DEBUG) { 1046 Trace.beginSection( 1047 "DisplayListenerDelegate(" + eventToString(msg.what) 1048 + ", display=" + msg.arg1 1049 + ", listener=" + mListener.getClass() + ")"); 1050 } 1051 switch (msg.what) { 1052 case EVENT_DISPLAY_ADDED: 1053 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { 1054 mListener.onDisplayAdded(msg.arg1); 1055 } 1056 break; 1057 case EVENT_DISPLAY_CHANGED: 1058 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { 1059 DisplayInfo newInfo = (DisplayInfo) msg.obj; 1060 if (newInfo != null && !newInfo.equals(mDisplayInfo)) { 1061 mDisplayInfo.copyFrom(newInfo); 1062 mListener.onDisplayChanged(msg.arg1); 1063 } 1064 } 1065 break; 1066 case EVENT_DISPLAY_BRIGHTNESS_CHANGED: 1067 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) { 1068 mListener.onDisplayChanged(msg.arg1); 1069 } 1070 break; 1071 case EVENT_DISPLAY_REMOVED: 1072 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { 1073 mListener.onDisplayRemoved(msg.arg1); 1074 } 1075 break; 1076 } 1077 if (DEBUG) { 1078 Trace.endSection(); 1079 } 1080 } 1081 } 1082 1083 /** 1084 * Assists in dispatching VirtualDisplay lifecycle event callbacks on a given Executor. 1085 */ 1086 public static final class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub { 1087 @Nullable private final VirtualDisplay.Callback mCallback; 1088 @Nullable private final Executor mExecutor; 1089 1090 /** 1091 * Creates a virtual display callback. 1092 * 1093 * @param callback The callback to call for virtual display events, or {@code null} if the 1094 * caller does not wish to receive callback events. 1095 * @param executor The executor to call the {@code callback} on. Must not be {@code null} if 1096 * the callback is not {@code null}. 1097 */ VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor)1098 public VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) { 1099 mCallback = callback; 1100 mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null; 1101 } 1102 1103 // These methods are called from the binder thread, but the AIDL is oneway, so it should be 1104 // safe to call the callback on arbitrary executors directly without risking blocking 1105 // the system. 1106 1107 @Override // Binder call onPaused()1108 public void onPaused() { 1109 if (mCallback != null) { 1110 mExecutor.execute(mCallback::onPaused); 1111 } 1112 } 1113 1114 @Override // Binder call onResumed()1115 public void onResumed() { 1116 if (mCallback != null) { 1117 mExecutor.execute(mCallback::onResumed); 1118 } 1119 } 1120 1121 @Override // Binder call onStopped()1122 public void onStopped() { 1123 if (mCallback != null) { 1124 mExecutor.execute(mCallback::onStopped); 1125 } 1126 } 1127 } 1128 1129 /** 1130 * Name of the property containing a unique token which changes every time we update the 1131 * system's display configuration. 1132 */ 1133 public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY = 1134 "cache_key.display_info"; 1135 1136 /** 1137 * Invalidates the contents of the display info cache for all applications. Can only 1138 * be called by system_server. 1139 */ invalidateLocalDisplayInfoCaches()1140 public static void invalidateLocalDisplayInfoCaches() { 1141 PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY); 1142 } 1143 1144 /** 1145 * Disables the binder call cache. 1146 */ disableLocalDisplayInfoCaches()1147 public void disableLocalDisplayInfoCaches() { 1148 mDisplayCache = null; 1149 } 1150 nSignalNativeCallbacks(float refreshRate)1151 private static native void nSignalNativeCallbacks(float refreshRate); 1152 1153 /** 1154 * Called from AChoreographer via JNI. 1155 * Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. 1156 * Public for unit testing to be able to call this method. 1157 */ 1158 @VisibleForTesting registerNativeChoreographerForRefreshRateCallbacks()1159 public void registerNativeChoreographerForRefreshRateCallbacks() { 1160 synchronized (mLock) { 1161 mDispatchNativeCallbacks = true; 1162 registerCallbackIfNeededLocked(); 1163 updateCallbackIfNeededLocked(); 1164 DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); 1165 if (display != null) { 1166 // We need to tell AChoreographer instances the current refresh rate so that apps 1167 // can get it for free once a callback first registers. 1168 mNativeCallbackReportedRefreshRate = display.getRefreshRate(); 1169 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate); 1170 } 1171 } 1172 } 1173 1174 /** 1175 * Called from AChoreographer via JNI. 1176 * Unregisters AChoreographer from receiving refresh rate callbacks. 1177 * Public for unit testing to be able to call this method. 1178 */ 1179 @VisibleForTesting unregisterNativeChoreographerForRefreshRateCallbacks()1180 public void unregisterNativeChoreographerForRefreshRateCallbacks() { 1181 synchronized (mLock) { 1182 mDispatchNativeCallbacks = false; 1183 updateCallbackIfNeededLocked(); 1184 } 1185 } 1186 eventToString(@isplayEvent int event)1187 private static String eventToString(@DisplayEvent int event) { 1188 switch (event) { 1189 case EVENT_DISPLAY_ADDED: 1190 return "ADDED"; 1191 case EVENT_DISPLAY_CHANGED: 1192 return "CHANGED"; 1193 case EVENT_DISPLAY_REMOVED: 1194 return "REMOVED"; 1195 case EVENT_DISPLAY_BRIGHTNESS_CHANGED: 1196 return "BRIGHTNESS_CHANGED"; 1197 } 1198 return "UNKNOWN"; 1199 } 1200 } 1201