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