Skip to content

Commit 4e0bf7c

Browse files
Jeff BrownAndroid (Google) Code Review
authored andcommitted
Merge "Add MediaRouter API to get presentation display." into jb-mr1-dev
2 parents 50e1f9e + 92130f6 commit 4e0bf7c

File tree

13 files changed

+438
-31
lines changed

13 files changed

+438
-31
lines changed

api/17.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10093,8 +10093,10 @@ package android.hardware.display {
1009310093
public final class DisplayManager {
1009410094
method public android.view.Display getDisplay(int);
1009510095
method public android.view.Display[] getDisplays();
10096+
method public android.view.Display[] getDisplays(java.lang.String);
1009610097
method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
1009710098
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
10099+
field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
1009810100
}
1009910101

1010010102
public static abstract interface DisplayManager.DisplayListener {
@@ -11768,6 +11770,7 @@ package android.media {
1176811770
method public abstract void onRouteAdded(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1176911771
method public abstract void onRouteChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1177011772
method public abstract void onRouteGrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup, int);
11773+
method public void onRoutePresentationDisplayChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1177111774
method public abstract void onRouteRemoved(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1177211775
method public abstract void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
1177311776
method public abstract void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup);
@@ -11802,6 +11805,7 @@ package android.media {
1180211805
method public java.lang.CharSequence getName(android.content.Context);
1180311806
method public int getPlaybackStream();
1180411807
method public int getPlaybackType();
11808+
method public android.view.Display getPresentationDisplay();
1180511809
method public java.lang.CharSequence getStatus();
1180611810
method public int getSupportedTypes();
1180711811
method public java.lang.Object getTag();

api/current.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10093,8 +10093,10 @@ package android.hardware.display {
1009310093
public final class DisplayManager {
1009410094
method public android.view.Display getDisplay(int);
1009510095
method public android.view.Display[] getDisplays();
10096+
method public android.view.Display[] getDisplays(java.lang.String);
1009610097
method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
1009710098
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
10099+
field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
1009810100
}
1009910101

1010010102
public static abstract interface DisplayManager.DisplayListener {
@@ -11768,6 +11770,7 @@ package android.media {
1176811770
method public abstract void onRouteAdded(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1176911771
method public abstract void onRouteChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1177011772
method public abstract void onRouteGrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup, int);
11773+
method public void onRoutePresentationDisplayChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1177111774
method public abstract void onRouteRemoved(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
1177211775
method public abstract void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
1177311776
method public abstract void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup);
@@ -11802,6 +11805,7 @@ package android.media {
1180211805
method public java.lang.CharSequence getName(android.content.Context);
1180311806
method public int getPlaybackStream();
1180411807
method public int getPlaybackType();
11808+
method public android.view.Display getPresentationDisplay();
1180511809
method public java.lang.CharSequence getStatus();
1180611810
method public int getSupportedTypes();
1180711811
method public java.lang.Object getTag();

core/java/android/app/Presentation.java

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,93 @@
5050
* whenever the activity itself is paused or resumed.
5151
* </p>
5252
*
53+
* <h3>Choosing a presentation display</h3>
54+
* <p>
55+
* Before showing a {@link Presentation} it's important to choose the {@link Display}
56+
* on which it will appear. Choosing a presentation display is sometimes difficult
57+
* because there may be multiple displays attached. Rather than trying to guess
58+
* which display is best, an application should let the system choose a suitable
59+
* presentation display.
60+
* </p><p>
61+
* There are two main ways to choose a {@link Display}.
62+
* </p>
63+
*
64+
* <h4>Using the media router to choose a presentation display</h4>
65+
* <p>
66+
* The easiest way to choose a presentation display is to use the
67+
* {@link android.media.MediaRouter MediaRouter} API. The media router service keeps
68+
* track of which audio and video routes are available on the system.
69+
* The media router sends notifications whenever routes are selected or unselected
70+
* or when the preferred presentation display of a route changes.
71+
* So an application can simply watch for these notifications and show or dismiss
72+
* a presentation on the preferred presentation display automatically.
73+
* </p><p>
74+
* The preferred presentation display is the display that the media router recommends
75+
* that the application should use if it wants to show content on the secondary display.
76+
* Sometimes there may not be a preferred presentation display in which
77+
* case the application should show its content locally without using a presentation.
78+
* </p><p>
79+
* Here's how to use the media router to create and show a presentation on the preferred
80+
* presentation display using {@link android.media.MediaRouter.RouteInfo#getPresentationDisplay()}.
81+
* </p>
82+
* {@samplecode
83+
* MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
84+
* MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
85+
* if (route != null) $&#123;
86+
* Display presentationDisplay = route.getPresentationDisplay();
87+
* if (presentationDisplay != null) $&#123;
88+
* Presentation presentation = new MyPresentation(context, presentationDisplay);
89+
* presentation.show();
90+
* $&#125;
91+
* $&#125;
92+
* }
93+
* <p>
94+
* The following sample code from <code>ApiDemos</code> demonstrates how to use the media
95+
* router to automatically switch between showing content in the main activity and showing
96+
* the content in a presentation when a presentation display is available.
97+
* </p>
98+
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationWithMediaRouterActivity.java
99+
* activity}
100+
*
101+
* <h4>Using the display manager to choose a presentation display</h4>
102+
* <p>
103+
* Another way to choose a presentation display is to use the {@link DisplayManager} API
104+
* directly. The display manager service provides functions to enumerate and describe all
105+
* displays that are attached to the system including displays that may be used
106+
* for presentations.
107+
* </p><p>
108+
* The display manager keeps track of all displays in the system. However, not all
109+
* displays are appropriate for showing presentations. For example, if an activity
110+
* attempted to show a presentation on the main display it might obscure its own content
111+
* (it's like opening a dialog on top of your activity).
112+
* </p><p>
113+
* Here's how to identify suitable displays for showing presentations using
114+
* {@link DisplayManager#getDisplays(String)} and the
115+
* {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION} category.
116+
* </p>
117+
* {@samplecode
118+
* DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
119+
* Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
120+
* if (presentationDisplays.length > 0) $&#123;
121+
* // If there is more than one suitable presentation display, then we could consider
122+
* // giving the user a choice. For this example, we simply choose the first display
123+
* // which is the one the system recommends as the preferred presentation display.
124+
* Display display = presentationDisplays[0];
125+
* Presentation presentation = new MyPresentation(context, presentationDisplay);
126+
* presentation.show();
127+
* $&#125;
128+
* }
129+
* <p>
130+
* The following sample code from <code>ApiDemos</code> demonstrates how to use the display
131+
* manager to enumerate displays and show content on multiple presentation displays
132+
* simultaneously.
133+
* </p>
134+
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java
135+
* activity}
136+
*
137+
* @see android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO for information on about live
138+
* video routes and how to obtain the preferred presentation display for the
139+
* current media route.
53140
* @see DisplayManager for information on how to enumerate displays and receive
54141
* notifications when displays are added or removed.
55142
*/
@@ -121,7 +208,7 @@ public Resources getResources() {
121208
@Override
122209
protected void onStart() {
123210
super.onStart();
124-
mDisplayManager.registerDisplayListener(mDisplayListener, null);
211+
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
125212

126213
// Since we were not watching for display changes until just now, there is a
127214
// chance that the display metrics have changed. If so, we will need to

core/java/android/hardware/display/DisplayManager.java

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import android.util.SparseArray;
2222
import android.view.Display;
2323

24+
import java.util.ArrayList;
25+
2426
/**
2527
* Manages the properties of attached displays.
2628
* <p>
@@ -40,6 +42,8 @@ public final class DisplayManager {
4042
private final Object mLock = new Object();
4143
private final SparseArray<Display> mDisplays = new SparseArray<Display>();
4244

45+
private final ArrayList<Display> mTempDisplays = new ArrayList<Display>();
46+
4347
/**
4448
* Broadcast receiver that indicates when the Wifi display status changes.
4549
* <p>
@@ -60,6 +64,20 @@ public final class DisplayManager {
6064
public static final String EXTRA_WIFI_DISPLAY_STATUS =
6165
"android.hardware.display.extra.WIFI_DISPLAY_STATUS";
6266

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+
6381
/** @hide */
6482
public DisplayManager(Context context) {
6583
mContext = context;
@@ -87,24 +105,52 @@ public Display getDisplay(int displayId) {
87105
* @return An array containing all displays.
88106
*/
89107
public Display[] getDisplays() {
90-
int[] displayIds = mGlobal.getDisplayIds();
91-
int expectedCount = displayIds.length;
92-
Display[] displays = new Display[expectedCount];
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();
93129
synchronized (mLock) {
94-
int actualCount = 0;
95-
for (int i = 0; i < expectedCount; i++) {
96-
Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
97-
if (display != null) {
98-
displays[actualCount++] = display;
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);
99137
}
138+
return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
139+
} finally {
140+
mTempDisplays.clear();
100141
}
101-
if (actualCount != expectedCount) {
102-
Display[] oldDisplays = displays;
103-
displays = new Display[actualCount];
104-
System.arraycopy(oldDisplays, 0, displays, 0, actualCount);
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);
105152
}
106153
}
107-
return displays;
108154
}
109155

110156
private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {

0 commit comments

Comments
 (0)