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.annotation.SystemService; 22 import android.content.Context; 23 import android.media.projection.MediaProjection; 24 import android.os.Handler; 25 import android.util.SparseArray; 26 import android.view.Display; 27 import android.view.Surface; 28 29 import java.util.ArrayList; 30 31 /** 32 * Manages the properties of attached displays. 33 */ 34 @SystemService(Context.DISPLAY_SERVICE) 35 public final class DisplayManager { 36 private static final String TAG = "DisplayManager"; 37 private static final boolean DEBUG = false; 38 39 private final Context mContext; 40 private final DisplayManagerGlobal mGlobal; 41 42 private final Object mLock = new Object(); 43 private final SparseArray<Display> mDisplays = new SparseArray<Display>(); 44 45 private final ArrayList<Display> mTempDisplays = new ArrayList<Display>(); 46 47 /** 48 * Broadcast receiver that indicates when the Wifi display status changes. 49 * <p> 50 * The status is provided as a {@link WifiDisplayStatus} object in the 51 * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra. 52 * </p><p> 53 * This broadcast is only sent to registered receivers and can only be sent by the system. 54 * </p> 55 * @hide 56 */ 57 public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED = 58 "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED"; 59 60 /** 61 * Contains a {@link WifiDisplayStatus} object. 62 * @hide 63 */ 64 public static final String EXTRA_WIFI_DISPLAY_STATUS = 65 "android.hardware.display.extra.WIFI_DISPLAY_STATUS"; 66 67 /** 68 * Display category: Presentation displays. 69 * <p> 70 * This category can be used to identify secondary displays that are suitable for 71 * use as presentation displays such as HDMI or Wireless displays. Applications 72 * may automatically project their content to presentation displays to provide 73 * richer second screen experiences. 74 * </p> 75 * 76 * @see android.app.Presentation 77 * @see Display#FLAG_PRESENTATION 78 * @see #getDisplays(String) 79 */ 80 public static final String DISPLAY_CATEGORY_PRESENTATION = 81 "android.hardware.display.category.PRESENTATION"; 82 83 /** 84 * Virtual display flag: Create a public display. 85 * 86 * <h3>Public virtual displays</h3> 87 * <p> 88 * When this flag is set, the virtual display is public. 89 * </p><p> 90 * A public virtual display behaves just like most any other display that is connected 91 * to the system such as an HDMI or Wireless display. Applications can open 92 * windows on the display and the system may mirror the contents of other displays 93 * onto it. 94 * </p><p> 95 * Creating a public virtual display that isn't restricted to own-content only implicitly 96 * creates an auto-mirroring display. See {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for 97 * restrictions on who is allowed to create an auto-mirroring display. 98 * </p> 99 * 100 * <h3>Private virtual displays</h3> 101 * <p> 102 * When this flag is not set, the virtual display is private as defined by the 103 * {@link Display#FLAG_PRIVATE} display flag. 104 * </p> 105 * 106 * <p> 107 * A private virtual display belongs to the application that created it. Only the a owner of a 108 * private virtual display and the apps that are already on that display are allowed to place 109 * windows upon it. The private virtual display also does not participate in display mirroring: 110 * it will neither receive mirrored content from another display nor allow its own content to be 111 * mirrored elsewhere. More precisely, the only processes that are allowed to enumerate or 112 * interact with the private display are those that have the same UID as the application that 113 * originally created the private virtual display or as the activities that are already on that 114 * display. 115 * </p> 116 * 117 * @see #createVirtualDisplay 118 * @see #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY 119 * @see #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR 120 */ 121 public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0; 122 123 /** 124 * Virtual display flag: Create a presentation display. 125 * 126 * <h3>Presentation virtual displays</h3> 127 * <p> 128 * When this flag is set, the virtual display is registered as a presentation 129 * display in the {@link #DISPLAY_CATEGORY_PRESENTATION presentation display category}. 130 * Applications may automatically project their content to presentation displays 131 * to provide richer second screen experiences. 132 * </p> 133 * 134 * <h3>Non-presentation virtual displays</h3> 135 * <p> 136 * When this flag is not set, the virtual display is not registered as a presentation 137 * display. Applications can still project their content on the display but they 138 * will typically not do so automatically. This option is appropriate for 139 * more special-purpose displays. 140 * </p> 141 * 142 * @see android.app.Presentation 143 * @see #createVirtualDisplay 144 * @see #DISPLAY_CATEGORY_PRESENTATION 145 * @see Display#FLAG_PRESENTATION 146 */ 147 public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1; 148 149 /** 150 * Virtual display flag: Create a secure display. 151 * 152 * <h3>Secure virtual displays</h3> 153 * <p> 154 * When this flag is set, the virtual display is considered secure as defined 155 * by the {@link Display#FLAG_SECURE} display flag. The caller promises to take 156 * reasonable measures, such as over-the-air encryption, to prevent the contents 157 * of the display from being intercepted or recorded on a persistent medium. 158 * </p><p> 159 * Creating a secure virtual display requires the 160 * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission. 161 * This permission is reserved for use by system components and is not available to 162 * third-party applications. 163 * </p> 164 * 165 * <h3>Non-secure virtual displays</h3> 166 * <p> 167 * When this flag is not set, the virtual display is considered unsecure. 168 * The content of secure windows will be blanked if shown on this display. 169 * </p> 170 * 171 * @see Display#FLAG_SECURE 172 * @see #createVirtualDisplay 173 */ 174 public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2; 175 176 /** 177 * Virtual display flag: Only show this display's own content; do not mirror 178 * the content of another display. 179 * 180 * <p> 181 * This flag is used in conjunction with {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}. 182 * Ordinarily public virtual displays will automatically mirror the content of the 183 * default display if they have no windows of their own. When this flag is 184 * specified, the virtual display will only ever show its own content and 185 * will be blanked instead if it has no windows. 186 * </p> 187 * 188 * <p> 189 * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. If both 190 * flags are specified then the own-content only behavior will be applied. 191 * </p> 192 * 193 * <p> 194 * This behavior of this flag is implied whenever neither {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC} 195 * nor {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} have been set. This flag is only required to 196 * override the default behavior when creating a public display. 197 * </p> 198 * 199 * @see #createVirtualDisplay 200 */ 201 public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3; 202 203 204 /** 205 * Virtual display flag: Allows content to be mirrored on private displays when no content is 206 * being shown. 207 * 208 * <p> 209 * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}. 210 * If both flags are specified then the own-content only behavior will be applied. 211 * </p> 212 * 213 * <p> 214 * The behavior of this flag is implied whenever {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC} is set 215 * and {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY} has not been set. This flag is only 216 * required to override the default behavior when creating a private display. 217 * </p> 218 * 219 * <p> 220 * Creating an auto-mirroing virtual display requires the 221 * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT} 222 * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission. 223 * These permissions are reserved for use by system components and are not available to 224 * third-party applications. 225 * 226 * Alternatively, an appropriate {@link MediaProjection} may be used to create an 227 * auto-mirroring virtual display. 228 * </p> 229 * 230 * @see #createVirtualDisplay 231 */ 232 public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4; 233 234 /** 235 * Virtual display flag: Allows content to be displayed on private virtual displays when 236 * keyguard is shown but is insecure. 237 * 238 * <p> 239 * This flag can only be applied to private displays as defined by the 240 * {@link Display#FLAG_PRIVATE} display flag. It is mutually exclusive with 241 * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}. If both flags are specified then this flag's behavior 242 * will not be applied. 243 * </p> 244 * 245 * @see #createVirtualDisplay 246 * @hide 247 */ 248 public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5; 249 250 /** 251 * Virtual display flag: Specifies that the virtual display can be associated with a 252 * touchpad device that matches its uniqueId. 253 * 254 * @see #createVirtualDisplay 255 * @hide 256 */ 257 public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6; 258 259 /** @hide */ DisplayManager(Context context)260 public DisplayManager(Context context) { 261 mContext = context; 262 mGlobal = DisplayManagerGlobal.getInstance(); 263 } 264 265 /** 266 * Gets information about a logical display. 267 * 268 * The display metrics may be adjusted to provide compatibility 269 * for legacy applications. 270 * 271 * @param displayId The logical display id. 272 * @return The display object, or null if there is no valid display with the given id. 273 */ getDisplay(int displayId)274 public Display getDisplay(int displayId) { 275 synchronized (mLock) { 276 return getOrCreateDisplayLocked(displayId, false /*assumeValid*/); 277 } 278 } 279 280 /** 281 * Gets all currently valid logical displays. 282 * 283 * @return An array containing all displays. 284 */ getDisplays()285 public Display[] getDisplays() { 286 return getDisplays(null); 287 } 288 289 /** 290 * Gets all currently valid logical displays of the specified category. 291 * <p> 292 * When there are multiple displays in a category the returned displays are sorted 293 * of preference. For example, if the requested category is 294 * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays 295 * then the displays are sorted so that the first display in the returned array 296 * is the most preferred presentation display. The application may simply 297 * use the first display or allow the user to choose. 298 * </p> 299 * 300 * @param category The requested display category or null to return all displays. 301 * @return An array containing all displays sorted by order of preference. 302 * 303 * @see #DISPLAY_CATEGORY_PRESENTATION 304 */ getDisplays(String category)305 public Display[] getDisplays(String category) { 306 final int[] displayIds = mGlobal.getDisplayIds(); 307 synchronized (mLock) { 308 try { 309 if (category == null) { 310 addAllDisplaysLocked(mTempDisplays, displayIds); 311 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) { 312 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI); 313 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI); 314 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY); 315 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL); 316 } 317 return mTempDisplays.toArray(new Display[mTempDisplays.size()]); 318 } finally { 319 mTempDisplays.clear(); 320 } 321 } 322 } 323 addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds)324 private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) { 325 for (int i = 0; i < displayIds.length; i++) { 326 Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); 327 if (display != null) { 328 displays.add(display); 329 } 330 } 331 } 332 addPresentationDisplaysLocked( ArrayList<Display> displays, int[] displayIds, int matchType)333 private void addPresentationDisplaysLocked( 334 ArrayList<Display> displays, int[] displayIds, int matchType) { 335 for (int i = 0; i < displayIds.length; i++) { 336 Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); 337 if (display != null 338 && (display.getFlags() & Display.FLAG_PRESENTATION) != 0 339 && display.getType() == matchType) { 340 displays.add(display); 341 } 342 } 343 } 344 getOrCreateDisplayLocked(int displayId, boolean assumeValid)345 private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { 346 Display display = mDisplays.get(displayId); 347 if (display == null) { 348 // TODO: We cannot currently provide any override configurations for metrics on displays 349 // other than the display the context is associated with. 350 final Context context = mContext.getDisplay().getDisplayId() == displayId 351 ? mContext : mContext.getApplicationContext(); 352 353 display = mGlobal.getCompatibleDisplay(displayId, context.getResources()); 354 if (display != null) { 355 mDisplays.put(displayId, display); 356 } 357 } else if (!assumeValid && !display.isValid()) { 358 display = null; 359 } 360 return display; 361 } 362 363 /** 364 * Registers an display listener to receive notifications about when 365 * displays are added, removed or changed. 366 * 367 * @param listener The listener to register. 368 * @param handler The handler on which the listener should be invoked, or null 369 * if the listener should be invoked on the calling thread's looper. 370 * 371 * @see #unregisterDisplayListener 372 */ registerDisplayListener(DisplayListener listener, Handler handler)373 public void registerDisplayListener(DisplayListener listener, Handler handler) { 374 mGlobal.registerDisplayListener(listener, handler); 375 } 376 377 /** 378 * Unregisters a display listener. 379 * 380 * @param listener The listener to unregister. 381 * 382 * @see #registerDisplayListener 383 */ unregisterDisplayListener(DisplayListener listener)384 public void unregisterDisplayListener(DisplayListener listener) { 385 mGlobal.unregisterDisplayListener(listener); 386 } 387 388 /** 389 * Starts scanning for available Wifi displays. 390 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 391 * <p> 392 * Calls to this method nest and must be matched by an equal number of calls to 393 * {@link #stopWifiDisplayScan()}. 394 * </p><p> 395 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 396 * </p> 397 * 398 * @hide 399 */ startWifiDisplayScan()400 public void startWifiDisplayScan() { 401 mGlobal.startWifiDisplayScan(); 402 } 403 404 /** 405 * Stops scanning for available Wifi displays. 406 * <p> 407 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 408 * </p> 409 * 410 * @hide 411 */ stopWifiDisplayScan()412 public void stopWifiDisplayScan() { 413 mGlobal.stopWifiDisplayScan(); 414 } 415 416 /** 417 * Connects to a Wifi display. 418 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 419 * <p> 420 * Automatically remembers the display after a successful connection, if not 421 * already remembered. 422 * </p><p> 423 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 424 * </p> 425 * 426 * @param deviceAddress The MAC address of the device to which we should connect. 427 * @hide 428 */ connectWifiDisplay(String deviceAddress)429 public void connectWifiDisplay(String deviceAddress) { 430 mGlobal.connectWifiDisplay(deviceAddress); 431 } 432 433 /** @hide */ pauseWifiDisplay()434 public void pauseWifiDisplay() { 435 mGlobal.pauseWifiDisplay(); 436 } 437 438 /** @hide */ resumeWifiDisplay()439 public void resumeWifiDisplay() { 440 mGlobal.resumeWifiDisplay(); 441 } 442 443 /** 444 * Disconnects from the current Wifi display. 445 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 446 * @hide 447 */ disconnectWifiDisplay()448 public void disconnectWifiDisplay() { 449 mGlobal.disconnectWifiDisplay(); 450 } 451 452 /** 453 * Renames a Wifi display. 454 * <p> 455 * The display must already be remembered for this call to succeed. In other words, 456 * we must already have successfully connected to the display at least once and then 457 * not forgotten it. 458 * </p><p> 459 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 460 * </p> 461 * 462 * @param deviceAddress The MAC address of the device to rename. 463 * @param alias The alias name by which to remember the device, or null 464 * or empty if no alias should be used. 465 * @hide 466 */ renameWifiDisplay(String deviceAddress, String alias)467 public void renameWifiDisplay(String deviceAddress, String alias) { 468 mGlobal.renameWifiDisplay(deviceAddress, alias); 469 } 470 471 /** 472 * Forgets a previously remembered Wifi display. 473 * <p> 474 * Automatically disconnects from the display if currently connected to it. 475 * </p><p> 476 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 477 * </p> 478 * 479 * @param deviceAddress The MAC address of the device to forget. 480 * @hide 481 */ forgetWifiDisplay(String deviceAddress)482 public void forgetWifiDisplay(String deviceAddress) { 483 mGlobal.forgetWifiDisplay(deviceAddress); 484 } 485 486 /** 487 * Gets the current Wifi display status. 488 * Watch for changes in the status by registering a broadcast receiver for 489 * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}. 490 * 491 * @return The current Wifi display status. 492 * @hide 493 */ getWifiDisplayStatus()494 public WifiDisplayStatus getWifiDisplayStatus() { 495 return mGlobal.getWifiDisplayStatus(); 496 } 497 498 /** 499 * Creates a virtual display. 500 * 501 * @see #createVirtualDisplay(String, int, int, int, Surface, int, 502 * VirtualDisplay.Callback, Handler) 503 */ createVirtualDisplay(@onNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags)504 public VirtualDisplay createVirtualDisplay(@NonNull String name, 505 int width, int height, int densityDpi, @Nullable Surface surface, int flags) { 506 return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null); 507 } 508 509 /** 510 * Creates a virtual display. 511 * <p> 512 * The content of a virtual display is rendered to a {@link Surface} provided 513 * by the application. 514 * </p><p> 515 * The virtual display should be {@link VirtualDisplay#release released} 516 * when no longer needed. Because a virtual display renders to a surface 517 * provided by the application, it will be released automatically when the 518 * process terminates and all remaining windows on it will be forcibly removed. 519 * </p><p> 520 * The behavior of the virtual display depends on the flags that are provided 521 * to this method. By default, virtual displays are created to be private, 522 * non-presentation and unsecure. Permissions may be required to use certain flags. 523 * </p><p> 524 * As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may 525 * be attached or detached dynamically using {@link VirtualDisplay#setSurface}. 526 * Previously, the surface had to be non-null when {@link #createVirtualDisplay} 527 * was called and could not be changed for the lifetime of the display. 528 * </p><p> 529 * Detaching the surface that backs a virtual display has a similar effect to 530 * turning off the screen. 531 * </p> 532 * 533 * @param name The name of the virtual display, must be non-empty. 534 * @param width The width of the virtual display in pixels, must be greater than 0. 535 * @param height The height of the virtual display in pixels, must be greater than 0. 536 * @param densityDpi The density of the virtual display in dpi, must be greater than 0. 537 * @param surface The surface to which the content of the virtual display should 538 * be rendered, or null if there is none initially. 539 * @param flags A combination of virtual display flags: 540 * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}, 541 * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}, 542 * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. 543 * @param callback Callback to call when the state of the {@link VirtualDisplay} changes 544 * @param handler The handler on which the listener should be invoked, or null 545 * if the listener should be invoked on the calling thread's looper. 546 * @return The newly created virtual display, or null if the application could 547 * not create the virtual display. 548 * 549 * @throws SecurityException if the caller does not have permission to create 550 * a virtual display with the specified flags. 551 */ createVirtualDisplay(@onNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler)552 public VirtualDisplay createVirtualDisplay(@NonNull String name, 553 int width, int height, int densityDpi, @Nullable Surface surface, int flags, 554 @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { 555 return createVirtualDisplay(null /* projection */, name, width, height, densityDpi, surface, 556 flags, callback, handler, null /* uniqueId */); 557 } 558 559 /** @hide */ createVirtualDisplay(@ullable MediaProjection projection, @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, @Nullable String uniqueId)560 public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, 561 @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, 562 int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, 563 @Nullable String uniqueId) { 564 return mGlobal.createVirtualDisplay(mContext, projection, 565 name, width, height, densityDpi, surface, flags, callback, handler, uniqueId); 566 } 567 568 /** 569 * Listens for changes in available display devices. 570 */ 571 public interface DisplayListener { 572 /** 573 * Called whenever a logical display has been added to the system. 574 * Use {@link DisplayManager#getDisplay} to get more information about 575 * the display. 576 * 577 * @param displayId The id of the logical display that was added. 578 */ onDisplayAdded(int displayId)579 void onDisplayAdded(int displayId); 580 581 /** 582 * Called whenever a logical display has been removed from the system. 583 * 584 * @param displayId The id of the logical display that was removed. 585 */ onDisplayRemoved(int displayId)586 void onDisplayRemoved(int displayId); 587 588 /** 589 * Called whenever the properties of a logical display have changed. 590 * 591 * @param displayId The id of the logical display that changed. 592 */ onDisplayChanged(int displayId)593 void onDisplayChanged(int displayId); 594 } 595 } 596