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 
17 package android.hardware.display;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemService;
22 import android.content.Context;
23 import android.media.projection.MediaProjection;
24 import android.os.Handler;
25 import android.util.SparseArray;
26 import android.view.Display;
27 import android.view.Surface;
28 
29 import java.util.ArrayList;
30 
31 /**
32  * Manages the properties of attached displays.
33  */
34 @SystemService(Context.DISPLAY_SERVICE)
35 public 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 */
DisplayManager(Context context)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      */
getDisplay(int displayId)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      */
getDisplays()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      */
getDisplays(String category)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 
addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds)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 
addPresentationDisplaysLocked( ArrayList<Display> displays, int[] displayIds, int matchType)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 
getOrCreateDisplayLocked(int displayId, boolean assumeValid)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      */
registerDisplayListener(DisplayListener listener, Handler handler)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      */
unregisterDisplayListener(DisplayListener listener)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      */
startWifiDisplayScan()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      */
stopWifiDisplayScan()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      */
connectWifiDisplay(String deviceAddress)429     public void connectWifiDisplay(String deviceAddress) {
430         mGlobal.connectWifiDisplay(deviceAddress);
431     }
432 
433     /** @hide */
pauseWifiDisplay()434     public void pauseWifiDisplay() {
435         mGlobal.pauseWifiDisplay();
436     }
437 
438     /** @hide */
resumeWifiDisplay()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      */
disconnectWifiDisplay()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      */
renameWifiDisplay(String deviceAddress, String alias)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      */
forgetWifiDisplay(String deviceAddress)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      */
getWifiDisplayStatus()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      */
createVirtualDisplay(@onNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags)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      */
createVirtualDisplay(@onNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler)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 */
createVirtualDisplay(@ullable MediaProjection projection, @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, @Nullable String uniqueId)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          */
onDisplayAdded(int displayId)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          */
onDisplayRemoved(int displayId)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          */
onDisplayChanged(int displayId)593         void onDisplayChanged(int displayId);
594     }
595 }
596