diff options
| author | Jeff Brown <jeffbrown@google.com> | 2012-10-24 21:28:33 -0700 |
|---|---|---|
| committer | Jeff Brown <jeffbrown@google.com> | 2012-10-25 20:31:21 -0700 |
| commit | 92130f6407dc51c58b3b941d28a6daf4e04b8d62 (patch) | |
| tree | 324aedc986d9d899918a5dc39aecb57aeeb1f057 /core/java/android | |
| parent | 148d413164ce0a780236ffb8ada15cad81be6ce7 (diff) | |
| download | frameworks_base-92130f6407dc51c58b3b941d28a6daf4e04b8d62.zip frameworks_base-92130f6407dc51c58b3b941d28a6daf4e04b8d62.tar.gz frameworks_base-92130f6407dc51c58b3b941d28a6daf4e04b8d62.tar.bz2 | |
Add MediaRouter API to get presentation display.
This new API makes it possible for an application to ask on
which Display it should show a Presentation based on the currently
selected media route.
Also added a new API on DisplayManager to query displays that
support a certain category of uses.
Improved the documentation of the Presentation class to explain
how to choose an appropriate Display for presentation.
Bug: 7409073
Change-Id: Iab451215e570ae55f3718fc228303143c800fe51
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/Presentation.java | 89 | ||||
| -rw-r--r-- | core/java/android/hardware/display/DisplayManager.java | 72 | ||||
| -rw-r--r-- | core/java/android/view/Display.java | 103 | ||||
| -rw-r--r-- | core/java/android/view/DisplayInfo.java | 27 |
4 files changed, 268 insertions, 23 deletions
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index 20b27c5..3e8af60 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -50,6 +50,93 @@ import android.util.TypedValue; * whenever the activity itself is paused or resumed. * </p> * + * <h3>Choosing a presentation display</h3> + * <p> + * Before showing a {@link Presentation} it's important to choose the {@link Display} + * on which it will appear. Choosing a presentation display is sometimes difficult + * because there may be multiple displays attached. Rather than trying to guess + * which display is best, an application should let the system choose a suitable + * presentation display. + * </p><p> + * There are two main ways to choose a {@link Display}. + * </p> + * + * <h4>Using the media router to choose a presentation display</h4> + * <p> + * The easiest way to choose a presentation display is to use the + * {@link android.media.MediaRouter MediaRouter} API. The media router service keeps + * track of which audio and video routes are available on the system. + * The media router sends notifications whenever routes are selected or unselected + * or when the preferred presentation display of a route changes. + * So an application can simply watch for these notifications and show or dismiss + * a presentation on the preferred presentation display automatically. + * </p><p> + * The preferred presentation display is the display that the media router recommends + * that the application should use if it wants to show content on the secondary display. + * Sometimes there may not be a preferred presentation display in which + * case the application should show its content locally without using a presentation. + * </p><p> + * Here's how to use the media router to create and show a presentation on the preferred + * presentation display using {@link android.media.MediaRouter.RouteInfo#getPresentationDisplay()}. + * </p> + * {@samplecode + * MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); + * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(); + * if (route != null) ${ + * Display presentationDisplay = route.getPresentationDisplay(); + * if (presentationDisplay != null) ${ + * Presentation presentation = new MyPresentation(context, presentationDisplay); + * presentation.show(); + * $} + * $} + * } + * <p> + * The following sample code from <code>ApiDemos</code> demonstrates how to use the media + * router to automatically switch between showing content in the main activity and showing + * the content in a presentation when a presentation display is available. + * </p> + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationWithMediaRouterActivity.java + * activity} + * + * <h4>Using the display manager to choose a presentation display</h4> + * <p> + * Another way to choose a presentation display is to use the {@link DisplayManager} API + * directly. The display manager service provides functions to enumerate and describe all + * displays that are attached to the system including displays that may be used + * for presentations. + * </p><p> + * The display manager keeps track of all displays in the system. However, not all + * displays are appropriate for showing presentations. For example, if an activity + * attempted to show a presentation on the main display it might obscure its own content + * (it's like opening a dialog on top of your activity). + * </p><p> + * Here's how to identify suitable displays for showing presentations using + * {@link DisplayManager#getDisplays(String)} and the + * {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION} category. + * </p> + * {@samplecode + * DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + * Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + * if (presentationDisplays.length > 0) ${ + * // If there is more than one suitable presentation display, then we could consider + * // giving the user a choice. For this example, we simply choose the first display + * // which is the one the system recommends as the preferred presentation display. + * Display display = presentationDisplays[0]; + * Presentation presentation = new MyPresentation(context, presentationDisplay); + * presentation.show(); + * $} + * } + * <p> + * The following sample code from <code>ApiDemos</code> demonstrates how to use the display + * manager to enumerate displays and show content on multiple presentation displays + * simultaneously. + * </p> + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java + * activity} + * + * @see android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO for information on about live + * video routes and how to obtain the preferred presentation display for the + * current media route. * @see DisplayManager for information on how to enumerate displays and receive * notifications when displays are added or removed. */ @@ -121,7 +208,7 @@ public class Presentation extends Dialog { @Override protected void onStart() { super.onStart(); - mDisplayManager.registerDisplayListener(mDisplayListener, null); + mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); // Since we were not watching for display changes until just now, there is a // chance that the display metrics have changed. If so, we will need to diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 28e320b..0a7a2e7 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -21,6 +21,8 @@ import android.os.Handler; import android.util.SparseArray; import android.view.Display; +import java.util.ArrayList; + /** * Manages the properties of attached displays. * <p> @@ -40,6 +42,8 @@ public final class DisplayManager { 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> @@ -60,6 +64,20 @@ public final class DisplayManager { 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; @@ -87,24 +105,52 @@ public final class DisplayManager { * @return An array containing all displays. */ public Display[] getDisplays() { - int[] displayIds = mGlobal.getDisplayIds(); - int expectedCount = displayIds.length; - Display[] displays = new Display[expectedCount]; + 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) { - int actualCount = 0; - for (int i = 0; i < expectedCount; i++) { - Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); - if (display != null) { - displays[actualCount++] = display; + 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); } + return mTempDisplays.toArray(new Display[mTempDisplays.size()]); + } finally { + mTempDisplays.clear(); } - if (actualCount != expectedCount) { - Display[] oldDisplays = displays; - displays = new Display[actualCount]; - System.arraycopy(oldDisplays, 0, displays, 0, actualCount); + } + } + + 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); } } - return displays; } private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 1cd3e05..758abb5 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -54,7 +54,9 @@ public final class Display { private final DisplayManagerGlobal mGlobal; private final int mDisplayId; private final int mLayerStack; - private final String mName; + private final int mFlags; + private final int mType; + private final String mAddress; private final CompatibilityInfoHolder mCompatibilityInfo; private DisplayInfo mDisplayInfo; // never null @@ -141,6 +143,36 @@ public final class Display { public static final int FLAG_SECURE = 1 << 1; /** + * Display type: Unknown display type. + * @hide + */ + public static final int TYPE_UNKNOWN = 0; + + /** + * Display type: Built-in display. + * @hide + */ + public static final int TYPE_BUILT_IN = 1; + + /** + * Display type: HDMI display. + * @hide + */ + public static final int TYPE_HDMI = 2; + + /** + * Display type: WiFi display. + * @hide + */ + public static final int TYPE_WIFI = 3; + + /** + * Display type: Overlay display. + * @hide + */ + public static final int TYPE_OVERLAY = 4; + + /** * Internal method to create a display. * Applications should use {@link android.view.WindowManager#getDefaultDisplay()} * or {@link android.hardware.display.DisplayManager#getDisplay} @@ -154,10 +186,14 @@ public final class Display { mGlobal = global; mDisplayId = displayId; mDisplayInfo = displayInfo; - mLayerStack = displayInfo.layerStack; // can never change as long as the display is valid - mName = displayInfo.name; // cannot change as long as the display is valid mCompatibilityInfo = compatibilityInfo; mIsValid = true; + + // Cache properties that cannot change as long as the display is valid. + mLayerStack = displayInfo.layerStack; + mFlags = displayInfo.flags; + mType = displayInfo.type; + mAddress = displayInfo.address; } /** @@ -228,10 +264,34 @@ public final class Display { * @see #FLAG_SECURE */ public int getFlags() { - synchronized (this) { - updateDisplayInfoLocked(); - return mDisplayInfo.flags; - } + return mFlags; + } + + /** + * Gets the display type. + * + * @return The display type. + * + * @see #TYPE_UNKNOWN + * @see #TYPE_BUILT_IN + * @see #TYPE_HDMI + * @see #TYPE_WIFI + * @see #TYPE_OVERLAY + * @hide + */ + public int getType() { + return mType; + } + + /** + * Gets the display address, or null if none. + * Interpretation varies by display type. + * + * @return The display address. + * @hide + */ + public String getAddress() { + return mAddress; } /** @@ -246,10 +306,17 @@ public final class Display { /** * Gets the name of the display. + * <p> + * Note that some displays may be renamed by the user. + * </p> + * * @return The display's name. */ public String getName() { - return mName; + synchronized (this) { + updateDisplayInfoLocked(); + return mDisplayInfo.name; + } } /** @@ -527,5 +594,25 @@ public final class Display { + ", " + mTempMetrics + ", isValid=" + mIsValid; } } + + /** + * @hide + */ + public static String typeToString(int type) { + switch (type) { + case TYPE_UNKNOWN: + return "UNKNOWN"; + case TYPE_BUILT_IN: + return "BUILT_IN"; + case TYPE_HDMI: + return "HDMI"; + case TYPE_WIFI: + return "WIFI"; + case TYPE_OVERLAY: + return "OVERLAY"; + default: + return Integer.toString(type); + } + } } diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index ead5ff4..f3841d5 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -39,6 +39,17 @@ public final class DisplayInfo implements Parcelable { public int flags; /** + * Display type. + */ + public int type; + + /** + * Display address, or null if none. + * Interpretation varies by display type. + */ + public String address; + + /** * The human-readable name of the display. */ public String name; @@ -143,10 +154,12 @@ public final class DisplayInfo implements Parcelable { public float physicalYDpi; public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() { + @Override public DisplayInfo createFromParcel(Parcel source) { return new DisplayInfo(source); } + @Override public DisplayInfo[] newArray(int size) { return new DisplayInfo[size]; } @@ -171,6 +184,9 @@ public final class DisplayInfo implements Parcelable { public boolean equals(DisplayInfo other) { return other != null && layerStack == other.layerStack + && flags == other.flags + && type == other.type + && Objects.equal(address, other.address) && Objects.equal(name, other.name) && appWidth == other.appWidth && appHeight == other.appHeight @@ -195,6 +211,8 @@ public final class DisplayInfo implements Parcelable { public void copyFrom(DisplayInfo other) { layerStack = other.layerStack; flags = other.flags; + type = other.type; + address = other.address; name = other.name; appWidth = other.appWidth; appHeight = other.appHeight; @@ -214,6 +232,8 @@ public final class DisplayInfo implements Parcelable { public void readFromParcel(Parcel source) { layerStack = source.readInt(); flags = source.readInt(); + type = source.readInt(); + address = source.readString(); name = source.readString(); appWidth = source.readInt(); appHeight = source.readInt(); @@ -234,6 +254,8 @@ public final class DisplayInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(layerStack); dest.writeInt(this.flags); + dest.writeInt(type); + dest.writeString(address); dest.writeString(name); dest.writeInt(appWidth); dest.writeInt(appHeight); @@ -294,7 +316,10 @@ public final class DisplayInfo implements Parcelable { + ", rotation " + rotation + ", density " + logicalDensityDpi + ", " + physicalXDpi + " x " + physicalYDpi + " dpi" - + ", layerStack " + layerStack + flagsToString(flags) + "}"; + + ", layerStack " + layerStack + + ", type " + Display.typeToString(type) + + ", address " + address + + flagsToString(flags) + "}"; } private static String flagsToString(int flags) { |
