DisplayManager.java revision 75ee9fcde4d9e1be3883eba6c8d193db4375b052
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.annotation.NonNull;
20import android.annotation.Nullable;
21import android.content.Context;
22import android.media.projection.MediaProjection;
23import android.os.Handler;
24import android.util.SparseArray;
25import android.view.Display;
26import android.view.Surface;
27
28import java.util.ArrayList;
29
30/**
31 * Manages the properties of attached displays.
32 * <p>
33 * Get an instance of this class by calling
34 * {@link android.content.Context#getSystemService(java.lang.String)
35 * Context.getSystemService()} with the argument
36 * {@link android.content.Context#DISPLAY_SERVICE}.
37 * </p>
38 */
39public final class DisplayManager {
40    private static final String TAG = "DisplayManager";
41    private static final boolean DEBUG = false;
42
43    private final Context mContext;
44    private final DisplayManagerGlobal mGlobal;
45
46    private final Object mLock = new Object();
47    private final SparseArray<Display> mDisplays = new SparseArray<Display>();
48
49    private final ArrayList<Display> mTempDisplays = new ArrayList<Display>();
50
51    /**
52     * Broadcast receiver that indicates when the Wifi display status changes.
53     * <p>
54     * The status is provided as a {@link WifiDisplayStatus} object in the
55     * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra.
56     * </p><p>
57     * This broadcast is only sent to registered receivers and can only be sent by the system.
58     * </p>
59     * @hide
60     */
61    public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED =
62            "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED";
63
64    /**
65     * Contains a {@link WifiDisplayStatus} object.
66     * @hide
67     */
68    public static final String EXTRA_WIFI_DISPLAY_STATUS =
69            "android.hardware.display.extra.WIFI_DISPLAY_STATUS";
70
71    /**
72     * Display category: Presentation displays.
73     * <p>
74     * This category can be used to identify secondary displays that are suitable for
75     * use as presentation displays such as HDMI or Wireless displays.  Applications
76     * may automatically project their content to presentation displays to provide
77     * richer second screen experiences.
78     * </p>
79     *
80     * @see android.app.Presentation
81     * @see Display#FLAG_PRESENTATION
82     * @see #getDisplays(String)
83     */
84    public static final String DISPLAY_CATEGORY_PRESENTATION =
85            "android.hardware.display.category.PRESENTATION";
86
87    /**
88     * Virtual display flag: Create a public display.
89     *
90     * <h3>Public virtual displays</h3>
91     * <p>
92     * When this flag is set, the virtual display is public.
93     * </p><p>
94     * A public virtual display behaves just like most any other display that is connected
95     * to the system such as an HDMI or Wireless display.  Applications can open
96     * windows on the display and the system may mirror the contents of other displays
97     * onto it.
98     * </p><p>
99     * Creating a public virtual display that isn't restricted to own-content only implicitly
100     * creates an auto-mirroring display. See {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for
101     * restrictions on who is allowed to create an auto-mirroring display.
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     *
110     * <p>
111     * A private virtual display belongs to the application that created it.
112     * Only the a owner of a private virtual display is allowed to place windows upon it.
113     * The private virtual display also does not participate in display mirroring: it will
114     * neither receive mirrored content from another display nor allow its own content to
115     * be mirrored elsewhere.  More precisely, the only processes that are allowed to
116     * enumerate or interact with the private display are those that have the same UID as the
117     * application that originally created the private virtual display.
118     * </p>
119     *
120     * @see #createVirtualDisplay
121     * @see #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
122     * @see #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
123     */
124    public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
125
126    /**
127     * Virtual display flag: Create a presentation display.
128     *
129     * <h3>Presentation virtual displays</h3>
130     * <p>
131     * When this flag is set, the virtual display is registered as a presentation
132     * display in the {@link #DISPLAY_CATEGORY_PRESENTATION presentation display category}.
133     * Applications may automatically project their content to presentation displays
134     * to provide richer second screen experiences.
135     * </p>
136     *
137     * <h3>Non-presentation virtual displays</h3>
138     * <p>
139     * When this flag is not set, the virtual display is not registered as a presentation
140     * display.  Applications can still project their content on the display but they
141     * will typically not do so automatically.  This option is appropriate for
142     * more special-purpose displays.
143     * </p>
144     *
145     * @see android.app.Presentation
146     * @see #createVirtualDisplay
147     * @see #DISPLAY_CATEGORY_PRESENTATION
148     * @see Display#FLAG_PRESENTATION
149     */
150    public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1;
151
152    /**
153     * Virtual display flag: Create a secure display.
154     *
155     * <h3>Secure virtual displays</h3>
156     * <p>
157     * When this flag is set, the virtual display is considered secure as defined
158     * by the {@link Display#FLAG_SECURE} display flag.  The caller promises to take
159     * reasonable measures, such as over-the-air encryption, to prevent the contents
160     * of the display from being intercepted or recorded on a persistent medium.
161     * </p><p>
162     * Creating a secure virtual display requires the
163     * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
164     * This permission is reserved for use by system components and is not available to
165     * third-party applications.
166     * </p>
167     *
168     * <h3>Non-secure virtual displays</h3>
169     * <p>
170     * When this flag is not set, the virtual display is considered unsecure.
171     * The content of secure windows will be blanked if shown on this display.
172     * </p>
173     *
174     * @see Display#FLAG_SECURE
175     * @see #createVirtualDisplay
176     */
177    public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
178
179    /**
180     * Virtual display flag: Only show this display's own content; do not mirror
181     * the content of another display.
182     *
183     * <p>
184     * This flag is used in conjunction with {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}.
185     * Ordinarily public virtual displays will automatically mirror the content of the
186     * default display if they have no windows of their own.  When this flag is
187     * specified, the virtual display will only ever show its own content and
188     * will be blanked instead if it has no windows.
189     * </p>
190     *
191     * <p>
192     * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.  If both
193     * flags are specified then the own-content only behavior will be applied.
194     * </p>
195     *
196     * <p>
197     * This behavior of this flag is implied whenever neither {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}
198     * nor {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} have been set.  This flag is only required to
199     * override the default behavior when creating a public display.
200     * </p>
201     *
202     * @see #createVirtualDisplay
203     */
204    public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3;
205
206
207    /**
208     * Virtual display flag: Allows content to be mirrored on private displays when no content is
209     * being shown.
210     *
211     * <p>
212     * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
213     * If both flags are specified then the own-content only behavior will be applied.
214     * </p>
215     *
216     * <p>
217     * The behavior of this flag is implied whenever {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC} is set
218     * and {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY} has not been set.   This flag is only
219     * required to override the default behavior when creating a private display.
220     * </p>
221     *
222     * <p>
223     * Creating an auto-mirroing virtual display requires the
224     * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
225     * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
226     * These permissions are reserved for use by system components and are not available to
227     * third-party applications.
228     *
229     * Alternatively, an appropriate {@link MediaProjection} may be used to create an
230     * auto-mirroring virtual display.
231     * </p>
232     *
233     * @see #createVirtualDisplay
234     */
235    public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4;
236
237    /** @hide */
238    public DisplayManager(Context context) {
239        mContext = context;
240        mGlobal = DisplayManagerGlobal.getInstance();
241    }
242
243    /**
244     * Gets information about a logical display.
245     *
246     * The display metrics may be adjusted to provide compatibility
247     * for legacy applications.
248     *
249     * @param displayId The logical display id.
250     * @return The display object, or null if there is no valid display with the given id.
251     */
252    public Display getDisplay(int displayId) {
253        synchronized (mLock) {
254            return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
255        }
256    }
257
258    /**
259     * Gets all currently valid logical displays.
260     *
261     * @return An array containing all displays.
262     */
263    public Display[] getDisplays() {
264        return getDisplays(null);
265    }
266
267    /**
268     * Gets all currently valid logical displays of the specified category.
269     * <p>
270     * When there are multiple displays in a category the returned displays are sorted
271     * of preference.  For example, if the requested category is
272     * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays
273     * then the displays are sorted so that the first display in the returned array
274     * is the most preferred presentation display.  The application may simply
275     * use the first display or allow the user to choose.
276     * </p>
277     *
278     * @param category The requested display category or null to return all displays.
279     * @return An array containing all displays sorted by order of preference.
280     *
281     * @see #DISPLAY_CATEGORY_PRESENTATION
282     */
283    public Display[] getDisplays(String category) {
284        final int[] displayIds = mGlobal.getDisplayIds();
285        synchronized (mLock) {
286            try {
287                if (category == null) {
288                    addAllDisplaysLocked(mTempDisplays, displayIds);
289                } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
290                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
291                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
292                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
293                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
294                }
295                return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
296            } finally {
297                mTempDisplays.clear();
298            }
299        }
300    }
301
302    private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
303        for (int i = 0; i < displayIds.length; i++) {
304            Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
305            if (display != null) {
306                displays.add(display);
307            }
308        }
309    }
310
311    private void addPresentationDisplaysLocked(
312            ArrayList<Display> displays, int[] displayIds, int matchType) {
313        for (int i = 0; i < displayIds.length; i++) {
314            Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
315            if (display != null
316                    && (display.getFlags() & Display.FLAG_PRESENTATION) != 0
317                    && display.getType() == matchType) {
318                displays.add(display);
319            }
320        }
321    }
322
323    private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
324        Display display = mDisplays.get(displayId);
325        if (display == null) {
326            display = mGlobal.getCompatibleDisplay(displayId,
327                    mContext.getDisplayAdjustments(displayId));
328            if (display != null) {
329                mDisplays.put(displayId, display);
330            }
331        } else if (!assumeValid && !display.isValid()) {
332            display = null;
333        }
334        return display;
335    }
336
337    /**
338     * Registers an display listener to receive notifications about when
339     * displays are added, removed or changed.
340     *
341     * @param listener The listener to register.
342     * @param handler The handler on which the listener should be invoked, or null
343     * if the listener should be invoked on the calling thread's looper.
344     *
345     * @see #unregisterDisplayListener
346     */
347    public void registerDisplayListener(DisplayListener listener, Handler handler) {
348        mGlobal.registerDisplayListener(listener, handler);
349    }
350
351    /**
352     * Unregisters a display listener.
353     *
354     * @param listener The listener to unregister.
355     *
356     * @see #registerDisplayListener
357     */
358    public void unregisterDisplayListener(DisplayListener listener) {
359        mGlobal.unregisterDisplayListener(listener);
360    }
361
362    /**
363     * Starts scanning for available Wifi displays.
364     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
365     * <p>
366     * Calls to this method nest and must be matched by an equal number of calls to
367     * {@link #stopWifiDisplayScan()}.
368     * </p><p>
369     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
370     * </p>
371     *
372     * @hide
373     */
374    public void startWifiDisplayScan() {
375        mGlobal.startWifiDisplayScan();
376    }
377
378    /**
379     * Stops scanning for available Wifi displays.
380     * <p>
381     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
382     * </p>
383     *
384     * @hide
385     */
386    public void stopWifiDisplayScan() {
387        mGlobal.stopWifiDisplayScan();
388    }
389
390    /**
391     * Connects to a Wifi display.
392     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
393     * <p>
394     * Automatically remembers the display after a successful connection, if not
395     * already remembered.
396     * </p><p>
397     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
398     * </p>
399     *
400     * @param deviceAddress The MAC address of the device to which we should connect.
401     * @hide
402     */
403    public void connectWifiDisplay(String deviceAddress) {
404        mGlobal.connectWifiDisplay(deviceAddress);
405    }
406
407    /** @hide */
408    public void pauseWifiDisplay() {
409        mGlobal.pauseWifiDisplay();
410    }
411
412    /** @hide */
413    public void resumeWifiDisplay() {
414        mGlobal.resumeWifiDisplay();
415    }
416
417    /**
418     * Disconnects from the current Wifi display.
419     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
420     * @hide
421     */
422    public void disconnectWifiDisplay() {
423        mGlobal.disconnectWifiDisplay();
424    }
425
426    /**
427     * Renames a Wifi display.
428     * <p>
429     * The display must already be remembered for this call to succeed.  In other words,
430     * we must already have successfully connected to the display at least once and then
431     * not forgotten it.
432     * </p><p>
433     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
434     * </p>
435     *
436     * @param deviceAddress The MAC address of the device to rename.
437     * @param alias The alias name by which to remember the device, or null
438     * or empty if no alias should be used.
439     * @hide
440     */
441    public void renameWifiDisplay(String deviceAddress, String alias) {
442        mGlobal.renameWifiDisplay(deviceAddress, alias);
443    }
444
445    /**
446     * Forgets a previously remembered Wifi display.
447     * <p>
448     * Automatically disconnects from the display if currently connected to it.
449     * </p><p>
450     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
451     * </p>
452     *
453     * @param deviceAddress The MAC address of the device to forget.
454     * @hide
455     */
456    public void forgetWifiDisplay(String deviceAddress) {
457        mGlobal.forgetWifiDisplay(deviceAddress);
458    }
459
460    /**
461     * Gets the current Wifi display status.
462     * Watch for changes in the status by registering a broadcast receiver for
463     * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
464     *
465     * @return The current Wifi display status.
466     * @hide
467     */
468    public WifiDisplayStatus getWifiDisplayStatus() {
469        return mGlobal.getWifiDisplayStatus();
470    }
471
472    /**
473     * Creates a virtual display.
474     *
475     * @see #createVirtualDisplay(String, int, int, int, Surface, int, VirtualDisplay.Callback)
476     */
477    public VirtualDisplay createVirtualDisplay(@NonNull String name,
478            int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
479        return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null);
480    }
481
482    /**
483     * Creates a virtual display.
484     * <p>
485     * The content of a virtual display is rendered to a {@link Surface} provided
486     * by the application.
487     * </p><p>
488     * The virtual display should be {@link VirtualDisplay#release released}
489     * when no longer needed.  Because a virtual display renders to a surface
490     * provided by the application, it will be released automatically when the
491     * process terminates and all remaining windows on it will be forcibly removed.
492     * </p><p>
493     * The behavior of the virtual display depends on the flags that are provided
494     * to this method.  By default, virtual displays are created to be private,
495     * non-presentation and unsecure.  Permissions may be required to use certain flags.
496     * </p><p>
497     * As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may
498     * be attached or detached dynamically using {@link VirtualDisplay#setSurface}.
499     * Previously, the surface had to be non-null when {@link #createVirtualDisplay}
500     * was called and could not be changed for the lifetime of the display.
501     * </p><p>
502     * Detaching the surface that backs a virtual display has a similar effect to
503     * turning off the screen.
504     * </p>
505     *
506     * @param name The name of the virtual display, must be non-empty.
507     * @param width The width of the virtual display in pixels, must be greater than 0.
508     * @param height The height of the virtual display in pixels, must be greater than 0.
509     * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
510     * @param surface The surface to which the content of the virtual display should
511     * be rendered, or null if there is none initially.
512     * @param flags A combination of virtual display flags:
513     * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
514     * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
515     * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
516     * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
517     * @param handler The handler on which the listener should be invoked, or null
518     * if the listener should be invoked on the calling thread's looper.
519     * @return The newly created virtual display, or null if the application could
520     * not create the virtual display.
521     *
522     * @throws SecurityException if the caller does not have permission to create
523     * a virtual display with the specified flags.
524     */
525    public VirtualDisplay createVirtualDisplay(@NonNull String name,
526            int width, int height, int densityDpi, @Nullable Surface surface, int flags,
527            @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
528        return createVirtualDisplay(null,
529                name, width, height, densityDpi, surface, flags, callback, handler);
530    }
531
532    /** @hide */
533    public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
534            @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
535            int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
536        return mGlobal.createVirtualDisplay(mContext, projection,
537                name, width, height, densityDpi, surface, flags, callback, handler);
538    }
539
540    /**
541     * Listens for changes in available display devices.
542     */
543    public interface DisplayListener {
544        /**
545         * Called whenever a logical display has been added to the system.
546         * Use {@link DisplayManager#getDisplay} to get more information about
547         * the display.
548         *
549         * @param displayId The id of the logical display that was added.
550         */
551        void onDisplayAdded(int displayId);
552
553        /**
554         * Called whenever a logical display has been removed from the system.
555         *
556         * @param displayId The id of the logical display that was removed.
557         */
558        void onDisplayRemoved(int displayId);
559
560        /**
561         * Called whenever the properties of a logical display have changed.
562         *
563         * @param displayId The id of the logical display that changed.
564         */
565        void onDisplayChanged(int displayId);
566    }
567}
568