summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-10-24 21:28:33 -0700
committerJeff Brown <jeffbrown@google.com>2012-10-25 20:31:21 -0700
commit92130f6407dc51c58b3b941d28a6daf4e04b8d62 (patch)
tree324aedc986d9d899918a5dc39aecb57aeeb1f057 /core/java/android
parent148d413164ce0a780236ffb8ada15cad81be6ce7 (diff)
downloadframeworks_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.java89
-rw-r--r--core/java/android/hardware/display/DisplayManager.java72
-rw-r--r--core/java/android/view/Display.java103
-rw-r--r--core/java/android/view/DisplayInfo.java27
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) $&#123;
+ * Display presentationDisplay = route.getPresentationDisplay();
+ * if (presentationDisplay != null) $&#123;
+ * Presentation presentation = new MyPresentation(context, presentationDisplay);
+ * presentation.show();
+ * $&#125;
+ * $&#125;
+ * }
+ * <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) $&#123;
+ * // 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();
+ * $&#125;
+ * }
+ * <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) {