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.content.Context;
22 import android.media.projection.MediaProjection;
23 import android.os.Handler;
24 import android.util.SparseArray;
25 import android.view.Display;
26 import android.view.Surface;
27 
28 import 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  */
39 public 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 */
DisplayManager(Context context)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      */
getDisplay(int displayId)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      */
getDisplays()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      */
getDisplays(String category)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 
addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds)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 
addPresentationDisplaysLocked( ArrayList<Display> displays, int[] displayIds, int matchType)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 
getOrCreateDisplayLocked(int displayId, boolean assumeValid)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      */
registerDisplayListener(DisplayListener listener, Handler handler)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      */
unregisterDisplayListener(DisplayListener listener)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      */
startWifiDisplayScan()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      */
stopWifiDisplayScan()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      */
connectWifiDisplay(String deviceAddress)403     public void connectWifiDisplay(String deviceAddress) {
404         mGlobal.connectWifiDisplay(deviceAddress);
405     }
406 
407     /** @hide */
pauseWifiDisplay()408     public void pauseWifiDisplay() {
409         mGlobal.pauseWifiDisplay();
410     }
411 
412     /** @hide */
resumeWifiDisplay()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      */
disconnectWifiDisplay()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      */
renameWifiDisplay(String deviceAddress, String alias)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      */
forgetWifiDisplay(String deviceAddress)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      */
getWifiDisplayStatus()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,
476      * VirtualDisplay.Callback, Handler)
477      */
createVirtualDisplay(@onNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags)478     public VirtualDisplay createVirtualDisplay(@NonNull String name,
479             int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
480         return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null);
481     }
482 
483     /**
484      * Creates a virtual display.
485      * <p>
486      * The content of a virtual display is rendered to a {@link Surface} provided
487      * by the application.
488      * </p><p>
489      * The virtual display should be {@link VirtualDisplay#release released}
490      * when no longer needed.  Because a virtual display renders to a surface
491      * provided by the application, it will be released automatically when the
492      * process terminates and all remaining windows on it will be forcibly removed.
493      * </p><p>
494      * The behavior of the virtual display depends on the flags that are provided
495      * to this method.  By default, virtual displays are created to be private,
496      * non-presentation and unsecure.  Permissions may be required to use certain flags.
497      * </p><p>
498      * As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may
499      * be attached or detached dynamically using {@link VirtualDisplay#setSurface}.
500      * Previously, the surface had to be non-null when {@link #createVirtualDisplay}
501      * was called and could not be changed for the lifetime of the display.
502      * </p><p>
503      * Detaching the surface that backs a virtual display has a similar effect to
504      * turning off the screen.
505      * </p>
506      *
507      * @param name The name of the virtual display, must be non-empty.
508      * @param width The width of the virtual display in pixels, must be greater than 0.
509      * @param height The height of the virtual display in pixels, must be greater than 0.
510      * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
511      * @param surface The surface to which the content of the virtual display should
512      * be rendered, or null if there is none initially.
513      * @param flags A combination of virtual display flags:
514      * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
515      * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
516      * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
517      * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
518      * @param handler The handler on which the listener should be invoked, or null
519      * if the listener should be invoked on the calling thread's looper.
520      * @return The newly created virtual display, or null if the application could
521      * not create the virtual display.
522      *
523      * @throws SecurityException if the caller does not have permission to create
524      * a virtual display with the specified flags.
525      */
createVirtualDisplay(@onNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler)526     public VirtualDisplay createVirtualDisplay(@NonNull String name,
527             int width, int height, int densityDpi, @Nullable Surface surface, int flags,
528             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
529         return createVirtualDisplay(null,
530                 name, width, height, densityDpi, surface, flags, callback, handler);
531     }
532 
533     /** @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)534     public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
535             @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
536             int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
537         return mGlobal.createVirtualDisplay(mContext, projection,
538                 name, width, height, densityDpi, surface, flags, callback, handler);
539     }
540 
541     /**
542      * Listens for changes in available display devices.
543      */
544     public interface DisplayListener {
545         /**
546          * Called whenever a logical display has been added to the system.
547          * Use {@link DisplayManager#getDisplay} to get more information about
548          * the display.
549          *
550          * @param displayId The id of the logical display that was added.
551          */
onDisplayAdded(int displayId)552         void onDisplayAdded(int displayId);
553 
554         /**
555          * Called whenever a logical display has been removed from the system.
556          *
557          * @param displayId The id of the logical display that was removed.
558          */
onDisplayRemoved(int displayId)559         void onDisplayRemoved(int displayId);
560 
561         /**
562          * Called whenever the properties of a logical display have changed.
563          *
564          * @param displayId The id of the logical display that changed.
565          */
onDisplayChanged(int displayId)566         void onDisplayChanged(int displayId);
567     }
568 }
569