DisplayManagerGlobal.java revision 122df868919f3e2b9a92d6e9dc66808884f3f080
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 17package android.hardware.display; 18 19import android.content.Context; 20import android.content.pm.ParceledListSlice; 21import android.content.res.Resources; 22import android.graphics.Point; 23import android.hardware.display.DisplayManager.DisplayListener; 24import android.media.projection.IMediaProjection; 25import android.media.projection.MediaProjection; 26import android.os.Handler; 27import android.os.IBinder; 28import android.os.Looper; 29import android.os.Message; 30import android.os.RemoteException; 31import android.os.ServiceManager; 32import android.text.TextUtils; 33import android.util.Log; 34import android.util.Pair; 35import android.util.SparseArray; 36import android.view.Display; 37import android.view.DisplayAdjustments; 38import android.view.DisplayInfo; 39import android.view.Surface; 40 41import java.util.ArrayList; 42import java.util.Collections; 43import java.util.List; 44 45/** 46 * Manager communication with the display manager service on behalf of 47 * an application process. You're probably looking for {@link DisplayManager}. 48 * 49 * @hide 50 */ 51public final class DisplayManagerGlobal { 52 private static final String TAG = "DisplayManager"; 53 private static final boolean DEBUG = false; 54 55 // True if display info and display ids should be cached. 56 // 57 // FIXME: The cache is currently disabled because it's unclear whether we have the 58 // necessary guarantees that the caches will always be flushed before clients 59 // attempt to observe their new state. For example, depending on the order 60 // in which the binder transactions take place, we might have a problem where 61 // an application could start processing a configuration change due to a display 62 // orientation change before the display info cache has actually been invalidated. 63 private static final boolean USE_CACHE = false; 64 65 public static final int EVENT_DISPLAY_ADDED = 1; 66 public static final int EVENT_DISPLAY_CHANGED = 2; 67 public static final int EVENT_DISPLAY_REMOVED = 3; 68 69 private static DisplayManagerGlobal sInstance; 70 71 private final Object mLock = new Object(); 72 73 private final IDisplayManager mDm; 74 75 private DisplayManagerCallback mCallback; 76 private final ArrayList<DisplayListenerDelegate> mDisplayListeners = 77 new ArrayList<DisplayListenerDelegate>(); 78 79 private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>(); 80 private int[] mDisplayIdCache; 81 82 private int mWifiDisplayScanNestCount; 83 84 private DisplayManagerGlobal(IDisplayManager dm) { 85 mDm = dm; 86 } 87 88 /** 89 * Gets an instance of the display manager global singleton. 90 * 91 * @return The display manager instance, may be null early in system startup 92 * before the display manager has been fully initialized. 93 */ 94 public static DisplayManagerGlobal getInstance() { 95 synchronized (DisplayManagerGlobal.class) { 96 if (sInstance == null) { 97 IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE); 98 if (b != null) { 99 sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b)); 100 } 101 } 102 return sInstance; 103 } 104 } 105 106 /** 107 * Get information about a particular logical display. 108 * 109 * @param displayId The logical display id. 110 * @return Information about the specified display, or null if it does not exist. 111 * This object belongs to an internal cache and should be treated as if it were immutable. 112 */ 113 public DisplayInfo getDisplayInfo(int displayId) { 114 try { 115 synchronized (mLock) { 116 DisplayInfo info; 117 if (USE_CACHE) { 118 info = mDisplayInfoCache.get(displayId); 119 if (info != null) { 120 return info; 121 } 122 } 123 124 info = mDm.getDisplayInfo(displayId); 125 if (info == null) { 126 return null; 127 } 128 129 if (USE_CACHE) { 130 mDisplayInfoCache.put(displayId, info); 131 } 132 registerCallbackIfNeededLocked(); 133 134 if (DEBUG) { 135 Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info); 136 } 137 return info; 138 } 139 } catch (RemoteException ex) { 140 throw ex.rethrowFromSystemServer(); 141 } 142 } 143 144 /** 145 * Gets all currently valid logical display ids. 146 * 147 * @return An array containing all display ids. 148 */ 149 public int[] getDisplayIds() { 150 try { 151 synchronized (mLock) { 152 if (USE_CACHE) { 153 if (mDisplayIdCache != null) { 154 return mDisplayIdCache; 155 } 156 } 157 158 int[] displayIds = mDm.getDisplayIds(); 159 if (USE_CACHE) { 160 mDisplayIdCache = displayIds; 161 } 162 registerCallbackIfNeededLocked(); 163 return displayIds; 164 } 165 } catch (RemoteException ex) { 166 throw ex.rethrowFromSystemServer(); 167 } 168 } 169 170 /** 171 * Gets information about a logical display. 172 * 173 * The display metrics may be adjusted to provide compatibility 174 * for legacy applications or limited screen areas. 175 * 176 * @param displayId The logical display id. 177 * @param daj The compatibility info and activityToken. 178 * @return The display object, or null if there is no display with the given id. 179 */ 180 public Display getCompatibleDisplay(int displayId, DisplayAdjustments daj) { 181 DisplayInfo displayInfo = getDisplayInfo(displayId); 182 if (displayInfo == null) { 183 return null; 184 } 185 return new Display(this, displayId, displayInfo, daj); 186 } 187 188 /** 189 * Gets information about a logical display. 190 * 191 * The display metrics may be adjusted to provide compatibility 192 * for legacy applications or limited screen areas. 193 * 194 * @param displayId The logical display id. 195 * @param resources Resources providing compatibility info. 196 * @return The display object, or null if there is no display with the given id. 197 */ 198 public Display getCompatibleDisplay(int displayId, Resources resources) { 199 DisplayInfo displayInfo = getDisplayInfo(displayId); 200 if (displayInfo == null) { 201 return null; 202 } 203 return new Display(this, displayId, displayInfo, resources); 204 } 205 206 /** 207 * Gets information about a logical display without applying any compatibility metrics. 208 * 209 * @param displayId The logical display id. 210 * @return The display object, or null if there is no display with the given id. 211 */ 212 public Display getRealDisplay(int displayId) { 213 return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); 214 } 215 216 public void registerDisplayListener(DisplayListener listener, Handler handler) { 217 if (listener == null) { 218 throw new IllegalArgumentException("listener must not be null"); 219 } 220 221 synchronized (mLock) { 222 int index = findDisplayListenerLocked(listener); 223 if (index < 0) { 224 mDisplayListeners.add(new DisplayListenerDelegate(listener, handler)); 225 registerCallbackIfNeededLocked(); 226 } 227 } 228 } 229 230 public void unregisterDisplayListener(DisplayListener listener) { 231 if (listener == null) { 232 throw new IllegalArgumentException("listener must not be null"); 233 } 234 235 synchronized (mLock) { 236 int index = findDisplayListenerLocked(listener); 237 if (index >= 0) { 238 DisplayListenerDelegate d = mDisplayListeners.get(index); 239 d.clearEvents(); 240 mDisplayListeners.remove(index); 241 } 242 } 243 } 244 245 private int findDisplayListenerLocked(DisplayListener listener) { 246 final int numListeners = mDisplayListeners.size(); 247 for (int i = 0; i < numListeners; i++) { 248 if (mDisplayListeners.get(i).mListener == listener) { 249 return i; 250 } 251 } 252 return -1; 253 } 254 255 private void registerCallbackIfNeededLocked() { 256 if (mCallback == null) { 257 mCallback = new DisplayManagerCallback(); 258 try { 259 mDm.registerCallback(mCallback); 260 } catch (RemoteException ex) { 261 throw ex.rethrowFromSystemServer(); 262 } 263 } 264 } 265 266 private void handleDisplayEvent(int displayId, int event) { 267 synchronized (mLock) { 268 if (USE_CACHE) { 269 mDisplayInfoCache.remove(displayId); 270 271 if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) { 272 mDisplayIdCache = null; 273 } 274 } 275 276 final int numListeners = mDisplayListeners.size(); 277 for (int i = 0; i < numListeners; i++) { 278 mDisplayListeners.get(i).sendDisplayEvent(displayId, event); 279 } 280 } 281 } 282 283 public void startWifiDisplayScan() { 284 synchronized (mLock) { 285 if (mWifiDisplayScanNestCount++ == 0) { 286 registerCallbackIfNeededLocked(); 287 try { 288 mDm.startWifiDisplayScan(); 289 } catch (RemoteException ex) { 290 throw ex.rethrowFromSystemServer(); 291 } 292 } 293 } 294 } 295 296 public void stopWifiDisplayScan() { 297 synchronized (mLock) { 298 if (--mWifiDisplayScanNestCount == 0) { 299 try { 300 mDm.stopWifiDisplayScan(); 301 } catch (RemoteException ex) { 302 throw ex.rethrowFromSystemServer(); 303 } 304 } else if (mWifiDisplayScanNestCount < 0) { 305 Log.wtf(TAG, "Wifi display scan nest count became negative: " 306 + mWifiDisplayScanNestCount); 307 mWifiDisplayScanNestCount = 0; 308 } 309 } 310 } 311 312 public void connectWifiDisplay(String deviceAddress) { 313 if (deviceAddress == null) { 314 throw new IllegalArgumentException("deviceAddress must not be null"); 315 } 316 317 try { 318 mDm.connectWifiDisplay(deviceAddress); 319 } catch (RemoteException ex) { 320 throw ex.rethrowFromSystemServer(); 321 } 322 } 323 324 public void pauseWifiDisplay() { 325 try { 326 mDm.pauseWifiDisplay(); 327 } catch (RemoteException ex) { 328 throw ex.rethrowFromSystemServer(); 329 } 330 } 331 332 public void resumeWifiDisplay() { 333 try { 334 mDm.resumeWifiDisplay(); 335 } catch (RemoteException ex) { 336 throw ex.rethrowFromSystemServer(); 337 } 338 } 339 340 public void disconnectWifiDisplay() { 341 try { 342 mDm.disconnectWifiDisplay(); 343 } catch (RemoteException ex) { 344 throw ex.rethrowFromSystemServer(); 345 } 346 } 347 348 public void renameWifiDisplay(String deviceAddress, String alias) { 349 if (deviceAddress == null) { 350 throw new IllegalArgumentException("deviceAddress must not be null"); 351 } 352 353 try { 354 mDm.renameWifiDisplay(deviceAddress, alias); 355 } catch (RemoteException ex) { 356 throw ex.rethrowFromSystemServer(); 357 } 358 } 359 360 public void forgetWifiDisplay(String deviceAddress) { 361 if (deviceAddress == null) { 362 throw new IllegalArgumentException("deviceAddress must not be null"); 363 } 364 365 try { 366 mDm.forgetWifiDisplay(deviceAddress); 367 } catch (RemoteException ex) { 368 throw ex.rethrowFromSystemServer(); 369 } 370 } 371 372 public WifiDisplayStatus getWifiDisplayStatus() { 373 try { 374 return mDm.getWifiDisplayStatus(); 375 } catch (RemoteException ex) { 376 throw ex.rethrowFromSystemServer(); 377 } 378 } 379 380 public void requestColorMode(int displayId, int colorMode) { 381 try { 382 mDm.requestColorMode(displayId, colorMode); 383 } catch (RemoteException ex) { 384 throw ex.rethrowFromSystemServer(); 385 } 386 } 387 388 /** 389 * Set the level of color saturation to apply to the display. 390 */ 391 public void setSaturationLevel(float level) { 392 try { 393 mDm.setSaturationLevel(level); 394 } catch (RemoteException ex) { 395 throw ex.rethrowFromSystemServer(); 396 } 397 } 398 399 public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection, 400 String name, int width, int height, int densityDpi, Surface surface, int flags, 401 VirtualDisplay.Callback callback, Handler handler, String uniqueId) { 402 if (TextUtils.isEmpty(name)) { 403 throw new IllegalArgumentException("name must be non-null and non-empty"); 404 } 405 if (width <= 0 || height <= 0 || densityDpi <= 0) { 406 throw new IllegalArgumentException("width, height, and densityDpi must be " 407 + "greater than 0"); 408 } 409 410 VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler); 411 IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; 412 int displayId; 413 try { 414 displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken, 415 context.getPackageName(), name, width, height, densityDpi, surface, flags, 416 uniqueId); 417 } catch (RemoteException ex) { 418 throw ex.rethrowFromSystemServer(); 419 } 420 if (displayId < 0) { 421 Log.e(TAG, "Could not create virtual display: " + name); 422 return null; 423 } 424 Display display = getRealDisplay(displayId); 425 if (display == null) { 426 Log.wtf(TAG, "Could not obtain display info for newly created " 427 + "virtual display: " + name); 428 try { 429 mDm.releaseVirtualDisplay(callbackWrapper); 430 } catch (RemoteException ex) { 431 throw ex.rethrowFromSystemServer(); 432 } 433 return null; 434 } 435 return new VirtualDisplay(this, display, callbackWrapper, surface); 436 } 437 438 public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) { 439 try { 440 mDm.setVirtualDisplaySurface(token, surface); 441 } catch (RemoteException ex) { 442 throw ex.rethrowFromSystemServer(); 443 } 444 } 445 446 public void resizeVirtualDisplay(IVirtualDisplayCallback token, 447 int width, int height, int densityDpi) { 448 try { 449 mDm.resizeVirtualDisplay(token, width, height, densityDpi); 450 } catch (RemoteException ex) { 451 throw ex.rethrowFromSystemServer(); 452 } 453 } 454 455 public void releaseVirtualDisplay(IVirtualDisplayCallback token) { 456 try { 457 mDm.releaseVirtualDisplay(token); 458 } catch (RemoteException ex) { 459 throw ex.rethrowFromSystemServer(); 460 } 461 } 462 463 /** 464 * Gets the stable device display size, in pixels. 465 */ 466 public Point getStableDisplaySize() { 467 try { 468 return mDm.getStableDisplaySize(); 469 } catch (RemoteException ex) { 470 throw ex.rethrowFromSystemServer(); 471 } 472 } 473 474 /** 475 * Retrieves brightness change events. 476 */ 477 public List<BrightnessChangeEvent> getBrightnessEvents(String callingPackage) { 478 try { 479 ParceledListSlice<BrightnessChangeEvent> events = 480 mDm.getBrightnessEvents(callingPackage); 481 if (events == null) { 482 return Collections.emptyList(); 483 } 484 return events.getList(); 485 } catch (RemoteException ex) { 486 throw ex.rethrowFromSystemServer(); 487 } 488 } 489 490 /** 491 * Sets the global brightness configuration for a given user. 492 * 493 * @hide 494 */ 495 public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userId, 496 String packageName) { 497 try { 498 mDm.setBrightnessConfigurationForUser(c, userId, packageName); 499 } catch (RemoteException ex) { 500 throw ex.rethrowFromSystemServer(); 501 } 502 } 503 504 /** 505 * Gets the global brightness configuration for a given user or null if one hasn't been set. 506 * 507 * @hide 508 */ 509 public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) { 510 try { 511 return mDm.getBrightnessConfigurationForUser(userId); 512 } catch (RemoteException ex) { 513 throw ex.rethrowFromSystemServer(); 514 } 515 } 516 517 /** 518 * Gets the default brightness configuration or null if one hasn't been configured. 519 * 520 * @hide 521 */ 522 public BrightnessConfiguration getDefaultBrightnessConfiguration() { 523 try { 524 return mDm.getDefaultBrightnessConfiguration(); 525 } catch (RemoteException ex) { 526 throw ex.rethrowFromSystemServer(); 527 } 528 } 529 530 /** 531 * Temporarily sets the brightness of the display. 532 * <p> 533 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 534 * </p> 535 * 536 * @param brightness The brightness value from 0 to 255. 537 * 538 * @hide Requires signature permission. 539 */ 540 public void setTemporaryBrightness(int brightness) { 541 try { 542 mDm.setTemporaryBrightness(brightness); 543 } catch (RemoteException ex) { 544 throw ex.rethrowFromSystemServer(); 545 } 546 } 547 548 /** 549 * Temporarily sets the auto brightness adjustment factor. 550 * <p> 551 * Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. 552 * </p> 553 * 554 * @param adjustment The adjustment factor from -1.0 to 1.0. 555 * 556 * @hide Requires signature permission. 557 */ 558 public void setTemporaryAutoBrightnessAdjustment(float adjustment) { 559 try { 560 mDm.setTemporaryAutoBrightnessAdjustment(adjustment); 561 } catch (RemoteException ex) { 562 throw ex.rethrowFromSystemServer(); 563 } 564 } 565 566 /** 567 * Returns the minimum brightness curve, which guarantess that any brightness curve that dips 568 * below it is rejected by the system. 569 * This prevent auto-brightness from setting the screen so dark as to prevent the user from 570 * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable 571 * in that ambient brightness. 572 * 573 * @return The minimum brightness curve (as lux values and their corresponding nits values). 574 */ 575 public Pair<float[], float[]> getMinimumBrightnessCurve() { 576 try { 577 Curve curve = mDm.getMinimumBrightnessCurve(); 578 return Pair.create(curve.getX(), curve.getY()); 579 } catch (RemoteException ex) { 580 throw ex.rethrowFromSystemServer(); 581 } 582 } 583 584 /** 585 * Retrieves ambient brightness stats. 586 */ 587 public List<AmbientBrightnessDayStats> getAmbientBrightnessStats() { 588 try { 589 ParceledListSlice<AmbientBrightnessDayStats> stats = mDm.getAmbientBrightnessStats(); 590 if (stats == null) { 591 return Collections.emptyList(); 592 } 593 return stats.getList(); 594 } catch (RemoteException ex) { 595 throw ex.rethrowFromSystemServer(); 596 } 597 } 598 599 private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub { 600 @Override 601 public void onDisplayEvent(int displayId, int event) { 602 if (DEBUG) { 603 Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event); 604 } 605 handleDisplayEvent(displayId, event); 606 } 607 } 608 609 private static final class DisplayListenerDelegate extends Handler { 610 public final DisplayListener mListener; 611 612 public DisplayListenerDelegate(DisplayListener listener, Handler handler) { 613 super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/); 614 mListener = listener; 615 } 616 617 public void sendDisplayEvent(int displayId, int event) { 618 Message msg = obtainMessage(event, displayId, 0); 619 sendMessage(msg); 620 } 621 622 public void clearEvents() { 623 removeCallbacksAndMessages(null); 624 } 625 626 @Override 627 public void handleMessage(Message msg) { 628 switch (msg.what) { 629 case EVENT_DISPLAY_ADDED: 630 mListener.onDisplayAdded(msg.arg1); 631 break; 632 case EVENT_DISPLAY_CHANGED: 633 mListener.onDisplayChanged(msg.arg1); 634 break; 635 case EVENT_DISPLAY_REMOVED: 636 mListener.onDisplayRemoved(msg.arg1); 637 break; 638 } 639 } 640 } 641 642 private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub { 643 private VirtualDisplayCallbackDelegate mDelegate; 644 645 public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) { 646 if (callback != null) { 647 mDelegate = new VirtualDisplayCallbackDelegate(callback, handler); 648 } 649 } 650 651 @Override // Binder call 652 public void onPaused() { 653 if (mDelegate != null) { 654 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED); 655 } 656 } 657 658 @Override // Binder call 659 public void onResumed() { 660 if (mDelegate != null) { 661 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED); 662 } 663 } 664 665 @Override // Binder call 666 public void onStopped() { 667 if (mDelegate != null) { 668 mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED); 669 } 670 } 671 } 672 673 private final static class VirtualDisplayCallbackDelegate extends Handler { 674 public static final int MSG_DISPLAY_PAUSED = 0; 675 public static final int MSG_DISPLAY_RESUMED = 1; 676 public static final int MSG_DISPLAY_STOPPED = 2; 677 678 private final VirtualDisplay.Callback mCallback; 679 680 public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, 681 Handler handler) { 682 super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/); 683 mCallback = callback; 684 } 685 686 @Override 687 public void handleMessage(Message msg) { 688 switch (msg.what) { 689 case MSG_DISPLAY_PAUSED: 690 mCallback.onPaused(); 691 break; 692 case MSG_DISPLAY_RESUMED: 693 mCallback.onResumed(); 694 break; 695 case MSG_DISPLAY_STOPPED: 696 mCallback.onStopped(); 697 break; 698 } 699 } 700 } 701} 702