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