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 return mask; 365 } 366 registerCallbackIfNeededLocked()367 private void registerCallbackIfNeededLocked() { 368 if (mCallback == null) { 369 mCallback = new DisplayManagerCallback(); 370 updateCallbackIfNeededLocked(); 371 } 372 } 373 updateCallbackIfNeededLocked()374 private void updateCallbackIfNeededLocked() { 375 int mask = calculateEventsMaskLocked(); 376 if (mask != mRegisteredEventsMask) { 377 try { 378 mDm.registerCallbackWithEventMask(mCallback, mask); 379 mRegisteredEventsMask = mask; 380 } catch (RemoteException ex) { 381 throw ex.rethrowFromSystemServer(); 382 } 383 } 384 } 385 handleDisplayEvent(int displayId, @DisplayEvent int event)386 private void handleDisplayEvent(int displayId, @DisplayEvent int event) { 387 synchronized (mLock) { 388 if (USE_CACHE) { 389 mDisplayInfoCache.remove(displayId); 390 391 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) { 392 mDisplayIdCache = null; 393 } 394 } 395 396 final int numListeners = mDisplayListeners.size(); 397 DisplayInfo info = getDisplayInfo(displayId); 398 for (int i = 0; i < numListeners; i++) { 399 mDisplayListeners.get(i).sendDisplayEvent(displayId, event, info); 400 } 401 if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { 402 // Choreographer only supports a single display, so only dispatch refresh rate 403 // changes for the default display. 404 if (displayId == Display.DEFAULT_DISPLAY) { 405 // We can likely save a binder hop if we attach the refresh rate onto the 406 // listener. 407 DisplayInfo display = getDisplayInfoLocked(displayId); 408 if (display != null 409 && mNativeCallbackReportedRefreshRate != display.getRefreshRate()) { 410 mNativeCallbackReportedRefreshRate = display.getRefreshRate(); 411 // Signal native callbacks if we ever set a refresh rate. 412 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate); 413 } 414 } 415 } 416 } 417 } 418 startWifiDisplayScan()419 public void startWifiDisplayScan() { 420 synchronized (mLock) { 421 if (mWifiDisplayScanNestCount++ == 0) { 422 registerCallbackIfNeededLocked(); 423 try { 424 mDm.startWifiDisplayScan(); 425 } catch (RemoteException ex) { 426 throw ex.rethrowFromSystemServer(); 427 } 428 } 429 } 430 } 431 stopWifiDisplayScan()432 public void stopWifiDisplayScan() { 433 synchronized (mLock) { 434 if (--mWifiDisplayScanNestCount == 0) { 435 try { 436 mDm.stopWifiDisplayScan(); 437 } catch (RemoteException ex) { 438 throw ex.rethrowFromSystemServer(); 439 } 440 } else if (mWifiDisplayScanNestCount < 0) { 441 Log.wtf(TAG, "Wifi display scan nest count became negative: " 442 + mWifiDisplayScanNestCount); 443 mWifiDisplayScanNestCount = 0; 444 } 445 } 446 } 447 connectWifiDisplay(String deviceAddress)448 public void connectWifiDisplay(String deviceAddress) { 449 if (deviceAddress == null) { 450 throw new IllegalArgumentException("deviceAddress must not be null"); 451 } 452 453 try { 454 mDm.connectWifiDisplay(deviceAddress); 455 } catch (RemoteException ex) { 456 throw ex.rethrowFromSystemServer(); 457 } 458 } 459 pauseWifiDisplay()460 public void pauseWifiDisplay() { 461 try { 462 mDm.pauseWifiDisplay(); 463 } catch (RemoteException ex) { 464 throw ex.rethrowFromSystemServer(); 465 } 466 } 467 resumeWifiDisplay()468 public void resumeWifiDisplay() { 469 try { 470 mDm.resumeWifiDisplay(); 471 } catch (RemoteException ex) { 472 throw ex.rethrowFromSystemServer(); 473 } 474 } 475 476 @UnsupportedAppUsage disconnectWifiDisplay()477 public void disconnectWifiDisplay() { 478 try { 479 mDm.disconnectWifiDisplay(); 480 } catch (RemoteException ex) { 481 throw ex.rethrowFromSystemServer(); 482 } 483 } 484 renameWifiDisplay(String deviceAddress, String alias)485 public void renameWifiDisplay(String deviceAddress, String alias) { 486 if (deviceAddress == null) { 487 throw new IllegalArgumentException("deviceAddress must not be null"); 488 } 489 490 try { 491 mDm.renameWifiDisplay(deviceAddress, alias); 492 } catch (RemoteException ex) { 493 throw ex.rethrowFromSystemServer(); 494 } 495 } 496 forgetWifiDisplay(String deviceAddress)497 public void forgetWifiDisplay(String deviceAddress) { 498 if (deviceAddress == null) { 499 throw new IllegalArgumentException("deviceAddress must not be null"); 500 } 501 502 try { 503 mDm.forgetWifiDisplay(deviceAddress); 504 } catch (RemoteException ex) { 505 throw ex.rethrowFromSystemServer(); 506 } 507 } 508 509 @UnsupportedAppUsage getWifiDisplayStatus()510 public WifiDisplayStatus getWifiDisplayStatus() { 511 try { 512 return mDm.getWifiDisplayStatus(); 513 } catch (RemoteException ex) { 514 throw ex.rethrowFromSystemServer(); 515 } 516 } 517 518 /** 519 * Sets the HDR types that have been disabled by user. 520 * @param userDisabledHdrTypes the HDR types to disable. The HDR types are any of 521 */ setUserDisabledHdrTypes(@drType int[] userDisabledHdrTypes)522 public void setUserDisabledHdrTypes(@HdrType int[] userDisabledHdrTypes) { 523 try { 524 mDm.setUserDisabledHdrTypes(userDisabledHdrTypes); 525 } catch (RemoteException ex) { 526 throw ex.rethrowFromSystemServer(); 527 } 528 } 529 530 /** 531 * Sets whether or not the user disabled HDR types are returned from 532 * {@link Display#getHdrCapabilities}. 533 * 534 * @param areUserDisabledHdrTypesAllowed If true, the user-disabled 535 * types are ignored and returned, if the display supports them. If 536 * false, the user-disabled types are taken into consideration and 537 * are never returned, even if the display supports them. 538 */ setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed)539 public void setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed) { 540 try { 541 mDm.setAreUserDisabledHdrTypesAllowed(areUserDisabledHdrTypesAllowed); 542 } catch (RemoteException ex) { 543 throw ex.rethrowFromSystemServer(); 544 } 545 } 546 547 /** 548 * Returns whether or not the user-disabled HDR types are returned from 549 * {@link Display#getHdrCapabilities}. 550 */ areUserDisabledHdrTypesAllowed()551 public boolean areUserDisabledHdrTypesAllowed() { 552 try { 553 return mDm.areUserDisabledHdrTypesAllowed(); 554 } catch (RemoteException ex) { 555 throw ex.rethrowFromSystemServer(); 556 } 557 } 558 559 /** 560 * Returns the HDR formats disabled by the user. 561 * 562 */ getUserDisabledHdrTypes()563 public int[] getUserDisabledHdrTypes() { 564 try { 565 return mDm.getUserDisabledHdrTypes(); 566 } catch (RemoteException ex) { 567 throw ex.rethrowFromSystemServer(); 568 } 569 } 570 requestColorMode(int displayId, int colorMode)571 public void requestColorMode(int displayId, int colorMode) { 572 try { 573 mDm.requestColorMode(displayId, colorMode); 574 } catch (RemoteException ex) { 575 throw ex.rethrowFromSystemServer(); 576 } 577 } 578 createVirtualDisplay(@onNull Context context, MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, Handler handler)579 public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection, 580 @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, 581 Handler handler) { 582 VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler); 583 IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; 584 int displayId; 585 try { 586 displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, 587 projectionToken, context.getPackageName()); 588 } catch (RemoteException ex) { 589 throw ex.rethrowFromSystemServer(); 590 } 591 if (displayId < 0) { 592 Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName()); 593 return null; 594 } 595 Display display = getRealDisplay(displayId); 596 if (display == null) { 597 Log.wtf(TAG, "Could not obtain display info for newly created " 598 + "virtual display: " + virtualDisplayConfig.getName()); 599 try { 600 mDm.releaseVirtualDisplay(callbackWrapper); 601 } catch (RemoteException ex) { 602 throw ex.rethrowFromSystemServer(); 603 } 604 return null; 605 } 606 return new VirtualDisplay(this, display, callbackWrapper, 607 virtualDisplayConfig.getSurface()); 608 } 609 setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface)610 public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) { 611 try { 612 mDm.setVirtualDisplaySurface(token, surface); 613 setVirtualDisplayState(token, surface != null); 614 } catch (RemoteException ex) { 615 throw ex.rethrowFromSystemServer(); 616 } 617 } 618 resizeVirtualDisplay(IVirtualDisplayCallback token, int width, int height, int densityDpi)619 public void resizeVirtualDisplay(IVirtualDisplayCallback token, 620 int width, int height, int densityDpi) { 621 try { 622 mDm.resizeVirtualDisplay(token, width, height, densityDpi); 623 } catch (RemoteException ex) { 624 throw ex.rethrowFromSystemServer(); 625 } 626 } 627 releaseVirtualDisplay(IVirtualDisplayCallback token)628 public void releaseVirtualDisplay(IVirtualDisplayCallback token) { 629 try { 630 mDm.releaseVirtualDisplay(token); 631 } catch (RemoteException ex) { 632 throw ex.rethrowFromSystemServer(); 633 } 634 } 635 setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn)636 void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) { 637 try { 638 mDm.setVirtualDisplayState(token, isOn); 639 } catch (RemoteException ex) { 640 throw ex.rethrowFromSystemServer(); 641 } 642 } 643 644 /** 645 * Gets the stable device display size, in pixels. 646 */ getStableDisplaySize()647 public Point getStableDisplaySize() { 648 try { 649 return mDm.getStableDisplaySize(); 650 } catch (RemoteException ex) { 651 throw ex.rethrowFromSystemServer(); 652 } 653 } 654 655 /** 656 * Retrieves brightness change events. 657 */ getBrightnessEvents(String callingPackage)658 public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) { 659 try { 660 ParceledListSlice<BrightnessChangeEvent> events = 661 mDm.getBrightnessEvents(callingPackage); 662 if (events == null) { 663 return Collections.emptyList(); 664 } 665 return events.getList(); 666 } catch (RemoteException ex) { 667 throw ex.rethrowFromSystemServer(); 668 } 669 } 670 671 /** 672 * Retrieves Brightness Info for the specified display. 673 */ getBrightnessInfo(int displayId)674 public BrightnessInfo getBrightnessInfo(int displayId) { 675 try { 676 return mDm.getBrightnessInfo(displayId); 677 } catch (RemoteException ex) { 678 throw ex.rethrowFromSystemServer(); 679 } 680 } 681 682 /** 683 * Gets the preferred wide gamut color space for all displays. 684 * The wide gamut color space is returned from composition pipeline 685 * based on hardware capability. 686 * 687 * @hide 688 */ getPreferredWideGamutColorSpace()689 public ColorSpace getPreferredWideGamutColorSpace() { 690 return mWideColorSpace; 691 } 692 693 /** 694 * Sets the global brightness configuration for a given user. 695 * 696 * @hide 697 */ setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, String packageName)698 public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, 699 String packageName) { 700 try { 701 mDm.setBrightnessConfigurationForUser(c, userId, packageName); 702 } catch (RemoteException ex) { 703 throw ex.rethrowFromSystemServer(); 704 } 705 } 706 707 /** 708 * Gets the global brightness configuration for a given user or null if one hasn't been set. 709 * 710 * @hide 711 */ getBrightnessConfigurationForUser(int userId)712 public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { 713 try { 714 return mDm.getBrightnessConfigurationForUser(userId); 715 } catch (RemoteException ex) { 716 throw ex.rethrowFromSystemServer(); 717 } 718 } 719 720 /** 721 * Gets the default brightness configuration or null if one hasn't been configured. 722 * 723 * @hide 724 */ getDefaultBrightnessConfiguration()725 public BrightnessConfiguration getDefaultBrightnessConfiguration() { 726 try { 727 return mDm.getDefaultBrightnessConfiguration(); 728 } catch (RemoteException ex) { 729 throw ex.rethrowFromSystemServer(); 730 } 731 } 732 733 /** 734 * Gets the last requested minimal post processing setting for the display with displayId. 735 * 736 * @hide 737 */ isMinimalPostProcessingRequested(int displayId)738 public boolean isMinimalPostProcessingRequested(int displayId) { 739 try { 740 return mDm.isMinimalPostProcessingRequested(displayId); 741 } catch (RemoteException ex) { 742 throw ex.rethrowFromSystemServer(); 743 } 744 } 745 746 /** 747 * Temporarily sets the brightness of the display. 748 * <p> 749 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 750 * </p> 751 * 752 * @param brightness The brightness value from 0.0f to 1.0f. 753 * 754 * @hide Requires signature permission. 755 */ setTemporaryBrightness(int displayId, float brightness)756 public void setTemporaryBrightness(int displayId, float brightness) { 757 try { 758 mDm.setTemporaryBrightness(displayId, brightness); 759 } catch (RemoteException ex) { 760 throw ex.rethrowFromSystemServer(); 761 } 762 } 763 764 765 /** 766 * Sets the brightness of the display. 767 * 768 * @param brightness The brightness value from 0.0f to 1.0f. 769 * 770 * @hide 771 */ setBrightness(int displayId, float brightness)772 public void setBrightness(int displayId, float brightness) { 773 try { 774 mDm.setBrightness(displayId, brightness); 775 } catch (RemoteException ex) { 776 throw ex.rethrowFromSystemServer(); 777 } 778 } 779 780 /** 781 * Gets the brightness of the display. 782 * 783 * @param displayId The display from which to get the brightness 784 * 785 * @hide 786 */ getBrightness(int displayId)787 public float getBrightness(int displayId) { 788 try { 789 return mDm.getBrightness(displayId); 790 } catch (RemoteException ex) { 791 throw ex.rethrowFromSystemServer(); 792 } 793 } 794 795 /** 796 * Temporarily sets the auto brightness adjustment factor. 797 * <p> 798 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 799 * </p> 800 * 801 * @param adjustment The adjustment factor from -1.0 to 1.0. 802 * 803 * @hide Requires signature permission. 804 */ setTemporaryAutoBrightnessAdjustment(float adjustment)805 public void setTemporaryAutoBrightnessAdjustment(float adjustment) { 806 try { 807 mDm.setTemporaryAutoBrightnessAdjustment(adjustment); 808 } catch (RemoteException ex) { 809 throw ex.rethrowFromSystemServer(); 810 } 811 } 812 813 /** 814 * Returns the minimum brightness curve, which guarantess that any brightness curve that dips 815 * below it is rejected by the system. 816 * This prevent auto-brightness from setting the screen so dark as to prevent the user from 817 * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable 818 * in that ambient brightness. 819 * 820 * @return The minimum brightness curve (as lux values and their corresponding nits values). 821 */ getMinimumBrightnessCurve()822 public Pair<float[], float[]> getMinimumBrightnessCurve() { 823 try { 824 Curve curve = mDm.getMinimumBrightnessCurve(); 825 return Pair.create(curve.getX(), curve.getY()); 826 } catch (RemoteException ex) { 827 throw ex.rethrowFromSystemServer(); 828 } 829 } 830 831 /** 832 * Retrieves ambient brightness stats. 833 */ getAmbientBrightnessStats()834 public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() { 835 try { 836 ParceledListSlice<AmbientBrightnessDayStats> stats = mDm.getAmbientBrightnessStats(); 837 if (stats == null) { 838 return Collections.emptyList(); 839 } 840 return stats.getList(); 841 } catch (RemoteException ex) { 842 throw ex.rethrowFromSystemServer(); 843 } 844 } 845 846 /** 847 * When enabled the app requested display resolution and refresh rate is always selected 848 * in DisplayModeDirector regardless of user settings and policies for low brightness, low 849 * battery etc. 850 */ setShouldAlwaysRespectAppRequestedMode(boolean enabled)851 public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) { 852 try { 853 mDm.setShouldAlwaysRespectAppRequestedMode(enabled); 854 } catch (RemoteException ex) { 855 throw ex.rethrowFromSystemServer(); 856 } 857 } 858 859 /** 860 * Returns whether DisplayModeDirector is running in a mode which always selects the app 861 * requested display mode and ignores user settings and policies for low brightness, low 862 * battery etc. 863 */ shouldAlwaysRespectAppRequestedMode()864 public boolean shouldAlwaysRespectAppRequestedMode() { 865 try { 866 return mDm.shouldAlwaysRespectAppRequestedMode(); 867 } catch (RemoteException ex) { 868 throw ex.rethrowFromSystemServer(); 869 } 870 } 871 872 /** 873 * Sets the refresh rate switching type. 874 * 875 * @hide 876 */ setRefreshRateSwitchingType(@isplayManager.SwitchingType int newValue)877 public void setRefreshRateSwitchingType(@DisplayManager.SwitchingType int newValue) { 878 try { 879 mDm.setRefreshRateSwitchingType(newValue); 880 } catch (RemoteException ex) { 881 throw ex.rethrowFromSystemServer(); 882 } 883 } 884 885 /** 886 * Returns the refresh rate switching type. 887 * 888 * @hide 889 */ 890 @DisplayManager.SwitchingType getRefreshRateSwitchingType()891 public int getRefreshRateSwitchingType() { 892 try { 893 return mDm.getRefreshRateSwitchingType(); 894 } catch (RemoteException ex) { 895 throw ex.rethrowFromSystemServer(); 896 } 897 } 898 899 private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { 900 @Override onDisplayEvent(int displayId, @DisplayEvent int event)901 public void onDisplayEvent(int displayId, @DisplayEvent int event) { 902 if (DEBUG) { 903 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event); 904 } 905 handleDisplayEvent(displayId, event); 906 } 907 } 908 909 private static final class DisplayListenerDelegate extends Handler { 910 public final DisplayListener mListener; 911 public long mEventsMask; 912 913 private final DisplayInfo mDisplayInfo = new DisplayInfo(); 914 DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, @EventsMask long eventsMask)915 DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper, 916 @EventsMask long eventsMask) { 917 super(looper, null, true /*async*/); 918 mListener = listener; 919 mEventsMask = eventsMask; 920 } 921 sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info)922 public void sendDisplayEvent(int displayId, @DisplayEvent int event, DisplayInfo info) { 923 Message msg = obtainMessage(event, displayId, 0, info); 924 sendMessage(msg); 925 } 926 clearEvents()927 public void clearEvents() { 928 removeCallbacksAndMessages(null); 929 } 930 setEventsMask(@ventsMask long newEventsMask)931 public synchronized void setEventsMask(@EventsMask long newEventsMask) { 932 mEventsMask = newEventsMask; 933 } 934 935 @Override handleMessage(Message msg)936 public synchronized void handleMessage(Message msg) { 937 switch (msg.what) { 938 case EVENT_DISPLAY_ADDED: 939 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { 940 mListener.onDisplayAdded(msg.arg1); 941 } 942 break; 943 case EVENT_DISPLAY_CHANGED: 944 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) { 945 DisplayInfo newInfo = (DisplayInfo) msg.obj; 946 if (newInfo != null && !newInfo.equals(mDisplayInfo)) { 947 mDisplayInfo.copyFrom(newInfo); 948 mListener.onDisplayChanged(msg.arg1); 949 } 950 } 951 break; 952 case EVENT_DISPLAY_BRIGHTNESS_CHANGED: 953 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) { 954 mListener.onDisplayChanged(msg.arg1); 955 } 956 break; 957 case EVENT_DISPLAY_REMOVED: 958 if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) { 959 mListener.onDisplayRemoved(msg.arg1); 960 } 961 break; 962 } 963 } 964 } 965 966 private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub { 967 private VirtualDisplayCallbackDelegate mDelegate; 968 VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler)969 public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) { 970 if (callback != null) { 971 mDelegate = new VirtualDisplayCallbackDelegate(callback, handler); 972 } 973 } 974 975 @Override // Binder call onPaused()976 public void onPaused() { 977 if (mDelegate != null) { 978 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED); 979 } 980 } 981 982 @Override // Binder call onResumed()983 public void onResumed() { 984 if (mDelegate != null) { 985 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED); 986 } 987 } 988 989 @Override // Binder call onStopped()990 public void onStopped() { 991 if (mDelegate != null) { 992 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED); 993 } 994 } 995 } 996 997 private final static class VirtualDisplayCallbackDelegate extends Handler { 998 public static final int MSG_DISPLAY_PAUSED = 0; 999 public static final int MSG_DISPLAY_RESUMED = 1; 1000 public static final int MSG_DISPLAY_STOPPED = 2; 1001 1002 private final VirtualDisplay.Callback mCallback; 1003 VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, Handler handler)1004 public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, 1005 Handler handler) { 1006 super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/); 1007 mCallback = callback; 1008 } 1009 1010 @Override handleMessage(Message msg)1011 public void handleMessage(Message msg) { 1012 switch (msg.what) { 1013 case MSG_DISPLAY_PAUSED: 1014 mCallback.onPaused(); 1015 break; 1016 case MSG_DISPLAY_RESUMED: 1017 mCallback.onResumed(); 1018 break; 1019 case MSG_DISPLAY_STOPPED: 1020 mCallback.onStopped(); 1021 break; 1022 } 1023 } 1024 } 1025 1026 /** 1027 * Name of the property containing a unique token which changes every time we update the 1028 * system's display configuration. 1029 */ 1030 public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY = 1031 "cache_key.display_info"; 1032 1033 /** 1034 * Invalidates the contents of the display info cache for all applications. Can only 1035 * be called by system_server. 1036 */ invalidateLocalDisplayInfoCaches()1037 public static void invalidateLocalDisplayInfoCaches() { 1038 PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY); 1039 } 1040 1041 /** 1042 * Disables the binder call cache. 1043 */ disableLocalDisplayInfoCaches()1044 public void disableLocalDisplayInfoCaches() { 1045 mDisplayCache = null; 1046 } 1047 nSignalNativeCallbacks(float refreshRate)1048 private static native void nSignalNativeCallbacks(float refreshRate); 1049 1050 // Called from AChoreographer via JNI. 1051 // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. registerNativeChoreographerForRefreshRateCallbacks()1052 private void registerNativeChoreographerForRefreshRateCallbacks() { 1053 synchronized (mLock) { 1054 registerCallbackIfNeededLocked(); 1055 mDispatchNativeCallbacks = true; 1056 DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); 1057 if (display != null) { 1058 // We need to tell AChoreographer instances the current refresh rate so that apps 1059 // can get it for free once a callback first registers. 1060 mNativeCallbackReportedRefreshRate = display.getRefreshRate(); 1061 nSignalNativeCallbacks(mNativeCallbackReportedRefreshRate); 1062 } 1063 } 1064 } 1065 1066 // Called from AChoreographer via JNI. 1067 // Unregisters AChoreographer from receiving refresh rate callbacks. unregisterNativeChoreographerForRefreshRateCallbacks()1068 private void unregisterNativeChoreographerForRefreshRateCallbacks() { 1069 synchronized (mLock) { 1070 mDispatchNativeCallbacks = false; 1071 } 1072 } 1073 } 1074