Merge "Media: Add group id for media router to sync" into qt-dev

This commit is contained in:
Kyunglyul Hyun
2019-05-24 02:32:17 +00:00
committed by Android (Google) Code Review
4 changed files with 186 additions and 1 deletions

View File

@@ -22,4 +22,5 @@ package android.media;
oneway interface IMediaRouterClient { oneway interface IMediaRouterClient {
void onStateChanged(); void onStateChanged();
void onRestoreRoute(); void onRestoreRoute();
void onSelectedRouteChanged(String routeId);
} }

View File

@@ -26,6 +26,8 @@ interface IMediaRouterService {
void registerClientAsUser(IMediaRouterClient client, String packageName, int userId); void registerClientAsUser(IMediaRouterClient client, String packageName, int userId);
void unregisterClient(IMediaRouterClient client); void unregisterClient(IMediaRouterClient client);
void registerClientGroupId(IMediaRouterClient client, String groupId);
MediaRouterClientState getState(IMediaRouterClient client); MediaRouterClientState getState(IMediaRouterClient client);
boolean isPlaybackActive(IMediaRouterClient client); boolean isPlaybackActive(IMediaRouterClient client);

View File

@@ -20,6 +20,7 @@ import android.Manifest;
import android.annotation.DrawableRes; import android.annotation.DrawableRes;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService; import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread; import android.app.ActivityThread;
@@ -343,6 +344,16 @@ public class MediaRouter {
updatePresentationDisplays(displayId); updatePresentationDisplays(displayId);
} }
public void setRouterGroupId(String groupId) {
if (mClient != null) {
try {
mMediaRouterService.registerClientGroupId(mClient, groupId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to register group ID of the client.", ex);
}
}
}
public Display[] getAllPresentationDisplays() { public Display[] getAllPresentationDisplays() {
return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
} }
@@ -358,6 +369,21 @@ public class MediaRouter {
} }
} }
void updateSelectedRouteForId(String routeId) {
RouteInfo selectedRoute = isBluetoothA2dpOn()
? mBluetoothA2dpRoute : mDefaultAudioVideo;
final int count = mRoutes.size();
for (int i = 0; i < count; i++) {
final RouteInfo route = mRoutes.get(i);
if (TextUtils.equals(route.mGlobalRouteId, routeId)) {
selectedRoute = route;
}
}
if (selectedRoute != mSelectedRoute) {
selectRouteStatic(selectedRoute.mSupportedTypes, selectedRoute, false);
}
}
void setSelectedRoute(RouteInfo info, boolean explicit) { void setSelectedRoute(RouteInfo info, boolean explicit) {
// Must be non-reentrant. // Must be non-reentrant.
mSelectedRoute = info; mSelectedRoute = info;
@@ -619,6 +645,15 @@ public class MediaRouter {
} }
}); });
} }
@Override
public void onSelectedRouteChanged(String routeId) {
mHandler.post(() -> {
if (Client.this == mClient) {
updateSelectedRouteForId(routeId);
}
});
}
} }
} }
@@ -728,6 +763,13 @@ public class MediaRouter {
*/ */
public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0; public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0;
/**
* The route group id used for sharing the selected mirroring device.
* System UI and Settings use this to synchronize their mirroring status.
* @hide
*/
public static final String MIRRORING_GROUP_ID = "android.media.mirroring_group";
// Maps application contexts // Maps application contexts
static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>(); static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>();
@@ -847,6 +889,25 @@ public class MediaRouter {
return false; return false;
} }
/**
* Sets the group ID of the router.
* Media routers with the same ID acts as if they were a single media router.
* For example, if a media router selects a route, the selected route of routers
* with the same group ID will be changed automatically.
*
* Two routers in a group are supposed to use the same route types.
*
* System UI and Settings use this to synchronize their mirroring status.
* Do not set the router group id unless it's necessary.
*
* {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} permission is required to
* call this method.
* @hide
*/
public void setRouterGroupId(@Nullable String groupId) {
sStatic.setRouterGroupId(groupId);
}
/** /**
* Add a callback to listen to events about specific kinds of media routes. * Add a callback to listen to events about specific kinds of media routes.
* If the specified callback is already registered, its registration will be updated for any * If the specified callback is already registered, its registration will be updated for any

View File

@@ -246,6 +246,29 @@ public final class MediaRouterService extends IMediaRouterService.Stub
} }
} }
// Binder call
@Override
public void registerClientGroupId(IMediaRouterClient client, String groupId) {
if (client == null) {
throw new NullPointerException("client must not be null");
}
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Ignoring client group request because "
+ "the client doesn't have the CONFIGURE_WIFI_DISPLAY permission.");
return;
}
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
registerClientGroupIdLocked(client, groupId);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
// Binder call // Binder call
@Override @Override
public void unregisterClient(IMediaRouterClient client) { public void unregisterClient(IMediaRouterClient client) {
@@ -502,11 +525,37 @@ public final class MediaRouterService extends IMediaRouterService.Stub
} }
} }
private void registerClientGroupIdLocked(IMediaRouterClient client, String groupId) {
final IBinder binder = client.asBinder();
ClientRecord clientRecord = mAllClientRecords.get(binder);
if (clientRecord == null) {
Log.w(TAG, "Ignoring group id register request of a unregistered client.");
return;
}
if (TextUtils.equals(clientRecord.mGroupId, groupId)) {
return;
}
UserRecord userRecord = clientRecord.mUserRecord;
if (clientRecord.mGroupId != null) {
userRecord.removeFromGroup(clientRecord.mGroupId, clientRecord);
}
clientRecord.mGroupId = groupId;
if (groupId != null) {
userRecord.addToGroup(groupId, clientRecord);
userRecord.mHandler.obtainMessage(UserHandler.MSG_UPDATE_SELECTED_ROUTE, groupId)
.sendToTarget();
}
}
private void unregisterClientLocked(IMediaRouterClient client, boolean died) { private void unregisterClientLocked(IMediaRouterClient client, boolean died) {
ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder()); ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
if (clientRecord != null) { if (clientRecord != null) {
UserRecord userRecord = clientRecord.mUserRecord; UserRecord userRecord = clientRecord.mUserRecord;
userRecord.mClientRecords.remove(clientRecord); userRecord.mClientRecords.remove(clientRecord);
if (clientRecord.mGroupId != null) {
userRecord.removeFromGroup(clientRecord.mGroupId, clientRecord);
clientRecord.mGroupId = null;
}
disposeClientLocked(clientRecord, died); disposeClientLocked(clientRecord, died);
disposeUserIfNeededLocked(userRecord); // since client removed from user disposeUserIfNeededLocked(userRecord); // since client removed from user
} }
@@ -568,6 +617,16 @@ public final class MediaRouterService extends IMediaRouterService.Stub
clientRecord.mUserRecord.mHandler.obtainMessage( clientRecord.mUserRecord.mHandler.obtainMessage(
UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget(); UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
} }
if (clientRecord.mGroupId != null) {
ClientGroup group =
clientRecord.mUserRecord.mClientGroupMap.get(clientRecord.mGroupId);
if (group != null) {
group.mSelectedRouteId = routeId;
clientRecord.mUserRecord.mHandler.obtainMessage(
UserHandler.MSG_UPDATE_SELECTED_ROUTE, clientRecord.mGroupId)
.sendToTarget();
}
}
} }
} }
} }
@@ -680,6 +739,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
public int mRouteTypes; public int mRouteTypes;
public boolean mActiveScan; public boolean mActiveScan;
public String mSelectedRouteId; public String mSelectedRouteId;
public String mGroupId;
public ClientRecord(UserRecord userRecord, IMediaRouterClient client, public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
int uid, int pid, String packageName, boolean trusted) { int uid, int pid, String packageName, boolean trusted) {
@@ -720,6 +780,11 @@ public final class MediaRouterService extends IMediaRouterService.Stub
} }
} }
final class ClientGroup {
public String mSelectedRouteId;
public final List<ClientRecord> mClientRecords = new ArrayList<>();
}
/** /**
* Information about a particular user. * Information about a particular user.
* The contents of this object is guarded by mLock. * The contents of this object is guarded by mLock.
@@ -729,6 +794,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
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 mRouterState; public MediaRouterClientState mRouterState;
private final ArrayMap<String, ClientGroup> mClientGroupMap = new ArrayMap<>();
public UserRecord(int userId) { public UserRecord(int userId) {
mUserId = userId; mUserId = userId;
@@ -759,7 +825,26 @@ public final class MediaRouterService extends IMediaRouterService.Stub
}, 1000)) { }, 1000)) {
pw.println(indent + "<could not dump handler state>"); pw.println(indent + "<could not dump handler state>");
} }
} }
public void addToGroup(String groupId, ClientRecord clientRecord) {
ClientGroup group = mClientGroupMap.get(groupId);
if (group == null) {
group = new ClientGroup();
mClientGroupMap.put(groupId, group);
}
group.mClientRecords.add(clientRecord);
}
public void removeFromGroup(String groupId, ClientRecord clientRecord) {
ClientGroup group = mClientGroupMap.get(groupId);
if (group != null) {
group.mClientRecords.remove(clientRecord);
if (group.mClientRecords.size() == 0) {
mClientGroupMap.remove(groupId);
}
}
}
@Override @Override
public String toString() { public String toString() {
@@ -791,6 +876,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
public static final int MSG_REQUEST_UPDATE_VOLUME = 7; public static final int MSG_REQUEST_UPDATE_VOLUME = 7;
private static final int MSG_UPDATE_CLIENT_STATE = 8; private static final int MSG_UPDATE_CLIENT_STATE = 8;
private static final int MSG_CONNECTION_TIMED_OUT = 9; private static final int MSG_CONNECTION_TIMED_OUT = 9;
private static final int MSG_UPDATE_SELECTED_ROUTE = 10;
private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1; private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1;
private static final int TIMEOUT_REASON_CONNECTION_LOST = 2; private static final int TIMEOUT_REASON_CONNECTION_LOST = 2;
@@ -867,6 +953,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub
connectionTimedOut(); connectionTimedOut();
break; break;
} }
case MSG_UPDATE_SELECTED_ROUTE: {
updateSelectedRoute((String) msg.obj);
break;
}
} }
} }
@@ -1191,6 +1281,37 @@ public final class MediaRouterService extends IMediaRouterService.Stub
} }
} }
private void updateSelectedRoute(String groupId) {
try {
String selectedRouteId = null;
synchronized (mService.mLock) {
ClientGroup group = mUserRecord.mClientGroupMap.get(groupId);
if (group == null) {
return;
}
selectedRouteId = group.mSelectedRouteId;
final int count = group.mClientRecords.size();
for (int i = 0; i < count; i++) {
ClientRecord clientRecord = group.mClientRecords.get(i);
if (!TextUtils.equals(selectedRouteId, clientRecord.mSelectedRouteId)) {
mTempClients.add(clientRecord.mClient);
}
}
}
final int count = mTempClients.size();
for (int i = 0; i < count; i++) {
try {
mTempClients.get(i).onSelectedRouteChanged(selectedRouteId);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to call onSelectedRouteChanged. Client probably died.");
}
}
} finally {
mTempClients.clear();
}
}
private int findProviderRecord(RemoteDisplayProviderProxy provider) { private int findProviderRecord(RemoteDisplayProviderProxy provider) {
final int count = mProviderRecords.size(); final int count = mProviderRecords.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {