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