blob: 9e2e4ba11f5633a4c01b51b389c29348b7112bd5 [file] [log] [blame]
Jeff Brownfa25bf52012-07-23 19:26:30 -07001/*
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;
Jeff Brown98365d72012-08-19 20:30:52 -070020import android.os.Handler;
Jeff Brownbd6e1502012-08-28 03:27:37 -070021import android.util.SparseArray;
Jeff Brown98365d72012-08-19 20:30:52 -070022import android.view.Display;
Jeff Browna506a6e2013-06-04 00:02:38 -070023import android.view.Surface;
Jeff Brown98365d72012-08-19 20:30:52 -070024
Jeff Brown92130f62012-10-24 21:28:33 -070025import java.util.ArrayList;
26
Jeff Brownfa25bf52012-07-23 19:26:30 -070027/**
Jeff Brownbd6e1502012-08-28 03:27:37 -070028 * Manages the properties of attached displays.
Jeff Brownfa25bf52012-07-23 19:26:30 -070029 * <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";
Jeff Brown98365d72012-08-19 20:30:52 -070038 private static final boolean DEBUG = false;
39
Jeff Brownbd6e1502012-08-28 03:27:37 -070040 private final Context mContext;
41 private final DisplayManagerGlobal mGlobal;
Jeff Brownfa25bf52012-07-23 19:26:30 -070042
Jeff Brownbd6e1502012-08-28 03:27:37 -070043 private final Object mLock = new Object();
44 private final SparseArray<Display> mDisplays = new SparseArray<Display>();
Jeff Brownfa25bf52012-07-23 19:26:30 -070045
Jeff Brown92130f62012-10-24 21:28:33 -070046 private final ArrayList<Display> mTempDisplays = new ArrayList<Display>();
47
Jeff Browne08ae382012-09-07 20:36:36 -070048 /**
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>
Jeff Brownbc335452012-09-26 18:34:47 -070054 * This broadcast is only sent to registered receivers and can only be sent by the system.
Jeff Browne08ae382012-09-07 20:36:36 -070055 * </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
Jeff Brown92130f62012-10-24 21:28:33 -070068 /**
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
Jeff Brownbd6e1502012-08-28 03:27:37 -070082 /** @hide */
83 public DisplayManager(Context context) {
84 mContext = context;
85 mGlobal = DisplayManagerGlobal.getInstance();
Jeff Brownfa25bf52012-07-23 19:26:30 -070086 }
87
88 /**
Jeff Brownbd6e1502012-08-28 03:27:37 -070089 * Gets information about a logical display.
Jeff Brown848c2dc2012-08-19 20:18:08 -070090 *
Jeff Brownbd6e1502012-08-28 03:27:37 -070091 * The display metrics may be adjusted to provide compatibility
92 * for legacy applications.
Jeff Brown848c2dc2012-08-19 20:18:08 -070093 *
Jeff Brownbd6e1502012-08-28 03:27:37 -070094 * @param displayId The logical display id.
95 * @return The display object, or null if there is no valid display with the given id.
Jeff Brownfa25bf52012-07-23 19:26:30 -070096 */
Jeff Brownbd6e1502012-08-28 03:27:37 -070097 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() {
Jeff Brown92130f62012-10-24 21:28:33 -0700109 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();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700130 synchronized (mLock) {
Jeff Brown92130f62012-10-24 21:28:33 -0700131 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);
Jeff Browna506a6e2013-06-04 00:02:38 -0700138 addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
Jeff Brown848c2dc2012-08-19 20:18:08 -0700139 }
Jeff Brown92130f62012-10-24 21:28:33 -0700140 return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
141 } finally {
142 mTempDisplays.clear();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700143 }
Jeff Brownfa25bf52012-07-23 19:26:30 -0700144 }
Jeff Brown92130f62012-10-24 21:28:33 -0700145 }
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 }
Jeff Brownfa25bf52012-07-23 19:26:30 -0700156 }
157
Jeff Brownbd6e1502012-08-28 03:27:37 -0700158 private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
159 Display display = mDisplays.get(displayId);
160 if (display == null) {
161 display = mGlobal.getCompatibleDisplay(displayId,
Craig Mautner48d0d182013-06-11 07:53:06 -0700162 mContext.getDisplayAdjustments(displayId));
Jeff Brownbd6e1502012-08-28 03:27:37 -0700163 if (display != null) {
164 mDisplays.put(displayId, display);
165 }
166 } else if (!assumeValid && !display.isValid()) {
167 display = null;
Jeff Brownfa25bf52012-07-23 19:26:30 -0700168 }
Jeff Brownbd6e1502012-08-28 03:27:37 -0700169 return display;
Jeff Brownfa25bf52012-07-23 19:26:30 -0700170 }
Jeff Brown98365d72012-08-19 20:30:52 -0700171
Jeff Brown98365d72012-08-19 20:30:52 -0700172 /**
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) {
Jeff Brownbd6e1502012-08-28 03:27:37 -0700183 mGlobal.registerDisplayListener(listener, handler);
Jeff Brown98365d72012-08-19 20:30:52 -0700184 }
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) {
Jeff Brownbd6e1502012-08-28 03:27:37 -0700194 mGlobal.unregisterDisplayListener(listener);
Jeff Brown98365d72012-08-19 20:30:52 -0700195 }
196
197 /**
Jeff Browne08ae382012-09-07 20:36:36 -0700198 * 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.
Jeff Brown89d55462012-09-19 11:33:42 -0700209 * <p>
210 * Automatically remembers the display after a successful connection, if not
211 * already remembered.
Jeff Brownbc335452012-09-26 18:34:47 -0700212 * </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.
Jeff Brown89d55462012-09-19 11:33:42 -0700215 * </p>
Jeff Browne08ae382012-09-07 20:36:36 -0700216 *
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 /**
Jeff Brown89d55462012-09-19 11:33:42 -0700234 * 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.
Jeff Brownbc335452012-09-26 18:34:47 -0700239 * </p><p>
240 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
Jeff Brown89d55462012-09-19 11:33:42 -0700241 * </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.
Jeff Brownbc335452012-09-26 18:34:47 -0700256 * </p><p>
257 * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
Jeff Brown89d55462012-09-19 11:33:42 -0700258 * </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 /**
Jeff Browne08ae382012-09-07 20:36:36 -0700268 * 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 /**
Jeff Browna506a6e2013-06-04 00:02:38 -0700280 * 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 /**
Jeff Brown98365d72012-08-19 20:30:52 -0700315 * 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.
Jeff Brownbd6e1502012-08-28 03:27:37 -0700320 * Use {@link DisplayManager#getDisplay} to get more information about
321 * the display.
Jeff Brown98365d72012-08-19 20:30:52 -0700322 *
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 }
Jeff Brownfa25bf52012-07-23 19:26:30 -0700341}