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.content.Context;
     20 import android.os.Handler;
     21 import android.util.SparseArray;
     22 import android.view.Display;
     23 import android.view.Surface;
     24 
     25 import java.util.ArrayList;
     26 
     27 /**
     28  * Manages the properties of attached displays.
     29  * <p>
     30  * Get an instance of this class by calling
     31  * {@link android.content.Context#getSystemService(java.lang.String)
     32  * Context.getSystemService()} with the argument
     33  * {@link android.content.Context#DISPLAY_SERVICE}.
     34  * </p>
     35  */
     36 public final class DisplayManager {
     37     private static final String TAG = "DisplayManager";
     38     private static final boolean DEBUG = false;
     39 
     40     private final Context mContext;
     41     private final DisplayManagerGlobal mGlobal;
     42 
     43     private final Object mLock = new Object();
     44     private final SparseArray<Display> mDisplays = new SparseArray<Display>();
     45 
     46     private final ArrayList<Display> mTempDisplays = new ArrayList<Display>();
     47 
     48     /**
     49      * Broadcast receiver that indicates when the Wifi display status changes.
     50      * <p>
     51      * The status is provided as a {@link WifiDisplayStatus} object in the
     52      * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra.
     53      * </p><p>
     54      * This broadcast is only sent to registered receivers and can only be sent by the system.
     55      * </p>
     56      * @hide
     57      */
     58     public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED =
     59             "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED";
     60 
     61     /**
     62      * Contains a {@link WifiDisplayStatus} object.
     63      * @hide
     64      */
     65     public static final String EXTRA_WIFI_DISPLAY_STATUS =
     66             "android.hardware.display.extra.WIFI_DISPLAY_STATUS";
     67 
     68     /**
     69      * Display category: Presentation displays.
     70      * <p>
     71      * This category can be used to identify secondary displays that are suitable for
     72      * use as presentation displays such as HDMI or Wireless displays.  Applications
     73      * may automatically project their content to presentation displays to provide
     74      * richer second screen experiences.
     75      * </p>
     76      *
     77      * @see android.app.Presentation
     78      * @see Display#FLAG_PRESENTATION
     79      * @see #getDisplays(String)
     80      */
     81     public static final String DISPLAY_CATEGORY_PRESENTATION =
     82             "android.hardware.display.category.PRESENTATION";
     83 
     84     /**
     85      * Virtual display flag: Create a public display.
     86      *
     87      * <h3>Public virtual displays</h3>
     88      * <p>
     89      * When this flag is set, the virtual display is public.
     90      * </p><p>
     91      * A public virtual display behaves just like most any other display that is connected
     92      * to the system such as an HDMI or Wireless display.  Applications can open
     93      * windows on the display and the system may mirror the contents of other displays
     94      * onto it.
     95      * </p><p>
     96      * Creating a public virtual display requires the
     97      * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
     98      * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
     99      * These permissions are reserved for use by system components and are not available to
    100      * third-party applications.
    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      * A private virtual display belongs to the application that created it.
    109      * Only the a owner of a private virtual display is allowed to place windows upon it.
    110      * The private virtual display also does not participate in display mirroring: it will
    111      * neither receive mirrored content from another display nor allow its own content to
    112      * be mirrored elsewhere.  More precisely, the only processes that are allowed to
    113      * enumerate or interact with the private display are those that have the same UID as the
    114      * application that originally created the private virtual display.
    115       * </p>
    116      *
    117      * @see #createVirtualDisplay
    118      */
    119     public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
    120 
    121     /**
    122      * Virtual display flag: Create a presentation display.
    123      *
    124      * <h3>Presentation virtual displays</h3>
    125      * <p>
    126      * When this flag is set, the virtual display is registered as a presentation
    127      * display in the {@link #DISPLAY_CATEGORY_PRESENTATION presentation display category}.
    128      * Applications may automatically project their content to presentation displays
    129      * to provide richer second screen experiences.
    130      * </p>
    131      *
    132      * <h3>Non-presentation virtual displays</h3>
    133      * <p>
    134      * When this flag is not set, the virtual display is not registered as a presentation
    135      * display.  Applications can still project their content on the display but they
    136      * will typically not do so automatically.  This option is appropriate for
    137      * more special-purpose displays.
    138      * </p>
    139      *
    140      * @see android.app.Presentation
    141      * @see #createVirtualDisplay
    142      * @see #DISPLAY_CATEGORY_PRESENTATION
    143      * @see Display#FLAG_PRESENTATION
    144      */
    145     public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1;
    146 
    147     /**
    148      * Virtual display flag: Create a secure display.
    149      *
    150      * <h3>Secure virtual displays</h3>
    151      * <p>
    152      * When this flag is set, the virtual display is considered secure as defined
    153      * by the {@link Display#FLAG_SECURE} display flag.  The caller promises to take
    154      * reasonable measures, such as over-the-air encryption, to prevent the contents
    155      * of the display from being intercepted or recorded on a persistent medium.
    156      * </p><p>
    157      * Creating a secure virtual display requires the
    158      * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
    159      * This permission is reserved for use by system components and is not available to
    160      * third-party applications.
    161      * </p>
    162      *
    163      * <h3>Non-secure virtual displays</h3>
    164      * <p>
    165      * When this flag is not set, the virtual display is considered unsecure.
    166      * The content of secure windows will be blanked if shown on this display.
    167      * </p>
    168      *
    169      * @see Display#FLAG_SECURE
    170      * @see #createVirtualDisplay
    171      */
    172     public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
    173 
    174     /** @hide */
    175     public DisplayManager(Context context) {
    176         mContext = context;
    177         mGlobal = DisplayManagerGlobal.getInstance();
    178     }
    179 
    180     /**
    181      * Gets information about a logical display.
    182      *
    183      * The display metrics may be adjusted to provide compatibility
    184      * for legacy applications.
    185      *
    186      * @param displayId The logical display id.
    187      * @return The display object, or null if there is no valid display with the given id.
    188      */
    189     public Display getDisplay(int displayId) {
    190         synchronized (mLock) {
    191             return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
    192         }
    193     }
    194 
    195     /**
    196      * Gets all currently valid logical displays.
    197      *
    198      * @return An array containing all displays.
    199      */
    200     public Display[] getDisplays() {
    201         return getDisplays(null);
    202     }
    203 
    204     /**
    205      * Gets all currently valid logical displays of the specified category.
    206      * <p>
    207      * When there are multiple displays in a category the returned displays are sorted
    208      * of preference.  For example, if the requested category is
    209      * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays
    210      * then the displays are sorted so that the first display in the returned array
    211      * is the most preferred presentation display.  The application may simply
    212      * use the first display or allow the user to choose.
    213      * </p>
    214      *
    215      * @param category The requested display category or null to return all displays.
    216      * @return An array containing all displays sorted by order of preference.
    217      *
    218      * @see #DISPLAY_CATEGORY_PRESENTATION
    219      */
    220     public Display[] getDisplays(String category) {
    221         final int[] displayIds = mGlobal.getDisplayIds();
    222         synchronized (mLock) {
    223             try {
    224                 if (category == null) {
    225                     addAllDisplaysLocked(mTempDisplays, displayIds);
    226                 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
    227                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
    228                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
    229                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
    230                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
    231                 }
    232                 return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
    233             } finally {
    234                 mTempDisplays.clear();
    235             }
    236         }
    237     }
    238 
    239     private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
    240         for (int i = 0; i < displayIds.length; i++) {
    241             Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
    242             if (display != null) {
    243                 displays.add(display);
    244             }
    245         }
    246     }
    247 
    248     private void addPresentationDisplaysLocked(
    249             ArrayList<Display> displays, int[] displayIds, int matchType) {
    250         for (int i = 0; i < displayIds.length; i++) {
    251             Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
    252             if (display != null
    253                     && (display.getFlags() & Display.FLAG_PRESENTATION) != 0
    254                     && display.getType() == matchType) {
    255                 displays.add(display);
    256             }
    257         }
    258     }
    259 
    260     private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
    261         Display display = mDisplays.get(displayId);
    262         if (display == null) {
    263             display = mGlobal.getCompatibleDisplay(displayId,
    264                     mContext.getDisplayAdjustments(displayId));
    265             if (display != null) {
    266                 mDisplays.put(displayId, display);
    267             }
    268         } else if (!assumeValid && !display.isValid()) {
    269             display = null;
    270         }
    271         return display;
    272     }
    273 
    274     /**
    275      * Registers an display listener to receive notifications about when
    276      * displays are added, removed or changed.
    277      *
    278      * @param listener The listener to register.
    279      * @param handler The handler on which the listener should be invoked, or null
    280      * if the listener should be invoked on the calling thread's looper.
    281      *
    282      * @see #unregisterDisplayListener
    283      */
    284     public void registerDisplayListener(DisplayListener listener, Handler handler) {
    285         mGlobal.registerDisplayListener(listener, handler);
    286     }
    287 
    288     /**
    289      * Unregisters an input device listener.
    290      *
    291      * @param listener The listener to unregister.
    292      *
    293      * @see #registerDisplayListener
    294      */
    295     public void unregisterDisplayListener(DisplayListener listener) {
    296         mGlobal.unregisterDisplayListener(listener);
    297     }
    298 
    299     /**
    300      * Starts scanning for available Wifi displays.
    301      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    302      * <p>
    303      * Calls to this method nest and must be matched by an equal number of calls to
    304      * {@link #stopWifiDisplayScan()}.
    305      * </p><p>
    306      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    307      * </p>
    308      *
    309      * @hide
    310      */
    311     public void startWifiDisplayScan() {
    312         mGlobal.startWifiDisplayScan();
    313     }
    314 
    315     /**
    316      * Stops scanning for available Wifi displays.
    317      * <p>
    318      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    319      * </p>
    320      *
    321      * @hide
    322      */
    323     public void stopWifiDisplayScan() {
    324         mGlobal.stopWifiDisplayScan();
    325     }
    326 
    327     /**
    328      * Connects to a Wifi display.
    329      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    330      * <p>
    331      * Automatically remembers the display after a successful connection, if not
    332      * already remembered.
    333      * </p><p>
    334      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    335      * </p>
    336      *
    337      * @param deviceAddress The MAC address of the device to which we should connect.
    338      * @hide
    339      */
    340     public void connectWifiDisplay(String deviceAddress) {
    341         mGlobal.connectWifiDisplay(deviceAddress);
    342     }
    343 
    344     /** @hide */
    345     public void pauseWifiDisplay() {
    346         mGlobal.pauseWifiDisplay();
    347     }
    348 
    349     /** @hide */
    350     public void resumeWifiDisplay() {
    351         mGlobal.resumeWifiDisplay();
    352     }
    353 
    354     /**
    355      * Disconnects from the current Wifi display.
    356      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    357      * @hide
    358      */
    359     public void disconnectWifiDisplay() {
    360         mGlobal.disconnectWifiDisplay();
    361     }
    362 
    363     /**
    364      * Renames a Wifi display.
    365      * <p>
    366      * The display must already be remembered for this call to succeed.  In other words,
    367      * we must already have successfully connected to the display at least once and then
    368      * not forgotten it.
    369      * </p><p>
    370      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    371      * </p>
    372      *
    373      * @param deviceAddress The MAC address of the device to rename.
    374      * @param alias The alias name by which to remember the device, or null
    375      * or empty if no alias should be used.
    376      * @hide
    377      */
    378     public void renameWifiDisplay(String deviceAddress, String alias) {
    379         mGlobal.renameWifiDisplay(deviceAddress, alias);
    380     }
    381 
    382     /**
    383      * Forgets a previously remembered Wifi display.
    384      * <p>
    385      * Automatically disconnects from the display if currently connected to it.
    386      * </p><p>
    387      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    388      * </p>
    389      *
    390      * @param deviceAddress The MAC address of the device to forget.
    391      * @hide
    392      */
    393     public void forgetWifiDisplay(String deviceAddress) {
    394         mGlobal.forgetWifiDisplay(deviceAddress);
    395     }
    396 
    397     /**
    398      * Gets the current Wifi display status.
    399      * Watch for changes in the status by registering a broadcast receiver for
    400      * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
    401      *
    402      * @return The current Wifi display status.
    403      * @hide
    404      */
    405     public WifiDisplayStatus getWifiDisplayStatus() {
    406         return mGlobal.getWifiDisplayStatus();
    407     }
    408 
    409     /**
    410      * Creates a virtual display.
    411      * <p>
    412      * The content of a virtual display is rendered to a {@link Surface} provided
    413      * by the application.
    414      * </p><p>
    415      * The virtual display should be {@link VirtualDisplay#release released}
    416      * when no longer needed.  Because a virtual display renders to a surface
    417      * provided by the application, it will be released automatically when the
    418      * process terminates and all remaining windows on it will be forcibly removed.
    419      * </p><p>
    420      * The behavior of the virtual display depends on the flags that are provided
    421      * to this method.  By default, virtual displays are created to be private,
    422      * non-presentation and unsecure.  Permissions may be required to use certain flags.
    423      * </p>
    424      *
    425      * @param name The name of the virtual display, must be non-empty.
    426      * @param width The width of the virtual display in pixels, must be greater than 0.
    427      * @param height The height of the virtual display in pixels, must be greater than 0.
    428      * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
    429      * @param surface The surface to which the content of the virtual display should
    430      * be rendered, must be non-null.
    431      * @param flags A combination of virtual display flags:
    432      * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}
    433      * or {@link #VIRTUAL_DISPLAY_FLAG_SECURE}.
    434      * @return The newly created virtual display, or null if the application could
    435      * not create the virtual display.
    436      *
    437      * @throws SecurityException if the caller does not have permission to create
    438      * a virtual display with the specified flags.
    439      */
    440     public VirtualDisplay createVirtualDisplay(String name,
    441             int width, int height, int densityDpi, Surface surface, int flags) {
    442         return mGlobal.createVirtualDisplay(mContext,
    443                 name, width, height, densityDpi, surface, flags);
    444     }
    445 
    446     /**
    447      * Listens for changes in available display devices.
    448      */
    449     public interface DisplayListener {
    450         /**
    451          * Called whenever a logical display has been added to the system.
    452          * Use {@link DisplayManager#getDisplay} to get more information about
    453          * the display.
    454          *
    455          * @param displayId The id of the logical display that was added.
    456          */
    457         void onDisplayAdded(int displayId);
    458 
    459         /**
    460          * Called whenever a logical display has been removed from the system.
    461          *
    462          * @param displayId The id of the logical display that was removed.
    463          */
    464         void onDisplayRemoved(int displayId);
    465 
    466         /**
    467          * Called whenever the properties of a logical display have changed.
    468          *
    469          * @param displayId The id of the logical display that changed.
    470          */
    471         void onDisplayChanged(int displayId);
    472     }
    473 }
    474