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.content.Context; 20 import android.os.Handler; 21 import android.util.SparseArray; 22 import android.view.Display; 23 import android.view.Surface; 24 25 import 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 */ 36 public 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 */ 119 public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0; 120 121 /** 122 * Virtual display flag: Create a presentation display. 123 * 124 * <h3>Presentation virtual displays</h3> 125 * <p> 126 * When this flag is set, the virtual display is registered as a presentation 127 * display in the {@link #DISPLAY_CATEGORY_PRESENTATION presentation display category}. 128 * Applications may automatically project their content to presentation displays 129 * to provide richer second screen experiences. 130 * </p> 131 * 132 * <h3>Non-presentation virtual displays</h3> 133 * <p> 134 * When this flag is not set, the virtual display is not registered as a presentation 135 * display. Applications can still project their content on the display but they 136 * will typically not do so automatically. This option is appropriate for 137 * more special-purpose displays. 138 * </p> 139 * 140 * @see android.app.Presentation 141 * @see #createVirtualDisplay 142 * @see #DISPLAY_CATEGORY_PRESENTATION 143 * @see Display#FLAG_PRESENTATION 144 */ 145 public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1; 146 147 /** 148 * Virtual display flag: Create a secure display. 149 * 150 * <h3>Secure virtual displays</h3> 151 * <p> 152 * When this flag is set, the virtual display is considered secure as defined 153 * by the {@link Display#FLAG_SECURE} display flag. The caller promises to take 154 * reasonable measures, such as over-the-air encryption, to prevent the contents 155 * of the display from being intercepted or recorded on a persistent medium. 156 * </p><p> 157 * Creating a secure virtual display requires the 158 * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission. 159 * This permission is reserved for use by system components and is not available to 160 * third-party applications. 161 * </p> 162 * 163 * <h3>Non-secure virtual displays</h3> 164 * <p> 165 * When this flag is not set, the virtual display is considered unsecure. 166 * The content of secure windows will be blanked if shown on this display. 167 * </p> 168 * 169 * @see Display#FLAG_SECURE 170 * @see #createVirtualDisplay 171 */ 172 public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2; 173 174 /** @hide */ 175 public DisplayManager(Context context) { 176 mContext = context; 177 mGlobal = DisplayManagerGlobal.getInstance(); 178 } 179 180 /** 181 * Gets information about a logical display. 182 * 183 * The display metrics may be adjusted to provide compatibility 184 * for legacy applications. 185 * 186 * @param displayId The logical display id. 187 * @return The display object, or null if there is no valid display with the given id. 188 */ 189 public Display getDisplay(int displayId) { 190 synchronized (mLock) { 191 return getOrCreateDisplayLocked(displayId, false /*assumeValid*/); 192 } 193 } 194 195 /** 196 * Gets all currently valid logical displays. 197 * 198 * @return An array containing all displays. 199 */ 200 public Display[] getDisplays() { 201 return getDisplays(null); 202 } 203 204 /** 205 * Gets all currently valid logical displays of the specified category. 206 * <p> 207 * When there are multiple displays in a category the returned displays are sorted 208 * of preference. For example, if the requested category is 209 * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays 210 * then the displays are sorted so that the first display in the returned array 211 * is the most preferred presentation display. The application may simply 212 * use the first display or allow the user to choose. 213 * </p> 214 * 215 * @param category The requested display category or null to return all displays. 216 * @return An array containing all displays sorted by order of preference. 217 * 218 * @see #DISPLAY_CATEGORY_PRESENTATION 219 */ 220 public Display[] getDisplays(String category) { 221 final int[] displayIds = mGlobal.getDisplayIds(); 222 synchronized (mLock) { 223 try { 224 if (category == null) { 225 addAllDisplaysLocked(mTempDisplays, displayIds); 226 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) { 227 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI); 228 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI); 229 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY); 230 addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL); 231 } 232 return mTempDisplays.toArray(new Display[mTempDisplays.size()]); 233 } finally { 234 mTempDisplays.clear(); 235 } 236 } 237 } 238 239 private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) { 240 for (int i = 0; i < displayIds.length; i++) { 241 Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); 242 if (display != null) { 243 displays.add(display); 244 } 245 } 246 } 247 248 private void addPresentationDisplaysLocked( 249 ArrayList<Display> displays, int[] displayIds, int matchType) { 250 for (int i = 0; i < displayIds.length; i++) { 251 Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); 252 if (display != null 253 && (display.getFlags() & Display.FLAG_PRESENTATION) != 0 254 && display.getType() == matchType) { 255 displays.add(display); 256 } 257 } 258 } 259 260 private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { 261 Display display = mDisplays.get(displayId); 262 if (display == null) { 263 display = mGlobal.getCompatibleDisplay(displayId, 264 mContext.getDisplayAdjustments(displayId)); 265 if (display != null) { 266 mDisplays.put(displayId, display); 267 } 268 } else if (!assumeValid && !display.isValid()) { 269 display = null; 270 } 271 return display; 272 } 273 274 /** 275 * Registers an display listener to receive notifications about when 276 * displays are added, removed or changed. 277 * 278 * @param listener The listener to register. 279 * @param handler The handler on which the listener should be invoked, or null 280 * if the listener should be invoked on the calling thread's looper. 281 * 282 * @see #unregisterDisplayListener 283 */ 284 public void registerDisplayListener(DisplayListener listener, Handler handler) { 285 mGlobal.registerDisplayListener(listener, handler); 286 } 287 288 /** 289 * Unregisters an input device listener. 290 * 291 * @param listener The listener to unregister. 292 * 293 * @see #registerDisplayListener 294 */ 295 public void unregisterDisplayListener(DisplayListener listener) { 296 mGlobal.unregisterDisplayListener(listener); 297 } 298 299 /** 300 * Starts scanning for available Wifi displays. 301 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 302 * <p> 303 * Calls to this method nest and must be matched by an equal number of calls to 304 * {@link #stopWifiDisplayScan()}. 305 * </p><p> 306 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 307 * </p> 308 * 309 * @hide 310 */ 311 public void startWifiDisplayScan() { 312 mGlobal.startWifiDisplayScan(); 313 } 314 315 /** 316 * Stops scanning for available Wifi displays. 317 * <p> 318 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 319 * </p> 320 * 321 * @hide 322 */ 323 public void stopWifiDisplayScan() { 324 mGlobal.stopWifiDisplayScan(); 325 } 326 327 /** 328 * Connects to a Wifi display. 329 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 330 * <p> 331 * Automatically remembers the display after a successful connection, if not 332 * already remembered. 333 * </p><p> 334 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 335 * </p> 336 * 337 * @param deviceAddress The MAC address of the device to which we should connect. 338 * @hide 339 */ 340 public void connectWifiDisplay(String deviceAddress) { 341 mGlobal.connectWifiDisplay(deviceAddress); 342 } 343 344 /** @hide */ 345 public void pauseWifiDisplay() { 346 mGlobal.pauseWifiDisplay(); 347 } 348 349 /** @hide */ 350 public void resumeWifiDisplay() { 351 mGlobal.resumeWifiDisplay(); 352 } 353 354 /** 355 * Disconnects from the current Wifi display. 356 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 357 * @hide 358 */ 359 public void disconnectWifiDisplay() { 360 mGlobal.disconnectWifiDisplay(); 361 } 362 363 /** 364 * Renames a Wifi display. 365 * <p> 366 * The display must already be remembered for this call to succeed. In other words, 367 * we must already have successfully connected to the display at least once and then 368 * not forgotten it. 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 rename. 374 * @param alias The alias name by which to remember the device, or null 375 * or empty if no alias should be used. 376 * @hide 377 */ 378 public void renameWifiDisplay(String deviceAddress, String alias) { 379 mGlobal.renameWifiDisplay(deviceAddress, alias); 380 } 381 382 /** 383 * Forgets a previously remembered Wifi display. 384 * <p> 385 * Automatically disconnects from the display if currently connected to 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 forget. 391 * @hide 392 */ 393 public void forgetWifiDisplay(String deviceAddress) { 394 mGlobal.forgetWifiDisplay(deviceAddress); 395 } 396 397 /** 398 * Gets the current Wifi display status. 399 * Watch for changes in the status by registering a broadcast receiver for 400 * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}. 401 * 402 * @return The current Wifi display status. 403 * @hide 404 */ 405 public WifiDisplayStatus getWifiDisplayStatus() { 406 return mGlobal.getWifiDisplayStatus(); 407 } 408 409 /** 410 * Creates a virtual display. 411 * <p> 412 * The content of a virtual display is rendered to a {@link Surface} provided 413 * by the application. 414 * </p><p> 415 * The virtual display should be {@link VirtualDisplay#release released} 416 * when no longer needed. Because a virtual display renders to a surface 417 * provided by the application, it will be released automatically when the 418 * process terminates and all remaining windows on it will be forcibly removed. 419 * </p><p> 420 * The behavior of the virtual display depends on the flags that are provided 421 * to this method. By default, virtual displays are created to be private, 422 * non-presentation and unsecure. Permissions may be required to use certain flags. 423 * </p> 424 * 425 * @param name The name of the virtual display, must be non-empty. 426 * @param width The width of the virtual display in pixels, must be greater than 0. 427 * @param height The height of the virtual display in pixels, must be greater than 0. 428 * @param densityDpi The density of the virtual display in dpi, must be greater than 0. 429 * @param surface The surface to which the content of the virtual display should 430 * be rendered, must be non-null. 431 * @param flags A combination of virtual display flags: 432 * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION} 433 * or {@link #VIRTUAL_DISPLAY_FLAG_SECURE}. 434 * @return The newly created virtual display, or null if the application could 435 * not create the virtual display. 436 * 437 * @throws SecurityException if the caller does not have permission to create 438 * a virtual display with the specified flags. 439 */ 440 public VirtualDisplay createVirtualDisplay(String name, 441 int width, int height, int densityDpi, Surface surface, int flags) { 442 return mGlobal.createVirtualDisplay(mContext, 443 name, width, height, densityDpi, surface, flags); 444 } 445 446 /** 447 * Listens for changes in available display devices. 448 */ 449 public interface DisplayListener { 450 /** 451 * Called whenever a logical display has been added to the system. 452 * Use {@link DisplayManager#getDisplay} to get more information about 453 * the display. 454 * 455 * @param displayId The id of the logical display that was added. 456 */ 457 void onDisplayAdded(int displayId); 458 459 /** 460 * Called whenever a logical display has been removed from the system. 461 * 462 * @param displayId The id of the logical display that was removed. 463 */ 464 void onDisplayRemoved(int displayId); 465 466 /** 467 * Called whenever the properties of a logical display have changed. 468 * 469 * @param displayId The id of the logical display that changed. 470 */ 471 void onDisplayChanged(int displayId); 472 } 473 } 474