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