am 3de885be
: Merge "Disallow applications from initiating cast screen." into klp-dev
* commit '3de885bef2f0f85ea76fd96c8f18cdd743ce66a4': Disallow applications from initiating cast screen.
This commit is contained in:
@ -299,6 +299,10 @@ public final class DisplayManager {
|
|||||||
/**
|
/**
|
||||||
* Initiates a fresh scan of availble Wifi displays.
|
* Initiates a fresh scan of availble Wifi displays.
|
||||||
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
|
* The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
|
||||||
|
* <p>
|
||||||
|
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void scanWifiDisplays() {
|
public void scanWifiDisplays() {
|
||||||
@ -312,8 +316,7 @@ public final class DisplayManager {
|
|||||||
* Automatically remembers the display after a successful connection, if not
|
* Automatically remembers the display after a successful connection, if not
|
||||||
* already remembered.
|
* already remembered.
|
||||||
* </p><p>
|
* </p><p>
|
||||||
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect
|
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
|
||||||
* to unknown displays. No permissions are required to connect to already known displays.
|
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param deviceAddress The MAC address of the device to which we should connect.
|
* @param deviceAddress The MAC address of the device to which we should connect.
|
||||||
|
@ -18,11 +18,13 @@ package android.media;
|
|||||||
|
|
||||||
import com.android.internal.util.Objects;
|
import com.android.internal.util.Objects;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.hardware.display.DisplayManager;
|
import android.hardware.display.DisplayManager;
|
||||||
@ -30,6 +32,7 @@ import android.hardware.display.WifiDisplay;
|
|||||||
import android.hardware.display.WifiDisplayStatus;
|
import android.hardware.display.WifiDisplayStatus;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
@ -82,6 +85,7 @@ public class MediaRouter {
|
|||||||
|
|
||||||
RouteInfo mSelectedRoute;
|
RouteInfo mSelectedRoute;
|
||||||
|
|
||||||
|
final boolean mCanConfigureWifiDisplays;
|
||||||
boolean mActivelyScanningWifiDisplays;
|
boolean mActivelyScanningWifiDisplays;
|
||||||
|
|
||||||
int mDiscoveryRequestRouteTypes;
|
int mDiscoveryRequestRouteTypes;
|
||||||
@ -129,6 +133,13 @@ public class MediaRouter {
|
|||||||
com.android.internal.R.string.default_audio_route_category_name,
|
com.android.internal.R.string.default_audio_route_category_name,
|
||||||
ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false);
|
ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false);
|
||||||
mSystemCategory.mIsSystem = true;
|
mSystemCategory.mIsSystem = true;
|
||||||
|
|
||||||
|
// Only the system can configure wifi displays. The display manager
|
||||||
|
// enforces this with a permission check. Set a flag here so that we
|
||||||
|
// know whether this process is actually allowed to scan and connect.
|
||||||
|
mCanConfigureWifiDisplays = appContext.checkPermission(
|
||||||
|
Manifest.permission.CONFIGURE_WIFI_DISPLAY,
|
||||||
|
Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after sStatic is initialized
|
// Called after sStatic is initialized
|
||||||
@ -255,7 +266,7 @@ public class MediaRouter {
|
|||||||
}
|
}
|
||||||
if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
|
if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
|
||||||
activeScan = true;
|
activeScan = true;
|
||||||
if ((cbi.type & (ROUTE_TYPE_LIVE_VIDEO | ROUTE_TYPE_REMOTE_DISPLAY)) != 0) {
|
if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
|
||||||
activeScanWifiDisplay = true;
|
activeScanWifiDisplay = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,7 +279,7 @@ public class MediaRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update wifi display scanning.
|
// Update wifi display scanning.
|
||||||
if (activeScanWifiDisplay) {
|
if (activeScanWifiDisplay && mCanConfigureWifiDisplays) {
|
||||||
if (!mActivelyScanningWifiDisplays) {
|
if (!mActivelyScanningWifiDisplays) {
|
||||||
mActivelyScanningWifiDisplays = true;
|
mActivelyScanningWifiDisplays = true;
|
||||||
mHandler.post(mScanWifiDisplays);
|
mHandler.post(mScanWifiDisplays);
|
||||||
@ -493,7 +504,8 @@ public class MediaRouter {
|
|||||||
route.mDescription = globalRoute.description;
|
route.mDescription = globalRoute.description;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
if (route.mSupportedTypes != globalRoute.supportedTypes) {
|
final int oldSupportedTypes = route.mSupportedTypes;
|
||||||
|
if (oldSupportedTypes != globalRoute.supportedTypes) {
|
||||||
route.mSupportedTypes = globalRoute.supportedTypes;
|
route.mSupportedTypes = globalRoute.supportedTypes;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
@ -536,7 +548,7 @@ public class MediaRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
dispatchRouteChanged(route);
|
dispatchRouteChanged(route, oldSupportedTypes);
|
||||||
}
|
}
|
||||||
if (volumeChanged) {
|
if (volumeChanged) {
|
||||||
dispatchRouteVolumeChanged(route);
|
dispatchRouteVolumeChanged(route);
|
||||||
@ -908,7 +920,12 @@ public class MediaRouter {
|
|||||||
final boolean newRouteHasAddress = route != null && route.mDeviceAddress != null;
|
final boolean newRouteHasAddress = route != null && route.mDeviceAddress != null;
|
||||||
if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) {
|
if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) {
|
||||||
if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) {
|
if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) {
|
||||||
|
if (sStatic.mCanConfigureWifiDisplays) {
|
||||||
sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress);
|
sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Cannot connect to wifi displays because this process "
|
||||||
|
+ "is not allowed to do so.");
|
||||||
|
}
|
||||||
} else if (activeDisplay != null && !newRouteHasAddress) {
|
} else if (activeDisplay != null && !newRouteHasAddress) {
|
||||||
sStatic.mDisplayService.disconnectWifiDisplay();
|
sStatic.mDisplayService.disconnectWifiDisplay();
|
||||||
}
|
}
|
||||||
@ -1175,10 +1192,34 @@ public class MediaRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchRouteChanged(RouteInfo info) {
|
static void dispatchRouteChanged(RouteInfo info) {
|
||||||
|
dispatchRouteChanged(info, info.mSupportedTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) {
|
||||||
|
final int newSupportedTypes = info.mSupportedTypes;
|
||||||
for (CallbackInfo cbi : sStatic.mCallbacks) {
|
for (CallbackInfo cbi : sStatic.mCallbacks) {
|
||||||
if (cbi.filterRouteEvent(info)) {
|
// Reconstruct some of the history for callbacks that may not have observed
|
||||||
|
// all of the events needed to correctly interpret the current state.
|
||||||
|
// FIXME: This is a strong signal that we should deprecate route type filtering
|
||||||
|
// completely in the future because it can lead to inconsistencies in
|
||||||
|
// applications.
|
||||||
|
final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes);
|
||||||
|
final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes);
|
||||||
|
if (!oldVisibility && newVisibility) {
|
||||||
|
cbi.cb.onRouteAdded(cbi.router, info);
|
||||||
|
if (info.isSelected()) {
|
||||||
|
cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oldVisibility || newVisibility) {
|
||||||
cbi.cb.onRouteChanged(cbi.router, info);
|
cbi.cb.onRouteChanged(cbi.router, info);
|
||||||
}
|
}
|
||||||
|
if (oldVisibility && !newVisibility) {
|
||||||
|
if (info.isSelected()) {
|
||||||
|
cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info);
|
||||||
|
}
|
||||||
|
cbi.cb.onRouteRemoved(cbi.router, info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1257,6 +1298,18 @@ public class MediaRouter {
|
|||||||
if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
|
if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
|
||||||
displays = status.getDisplays();
|
displays = status.getDisplays();
|
||||||
activeDisplay = status.getActiveDisplay();
|
activeDisplay = status.getActiveDisplay();
|
||||||
|
|
||||||
|
// Only the system is able to connect to wifi display routes.
|
||||||
|
// The display manager will enforce this with a permission check but it
|
||||||
|
// still publishes information about all available displays.
|
||||||
|
// Filter the list down to just the active display.
|
||||||
|
if (!sStatic.mCanConfigureWifiDisplays) {
|
||||||
|
if (activeDisplay != null) {
|
||||||
|
displays = new WifiDisplay[] { activeDisplay };
|
||||||
|
} else {
|
||||||
|
displays = WifiDisplay.EMPTY_ARRAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
displays = WifiDisplay.EMPTY_ARRAY;
|
displays = WifiDisplay.EMPTY_ARRAY;
|
||||||
activeDisplay = null;
|
activeDisplay = null;
|
||||||
@ -1293,7 +1346,7 @@ public class MediaRouter {
|
|||||||
|
|
||||||
// Don't scan if we're already connected to a wifi display,
|
// Don't scan if we're already connected to a wifi display,
|
||||||
// the scanning process can cause a hiccup with some configurations.
|
// the scanning process can cause a hiccup with some configurations.
|
||||||
if (wantScan && activeDisplay != null) {
|
if (wantScan && activeDisplay != null && sStatic.mCanConfigureWifiDisplays) {
|
||||||
sStatic.mDisplayService.scanWifiDisplays();
|
sStatic.mDisplayService.scanWifiDisplays();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2547,8 +2600,12 @@ public class MediaRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean filterRouteEvent(RouteInfo route) {
|
public boolean filterRouteEvent(RouteInfo route) {
|
||||||
|
return filterRouteEvent(route.mSupportedTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean filterRouteEvent(int supportedTypes) {
|
||||||
return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0
|
return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0
|
||||||
|| (type & route.mSupportedTypes) != 0;
|
|| (type & supportedTypes) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,17 @@ public final class MediaRouterClientState implements Parcelable {
|
|||||||
globallySelectedRouteId = src.readString();
|
globallySelectedRouteId = src.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RouteInfo getRoute(String id) {
|
||||||
|
final int count = routes.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final RouteInfo route = routes.get(i);
|
||||||
|
if (route.id.equals(id)) {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
@ -61,6 +72,12 @@ public final class MediaRouterClientState implements Parcelable {
|
|||||||
dest.writeString(globallySelectedRouteId);
|
dest.writeString(globallySelectedRouteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MediaRouterClientState{ globallySelectedRouteId="
|
||||||
|
+ globallySelectedRouteId + ", routes=" + routes.toString() + " }";
|
||||||
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<MediaRouterClientState> CREATOR =
|
public static final Parcelable.Creator<MediaRouterClientState> CREATOR =
|
||||||
new Parcelable.Creator<MediaRouterClientState>() {
|
new Parcelable.Creator<MediaRouterClientState>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -71,6 +71,9 @@
|
|||||||
<!-- Keyguard -->
|
<!-- Keyguard -->
|
||||||
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
|
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
|
||||||
|
|
||||||
|
<!-- Wifi Display -->
|
||||||
|
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:persistent="true"
|
android:persistent="true"
|
||||||
android:allowClearUserData="false"
|
android:allowClearUserData="false"
|
||||||
|
@ -466,6 +466,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
|
|
||||||
@Override // Binder call
|
@Override // Binder call
|
||||||
public void scanWifiDisplays() {
|
public void scanWifiDisplays() {
|
||||||
|
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
|
||||||
|
"Permission required to scan wifi displays");
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mSyncRoot) {
|
synchronized (mSyncRoot) {
|
||||||
@ -483,13 +486,14 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
if (address == null) {
|
if (address == null) {
|
||||||
throw new IllegalArgumentException("address must not be null");
|
throw new IllegalArgumentException("address must not be null");
|
||||||
}
|
}
|
||||||
|
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
|
||||||
|
"Permission required to connect to a wifi display");
|
||||||
|
|
||||||
final boolean trusted = canCallerConfigureWifiDisplay();
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mSyncRoot) {
|
synchronized (mSyncRoot) {
|
||||||
if (mWifiDisplayAdapter != null) {
|
if (mWifiDisplayAdapter != null) {
|
||||||
mWifiDisplayAdapter.requestConnectLocked(address, trusted);
|
mWifiDisplayAdapter.requestConnectLocked(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -499,12 +503,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pauseWifiDisplay() {
|
public void pauseWifiDisplay() {
|
||||||
if (mContext.checkCallingPermission(
|
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
|
||||||
android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
|
"Permission required to pause a wifi display session");
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
|
||||||
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
|
|
||||||
+ "permission to pause a wifi display session.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@ -520,12 +520,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resumeWifiDisplay() {
|
public void resumeWifiDisplay() {
|
||||||
if (mContext.checkCallingPermission(
|
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
|
||||||
android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
|
"Permission required to resume a wifi display session");
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
|
||||||
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
|
|
||||||
+ "permission to resume a wifi display session.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@ -541,6 +537,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
|
|
||||||
@Override // Binder call
|
@Override // Binder call
|
||||||
public void disconnectWifiDisplay() {
|
public void disconnectWifiDisplay() {
|
||||||
|
// This request does not require special permissions.
|
||||||
|
// Any app can request disconnection from the currently active wifi display.
|
||||||
|
// This exception should no longer be needed once wifi display control moves
|
||||||
|
// to the media router service.
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mSyncRoot) {
|
synchronized (mSyncRoot) {
|
||||||
@ -558,10 +559,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
if (address == null) {
|
if (address == null) {
|
||||||
throw new IllegalArgumentException("address must not be null");
|
throw new IllegalArgumentException("address must not be null");
|
||||||
}
|
}
|
||||||
if (!canCallerConfigureWifiDisplay()) {
|
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
|
||||||
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
|
"Permission required to rename to a wifi display");
|
||||||
+ "rename a wifi display.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@ -580,10 +579,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
if (address == null) {
|
if (address == null) {
|
||||||
throw new IllegalArgumentException("address must not be null");
|
throw new IllegalArgumentException("address must not be null");
|
||||||
}
|
}
|
||||||
if (!canCallerConfigureWifiDisplay()) {
|
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
|
||||||
throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
|
"Permission required to forget to a wifi display");
|
||||||
+ "forget a wifi display.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@ -599,6 +596,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
|
|
||||||
@Override // Binder call
|
@Override // Binder call
|
||||||
public WifiDisplayStatus getWifiDisplayStatus() {
|
public WifiDisplayStatus getWifiDisplayStatus() {
|
||||||
|
// This request does not require special permissions.
|
||||||
|
// Any app can get information about available wifi displays.
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mSyncRoot) {
|
synchronized (mSyncRoot) {
|
||||||
@ -612,11 +612,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canCallerConfigureWifiDisplay() {
|
|
||||||
return mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
|
|
||||||
== PackageManager.PERMISSION_GRANTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override // Binder call
|
@Override // Binder call
|
||||||
public int createVirtualDisplay(IBinder appToken, String packageName,
|
public int createVirtualDisplay(IBinder appToken, String packageName,
|
||||||
String name, int width, int height, int densityDpi, Surface surface, int flags) {
|
String name, int width, int height, int densityDpi, Surface surface, int flags) {
|
||||||
|
@ -172,19 +172,9 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestConnectLocked(final String address, final boolean trusted) {
|
public void requestConnectLocked(final String address) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
|
Slog.d(TAG, "requestConnectLocked: address=" + address);
|
||||||
}
|
|
||||||
|
|
||||||
if (!trusted) {
|
|
||||||
synchronized (getSyncRoot()) {
|
|
||||||
if (!isRememberedDisplayLocked(address)) {
|
|
||||||
Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
|
|
||||||
+ "an unknown wifi display: " + address);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getHandler().post(new Runnable() {
|
getHandler().post(new Runnable() {
|
||||||
|
@ -128,10 +128,13 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
final int pid = Binder.getCallingPid();
|
final int pid = Binder.getCallingPid();
|
||||||
final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
|
final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
|
||||||
false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName);
|
false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName);
|
||||||
|
final boolean trusted = mContext.checkCallingOrSelfPermission(
|
||||||
|
android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) ==
|
||||||
|
PackageManager.PERMISSION_GRANTED;
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
registerClientLocked(client, pid, packageName, resolvedUserId);
|
registerClientLocked(client, pid, packageName, resolvedUserId, trusted);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
@ -306,7 +309,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void registerClientLocked(IMediaRouterClient client,
|
private void registerClientLocked(IMediaRouterClient client,
|
||||||
int pid, String packageName, int userId) {
|
int pid, String packageName, int userId, boolean trusted) {
|
||||||
final IBinder binder = client.asBinder();
|
final IBinder binder = client.asBinder();
|
||||||
ClientRecord clientRecord = mAllClientRecords.get(binder);
|
ClientRecord clientRecord = mAllClientRecords.get(binder);
|
||||||
if (clientRecord == null) {
|
if (clientRecord == null) {
|
||||||
@ -316,7 +319,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
userRecord = new UserRecord(userId);
|
userRecord = new UserRecord(userId);
|
||||||
newUser = true;
|
newUser = true;
|
||||||
}
|
}
|
||||||
clientRecord = new ClientRecord(userRecord, client, pid, packageName);
|
clientRecord = new ClientRecord(userRecord, client, pid, packageName, trusted);
|
||||||
try {
|
try {
|
||||||
binder.linkToDeath(clientRecord, 0);
|
binder.linkToDeath(clientRecord, 0);
|
||||||
} catch (RemoteException ex) {
|
} catch (RemoteException ex) {
|
||||||
@ -347,7 +350,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
private MediaRouterClientState getStateLocked(IMediaRouterClient client) {
|
private MediaRouterClientState getStateLocked(IMediaRouterClient client) {
|
||||||
ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
|
ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
|
||||||
if (clientRecord != null) {
|
if (clientRecord != null) {
|
||||||
return clientRecord.mUserRecord.mState;
|
return clientRecord.getState();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -357,6 +360,11 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
final IBinder binder = client.asBinder();
|
final IBinder binder = client.asBinder();
|
||||||
ClientRecord clientRecord = mAllClientRecords.get(binder);
|
ClientRecord clientRecord = mAllClientRecords.get(binder);
|
||||||
if (clientRecord != null) {
|
if (clientRecord != null) {
|
||||||
|
// Only let the system discover remote display routes for now.
|
||||||
|
if (!clientRecord.mTrusted) {
|
||||||
|
routeTypes &= ~MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
if (clientRecord.mRouteTypes != routeTypes
|
if (clientRecord.mRouteTypes != routeTypes
|
||||||
|| clientRecord.mActiveScan != activeScan) {
|
|| clientRecord.mActiveScan != activeScan) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -385,11 +393,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
|
|
||||||
clientRecord.mSelectedRouteId = routeId;
|
clientRecord.mSelectedRouteId = routeId;
|
||||||
if (explicit) {
|
if (explicit) {
|
||||||
|
// Any app can disconnect from the globally selected route.
|
||||||
if (oldRouteId != null) {
|
if (oldRouteId != null) {
|
||||||
clientRecord.mUserRecord.mHandler.obtainMessage(
|
clientRecord.mUserRecord.mHandler.obtainMessage(
|
||||||
UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget();
|
UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget();
|
||||||
}
|
}
|
||||||
if (routeId != null) {
|
// Only let the system connect to new global routes for now.
|
||||||
|
// A similar check exists in the display manager for wifi display.
|
||||||
|
if (routeId != null && clientRecord.mTrusted) {
|
||||||
clientRecord.mUserRecord.mHandler.obtainMessage(
|
clientRecord.mUserRecord.mHandler.obtainMessage(
|
||||||
UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
|
UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
|
||||||
}
|
}
|
||||||
@ -486,17 +497,19 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
public final IMediaRouterClient mClient;
|
public final IMediaRouterClient mClient;
|
||||||
public final int mPid;
|
public final int mPid;
|
||||||
public final String mPackageName;
|
public final String mPackageName;
|
||||||
|
public final boolean mTrusted;
|
||||||
|
|
||||||
public int mRouteTypes;
|
public int mRouteTypes;
|
||||||
public boolean mActiveScan;
|
public boolean mActiveScan;
|
||||||
public String mSelectedRouteId;
|
public String mSelectedRouteId;
|
||||||
|
|
||||||
public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
|
public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
|
||||||
int pid, String packageName) {
|
int pid, String packageName, boolean trusted) {
|
||||||
mUserRecord = userRecord;
|
mUserRecord = userRecord;
|
||||||
mClient = client;
|
mClient = client;
|
||||||
mPid = pid;
|
mPid = pid;
|
||||||
mPackageName = packageName;
|
mPackageName = packageName;
|
||||||
|
mTrusted = trusted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
@ -508,10 +521,15 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
clientDied(this);
|
clientDied(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaRouterClientState getState() {
|
||||||
|
return mTrusted ? mUserRecord.mTrustedState : mUserRecord.mUntrustedState;
|
||||||
|
}
|
||||||
|
|
||||||
public void dump(PrintWriter pw, String prefix) {
|
public void dump(PrintWriter pw, String prefix) {
|
||||||
pw.println(prefix + this);
|
pw.println(prefix + this);
|
||||||
|
|
||||||
final String indent = prefix + " ";
|
final String indent = prefix + " ";
|
||||||
|
pw.println(indent + "mTrusted=" + mTrusted);
|
||||||
pw.println(indent + "mRouteTypes=0x" + Integer.toHexString(mRouteTypes));
|
pw.println(indent + "mRouteTypes=0x" + Integer.toHexString(mRouteTypes));
|
||||||
pw.println(indent + "mActiveScan=" + mActiveScan);
|
pw.println(indent + "mActiveScan=" + mActiveScan);
|
||||||
pw.println(indent + "mSelectedRouteId=" + mSelectedRouteId);
|
pw.println(indent + "mSelectedRouteId=" + mSelectedRouteId);
|
||||||
@ -531,7 +549,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
public final int mUserId;
|
public final int mUserId;
|
||||||
public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>();
|
public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>();
|
||||||
public final UserHandler mHandler;
|
public final UserHandler mHandler;
|
||||||
public MediaRouterClientState mState;
|
public MediaRouterClientState mTrustedState;
|
||||||
|
public MediaRouterClientState mUntrustedState;
|
||||||
|
|
||||||
public UserRecord(int userId) {
|
public UserRecord(int userId) {
|
||||||
mUserId = userId;
|
mUserId = userId;
|
||||||
@ -551,6 +570,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
pw.println(indent + "<no clients>");
|
pw.println(indent + "<no clients>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pw.println(indent + "State");
|
||||||
|
pw.println(indent + "mTrustedState=" + mTrustedState);
|
||||||
|
pw.println(indent + "mUntrustedState=" + mUntrustedState);
|
||||||
|
|
||||||
if (!mHandler.runWithScissors(new Runnable() {
|
if (!mHandler.runWithScissors(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -729,8 +752,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int newDiscoveryMode;
|
final int newDiscoveryMode;
|
||||||
if ((routeTypes & (MediaRouter.ROUTE_TYPE_LIVE_VIDEO
|
if ((routeTypes & MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
|
||||||
| MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) != 0) {
|
|
||||||
if (activeScan) {
|
if (activeScan) {
|
||||||
newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
|
newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
|
||||||
} else {
|
} else {
|
||||||
@ -968,19 +990,30 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
|||||||
private void updateClientState() {
|
private void updateClientState() {
|
||||||
mClientStateUpdateScheduled = false;
|
mClientStateUpdateScheduled = false;
|
||||||
|
|
||||||
// Build a new client state.
|
final String globallySelectedRouteId = mGloballySelectedRouteRecord != null ?
|
||||||
MediaRouterClientState state = new MediaRouterClientState();
|
|
||||||
state.globallySelectedRouteId = mGloballySelectedRouteRecord != null ?
|
|
||||||
mGloballySelectedRouteRecord.getUniqueId() : null;
|
mGloballySelectedRouteRecord.getUniqueId() : null;
|
||||||
|
|
||||||
|
// Build a new client state for trusted clients.
|
||||||
|
MediaRouterClientState trustedState = new MediaRouterClientState();
|
||||||
|
trustedState.globallySelectedRouteId = globallySelectedRouteId;
|
||||||
final int providerCount = mProviderRecords.size();
|
final int providerCount = mProviderRecords.size();
|
||||||
for (int i = 0; i < providerCount; i++) {
|
for (int i = 0; i < providerCount; i++) {
|
||||||
mProviderRecords.get(i).appendClientState(state);
|
mProviderRecords.get(i).appendClientState(trustedState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a new client state for untrusted clients that can only see
|
||||||
|
// the currently selected route.
|
||||||
|
MediaRouterClientState untrustedState = new MediaRouterClientState();
|
||||||
|
untrustedState.globallySelectedRouteId = globallySelectedRouteId;
|
||||||
|
if (globallySelectedRouteId != null) {
|
||||||
|
untrustedState.routes.add(trustedState.getRoute(globallySelectedRouteId));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
synchronized (mService.mLock) {
|
synchronized (mService.mLock) {
|
||||||
// Update the UserRecord.
|
// Update the UserRecord.
|
||||||
mUserRecord.mState = state;
|
mUserRecord.mTrustedState = trustedState;
|
||||||
|
mUserRecord.mUntrustedState = untrustedState;
|
||||||
|
|
||||||
// Collect all clients.
|
// Collect all clients.
|
||||||
final int count = mUserRecord.mClientRecords.size();
|
final int count = mUserRecord.mClientRecords.size();
|
||||||
|
Reference in New Issue
Block a user