Skip to content

Commit 92130f6

Browse files
author
Jeff Brown
committed
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
1 parent 148d413 commit 92130f6

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)