DisplayManager.java revision a506a6ec94863a35acca9feb165db76ddac3892c
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. 73 * </p> 74 * 75 * @see android.app.Presentation for information about presenting content 76 * on secondary displays. 77 * @see #getDisplays(String) 78 */ 79 public static final String DISPLAY_CATEGORY_PRESENTATION = 80 "android.hardware.display.category.PRESENTATION"; 81 82 /** @hide */ 83 public DisplayManager(Context context) { 84 mContext = context; 85 mGlobal = DisplayManagerGlobal.getInstance(); 86 } 87 88 /** 89 * Gets information about a logical display. 90 * 91 * The display metrics may be adjusted to provide compatibility 92 * for legacy applications. 93 * 94 * @param displayId The logical display id. 95 * @return The display object, or null if there is no valid display with the given id. 96 */ 97 public Display getDisplay(int displayId) { 98 synchronized (mLock) { 99 return getOrCreateDisplayLocked(displayId, false /*assumeValid*/); 100 } 101 } 102 103 /** 104 * Gets all currently valid logical displays. 105 * 106 * @return An array containing all displays. 107 */ 108 public Display[] getDisplays() { 109 return getDisplays(null); 110 } 111 112 /** 113 * Gets all currently valid logical displays of the specified category. 114 * <p> 115 * When there are multiple displays in a category the returned displays are sorted 116 * of preference. For example, if the requested category is 117 * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays 118 * then the displays are sorted so that the first display in the returned array 119 * is the most preferred presentation display. The application may simply 120 * use the first display or allow the user to choose. 121 * </p> 122 * 123 * @param category The requested display category or null to return all displays. 124 * @return An array containing all displays sorted by order of preference. 125 * 126 * @see #DISPLAY_CATEGORY_PRESENTATION 127 */ 128 public Display[] getDisplays(String category) { 129 final int[] displayIds = mGlobal.getDisplayIds(); 130 synchronized (mLock) { 131 try { 132 if (category == null) { 133 addMatchingDisplaysLocked(mTempDisplays, displayIds, -1); 134 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) { 135 addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI); 136 addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI); 137 addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY); 138 addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL); 139 } 140 return mTempDisplays.toArray(new Display[mTempDisplays.size()]); 141 } finally { 142 mTempDisplays.clear(); 143 } 144 } 145 } 146 147 private void addMatchingDisplaysLocked( 148 ArrayList<Display> displays, int[] displayIds, int matchType) { 149 for (int i = 0; i < displayIds.length; i++) { 150 Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); 151 if (display != null 152 && (matchType < 0 || display.getType() == matchType)) { 153 displays.add(display); 154 } 155 } 156 } 157 158 private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { 159 Display display = mDisplays.get(displayId); 160 if (display == null) { 161 display = mGlobal.getCompatibleDisplay(displayId, 162 mContext.getCompatibilityInfo(displayId)); 163 if (display != null) { 164 mDisplays.put(displayId, display); 165 } 166 } else if (!assumeValid && !display.isValid()) { 167 display = null; 168 } 169 return display; 170 } 171 172 /** 173 * Registers an display listener to receive notifications about when 174 * displays are added, removed or changed. 175 * 176 * @param listener The listener to register. 177 * @param handler The handler on which the listener should be invoked, or null 178 * if the listener should be invoked on the calling thread's looper. 179 * 180 * @see #unregisterDisplayListener 181 */ 182 public void registerDisplayListener(DisplayListener listener, Handler handler) { 183 mGlobal.registerDisplayListener(listener, handler); 184 } 185 186 /** 187 * Unregisters an input device listener. 188 * 189 * @param listener The listener to unregister. 190 * 191 * @see #registerDisplayListener 192 */ 193 public void unregisterDisplayListener(DisplayListener listener) { 194 mGlobal.unregisterDisplayListener(listener); 195 } 196 197 /** 198 * Initiates a fresh scan of availble Wifi displays. 199 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 200 * @hide 201 */ 202 public void scanWifiDisplays() { 203 mGlobal.scanWifiDisplays(); 204 } 205 206 /** 207 * Connects to a Wifi display. 208 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 209 * <p> 210 * Automatically remembers the display after a successful connection, if not 211 * already remembered. 212 * </p><p> 213 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect 214 * to unknown displays. No permissions are required to connect to already known displays. 215 * </p> 216 * 217 * @param deviceAddress The MAC address of the device to which we should connect. 218 * @hide 219 */ 220 public void connectWifiDisplay(String deviceAddress) { 221 mGlobal.connectWifiDisplay(deviceAddress); 222 } 223 224 /** 225 * Disconnects from the current Wifi display. 226 * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. 227 * @hide 228 */ 229 public void disconnectWifiDisplay() { 230 mGlobal.disconnectWifiDisplay(); 231 } 232 233 /** 234 * Renames a Wifi display. 235 * <p> 236 * The display must already be remembered for this call to succeed. In other words, 237 * we must already have successfully connected to the display at least once and then 238 * not forgotten it. 239 * </p><p> 240 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 241 * </p> 242 * 243 * @param deviceAddress The MAC address of the device to rename. 244 * @param alias The alias name by which to remember the device, or null 245 * or empty if no alias should be used. 246 * @hide 247 */ 248 public void renameWifiDisplay(String deviceAddress, String alias) { 249 mGlobal.renameWifiDisplay(deviceAddress, alias); 250 } 251 252 /** 253 * Forgets a previously remembered Wifi display. 254 * <p> 255 * Automatically disconnects from the display if currently connected to it. 256 * </p><p> 257 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. 258 * </p> 259 * 260 * @param deviceAddress The MAC address of the device to forget. 261 * @hide 262 */ 263 public void forgetWifiDisplay(String deviceAddress) { 264 mGlobal.forgetWifiDisplay(deviceAddress); 265 } 266 267 /** 268 * Gets the current Wifi display status. 269 * Watch for changes in the status by registering a broadcast receiver for 270 * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}. 271 * 272 * @return The current Wifi display status. 273 * @hide 274 */ 275 public WifiDisplayStatus getWifiDisplayStatus() { 276 return mGlobal.getWifiDisplayStatus(); 277 } 278 279 /** 280 * Creates a private virtual display. 281 * <p> 282 * The content of a virtual display is rendered to a {@link Surface} provided 283 * by the application that created the virtual display. 284 * </p><p> 285 * Only the application that created a private virtual display is allowed to 286 * place windows upon it. The private virtual display also does not participate 287 * in display mirroring: it will neither receive mirrored content from another 288 * display nor allow its own content to be mirrored elsewhere. More precisely, 289 * the only processes that are allowed to enumerate or interact with a private 290 * display are those that have the same UID as the application that originally 291 * created the private virtual display. 292 * </p><p> 293 * The private virtual display should be {@link VirtualDisplay#release released} 294 * when no longer needed. Because a private virtual display renders to a surface 295 * provided by the application, it will be released automatically when the 296 * process terminates and all remaining windows on it will be forcibly removed. 297 * </p> 298 * 299 * @param name The name of the virtual display, must be non-empty. 300 * @param width The width of the virtual display in pixels, must be greater than 0. 301 * @param height The height of the virtual display in pixels, must be greater than 0. 302 * @param densityDpi The density of the virtual display in dpi, must be greater than 0. 303 * @param surface The surface to which the content of the virtual display should 304 * be rendered, must be non-null. 305 * @return The newly created virtual display, or null if the application could 306 * not create the virtual display. 307 */ 308 public VirtualDisplay createPrivateVirtualDisplay(String name, 309 int width, int height, int densityDpi, Surface surface) { 310 return mGlobal.createPrivateVirtualDisplay(mContext, 311 name, width, height, densityDpi, surface); 312 } 313 314 /** 315 * Listens for changes in available display devices. 316 */ 317 public interface DisplayListener { 318 /** 319 * Called whenever a logical display has been added to the system. 320 * Use {@link DisplayManager#getDisplay} to get more information about 321 * the display. 322 * 323 * @param displayId The id of the logical display that was added. 324 */ 325 void onDisplayAdded(int displayId); 326 327 /** 328 * Called whenever a logical display has been removed from the system. 329 * 330 * @param displayId The id of the logical display that was removed. 331 */ 332 void onDisplayRemoved(int displayId); 333 334 /** 335 * Called whenever the properties of a logical display have changed. 336 * 337 * @param displayId The id of the logical display that changed. 338 */ 339 void onDisplayChanged(int displayId); 340 } 341} 342