public final class DisplayManager {
method public android.view.Display getDisplay(int);
method public android.view.Display[] getDisplays();
+ method public android.view.Display[] getDisplays(java.lang.String);
method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
+ field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
}
public static abstract interface DisplayManager.DisplayListener {
method public abstract void onRouteAdded(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteGrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup, int);
+ method public void onRoutePresentationDisplayChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteRemoved(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup);
method public java.lang.CharSequence getName(android.content.Context);
method public int getPlaybackStream();
method public int getPlaybackType();
+ method public android.view.Display getPresentationDisplay();
method public java.lang.CharSequence getStatus();
method public int getSupportedTypes();
method public java.lang.Object getTag();
public final class DisplayManager {
method public android.view.Display getDisplay(int);
method public android.view.Display[] getDisplays();
+ method public android.view.Display[] getDisplays(java.lang.String);
method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
+ field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
}
public static abstract interface DisplayManager.DisplayListener {
method public abstract void onRouteAdded(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteGrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup, int);
+ method public void onRoutePresentationDisplayChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteRemoved(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo);
method public abstract void onRouteUngrouped(android.media.MediaRouter, android.media.MediaRouter.RouteInfo, android.media.MediaRouter.RouteGroup);
method public java.lang.CharSequence getName(android.content.Context);
method public int getPlaybackStream();
method public int getPlaybackType();
+ method public android.view.Display getPresentationDisplay();
method public java.lang.CharSequence getStatus();
method public int getSupportedTypes();
method public java.lang.Object getTag();
* 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.
*/
@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
import android.util.SparseArray;
import android.view.Display;
+import java.util.ArrayList;
+
/**
* Manages the properties of attached displays.
* <p>
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>
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;
* @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) {
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
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}
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;
}
/**
* @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;
}
/**
/**
* 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;
+ }
}
/**
+ ", " + 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);
+ }
+ }
}
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;
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];
}
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
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;
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();
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);
+ ", 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) {
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
-import android.view.DisplayInfo;
import java.util.ArrayList;
import java.util.HashMap;
public class MediaRouter {
private static final String TAG = "MediaRouter";
- static class Static {
+ static class Static implements DisplayManager.DisplayListener {
final Resources mResources;
final IAudioService mAudioService;
final DisplayManager mDisplayService;
mDefaultAudioVideo = new RouteInfo(mSystemCategory);
mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name;
mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
+ mDefaultAudioVideo.mPresentationDisplay = choosePresentationDisplayForRoute(
+ mDefaultAudioVideo, getAllPresentationDisplays());
addRouteStatic(mDefaultAudioVideo);
// This will select the active wifi display route if there is one.
appContext.registerReceiver(new VolumeChangeReceiver(),
new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));
+ mDisplayService.registerDisplayListener(this, mHandler);
+
AudioRoutesInfo newAudioRoutes = null;
try {
newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
}
}
}
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ updatePresentationDisplays(displayId);
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ updatePresentationDisplays(displayId);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ updatePresentationDisplays(displayId);
+ }
+
+ public Display[] getAllPresentationDisplays() {
+ return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
+ }
+
+ private void updatePresentationDisplays(int changedDisplayId) {
+ final Display[] displays = getAllPresentationDisplays();
+ final int count = mRoutes.size();
+ for (int i = 0; i < count; i++) {
+ final RouteInfo info = mRoutes.get(i);
+ Display display = choosePresentationDisplayForRoute(info, displays);
+ if (display != info.mPresentationDisplay
+ || (display != null && display.getDisplayId() == changedDisplayId)) {
+ info.mPresentationDisplay = display;
+ dispatchRoutePresentationDisplayChanged(info);
+ }
+ }
+ }
}
static Static sStatic;
* While remote routing is active the application may use a
* {@link android.app.Presentation Presentation} to replace the mirrored view
* on the external display with different content.</p>
+ *
+ * @see RouteInfo#getPresentationDisplay()
+ * @see android.app.Presentation
*/
public static final int ROUTE_TYPE_LIVE_VIDEO = 0x2;
}
}
+ static void dispatchRoutePresentationDisplayChanged(RouteInfo info) {
+ for (CallbackInfo cbi : sStatic.mCallbacks) {
+ if ((cbi.type & info.mSupportedTypes) != 0) {
+ cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info);
+ }
+ }
+ }
+
static void systemVolumeChanged(int newValue) {
final RouteInfo selectedRoute = sStatic.mSelectedRoute;
if (selectedRoute == null) return;
newRoute.mEnabled = available;
newRoute.mName = display.getFriendlyDisplayName();
+
+ newRoute.mPresentationDisplay = choosePresentationDisplayForRoute(newRoute,
+ sStatic.getAllPresentationDisplays());
return newRoute;
}
return null;
}
+ private static Display choosePresentationDisplayForRoute(RouteInfo route, Display[] displays) {
+ if ((route.mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) {
+ if (route.mDeviceAddress != null) {
+ // Find the indicated Wifi display by its address.
+ for (Display display : displays) {
+ if (display.getType() == Display.TYPE_WIFI
+ && route.mDeviceAddress.equals(display.getAddress())) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ if (route == sStatic.mDefaultAudioVideo && displays.length > 0) {
+ // Choose the first presentation display from the list.
+ return displays[0];
+ }
+ }
+ return null;
+ }
+
/**
* Information about a media route.
*/
int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
int mPlaybackStream = AudioManager.STREAM_MUSIC;
VolumeCallbackInfo mVcb;
+ Display mPresentationDisplay;
String mDeviceAddress;
boolean mEnabled = true;
}
/**
+ * Gets the {@link Display} that should be used by the application to show
+ * a {@link android.app.Presentation} on an external display when this route is selected.
+ * Depending on the route, this may only be valid if the route is currently
+ * selected.
+ * <p>
+ * The preferred presentation display may change independently of the route
+ * being selected or unselected. For example, the presentation display
+ * of the default system route may change when an external HDMI display is connected
+ * or disconnected even though the route itself has not changed.
+ * </p><p>
+ * This method may return null if there is no external display associated with
+ * the route or if the display is not ready to show UI yet.
+ * </p><p>
+ * The application should listen for changes to the presentation display
+ * using the {@link Callback#onRoutePresentationDisplayChanged} callback and
+ * show or dismiss its {@link android.app.Presentation} accordingly when the display
+ * becomes available or is removed.
+ * </p><p>
+ * This method only makes sense for {@link #ROUTE_TYPE_LIVE_VIDEO live video} routes.
+ * </p>
+ *
+ * @return The preferred presentation display to use when this route is
+ * selected or null if none.
+ *
+ * @see #ROUTE_TYPE_LIVE_VIDEO
+ * @see android.app.Presentation
+ */
+ public Display getPresentationDisplay() {
+ return mPresentationDisplay;
+ }
+
+ /**
* @return true if this route is enabled and may be selected
*/
public boolean isEnabled() {
@Override
public String toString() {
String supportedTypes = typesToString(getSupportedTypes());
- return getClass().getSimpleName() + "{ name=" + getName() + ", status=" + getStatus() +
- " category=" + getCategory() +
- " supportedTypes=" + supportedTypes + "}";
+ return getClass().getSimpleName() + "{ name=" + getName() +
+ ", status=" + getStatus() +
+ ", category=" + getCategory() +
+ ", supportedTypes=" + supportedTypes +
+ ", presentationDisplay=" + mPresentationDisplay + "}";
}
}
* @param info The route with altered volume
*/
public abstract void onRouteVolumeChanged(MediaRouter router, RouteInfo info);
+
+ /**
+ * Called when a route's presentation display changes.
+ * <p>
+ * This method is called whenever the route's presentation display becomes
+ * available, is removes or has changes to some of its properties (such as its size).
+ * </p>
+ *
+ * @param router the MediaRouter reporting the event
+ * @param info The route whose presentation display changed
+ *
+ * @see RouteInfo#getPresentationDisplay()
+ */
+ public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
+ }
}
/**
package com.android.server.display;
import android.util.DisplayMetrics;
+import android.view.Display;
import android.view.Surface;
import libcore.util.Objects;
*/
public int rotation = Surface.ROTATION_0;
+ /**
+ * Display type.
+ */
+ public int type;
+
+ /**
+ * Display address, or null if none.
+ * Interpretation varies by display type.
+ */
+ public String address;
+
public void setAssumedDensityForExternalDisplay(int width, int height) {
densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
// Technically, these values should be smaller than the apparent density
&& yDpi == other.yDpi
&& flags == other.flags
&& touch == other.touch
- && rotation == other.rotation;
+ && rotation == other.rotation
+ && type == other.type
+ && Objects.equal(address, other.address);
}
@Override
flags = other.flags;
touch = other.touch;
rotation = other.rotation;
+ type = other.type;
+ address = other.address;
}
// For debugging purposes
+ "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi"
+ ", touch " + touchToString(touch) + flagsToString(flags)
+ ", rotation " + rotation
+ + ", type " + Display.typeToString(type)
+ + ", address " + address
+ "}";
}
import android.content.Context;
import android.os.Handler;
import android.util.DisplayMetrics;
+import android.view.Display;
/**
* Provides a fake default display for headless systems.
mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
| DisplayDeviceInfo.FLAG_SECURE
| DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
+ mInfo.type = Display.TYPE_BUILT_IN;
mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
}
return mInfo;
import android.os.Looper;
import android.os.SystemProperties;
import android.util.SparseArray;
+import android.view.Display;
import android.view.DisplayEventReceiver;
import android.view.Surface;
import android.view.Surface.PhysicalDisplayInfo;
com.android.internal.R.string.display_manager_built_in_display_name);
mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
| DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
+ mInfo.type = Display.TYPE_BUILT_IN;
mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
mInfo.xDpi = mPhys.xDpi;
mInfo.yDpi = mPhys.yDpi;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
} else {
+ mInfo.type = Display.TYPE_HDMI;
mInfo.name = getContext().getResources().getString(
com.android.internal.R.string.display_manager_hdmi_display_name);
mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SECURE) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_SECURE;
}
+ mBaseDisplayInfo.type = deviceInfo.type;
+ mBaseDisplayInfo.address = deviceInfo.address;
mBaseDisplayInfo.name = deviceInfo.name;
mBaseDisplayInfo.appWidth = deviceInfo.width;
mBaseDisplayInfo.appHeight = deviceInfo.height;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Slog;
+import android.view.Display;
import android.view.Gravity;
import android.view.Surface;
mInfo.xDpi = mDensityDpi;
mInfo.yDpi = mDensityDpi;
mInfo.flags = 0;
+ mInfo.type = Display.TYPE_OVERLAY;
mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
}
return mInfo;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
+import android.view.Display;
import android.view.Surface;
import java.io.PrintWriter;
float refreshRate = 60.0f; // TODO: get this for real
String name = display.getFriendlyDisplayName();
+ String address = display.getDeviceAddress();
IBinder displayToken = Surface.createDisplay(name, secure);
mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
- refreshRate, deviceFlags, surface);
+ refreshRate, deviceFlags, address, surface);
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
scheduleUpdateNotificationLocked();
private final int mHeight;
private final float mRefreshRate;
private final int mFlags;
+ private final String mAddress;
private Surface mSurface;
private DisplayDeviceInfo mInfo;
public WifiDisplayDevice(IBinder displayToken, String name,
- int width, int height, float refreshRate, int flags,
+ int width, int height, float refreshRate, int flags, String address,
Surface surface) {
super(WifiDisplayAdapter.this, displayToken);
mName = name;
mHeight = height;
mRefreshRate = refreshRate;
mFlags = flags;
+ mAddress = address;
mSurface = surface;
}
mInfo.height = mHeight;
mInfo.refreshRate = mRefreshRate;
mInfo.flags = mFlags;
+ mInfo.type = Display.TYPE_WIFI;
+ mInfo.address = mAddress;
mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
}