| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.hardware.display; |
| |
| import android.content.Context; |
| import android.os.Handler; |
| import android.util.SparseArray; |
| import android.view.Display; |
| import android.view.Surface; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * Manages the properties of attached displays. |
| * <p> |
| * Get an instance of this class by calling |
| * {@link android.content.Context#getSystemService(java.lang.String) |
| * Context.getSystemService()} with the argument |
| * {@link android.content.Context#DISPLAY_SERVICE}. |
| * </p> |
| */ |
| public final class DisplayManager { |
| private static final String TAG = "DisplayManager"; |
| private static final boolean DEBUG = false; |
| |
| private final Context mContext; |
| private final DisplayManagerGlobal mGlobal; |
| |
| private final Object mLock = new Object(); |
| private final SparseArray<Display> mDisplays = new SparseArray<Display>(); |
| |
| private final ArrayList<Display> mTempDisplays = new ArrayList<Display>(); |
| |
| /** |
| * Broadcast receiver that indicates when the Wifi display status changes. |
| * <p> |
| * The status is provided as a {@link WifiDisplayStatus} object in the |
| * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra. |
| * </p><p> |
| * This broadcast is only sent to registered receivers and can only be sent by the system. |
| * </p> |
| * @hide |
| */ |
| public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED = |
| "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED"; |
| |
| /** |
| * Contains a {@link WifiDisplayStatus} object. |
| * @hide |
| */ |
| public static final String EXTRA_WIFI_DISPLAY_STATUS = |
| "android.hardware.display.extra.WIFI_DISPLAY_STATUS"; |
| |
| /** |
| * Display category: Presentation displays. |
| * <p> |
| * This category can be used to identify secondary displays that are suitable for |
| * use as presentation displays. |
| * </p> |
| * |
| * @see android.app.Presentation for information about presenting content |
| * on secondary displays. |
| * @see #getDisplays(String) |
| */ |
| public static final String DISPLAY_CATEGORY_PRESENTATION = |
| "android.hardware.display.category.PRESENTATION"; |
| |
| /** @hide */ |
| public DisplayManager(Context context) { |
| mContext = context; |
| mGlobal = DisplayManagerGlobal.getInstance(); |
| } |
| |
| /** |
| * Gets information about a logical display. |
| * |
| * The display metrics may be adjusted to provide compatibility |
| * for legacy applications. |
| * |
| * @param displayId The logical display id. |
| * @return The display object, or null if there is no valid display with the given id. |
| */ |
| public Display getDisplay(int displayId) { |
| synchronized (mLock) { |
| return getOrCreateDisplayLocked(displayId, false /*assumeValid*/); |
| } |
| } |
| |
| /** |
| * Gets all currently valid logical displays. |
| * |
| * @return An array containing all displays. |
| */ |
| public Display[] getDisplays() { |
| return getDisplays(null); |
| } |
| |
| /** |
| * Gets all currently valid logical displays of the specified category. |
| * <p> |
| * When there are multiple displays in a category the returned displays are sorted |
| * of preference. For example, if the requested category is |
| * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays |
| * then the displays are sorted so that the first display in the returned array |
| * is the most preferred presentation display. The application may simply |
| * use the first display or allow the user to choose. |
| * </p> |
| * |
| * @param category The requested display category or null to return all displays. |
| * @return An array containing all displays sorted by order of preference. |
| * |
| * @see #DISPLAY_CATEGORY_PRESENTATION |
| */ |
| public Display[] getDisplays(String category) { |
| final int[] displayIds = mGlobal.getDisplayIds(); |
| synchronized (mLock) { |
| try { |
| if (category == null) { |
| addMatchingDisplaysLocked(mTempDisplays, displayIds, -1); |
| } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) { |
| addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI); |
| addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI); |
| addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY); |
| addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL); |
| } |
| return mTempDisplays.toArray(new Display[mTempDisplays.size()]); |
| } finally { |
| mTempDisplays.clear(); |
| } |
| } |
| } |
| |
| private void addMatchingDisplaysLocked( |
| ArrayList<Display> displays, int[] displayIds, int matchType) { |
| for (int i = 0; i < displayIds.length; i++) { |
| Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); |
| if (display != null |
| && (matchType < 0 || display.getType() == matchType)) { |
| displays.add(display); |
| } |
| } |
| } |
| |
| private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { |
| Display display = mDisplays.get(displayId); |
| if (display == null) { |
| display = mGlobal.getCompatibleDisplay(displayId, |
| mContext.getDisplayAdjustments(displayId)); |
| if (display != null) { |
| mDisplays.put(displayId, display); |
| } |
| } else if (!assumeValid && !display.isValid()) { |
| display = null; |
| } |
| return display; |
| } |
| |
| /** |
| * Registers an display listener to receive notifications about when |
| * displays are added, removed or changed. |
| * |
| * @param listener The listener to register. |
| * @param handler The handler on which the listener should be invoked, or null |
| * if the listener should be invoked on the calling thread's looper. |
| * |
| * @see #unregisterDisplayListener |
| */ |
| public void registerDisplayListener(DisplayListener listener, Handler handler) { |
| mGlobal.registerDisplayListener(listener, handler); |
| } |
| |
| /** |
| * Unregisters an input device listener. |
| * |
| * @param listener The listener to unregister. |
| * |
| * @see #registerDisplayListener |
| */ |
| public void unregisterDisplayListener(DisplayListener listener) { |
| mGlobal.unregisterDisplayListener(listener); |
| } |
| |
| /** |
| * Initiates a fresh scan of availble Wifi displays. |
| * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. |
| * @hide |
| */ |
| public void scanWifiDisplays() { |
| mGlobal.scanWifiDisplays(); |
| } |
| |
| /** |
| * Connects to a Wifi display. |
| * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. |
| * <p> |
| * Automatically remembers the display after a successful connection, if not |
| * already remembered. |
| * </p><p> |
| * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect |
| * to unknown displays. No permissions are required to connect to already known displays. |
| * </p> |
| * |
| * @param deviceAddress The MAC address of the device to which we should connect. |
| * @hide |
| */ |
| public void connectWifiDisplay(String deviceAddress) { |
| mGlobal.connectWifiDisplay(deviceAddress); |
| } |
| |
| /** |
| * Disconnects from the current Wifi display. |
| * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. |
| * @hide |
| */ |
| public void disconnectWifiDisplay() { |
| mGlobal.disconnectWifiDisplay(); |
| } |
| |
| /** |
| * Renames a Wifi display. |
| * <p> |
| * The display must already be remembered for this call to succeed. In other words, |
| * we must already have successfully connected to the display at least once and then |
| * not forgotten it. |
| * </p><p> |
| * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. |
| * </p> |
| * |
| * @param deviceAddress The MAC address of the device to rename. |
| * @param alias The alias name by which to remember the device, or null |
| * or empty if no alias should be used. |
| * @hide |
| */ |
| public void renameWifiDisplay(String deviceAddress, String alias) { |
| mGlobal.renameWifiDisplay(deviceAddress, alias); |
| } |
| |
| /** |
| * Forgets a previously remembered Wifi display. |
| * <p> |
| * Automatically disconnects from the display if currently connected to it. |
| * </p><p> |
| * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. |
| * </p> |
| * |
| * @param deviceAddress The MAC address of the device to forget. |
| * @hide |
| */ |
| public void forgetWifiDisplay(String deviceAddress) { |
| mGlobal.forgetWifiDisplay(deviceAddress); |
| } |
| |
| /** |
| * Gets the current Wifi display status. |
| * Watch for changes in the status by registering a broadcast receiver for |
| * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}. |
| * |
| * @return The current Wifi display status. |
| * @hide |
| */ |
| public WifiDisplayStatus getWifiDisplayStatus() { |
| return mGlobal.getWifiDisplayStatus(); |
| } |
| |
| /** |
| * Creates a private virtual display. |
| * <p> |
| * The content of a virtual display is rendered to a {@link Surface} provided |
| * by the application that created the virtual display. |
| * </p><p> |
| * Only the application that created a private virtual display is allowed to |
| * place windows upon it. The private virtual display also does not participate |
| * in display mirroring: it will neither receive mirrored content from another |
| * display nor allow its own content to be mirrored elsewhere. More precisely, |
| * the only processes that are allowed to enumerate or interact with a private |
| * display are those that have the same UID as the application that originally |
| * created the private virtual display. |
| * </p><p> |
| * The private virtual display should be {@link VirtualDisplay#release released} |
| * when no longer needed. Because a private virtual display renders to a surface |
| * provided by the application, it will be released automatically when the |
| * process terminates and all remaining windows on it will be forcibly removed. |
| * </p> |
| * |
| * @param name The name of the virtual display, must be non-empty. |
| * @param width The width of the virtual display in pixels, must be greater than 0. |
| * @param height The height of the virtual display in pixels, must be greater than 0. |
| * @param densityDpi The density of the virtual display in dpi, must be greater than 0. |
| * @param surface The surface to which the content of the virtual display should |
| * be rendered, must be non-null. |
| * @return The newly created virtual display, or null if the application could |
| * not create the virtual display. |
| */ |
| public VirtualDisplay createPrivateVirtualDisplay(String name, |
| int width, int height, int densityDpi, Surface surface) { |
| return mGlobal.createPrivateVirtualDisplay(mContext, |
| name, width, height, densityDpi, surface); |
| } |
| |
| /** |
| * Listens for changes in available display devices. |
| */ |
| public interface DisplayListener { |
| /** |
| * Called whenever a logical display has been added to the system. |
| * Use {@link DisplayManager#getDisplay} to get more information about |
| * the display. |
| * |
| * @param displayId The id of the logical display that was added. |
| */ |
| void onDisplayAdded(int displayId); |
| |
| /** |
| * Called whenever a logical display has been removed from the system. |
| * |
| * @param displayId The id of the logical display that was removed. |
| */ |
| void onDisplayRemoved(int displayId); |
| |
| /** |
| * Called whenever the properties of a logical display have changed. |
| * |
| * @param displayId The id of the logical display that changed. |
| */ |
| void onDisplayChanged(int displayId); |
| } |
| } |