Home | History | Annotate | Download | only in display
      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.SystemApi;
     22 import android.annotation.SystemService;
     23 import android.content.Context;
     24 import android.graphics.Point;
     25 import android.media.projection.MediaProjection;
     26 import android.os.Handler;
     27 import android.util.SparseArray;
     28 import android.view.Display;
     29 import android.view.Surface;
     30 import android.view.WindowManagerPolicy;
     31 
     32 import java.util.ArrayList;
     33 
     34 /**
     35  * Manages the properties of attached displays.
     36  */
     37 @SystemService(Context.DISPLAY_SERVICE)
     38 public final class DisplayManager {
     39     private static final String TAG = "DisplayManager";
     40     private static final boolean DEBUG = false;
     41 
     42     private final Context mContext;
     43     private final DisplayManagerGlobal mGlobal;
     44 
     45     private final Object mLock = new Object();
     46     private final SparseArray<Display> mDisplays = new SparseArray<Display>();
     47 
     48     private final ArrayList<Display> mTempDisplays = new ArrayList<Display>();
     49 
     50     /**
     51      * Broadcast receiver that indicates when the Wifi display status changes.
     52      * <p>
     53      * The status is provided as a {@link WifiDisplayStatus} object in the
     54      * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra.
     55      * </p><p>
     56      * This broadcast is only sent to registered receivers and can only be sent by the system.
     57      * </p>
     58      * @hide
     59      */
     60     public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED =
     61             "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED";
     62 
     63     /**
     64      * Contains a {@link WifiDisplayStatus} object.
     65      * @hide
     66      */
     67     public static final String EXTRA_WIFI_DISPLAY_STATUS =
     68             "android.hardware.display.extra.WIFI_DISPLAY_STATUS";
     69 
     70     /**
     71      * Display category: Presentation displays.
     72      * <p>
     73      * This category can be used to identify secondary displays that are suitable for
     74      * use as presentation displays such as HDMI or Wireless displays.  Applications
     75      * may automatically project their content to presentation displays to provide
     76      * richer second screen experiences.
     77      * </p>
     78      *
     79      * @see android.app.Presentation
     80      * @see Display#FLAG_PRESENTATION
     81      * @see #getDisplays(String)
     82      */
     83     public static final String DISPLAY_CATEGORY_PRESENTATION =
     84             "android.hardware.display.category.PRESENTATION";
     85 
     86     /**
     87      * Virtual display flag: Create a public display.
     88      *
     89      * <h3>Public virtual displays</h3>
     90      * <p>
     91      * When this flag is set, the virtual display is public.
     92      * </p><p>
     93      * A public virtual display behaves just like most any other display that is connected
     94      * to the system such as an HDMI or Wireless display.  Applications can open
     95      * windows on the display and the system may mirror the contents of other displays
     96      * onto it.
     97      * </p><p>
     98      * Creating a public virtual display that isn't restricted to own-content only implicitly
     99      * creates an auto-mirroring display. See {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for
    100      * restrictions on who is allowed to create an auto-mirroring display.
    101      * </p>
    102      *
    103      * <h3>Private virtual displays</h3>
    104      * <p>
    105      * When this flag is not set, the virtual display is private as defined by the
    106      * {@link Display#FLAG_PRIVATE} display flag.
    107      * </p>
    108      *
    109      * <p>
    110      * A private virtual display belongs to the application that created it.  Only the a owner of a
    111      * private virtual display and the apps that are already on that display are allowed to place
    112      * windows upon it.  The private virtual display also does not participate in display mirroring:
    113      * it will neither receive mirrored content from another display nor allow its own content to be
    114      * mirrored elsewhere.  More precisely, the only processes that are allowed to enumerate or
    115      * interact with the private display are those that have the same UID as the application that
    116      * originally created the private virtual display or as the activities that are already on that
    117      * 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     /**
    238      * Virtual display flag: Allows content to be displayed on private virtual displays when
    239      * keyguard is shown but is insecure.
    240      *
    241      * <p>
    242      * This might be used in a case when the content of a virtual display is captured and sent to an
    243      * external hardware display that is not visible to the system directly. This flag will allow
    244      * the continued display of content while other displays will be covered by a keyguard which
    245      * doesn't require providing credentials to unlock. This means that there is either no password
    246      * or other authentication method set, or the device is in a trusted state -
    247      * {@link android.service.trust.TrustAgentService} has available and active trust agent.
    248      * </p><p>
    249      * This flag can only be applied to private displays as defined by the
    250      * {@link Display#FLAG_PRIVATE} display flag. It is mutually exclusive with
    251      * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}. If both flags are specified then this flag's behavior
    252      * will not be applied.
    253      * </p>
    254      *
    255      * @see #createVirtualDisplay
    256      * @see WindowManagerPolicy#isKeyguardSecure(int)
    257      * @see WindowManagerPolicy#isKeyguardTrustedLw()
    258      * @hide
    259      */
    260     // TODO: Update name and documentation and un-hide the flag. Don't change the value before that.
    261     public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
    262 
    263     /**
    264      * Virtual display flag: Specifies that the virtual display can be associated with a
    265      * touchpad device that matches its uniqueId.
    266      *
    267      * @see #createVirtualDisplay
    268      * @hide
    269      */
    270     public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
    271 
    272     /**
    273      * Virtual display flag: Indicates that the orientation of this display device is coupled to
    274      * the rotation of its associated logical display.
    275      *
    276      * @see #createVirtualDisplay
    277      * @hide
    278      */
    279     public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
    280 
    281     /**
    282      * Virtual display flag: Indicates that the contents will be destroyed once
    283      * the display is removed.
    284      *
    285      * Public virtual displays without this flag will move their content to main display
    286      * stack once they're removed. Private vistual displays will always destroy their
    287      * content on removal even without this flag.
    288      *
    289      * @see #createVirtualDisplay
    290      * @hide
    291      */
    292     public static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
    293 
    294     /** @hide */
    295     public DisplayManager(Context context) {
    296         mContext = context;
    297         mGlobal = DisplayManagerGlobal.getInstance();
    298     }
    299 
    300     /**
    301      * Gets information about a logical display.
    302      *
    303      * The display metrics may be adjusted to provide compatibility
    304      * for legacy applications.
    305      *
    306      * @param displayId The logical display id.
    307      * @return The display object, or null if there is no valid display with the given id.
    308      */
    309     public Display getDisplay(int displayId) {
    310         synchronized (mLock) {
    311             return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
    312         }
    313     }
    314 
    315     /**
    316      * Gets all currently valid logical displays.
    317      *
    318      * @return An array containing all displays.
    319      */
    320     public Display[] getDisplays() {
    321         return getDisplays(null);
    322     }
    323 
    324     /**
    325      * Gets all currently valid logical displays of the specified category.
    326      * <p>
    327      * When there are multiple displays in a category the returned displays are sorted
    328      * of preference.  For example, if the requested category is
    329      * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays
    330      * then the displays are sorted so that the first display in the returned array
    331      * is the most preferred presentation display.  The application may simply
    332      * use the first display or allow the user to choose.
    333      * </p>
    334      *
    335      * @param category The requested display category or null to return all displays.
    336      * @return An array containing all displays sorted by order of preference.
    337      *
    338      * @see #DISPLAY_CATEGORY_PRESENTATION
    339      */
    340     public Display[] getDisplays(String category) {
    341         final int[] displayIds = mGlobal.getDisplayIds();
    342         synchronized (mLock) {
    343             try {
    344                 if (category == null) {
    345                     addAllDisplaysLocked(mTempDisplays, displayIds);
    346                 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
    347                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
    348                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
    349                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
    350                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
    351                 }
    352                 return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
    353             } finally {
    354                 mTempDisplays.clear();
    355             }
    356         }
    357     }
    358 
    359     private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
    360         for (int i = 0; i < displayIds.length; i++) {
    361             Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
    362             if (display != null) {
    363                 displays.add(display);
    364             }
    365         }
    366     }
    367 
    368     private void addPresentationDisplaysLocked(
    369             ArrayList<Display> displays, int[] displayIds, int matchType) {
    370         for (int i = 0; i < displayIds.length; i++) {
    371             Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
    372             if (display != null
    373                     && (display.getFlags() & Display.FLAG_PRESENTATION) != 0
    374                     && display.getType() == matchType) {
    375                 displays.add(display);
    376             }
    377         }
    378     }
    379 
    380     private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
    381         Display display = mDisplays.get(displayId);
    382         if (display == null) {
    383             // TODO: We cannot currently provide any override configurations for metrics on displays
    384             // other than the display the context is associated with.
    385             final Context context = mContext.getDisplay().getDisplayId() == displayId
    386                     ? mContext : mContext.getApplicationContext();
    387 
    388             display = mGlobal.getCompatibleDisplay(displayId, context.getResources());
    389             if (display != null) {
    390                 mDisplays.put(displayId, display);
    391             }
    392         } else if (!assumeValid && !display.isValid()) {
    393             display = null;
    394         }
    395         return display;
    396     }
    397 
    398     /**
    399      * Registers an display listener to receive notifications about when
    400      * displays are added, removed or changed.
    401      *
    402      * @param listener The listener to register.
    403      * @param handler The handler on which the listener should be invoked, or null
    404      * if the listener should be invoked on the calling thread's looper.
    405      *
    406      * @see #unregisterDisplayListener
    407      */
    408     public void registerDisplayListener(DisplayListener listener, Handler handler) {
    409         mGlobal.registerDisplayListener(listener, handler);
    410     }
    411 
    412     /**
    413      * Unregisters a display listener.
    414      *
    415      * @param listener The listener to unregister.
    416      *
    417      * @see #registerDisplayListener
    418      */
    419     public void unregisterDisplayListener(DisplayListener listener) {
    420         mGlobal.unregisterDisplayListener(listener);
    421     }
    422 
    423     /**
    424      * Starts scanning for available Wifi displays.
    425      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    426      * <p>
    427      * Calls to this method nest and must be matched by an equal number of calls to
    428      * {@link #stopWifiDisplayScan()}.
    429      * </p><p>
    430      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    431      * </p>
    432      *
    433      * @hide
    434      */
    435     public void startWifiDisplayScan() {
    436         mGlobal.startWifiDisplayScan();
    437     }
    438 
    439     /**
    440      * Stops scanning for available Wifi displays.
    441      * <p>
    442      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    443      * </p>
    444      *
    445      * @hide
    446      */
    447     public void stopWifiDisplayScan() {
    448         mGlobal.stopWifiDisplayScan();
    449     }
    450 
    451     /**
    452      * Connects to a Wifi display.
    453      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    454      * <p>
    455      * Automatically remembers the display after a successful connection, if not
    456      * already remembered.
    457      * </p><p>
    458      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    459      * </p>
    460      *
    461      * @param deviceAddress The MAC address of the device to which we should connect.
    462      * @hide
    463      */
    464     public void connectWifiDisplay(String deviceAddress) {
    465         mGlobal.connectWifiDisplay(deviceAddress);
    466     }
    467 
    468     /** @hide */
    469     public void pauseWifiDisplay() {
    470         mGlobal.pauseWifiDisplay();
    471     }
    472 
    473     /** @hide */
    474     public void resumeWifiDisplay() {
    475         mGlobal.resumeWifiDisplay();
    476     }
    477 
    478     /**
    479      * Disconnects from the current Wifi display.
    480      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    481      * @hide
    482      */
    483     public void disconnectWifiDisplay() {
    484         mGlobal.disconnectWifiDisplay();
    485     }
    486 
    487     /**
    488      * Renames a Wifi display.
    489      * <p>
    490      * The display must already be remembered for this call to succeed.  In other words,
    491      * we must already have successfully connected to the display at least once and then
    492      * not forgotten it.
    493      * </p><p>
    494      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    495      * </p>
    496      *
    497      * @param deviceAddress The MAC address of the device to rename.
    498      * @param alias The alias name by which to remember the device, or null
    499      * or empty if no alias should be used.
    500      * @hide
    501      */
    502     public void renameWifiDisplay(String deviceAddress, String alias) {
    503         mGlobal.renameWifiDisplay(deviceAddress, alias);
    504     }
    505 
    506     /**
    507      * Forgets a previously remembered Wifi display.
    508      * <p>
    509      * Automatically disconnects from the display if currently connected to it.
    510      * </p><p>
    511      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    512      * </p>
    513      *
    514      * @param deviceAddress The MAC address of the device to forget.
    515      * @hide
    516      */
    517     public void forgetWifiDisplay(String deviceAddress) {
    518         mGlobal.forgetWifiDisplay(deviceAddress);
    519     }
    520 
    521     /**
    522      * Gets the current Wifi display status.
    523      * Watch for changes in the status by registering a broadcast receiver for
    524      * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
    525      *
    526      * @return The current Wifi display status.
    527      * @hide
    528      */
    529     public WifiDisplayStatus getWifiDisplayStatus() {
    530         return mGlobal.getWifiDisplayStatus();
    531     }
    532 
    533     /**
    534      * Creates a virtual display.
    535      *
    536      * @see #createVirtualDisplay(String, int, int, int, Surface, int,
    537      * VirtualDisplay.Callback, Handler)
    538      */
    539     public VirtualDisplay createVirtualDisplay(@NonNull String name,
    540             int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
    541         return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null);
    542     }
    543 
    544     /**
    545      * Creates a virtual display.
    546      * <p>
    547      * The content of a virtual display is rendered to a {@link Surface} provided
    548      * by the application.
    549      * </p><p>
    550      * The virtual display should be {@link VirtualDisplay#release released}
    551      * when no longer needed.  Because a virtual display renders to a surface
    552      * provided by the application, it will be released automatically when the
    553      * process terminates and all remaining windows on it will be forcibly removed.
    554      * </p><p>
    555      * The behavior of the virtual display depends on the flags that are provided
    556      * to this method.  By default, virtual displays are created to be private,
    557      * non-presentation and unsecure.  Permissions may be required to use certain flags.
    558      * </p><p>
    559      * As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may
    560      * be attached or detached dynamically using {@link VirtualDisplay#setSurface}.
    561      * Previously, the surface had to be non-null when {@link #createVirtualDisplay}
    562      * was called and could not be changed for the lifetime of the display.
    563      * </p><p>
    564      * Detaching the surface that backs a virtual display has a similar effect to
    565      * turning off the screen.
    566      * </p>
    567      *
    568      * @param name The name of the virtual display, must be non-empty.
    569      * @param width The width of the virtual display in pixels, must be greater than 0.
    570      * @param height The height of the virtual display in pixels, must be greater than 0.
    571      * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
    572      * @param surface The surface to which the content of the virtual display should
    573      * be rendered, or null if there is none initially.
    574      * @param flags A combination of virtual display flags:
    575      * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
    576      * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
    577      * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
    578      * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
    579      * @param handler The handler on which the listener should be invoked, or null
    580      * if the listener should be invoked on the calling thread's looper.
    581      * @return The newly created virtual display, or null if the application could
    582      * not create the virtual display.
    583      *
    584      * @throws SecurityException if the caller does not have permission to create
    585      * a virtual display with the specified flags.
    586      */
    587     public VirtualDisplay createVirtualDisplay(@NonNull String name,
    588             int width, int height, int densityDpi, @Nullable Surface surface, int flags,
    589             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
    590         return createVirtualDisplay(null /* projection */, name, width, height, densityDpi, surface,
    591                 flags, callback, handler, null /* uniqueId */);
    592     }
    593 
    594     /** @hide */
    595     public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
    596             @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
    597             int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
    598             @Nullable String uniqueId) {
    599         return mGlobal.createVirtualDisplay(mContext, projection,
    600                 name, width, height, densityDpi, surface, flags, callback, handler, uniqueId);
    601     }
    602 
    603     /**
    604      * Gets the stable device display size, in pixels.
    605      *
    606      * This should really only be used for things like server-side filtering of available
    607      * applications. Most applications don't need the level of stability guaranteed by this and
    608      * should instead query either the size of the display they're currently running on or the
    609      * size of the default display.
    610      * @hide
    611      */
    612     @SystemApi
    613     public Point getStableDisplaySize() {
    614         return mGlobal.getStableDisplaySize();
    615     }
    616 
    617     /**
    618      * Listens for changes in available display devices.
    619      */
    620     public interface DisplayListener {
    621         /**
    622          * Called whenever a logical display has been added to the system.
    623          * Use {@link DisplayManager#getDisplay} to get more information about
    624          * the display.
    625          *
    626          * @param displayId The id of the logical display that was added.
    627          */
    628         void onDisplayAdded(int displayId);
    629 
    630         /**
    631          * Called whenever a logical display has been removed from the system.
    632          *
    633          * @param displayId The id of the logical display that was removed.
    634          */
    635         void onDisplayRemoved(int displayId);
    636 
    637         /**
    638          * Called whenever the properties of a logical display have changed.
    639          *
    640          * @param displayId The id of the logical display that changed.
    641          */
    642         void onDisplayChanged(int displayId);
    643     }
    644 }
    645