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