DisplayManager.java revision 7d00affce6e25b22fd8fc135933b3bf6b547a0dc
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 for information about presenting content
78     * on secondary displays.
79     * @see Display#FLAG_PRESENTATION
80     * @see #getDisplays(String)
81     */
82    public static final String DISPLAY_CATEGORY_PRESENTATION =
83            "android.hardware.display.category.PRESENTATION";
84
85    /**
86     * Virtual display flag: Create a public display.
87     *
88     * <h3>Public virtual displays</h3>
89     * <p>
90     * When this flag is set, the virtual display is public.
91     * </p><p>
92     * A public virtual display behaves just like most any other display that is connected
93     * to the system such as an HDMI or Wireless display.  Applications can open
94     * windows on the display and the system may mirror the contents of other displays
95     * onto it.
96     * </p><p>
97     * Creating a public virtual display requires the
98     * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
99     * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
100     * These permissions are reserved for use by system components and are not available to
101     * third-party applications.
102     * </p>
103     *
104     * <h3>Private virtual displays</h3>
105     * <p>
106     * When this flag is not set, the virtual display is private as defined by the
107     * {@link Display#FLAG_PRIVATE} display flag.
108     * </p>
109     * A private virtual display belongs to the application that created it.
110     * Only the a owner of a private virtual display is allowed to place windows upon it.
111     * The private virtual display also does not participate in display mirroring: it will
112     * neither receive mirrored content from another display nor allow its own content to
113     * be mirrored elsewhere.  More precisely, the only processes that are allowed to
114     * enumerate or interact with the private display are those that have the same UID as the
115     * application that originally created the private virtual display.
116      * </p>
117     *
118     * @see #createVirtualDisplay
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 for information about presenting content
142     * on secondary displays.
143     * @see #createVirtualDisplay
144     * @see #DISPLAY_CATEGORY_PRESENTATION
145     * @see Display#FLAG_PRESENTATION
146     */
147    public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1;
148
149    /**
150     * Virtual display flag: Create a secure display.
151     *
152     * <h3>Secure virtual displays</h3>
153     * <p>
154     * When this flag is set, the virtual display is considered secure as defined
155     * by the {@link Display#FLAG_SECURE} display flag.  The caller promises to take
156     * reasonable measures, such as over-the-air encryption, to prevent the contents
157     * of the display from being intercepted or recorded on a persistent medium.
158     * </p><p>
159     * Creating a secure virtual display requires the
160     * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
161     * This permission is reserved for use by system components and is not available to
162     * third-party applications.
163     * </p>
164     *
165     * <h3>Non-secure virtual displays</h3>
166     * <p>
167     * When this flag is not set, the virtual display is considered unsecure.
168     * The content of secure windows will be blanked if shown on this display.
169     * </p>
170     *
171     * @see Display#FLAG_SECURE for information about secure displays.
172     * @see #createVirtualDisplay
173     */
174    public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
175
176    /** @hide */
177    public DisplayManager(Context context) {
178        mContext = context;
179        mGlobal = DisplayManagerGlobal.getInstance();
180    }
181
182    /**
183     * Gets information about a logical display.
184     *
185     * The display metrics may be adjusted to provide compatibility
186     * for legacy applications.
187     *
188     * @param displayId The logical display id.
189     * @return The display object, or null if there is no valid display with the given id.
190     */
191    public Display getDisplay(int displayId) {
192        synchronized (mLock) {
193            return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
194        }
195    }
196
197    /**
198     * Gets all currently valid logical displays.
199     *
200     * @return An array containing all displays.
201     */
202    public Display[] getDisplays() {
203        return getDisplays(null);
204    }
205
206    /**
207     * Gets all currently valid logical displays of the specified category.
208     * <p>
209     * When there are multiple displays in a category the returned displays are sorted
210     * of preference.  For example, if the requested category is
211     * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays
212     * then the displays are sorted so that the first display in the returned array
213     * is the most preferred presentation display.  The application may simply
214     * use the first display or allow the user to choose.
215     * </p>
216     *
217     * @param category The requested display category or null to return all displays.
218     * @return An array containing all displays sorted by order of preference.
219     *
220     * @see #DISPLAY_CATEGORY_PRESENTATION
221     */
222    public Display[] getDisplays(String category) {
223        final int[] displayIds = mGlobal.getDisplayIds();
224        synchronized (mLock) {
225            try {
226                if (category == null) {
227                    addAllDisplaysLocked(mTempDisplays, displayIds);
228                } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
229                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
230                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
231                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
232                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
233                }
234                return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
235            } finally {
236                mTempDisplays.clear();
237            }
238        }
239    }
240
241    private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
242        for (int i = 0; i < displayIds.length; i++) {
243            Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
244            if (display != null) {
245                displays.add(display);
246            }
247        }
248    }
249
250    private void addPresentationDisplaysLocked(
251            ArrayList<Display> displays, int[] displayIds, int matchType) {
252        for (int i = 0; i < displayIds.length; i++) {
253            Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
254            if (display != null
255                    && (display.getFlags() & Display.FLAG_PRESENTATION) != 0
256                    && display.getType() == matchType) {
257                displays.add(display);
258            }
259        }
260    }
261
262    private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
263        Display display = mDisplays.get(displayId);
264        if (display == null) {
265            display = mGlobal.getCompatibleDisplay(displayId,
266                    mContext.getDisplayAdjustments(displayId));
267            if (display != null) {
268                mDisplays.put(displayId, display);
269            }
270        } else if (!assumeValid && !display.isValid()) {
271            display = null;
272        }
273        return display;
274    }
275
276    /**
277     * Registers an display listener to receive notifications about when
278     * displays are added, removed or changed.
279     *
280     * @param listener The listener to register.
281     * @param handler The handler on which the listener should be invoked, or null
282     * if the listener should be invoked on the calling thread's looper.
283     *
284     * @see #unregisterDisplayListener
285     */
286    public void registerDisplayListener(DisplayListener listener, Handler handler) {
287        mGlobal.registerDisplayListener(listener, handler);
288    }
289
290    /**
291     * Unregisters an input device listener.
292     *
293     * @param listener The listener to unregister.
294     *
295     * @see #registerDisplayListener
296     */
297    public void unregisterDisplayListener(DisplayListener listener) {
298        mGlobal.unregisterDisplayListener(listener);
299    }
300
301    /**
302     * Initiates a fresh scan of availble Wifi displays.
303     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
304     * @hide
305     */
306    public void scanWifiDisplays() {
307        mGlobal.scanWifiDisplays();
308    }
309
310    /**
311     * Connects to a Wifi display.
312     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
313     * <p>
314     * Automatically remembers the display after a successful connection, if not
315     * already remembered.
316     * </p><p>
317     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect
318     * to unknown displays.  No permissions are required to connect to already known displays.
319     * </p>
320     *
321     * @param deviceAddress The MAC address of the device to which we should connect.
322     * @hide
323     */
324    public void connectWifiDisplay(String deviceAddress) {
325        mGlobal.connectWifiDisplay(deviceAddress);
326    }
327
328    /**
329     * Disconnects from the current Wifi display.
330     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
331     * @hide
332     */
333    public void disconnectWifiDisplay() {
334        mGlobal.disconnectWifiDisplay();
335    }
336
337    /**
338     * Renames a Wifi display.
339     * <p>
340     * The display must already be remembered for this call to succeed.  In other words,
341     * we must already have successfully connected to the display at least once and then
342     * not forgotten it.
343     * </p><p>
344     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
345     * </p>
346     *
347     * @param deviceAddress The MAC address of the device to rename.
348     * @param alias The alias name by which to remember the device, or null
349     * or empty if no alias should be used.
350     * @hide
351     */
352    public void renameWifiDisplay(String deviceAddress, String alias) {
353        mGlobal.renameWifiDisplay(deviceAddress, alias);
354    }
355
356    /**
357     * Forgets a previously remembered Wifi display.
358     * <p>
359     * Automatically disconnects from the display if currently connected to it.
360     * </p><p>
361     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
362     * </p>
363     *
364     * @param deviceAddress The MAC address of the device to forget.
365     * @hide
366     */
367    public void forgetWifiDisplay(String deviceAddress) {
368        mGlobal.forgetWifiDisplay(deviceAddress);
369    }
370
371    /**
372     * Gets the current Wifi display status.
373     * Watch for changes in the status by registering a broadcast receiver for
374     * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
375     *
376     * @return The current Wifi display status.
377     * @hide
378     */
379    public WifiDisplayStatus getWifiDisplayStatus() {
380        return mGlobal.getWifiDisplayStatus();
381    }
382
383    /**
384     * Creates a virtual display.
385     * <p>
386     * The content of a virtual display is rendered to a {@link Surface} provided
387     * by the application.
388     * </p><p>
389     * The virtual display should be {@link VirtualDisplay#release released}
390     * when no longer needed.  Because a virtual display renders to a surface
391     * provided by the application, it will be released automatically when the
392     * process terminates and all remaining windows on it will be forcibly removed.
393     * </p><p>
394     * The behavior of the virtual display depends on the flags that are provided
395     * to this method.  By default, virtual displays are created to be private,
396     * non-presentation and unsecure.  Permissions may be required to use certain flags.
397     * </p>
398     *
399     * @param name The name of the virtual display, must be non-empty.
400     * @param width The width of the virtual display in pixels, must be greater than 0.
401     * @param height The height of the virtual display in pixels, must be greater than 0.
402     * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
403     * @param surface The surface to which the content of the virtual display should
404     * be rendered, must be non-null.
405     * @param flags A combination of virtual display flags:
406     * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}
407     * or {@link #VIRTUAL_DISPLAY_FLAG_SECURE}.
408     * @return The newly created virtual display, or null if the application could
409     * not create the virtual display.
410     *
411     * @throws SecurityException if the caller does not have permission to create
412     * a virtual display with the specified flags.
413     */
414    public VirtualDisplay createVirtualDisplay(String name,
415            int width, int height, int densityDpi, Surface surface, int flags) {
416        return mGlobal.createVirtualDisplay(mContext,
417                name, width, height, densityDpi, surface, flags);
418    }
419
420    /**
421     * Listens for changes in available display devices.
422     */
423    public interface DisplayListener {
424        /**
425         * Called whenever a logical display has been added to the system.
426         * Use {@link DisplayManager#getDisplay} to get more information about
427         * the display.
428         *
429         * @param displayId The id of the logical display that was added.
430         */
431        void onDisplayAdded(int displayId);
432
433        /**
434         * Called whenever a logical display has been removed from the system.
435         *
436         * @param displayId The id of the logical display that was removed.
437         */
438        void onDisplayRemoved(int displayId);
439
440        /**
441         * Called whenever the properties of a logical display have changed.
442         *
443         * @param displayId The id of the logical display that changed.
444         */
445        void onDisplayChanged(int displayId);
446    }
447}
448