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 
     24 import java.util.ArrayList;
     25 
     26 /**
     27  * Manages the properties of attached displays.
     28  * <p>
     29  * Get an instance of this class by calling
     30  * {@link android.content.Context#getSystemService(java.lang.String)
     31  * Context.getSystemService()} with the argument
     32  * {@link android.content.Context#DISPLAY_SERVICE}.
     33  * </p>
     34  */
     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.
     72      * </p>
     73      *
     74      * @see android.app.Presentation for information about presenting content
     75      * on secondary displays.
     76      * @see #getDisplays(String)
     77      */
     78     public static final String DISPLAY_CATEGORY_PRESENTATION =
     79             "android.hardware.display.category.PRESENTATION";
     80 
     81     /** @hide */
     82     public DisplayManager(Context context) {
     83         mContext = context;
     84         mGlobal = DisplayManagerGlobal.getInstance();
     85     }
     86 
     87     /**
     88      * Gets information about a logical display.
     89      *
     90      * The display metrics may be adjusted to provide compatibility
     91      * for legacy applications.
     92      *
     93      * @param displayId The logical display id.
     94      * @return The display object, or null if there is no valid display with the given id.
     95      */
     96     public Display getDisplay(int displayId) {
     97         synchronized (mLock) {
     98             return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
     99         }
    100     }
    101 
    102     /**
    103      * Gets all currently valid logical displays.
    104      *
    105      * @return An array containing all displays.
    106      */
    107     public Display[] getDisplays() {
    108         return getDisplays(null);
    109     }
    110 
    111     /**
    112      * Gets all currently valid logical displays of the specified category.
    113      * <p>
    114      * When there are multiple displays in a category the returned displays are sorted
    115      * of preference.  For example, if the requested category is
    116      * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays
    117      * then the displays are sorted so that the first display in the returned array
    118      * is the most preferred presentation display.  The application may simply
    119      * use the first display or allow the user to choose.
    120      * </p>
    121      *
    122      * @param category The requested display category or null to return all displays.
    123      * @return An array containing all displays sorted by order of preference.
    124      *
    125      * @see #DISPLAY_CATEGORY_PRESENTATION
    126      */
    127     public Display[] getDisplays(String category) {
    128         final int[] displayIds = mGlobal.getDisplayIds();
    129         synchronized (mLock) {
    130             try {
    131                 if (category == null) {
    132                     addMatchingDisplaysLocked(mTempDisplays, displayIds, -1);
    133                 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
    134                     addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
    135                     addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
    136                     addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
    137                 }
    138                 return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
    139             } finally {
    140                 mTempDisplays.clear();
    141             }
    142         }
    143     }
    144 
    145     private void addMatchingDisplaysLocked(
    146             ArrayList<Display> displays, int[] displayIds, int matchType) {
    147         for (int i = 0; i < displayIds.length; i++) {
    148             Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
    149             if (display != null
    150                     && (matchType < 0 || display.getType() == matchType)) {
    151                 displays.add(display);
    152             }
    153         }
    154     }
    155 
    156     private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
    157         Display display = mDisplays.get(displayId);
    158         if (display == null) {
    159             display = mGlobal.getCompatibleDisplay(displayId,
    160                     mContext.getCompatibilityInfo(displayId));
    161             if (display != null) {
    162                 mDisplays.put(displayId, display);
    163             }
    164         } else if (!assumeValid && !display.isValid()) {
    165             display = null;
    166         }
    167         return display;
    168     }
    169 
    170     /**
    171      * Registers an display listener to receive notifications about when
    172      * displays are added, removed or changed.
    173      *
    174      * @param listener The listener to register.
    175      * @param handler The handler on which the listener should be invoked, or null
    176      * if the listener should be invoked on the calling thread's looper.
    177      *
    178      * @see #unregisterDisplayListener
    179      */
    180     public void registerDisplayListener(DisplayListener listener, Handler handler) {
    181         mGlobal.registerDisplayListener(listener, handler);
    182     }
    183 
    184     /**
    185      * Unregisters an input device listener.
    186      *
    187      * @param listener The listener to unregister.
    188      *
    189      * @see #registerDisplayListener
    190      */
    191     public void unregisterDisplayListener(DisplayListener listener) {
    192         mGlobal.unregisterDisplayListener(listener);
    193     }
    194 
    195     /**
    196      * Initiates a fresh scan of availble Wifi displays.
    197      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    198      * @hide
    199      */
    200     public void scanWifiDisplays() {
    201         mGlobal.scanWifiDisplays();
    202     }
    203 
    204     /**
    205      * Connects to a Wifi display.
    206      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    207      * <p>
    208      * Automatically remembers the display after a successful connection, if not
    209      * already remembered.
    210      * </p><p>
    211      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect
    212      * to unknown displays.  No permissions are required to connect to already known displays.
    213      * </p>
    214      *
    215      * @param deviceAddress The MAC address of the device to which we should connect.
    216      * @hide
    217      */
    218     public void connectWifiDisplay(String deviceAddress) {
    219         mGlobal.connectWifiDisplay(deviceAddress);
    220     }
    221 
    222     /**
    223      * Disconnects from the current Wifi display.
    224      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
    225      * @hide
    226      */
    227     public void disconnectWifiDisplay() {
    228         mGlobal.disconnectWifiDisplay();
    229     }
    230 
    231     /**
    232      * Renames a Wifi display.
    233      * <p>
    234      * The display must already be remembered for this call to succeed.  In other words,
    235      * we must already have successfully connected to the display at least once and then
    236      * not forgotten it.
    237      * </p><p>
    238      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    239      * </p>
    240      *
    241      * @param deviceAddress The MAC address of the device to rename.
    242      * @param alias The alias name by which to remember the device, or null
    243      * or empty if no alias should be used.
    244      * @hide
    245      */
    246     public void renameWifiDisplay(String deviceAddress, String alias) {
    247         mGlobal.renameWifiDisplay(deviceAddress, alias);
    248     }
    249 
    250     /**
    251      * Forgets a previously remembered Wifi display.
    252      * <p>
    253      * Automatically disconnects from the display if currently connected to it.
    254      * </p><p>
    255      * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
    256      * </p>
    257      *
    258      * @param deviceAddress The MAC address of the device to forget.
    259      * @hide
    260      */
    261     public void forgetWifiDisplay(String deviceAddress) {
    262         mGlobal.forgetWifiDisplay(deviceAddress);
    263     }
    264 
    265     /**
    266      * Gets the current Wifi display status.
    267      * Watch for changes in the status by registering a broadcast receiver for
    268      * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
    269      *
    270      * @return The current Wifi display status.
    271      * @hide
    272      */
    273     public WifiDisplayStatus getWifiDisplayStatus() {
    274         return mGlobal.getWifiDisplayStatus();
    275     }
    276 
    277     /**
    278      * Listens for changes in available display devices.
    279      */
    280     public interface DisplayListener {
    281         /**
    282          * Called whenever a logical display has been added to the system.
    283          * Use {@link DisplayManager#getDisplay} to get more information about
    284          * the display.
    285          *
    286          * @param displayId The id of the logical display that was added.
    287          */
    288         void onDisplayAdded(int displayId);
    289 
    290         /**
    291          * Called whenever a logical display has been removed from the system.
    292          *
    293          * @param displayId The id of the logical display that was removed.
    294          */
    295         void onDisplayRemoved(int displayId);
    296 
    297         /**
    298          * Called whenever the properties of a logical display have changed.
    299          *
    300          * @param displayId The id of the logical display that changed.
    301          */
    302         void onDisplayChanged(int displayId);
    303     }
    304 }
    305