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 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.PropertyInvalidatedCache; 22 import android.compat.annotation.UnsupportedAppUsage; 23 import android.content.Context; 24 import android.content.pm.ParceledListSlice; 25 import android.content.res.Resources; 26 import android.graphics.ColorSpace; 27 import android.graphics.Point; 28 import android.hardware.display.DisplayManager.DisplayListener; 29 import android.media.projection.IMediaProjection; 30 import android.media.projection.MediaProjection; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.RemoteException; 36 import android.os.ServiceManager; 37 import android.util.Log; 38 import android.util.Pair; 39 import android.util.SparseArray; 40 import android.view.Display; 41 import android.view.DisplayAdjustments; 42 import android.view.DisplayInfo; 43 import android.view.Surface; 44 45 import java.util.ArrayList; 46 import java.util.Collections; 47 import java.util.List; 48 49 /** 50 * Manager communication with the display manager service on behalf of 51 * an application process. You're probably looking for {@link DisplayManager}. 52 * 53 * @hide 54 */ 55 public final class DisplayManagerGlobal { 56 private static final String TAG = "DisplayManager"; 57 private static final boolean DEBUG = false; 58 59 // True if display info and display ids should be cached. 60 // 61 // FIXME: The cache is currently disabled because it's unclear whether we have the 62 // necessary guarantees that the caches will always be flushed before clients 63 // attempt to observe their new state. For example, depending on the order 64 // in which the binder transactions take place, we might have a problem where 65 // an application could start processing a configuration change due to a display 66 // orientation change before the display info cache has actually been invalidated. 67 private static final boolean USE_CACHE = false; 68 69 public static final int EVENT_DISPLAY_ADDED = 1; 70 public static final int EVENT_DISPLAY_CHANGED = 2; 71 public static final int EVENT_DISPLAY_REMOVED = 3; 72 73 @UnsupportedAppUsage 74 private static DisplayManagerGlobal sInstance; 75 76 // Guarded by mLock 77 private boolean mDispatchNativeCallbacks = false; 78 private final Object mLock = new Object(); 79 80 @UnsupportedAppUsage 81 private final IDisplayManager mDm; 82 83 private DisplayManagerCallback mCallback; 84 private final ArrayList<DisplayListenerDelegate> mDisplayListeners = 85 new ArrayList<DisplayListenerDelegate>(); 86 87 private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>(); 88 private final ColorSpace mWideColorSpace; 89 private int[] mDisplayIdCache; 90 91 private int mWifiDisplayScanNestCount; 92 DisplayManagerGlobal(IDisplayManager dm)93 private DisplayManagerGlobal(IDisplayManager dm) { 94 mDm = dm; 95 try { 96 mWideColorSpace = 97 ColorSpace.get( 98 ColorSpace.Named.values()[mDm.getPreferredWideGamutColorSpaceId()]); 99 } catch (RemoteException ex) { 100 throw ex.rethrowFromSystemServer(); 101 } 102 } 103 104 private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache = 105 new PropertyInvalidatedCache<Integer, DisplayInfo>( 106 8, // size of display cache 107 CACHE_KEY_DISPLAY_INFO_PROPERTY) { 108 @Override 109 protected DisplayInfo recompute(Integer id) { 110 try { 111 return mDm.getDisplayInfo(id); 112 } catch (RemoteException ex) { 113 throw ex.rethrowFromSystemServer(); 114 } 115 } 116 }; 117 118 /** 119 * Gets an instance of the display manager global singleton. 120 * 121 * @return The display manager instance, may be null early in system startup 122 * before the display manager has been fully initialized. 123 */ 124 @UnsupportedAppUsage getInstance()125 public static DisplayManagerGlobal getInstance() { 126 synchronized (DisplayManagerGlobal.class) { 127 if (sInstance == null) { 128 IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE); 129 if (b != null) { 130 sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b)); 131 } 132 } 133 return sInstance; 134 } 135 } 136 137 /** 138 * Get information about a particular logical display. 139 * 140 * @param displayId The logical display id. 141 * @return Information about the specified display, or null if it does not exist. 142 * This object belongs to an internal cache and should be treated as if it were immutable. 143 */ 144 @UnsupportedAppUsage getDisplayInfo(int displayId)145 public DisplayInfo getDisplayInfo(int displayId) { 146 synchronized (mLock) { 147 return getDisplayInfoLocked(displayId); 148 } 149 } 150 151 /** 152 * Gets information about a particular logical display 153 * See {@link getDisplayInfo}, but assumes that {@link mLock} is held 154 */ getDisplayInfoLocked(int displayId)155 private @Nullable DisplayInfo getDisplayInfoLocked(int displayId) { 156 DisplayInfo info = null; 157 if (mDisplayCache != null) { 158 info = mDisplayCache.query(displayId); 159 } else { 160 try { 161 info = mDm.getDisplayInfo(displayId); 162 } catch (RemoteException ex) { 163 ex.rethrowFromSystemServer(); 164 } 165 } 166 if (info == null) { 167 return null; 168 } 169 170 registerCallbackIfNeededLocked(); 171 172 if (DEBUG) { 173 Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info); 174 } 175 return info; 176 } 177 178 /** 179 * Gets all currently valid logical display ids. 180 * 181 * @return An array containing all display ids. 182 */ 183 @UnsupportedAppUsage getDisplayIds()184 public int[] getDisplayIds() { 185 try { 186 synchronized (mLock) { 187 if (USE_CACHE) { 188 if (mDisplayIdCache != null) { 189 return mDisplayIdCache; 190 } 191 } 192 193 int[] displayIds = mDm.getDisplayIds(); 194 if (USE_CACHE) { 195 mDisplayIdCache = displayIds; 196 } 197 registerCallbackIfNeededLocked(); 198 return displayIds; 199 } 200 } catch (RemoteException ex) { 201 throw ex.rethrowFromSystemServer(); 202 } 203 } 204 205 /** 206 * Check if specified UID's content is present on display and should be granted access to it. 207 * 208 * @param uid UID to be checked. 209 * @param displayId id of the display where presence of the content is checked. 210 * @return {@code true} if UID is present on display, {@code false} otherwise. 211 */ isUidPresentOnDisplay(int uid, int displayId)212 public boolean isUidPresentOnDisplay(int uid, int displayId) { 213 try { 214 return mDm.isUidPresentOnDisplay(uid, displayId); 215 } catch (RemoteException ex) { 216 throw ex.rethrowFromSystemServer(); 217 } 218 } 219 220 /** 221 * Gets information about a logical display. 222 * 223 * The display metrics may be adjusted to provide compatibility 224 * for legacy applications or limited screen areas. 225 * 226 * @param displayId The logical display id. 227 * @param daj The compatibility info and activityToken. 228 * @return The display object, or null if there is no display with the given id. 229 */ getCompatibleDisplay(int displayId, DisplayAdjustments daj)230 public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) { 231 DisplayInfo displayInfo = getDisplayInfo(displayId); 232 if (displayInfo == null) { 233 return null; 234 } 235 return new Display(this, displayId, displayInfo, daj); 236 } 237 238 /** 239 * Gets information about a logical display. 240 * 241 * The display metrics may be adjusted to provide compatibility 242 * for legacy applications or limited screen areas. 243 * 244 * @param displayId The logical display id. 245 * @param resources Resources providing compatibility info. 246 * @return The display object, or null if there is no display with the given id. 247 */ getCompatibleDisplay(int displayId, Resources resources)248 public Display getCompatibleDisplay(int displayId, Resources resources) { 249 DisplayInfo displayInfo = getDisplayInfo(displayId); 250 if (displayInfo == null) { 251 return null; 252 } 253 return new Display(this, displayId, displayInfo, resources); 254 } 255 256 /** 257 * Gets information about a logical display without applying any compatibility metrics. 258 * 259 * @param displayId The logical display id. 260 * @return The display object, or null if there is no display with the given id. 261 */ 262 @UnsupportedAppUsage getRealDisplay(int displayId)263 public Display getRealDisplay(int displayId) { 264 return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); 265 } 266 267 /** 268 * Register a listener for display-related changes. 269 * 270 * @param listener The listener that will be called when display changes occur. 271 * @param handler Handler for the thread that will be receiving the callbacks. May be null. 272 * If null, listener will use the handler for the current thread, and if still null, 273 * the handler for the main thread. 274 * If that is still null, a runtime exception will be thrown. 275 */ registerDisplayListener(@onNull DisplayListener listener, @Nullable Handler handler)276 public void registerDisplayListener(@NonNull DisplayListener listener, 277 @Nullable Handler handler) { 278 if (listener == null) { 279 throw new IllegalArgumentException("listener must not be null"); 280 } 281 282 synchronized (mLock) { 283 int index = findDisplayListenerLocked(listener); 284 if (index < 0) { 285 Looper looper = getLooperForHandler(handler); 286 mDisplayListeners.add(new DisplayListenerDelegate(listener, looper)); 287 registerCallbackIfNeededLocked(); 288 } 289 } 290 } 291 unregisterDisplayListener(DisplayListener listener)292 public void unregisterDisplayListener(DisplayListener listener) { 293 if (listener == null) { 294 throw new IllegalArgumentException("listener must not be null"); 295 } 296 297 synchronized (mLock) { 298 int index = findDisplayListenerLocked(listener); 299 if (index >= 0) { 300 DisplayListenerDelegate d = mDisplayListeners.get(index); 301 d.clearEvents(); 302 mDisplayListeners.remove(index); 303 } 304 } 305 } 306 getLooperForHandler(@ullable Handler handler)307 private static Looper getLooperForHandler(@Nullable Handler handler) { 308 Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); 309 if (looper == null) { 310 looper = Looper.getMainLooper(); 311 } 312 if (looper == null) { 313 throw new RuntimeException("Could not get Looper for the UI thread."); 314 } 315 return looper; 316 } 317 findDisplayListenerLocked(DisplayListener listener)318 private int findDisplayListenerLocked(DisplayListener listener) { 319 final int numListeners = mDisplayListeners.size(); 320 for (int i = 0; i < numListeners; i++) { 321 if (mDisplayListeners.get(i).mListener == listener) { 322 return i; 323 } 324 } 325 return -1; 326 } 327 registerCallbackIfNeededLocked()328 private void registerCallbackIfNeededLocked() { 329 if (mCallback == null) { 330 mCallback = new DisplayManagerCallback(); 331 try { 332 mDm.registerCallback(mCallback); 333 } catch (RemoteException ex) { 334 throw ex.rethrowFromSystemServer(); 335 } 336 } 337 } 338 handleDisplayEvent(int displayId, int event)339 private void handleDisplayEvent(int displayId, int event) { 340 synchronized (mLock) { 341 if (USE_CACHE) { 342 mDisplayInfoCache.remove(displayId); 343 344 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) { 345 mDisplayIdCache = null; 346 } 347 } 348 349 final int numListeners = mDisplayListeners.size(); 350 for (int i = 0; i < numListeners; i++) { 351 mDisplayListeners.get(i).sendDisplayEvent(displayId, event); 352 } 353 if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { 354 // Choreographer only supports a single display, so only dispatch refresh rate 355 // changes for the default display. 356 if (displayId == Display.DEFAULT_DISPLAY) { 357 // We can likely save a binder hop if we attach the refresh rate onto the 358 // listener. 359 DisplayInfo display = getDisplayInfoLocked(displayId); 360 if (display != null) { 361 float refreshRate = display.getMode().getRefreshRate(); 362 // Signal native callbacks if we ever set a refresh rate. 363 nSignalNativeCallbacks(refreshRate); 364 } 365 } 366 } 367 } 368 } 369 startWifiDisplayScan()370 public void startWifiDisplayScan() { 371 synchronized (mLock) { 372 if (mWifiDisplayScanNestCount++ == 0) { 373 registerCallbackIfNeededLocked(); 374 try { 375 mDm.startWifiDisplayScan(); 376 } catch (RemoteException ex) { 377 throw ex.rethrowFromSystemServer(); 378 } 379 } 380 } 381 } 382 stopWifiDisplayScan()383 public void stopWifiDisplayScan() { 384 synchronized (mLock) { 385 if (--mWifiDisplayScanNestCount == 0) { 386 try { 387 mDm.stopWifiDisplayScan(); 388 } catch (RemoteException ex) { 389 throw ex.rethrowFromSystemServer(); 390 } 391 } else if (mWifiDisplayScanNestCount < 0) { 392 Log.wtf(TAG, "Wifi display scan nest count became negative: " 393 + mWifiDisplayScanNestCount); 394 mWifiDisplayScanNestCount = 0; 395 } 396 } 397 } 398 connectWifiDisplay(String deviceAddress)399 public void connectWifiDisplay(String deviceAddress) { 400 if (deviceAddress == null) { 401 throw new IllegalArgumentException("deviceAddress must not be null"); 402 } 403 404 try { 405 mDm.connectWifiDisplay(deviceAddress); 406 } catch (RemoteException ex) { 407 throw ex.rethrowFromSystemServer(); 408 } 409 } 410 pauseWifiDisplay()411 public void pauseWifiDisplay() { 412 try { 413 mDm.pauseWifiDisplay(); 414 } catch (RemoteException ex) { 415 throw ex.rethrowFromSystemServer(); 416 } 417 } 418 resumeWifiDisplay()419 public void resumeWifiDisplay() { 420 try { 421 mDm.resumeWifiDisplay(); 422 } catch (RemoteException ex) { 423 throw ex.rethrowFromSystemServer(); 424 } 425 } 426 427 @UnsupportedAppUsage disconnectWifiDisplay()428 public void disconnectWifiDisplay() { 429 try { 430 mDm.disconnectWifiDisplay(); 431 } catch (RemoteException ex) { 432 throw ex.rethrowFromSystemServer(); 433 } 434 } 435 renameWifiDisplay(String deviceAddress, String alias)436 public void renameWifiDisplay(String deviceAddress, String alias) { 437 if (deviceAddress == null) { 438 throw new IllegalArgumentException("deviceAddress must not be null"); 439 } 440 441 try { 442 mDm.renameWifiDisplay(deviceAddress, alias); 443 } catch (RemoteException ex) { 444 throw ex.rethrowFromSystemServer(); 445 } 446 } 447 forgetWifiDisplay(String deviceAddress)448 public void forgetWifiDisplay(String deviceAddress) { 449 if (deviceAddress == null) { 450 throw new IllegalArgumentException("deviceAddress must not be null"); 451 } 452 453 try { 454 mDm.forgetWifiDisplay(deviceAddress); 455 } catch (RemoteException ex) { 456 throw ex.rethrowFromSystemServer(); 457 } 458 } 459 460 @UnsupportedAppUsage getWifiDisplayStatus()461 public WifiDisplayStatus getWifiDisplayStatus() { 462 try { 463 return mDm.getWifiDisplayStatus(); 464 } catch (RemoteException ex) { 465 throw ex.rethrowFromSystemServer(); 466 } 467 } 468 requestColorMode(int displayId, int colorMode)469 public void requestColorMode(int displayId, int colorMode) { 470 try { 471 mDm.requestColorMode(displayId, colorMode); 472 } catch (RemoteException ex) { 473 throw ex.rethrowFromSystemServer(); 474 } 475 } 476 createVirtualDisplay(@onNull Context context, MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, Handler handler)477 public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection, 478 @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, 479 Handler handler) { 480 VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler); 481 IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; 482 int displayId; 483 try { 484 displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, 485 projectionToken, context.getPackageName()); 486 } catch (RemoteException ex) { 487 throw ex.rethrowFromSystemServer(); 488 } 489 if (displayId < 0) { 490 Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName()); 491 return null; 492 } 493 Display display = getRealDisplay(displayId); 494 if (display == null) { 495 Log.wtf(TAG, "Could not obtain display info for newly created " 496 + "virtual display: " + virtualDisplayConfig.getName()); 497 try { 498 mDm.releaseVirtualDisplay(callbackWrapper); 499 } catch (RemoteException ex) { 500 throw ex.rethrowFromSystemServer(); 501 } 502 return null; 503 } 504 return new VirtualDisplay(this, display, callbackWrapper, 505 virtualDisplayConfig.getSurface()); 506 } 507 setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface)508 public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) { 509 try { 510 mDm.setVirtualDisplaySurface(token, surface); 511 setVirtualDisplayState(token, surface != null); 512 } catch (RemoteException ex) { 513 throw ex.rethrowFromSystemServer(); 514 } 515 } 516 resizeVirtualDisplay(IVirtualDisplayCallback token, int width, int height, int densityDpi)517 public void resizeVirtualDisplay(IVirtualDisplayCallback token, 518 int width, int height, int densityDpi) { 519 try { 520 mDm.resizeVirtualDisplay(token, width, height, densityDpi); 521 } catch (RemoteException ex) { 522 throw ex.rethrowFromSystemServer(); 523 } 524 } 525 releaseVirtualDisplay(IVirtualDisplayCallback token)526 public void releaseVirtualDisplay(IVirtualDisplayCallback token) { 527 try { 528 mDm.releaseVirtualDisplay(token); 529 } catch (RemoteException ex) { 530 throw ex.rethrowFromSystemServer(); 531 } 532 } 533 setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn)534 void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) { 535 try { 536 mDm.setVirtualDisplayState(token, isOn); 537 } catch (RemoteException ex) { 538 throw ex.rethrowFromSystemServer(); 539 } 540 } 541 542 /** 543 * Gets the stable device display size, in pixels. 544 */ getStableDisplaySize()545 public Point getStableDisplaySize() { 546 try { 547 return mDm.getStableDisplaySize(); 548 } catch (RemoteException ex) { 549 throw ex.rethrowFromSystemServer(); 550 } 551 } 552 553 /** 554 * Retrieves brightness change events. 555 */ getBrightnessEvents(String callingPackage)556 public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) { 557 try { 558 ParceledListSlice<BrightnessChangeEvent> events = 559 mDm.getBrightnessEvents(callingPackage); 560 if (events == null) { 561 return Collections.emptyList(); 562 } 563 return events.getList(); 564 } catch (RemoteException ex) { 565 throw ex.rethrowFromSystemServer(); 566 } 567 } 568 569 /** 570 * Gets the preferred wide gamut color space for all displays. 571 * The wide gamut color space is returned from composition pipeline 572 * based on hardware capability. 573 * 574 * @hide 575 */ getPreferredWideGamutColorSpace()576 public ColorSpace getPreferredWideGamutColorSpace() { 577 return mWideColorSpace; 578 } 579 580 /** 581 * Sets the global brightness configuration for a given user. 582 * 583 * @hide 584 */ setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, String packageName)585 public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, 586 String packageName) { 587 try { 588 mDm.setBrightnessConfigurationForUser(c, userId, packageName); 589 } catch (RemoteException ex) { 590 throw ex.rethrowFromSystemServer(); 591 } 592 } 593 594 /** 595 * Gets the global brightness configuration for a given user or null if one hasn't been set. 596 * 597 * @hide 598 */ getBrightnessConfigurationForUser(int userId)599 public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { 600 try { 601 return mDm.getBrightnessConfigurationForUser(userId); 602 } catch (RemoteException ex) { 603 throw ex.rethrowFromSystemServer(); 604 } 605 } 606 607 /** 608 * Gets the default brightness configuration or null if one hasn't been configured. 609 * 610 * @hide 611 */ getDefaultBrightnessConfiguration()612 public BrightnessConfiguration getDefaultBrightnessConfiguration() { 613 try { 614 return mDm.getDefaultBrightnessConfiguration(); 615 } catch (RemoteException ex) { 616 throw ex.rethrowFromSystemServer(); 617 } 618 } 619 620 /** 621 * Gets the last requested minimal post processing setting for the display with displayId. 622 * 623 * @hide 624 */ isMinimalPostProcessingRequested(int displayId)625 public boolean isMinimalPostProcessingRequested(int displayId) { 626 try { 627 return mDm.isMinimalPostProcessingRequested(displayId); 628 } catch (RemoteException ex) { 629 throw ex.rethrowFromSystemServer(); 630 } 631 } 632 633 /** 634 * Temporarily sets the brightness of the display. 635 * <p> 636 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 637 * </p> 638 * 639 * @param brightness The brightness value from 0 to 255. 640 * 641 * @hide Requires signature permission. 642 */ setTemporaryBrightness(float brightness)643 public void setTemporaryBrightness(float brightness) { 644 try { 645 mDm.setTemporaryBrightness(brightness); 646 } catch (RemoteException ex) { 647 throw ex.rethrowFromSystemServer(); 648 } 649 } 650 651 /** 652 * Temporarily sets the auto brightness adjustment factor. 653 * <p> 654 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 655 * </p> 656 * 657 * @param adjustment The adjustment factor from -1.0 to 1.0. 658 * 659 * @hide Requires signature permission. 660 */ setTemporaryAutoBrightnessAdjustment(float adjustment)661 public void setTemporaryAutoBrightnessAdjustment(float adjustment) { 662 try { 663 mDm.setTemporaryAutoBrightnessAdjustment(adjustment); 664 } catch (RemoteException ex) { 665 throw ex.rethrowFromSystemServer(); 666 } 667 } 668 669 /** 670 * Returns the minimum brightness curve, which guarantess that any brightness curve that dips 671 * below it is rejected by the system. 672 * This prevent auto-brightness from setting the screen so dark as to prevent the user from 673 * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable 674 * in that ambient brightness. 675 * 676 * @return The minimum brightness curve (as lux values and their corresponding nits values). 677 */ getMinimumBrightnessCurve()678 public Pair<float[], float[]> getMinimumBrightnessCurve() { 679 try { 680 Curve curve = mDm.getMinimumBrightnessCurve(); 681 return Pair.create(curve.getX(), curve.getY()); 682 } catch (RemoteException ex) { 683 throw ex.rethrowFromSystemServer(); 684 } 685 } 686 687 /** 688 * Retrieves ambient brightness stats. 689 */ getAmbientBrightnessStats()690 public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() { 691 try { 692 ParceledListSlice<AmbientBrightnessDayStats> stats = mDm.getAmbientBrightnessStats(); 693 if (stats == null) { 694 return Collections.emptyList(); 695 } 696 return stats.getList(); 697 } catch (RemoteException ex) { 698 throw ex.rethrowFromSystemServer(); 699 } 700 } 701 702 private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { 703 @Override onDisplayEvent(int displayId, int event)704 public void onDisplayEvent(int displayId, int event) { 705 if (DEBUG) { 706 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event); 707 } 708 handleDisplayEvent(displayId, event); 709 } 710 } 711 712 private static final class DisplayListenerDelegate extends Handler { 713 public final DisplayListener mListener; 714 DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper)715 DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper) { 716 super(looper, null, true /*async*/); 717 mListener = listener; 718 } 719 sendDisplayEvent(int displayId, int event)720 public void sendDisplayEvent(int displayId, int event) { 721 Message msg = obtainMessage(event, displayId, 0); 722 sendMessage(msg); 723 } 724 clearEvents()725 public void clearEvents() { 726 removeCallbacksAndMessages(null); 727 } 728 729 @Override handleMessage(Message msg)730 public void handleMessage(Message msg) { 731 switch (msg.what) { 732 case EVENT_DISPLAY_ADDED: 733 mListener.onDisplayAdded(msg.arg1); 734 break; 735 case EVENT_DISPLAY_CHANGED: 736 mListener.onDisplayChanged(msg.arg1); 737 break; 738 case EVENT_DISPLAY_REMOVED: 739 mListener.onDisplayRemoved(msg.arg1); 740 break; 741 } 742 } 743 } 744 745 private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub { 746 private VirtualDisplayCallbackDelegate mDelegate; 747 VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler)748 public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) { 749 if (callback != null) { 750 mDelegate = new VirtualDisplayCallbackDelegate(callback, handler); 751 } 752 } 753 754 @Override // Binder call onPaused()755 public void onPaused() { 756 if (mDelegate != null) { 757 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED); 758 } 759 } 760 761 @Override // Binder call onResumed()762 public void onResumed() { 763 if (mDelegate != null) { 764 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED); 765 } 766 } 767 768 @Override // Binder call onStopped()769 public void onStopped() { 770 if (mDelegate != null) { 771 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED); 772 } 773 } 774 } 775 776 private final static class VirtualDisplayCallbackDelegate extends Handler { 777 public static final int MSG_DISPLAY_PAUSED = 0; 778 public static final int MSG_DISPLAY_RESUMED = 1; 779 public static final int MSG_DISPLAY_STOPPED = 2; 780 781 private final VirtualDisplay.Callback mCallback; 782 VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, Handler handler)783 public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, 784 Handler handler) { 785 super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/); 786 mCallback = callback; 787 } 788 789 @Override handleMessage(Message msg)790 public void handleMessage(Message msg) { 791 switch (msg.what) { 792 case MSG_DISPLAY_PAUSED: 793 mCallback.onPaused(); 794 break; 795 case MSG_DISPLAY_RESUMED: 796 mCallback.onResumed(); 797 break; 798 case MSG_DISPLAY_STOPPED: 799 mCallback.onStopped(); 800 break; 801 } 802 } 803 } 804 805 /** 806 * Name of the property containing a unique token which changes every time we update the 807 * system's display configuration. 808 */ 809 public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY = 810 "cache_key.display_info"; 811 812 /** 813 * Invalidates the contents of the display info cache for all applications. Can only 814 * be called by system_server. 815 */ invalidateLocalDisplayInfoCaches()816 public static void invalidateLocalDisplayInfoCaches() { 817 PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY); 818 } 819 820 /** 821 * Disables the binder call cache. 822 */ disableLocalDisplayInfoCaches()823 public void disableLocalDisplayInfoCaches() { 824 mDisplayCache = null; 825 } 826 nSignalNativeCallbacks(float refreshRate)827 private static native void nSignalNativeCallbacks(float refreshRate); 828 829 // Called from AChoreographer via JNI. 830 // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. registerNativeChoreographerForRefreshRateCallbacks()831 private void registerNativeChoreographerForRefreshRateCallbacks() { 832 synchronized (mLock) { 833 registerCallbackIfNeededLocked(); 834 mDispatchNativeCallbacks = true; 835 DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); 836 if (display != null) { 837 // We need to tell AChoreographer instances the current refresh rate so that apps 838 // can get it for free once a callback first registers. 839 float refreshRate = display.getMode().getRefreshRate(); 840 nSignalNativeCallbacks(refreshRate); 841 } 842 } 843 } 844 845 // Called from AChoreographer via JNI. 846 // Unregisters AChoreographer from receiving refresh rate callbacks. unregisterNativeChoreographerForRefreshRateCallbacks()847 private void unregisterNativeChoreographerForRefreshRateCallbacks() { 848 synchronized (mLock) { 849 mDispatchNativeCallbacks = false; 850 } 851 } 852 } 853