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