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