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