diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index 86bab878ff005..b8c00a335d139 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -17,12 +17,13 @@
package android.media;
import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2Info;
/**
* {@hide}
*/
oneway interface IMediaRouter2Manager {
- void notifyRouteSelected(int uid, String routeId);
+ void notifyRouteSelected(int uid, in MediaRoute2Info route);
void notifyControlCategoriesChanged(int uid, in List categories);
void notifyProviderInfosUpdated(in List providers);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index b1489212f66ca..fb108b4a85ec8 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -45,11 +45,25 @@ interface IMediaRouterService {
void registerClient2AsUser(IMediaRouter2Client client, String packageName, int userId);
void unregisterClient2(IMediaRouter2Client client);
void sendControlRequest(IMediaRouter2Client client, in MediaRoute2Info route, in Intent request);
+ /**
+ * Changes the selected route of the client.
+ *
+ * @param client Client to change it's selected route.
+ * @param route Route to be selected.
+ */
+ void selectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
void setControlCategories(IMediaRouter2Client client, in List categories);
void registerManagerAsUser(IMediaRouter2Manager manager,
String packageName, int userId);
void unregisterManager(IMediaRouter2Manager manager);
- void setRemoteRoute(IMediaRouter2Manager manager,
- int uid, String routeId, boolean explicit);
+ /**
+ * Changes the selected route of an application.
+ *
+ * @param manager Manager that calls the method
+ * @param uid UID of the client that will change the selected route.
+ * @param route Route to be selected.
+ */
+ void selectClientRoute2(IMediaRouter2Manager manager, int clientUid,
+ in @nullable MediaRoute2Info route);
}
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 03b49d9d84725..855cd77f019e4 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -23,6 +23,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.util.Objects;
+
/**
* Describes the properties of a route.
* @hide
@@ -43,6 +45,8 @@ public final class MediaRoute2Info implements Parcelable {
@NonNull
final String mId;
+ @Nullable
+ final String mProviderId;
@NonNull
final String mName;
@Nullable
@@ -52,6 +56,7 @@ public final class MediaRoute2Info implements Parcelable {
MediaRoute2Info(@NonNull Builder builder) {
mId = builder.mId;
+ mProviderId = builder.mProviderId;
mName = builder.mName;
mDescription = builder.mDescription;
mExtras = builder.mExtras;
@@ -59,28 +64,63 @@ public final class MediaRoute2Info implements Parcelable {
MediaRoute2Info(@NonNull Parcel in) {
mId = in.readString();
+ mProviderId = in.readString();
mName = in.readString();
mDescription = in.readString();
mExtras = in.readBundle();
}
/**
- * Returns true if the route info has all of the required field
+ * Returns true if the route info has all of the required field.
+ * A route info only obtained from {@link com.android.server.media.MediaRouterService}
+ * is valid.
* @hide
*/
//TODO: Reconsider the validity of a route info when fields are added.
public boolean isValid() {
- if (TextUtils.isEmpty(getId()) || TextUtils.isEmpty(getName())) {
+ if (TextUtils.isEmpty(getId()) || TextUtils.isEmpty(getName())
+ || TextUtils.isEmpty(getProviderId())) {
return false;
}
return true;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof MediaRoute2Info)) {
+ return false;
+ }
+ MediaRoute2Info other = (MediaRoute2Info) obj;
+ return Objects.equals(mId, other.mId)
+ && Objects.equals(mProviderId, other.mProviderId)
+ && Objects.equals(mName, other.mName)
+ && Objects.equals(mDescription, other.mDescription)
+ //TODO: This will be evaluated as false in most cases. Try not to.
+ && Objects.equals(mExtras, other.mExtras);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mName, mDescription);
+ }
+
@NonNull
public String getId() {
return mId;
}
+ /**
+ * Gets the provider id of the route.
+ * @hide
+ */
+ @Nullable
+ public String getProviderId() {
+ return mProviderId;
+ }
+
@NonNull
public String getName() {
return mName;
@@ -104,6 +144,7 @@ public final class MediaRoute2Info implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mId);
+ dest.writeString(mProviderId);
dest.writeString(mName);
dest.writeString(mDescription);
dest.writeBundle(mExtras);
@@ -115,6 +156,8 @@ public final class MediaRoute2Info implements Parcelable {
.append("MediaRouteInfo{ ")
.append("id=").append(getId())
.append(", name=").append(getName())
+ .append(", description=").append(getDescription())
+ .append(", providerId=").append(getProviderId())
.append(" }");
return result.toString();
}
@@ -124,6 +167,7 @@ public final class MediaRoute2Info implements Parcelable {
*/
public static final class Builder {
String mId;
+ String mProviderId;
String mName;
String mDescription;
Bundle mExtras;
@@ -145,8 +189,14 @@ public final class MediaRoute2Info implements Parcelable {
}
setId(routeInfo.mId);
+ if (!TextUtils.isEmpty(routeInfo.mProviderId)) {
+ setProviderId(routeInfo.mProviderId);
+ }
setName(routeInfo.mName);
mDescription = routeInfo.mDescription;
+ if (routeInfo.mExtras != null) {
+ mExtras = new Bundle(routeInfo.mExtras);
+ }
}
/**
@@ -161,6 +211,19 @@ public final class MediaRoute2Info implements Parcelable {
return this;
}
+ /**
+ * Sets the provider id of the route.
+ * @hide
+ */
+ @NonNull
+ public Builder setProviderId(@NonNull String providerId) {
+ if (TextUtils.isEmpty(providerId)) {
+ throw new IllegalArgumentException("id must not be null or empty");
+ }
+ mProviderId = providerId;
+ return this;
+ }
+
/**
* Sets the user-visible name of the route.
*/
@@ -182,6 +245,15 @@ public final class MediaRoute2Info implements Parcelable {
return this;
}
+ /**
+ * Sets a bundle of extras for the route.
+ */
+ @NonNull
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
/**
* Builds the {@link MediaRoute2Info media route info}.
*/
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index 57d82d4e9d27c..8541f32ae98f9 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.ArrayMap;
import java.util.Arrays;
@@ -82,8 +83,11 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
return true;
}
+ /**
+ * @hide
+ */
@Nullable
- String getUniqueId() {
+ public String getUniqueId() {
return mUniqueId;
}
@@ -149,9 +153,21 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
* {@link com.android.server.media.MediaRouterService} and used to identify providers.
* The id set by {@link MediaRoute2ProviderService} will be ignored.
*
+ * @hide
*/
public Builder setUniqueId(@Nullable String uniqueId) {
+ if (TextUtils.equals(mUniqueId, uniqueId)) {
+ return this;
+ }
mUniqueId = uniqueId;
+ final int count = mRoutes.size();
+ for (int i = 0; i < count; i++) {
+ MediaRoute2Info route = mRoutes.valueAt(i);
+ mRoutes.setValueAt(i, new MediaRoute2Info.Builder(route)
+ .setProviderId(mUniqueId)
+ .build());
+ }
+
return this;
}
@@ -164,7 +180,12 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
if (mRoutes.containsValue(route)) {
throw new IllegalArgumentException("route descriptor already added");
}
- mRoutes.put(route.getId(), route);
+ if (mUniqueId != null) {
+ mRoutes.put(route.getId(),
+ new MediaRoute2Info.Builder(route).setProviderId(mUniqueId).build());
+ } else {
+ mRoutes.put(route.getId(), route);
+ }
return this;
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index d37a8321a9783..a69b105f0f50e 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -18,6 +18,7 @@ package android.media;
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
@@ -168,6 +169,22 @@ public class MediaRouter2 {
return -1;
}
+ /**
+ * Selects the specified route.
+ *
+ * @param route The route to select.
+ */
+ //TODO: add a parameter for category (e.g. mirroring/casting)
+ public void selectRoute(@Nullable MediaRoute2Info route) {
+ if (mClient != null) {
+ try {
+ mMediaRouterService.selectRoute2(mClient, route);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to select route.", ex);
+ }
+ }
+ }
+
/**
* Sends a media control request to be performed asynchronously by the route's destination.
* @param route the route that will receive the control request
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 5fcb684b70090..2d7dc56339e1b 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
@@ -59,8 +60,9 @@ public class MediaRouter2Manager {
@GuardedBy("sLock")
final ArrayList mCallbacks = new ArrayList<>();
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
@NonNull
- private List mProviders = Collections.emptyList();
+ List mProviders = Collections.emptyList();
/**
* Gets an instance of media router manager that controls media route of other applications.
@@ -93,17 +95,12 @@ public class MediaRouter2Manager {
public void addCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull Callback callback) {
- if (executor == null) {
- throw new IllegalArgumentException("executor must not be null");
- }
- if (callback == null) {
- throw new IllegalArgumentException("callback must not be null");
- }
+ Objects.requireNonNull(executor, "executor must not be null");
+ Objects.requireNonNull(callback, "callback must not be null");
synchronized (sLock) {
- final int index = findCallbackRecord(callback);
- if (index >= 0) {
- Log.w(TAG, "Ignore adding the same callback twice.");
+ if (findCallbackRecordIndex(callback) >= 0) {
+ Log.w(TAG, "Ignoring to add the same callback twice.");
return;
}
if (mCallbacks.size() == 0) {
@@ -116,7 +113,9 @@ public class MediaRouter2Manager {
Log.e(TAG, "Unable to register media router manager.", ex);
}
}
- mCallbacks.add(new CallbackRecord(executor, callback));
+ CallbackRecord record = new CallbackRecord(executor, callback);
+ mCallbacks.add(record);
+ record.notifyRoutes();
}
}
@@ -131,7 +130,7 @@ public class MediaRouter2Manager {
}
synchronized (sLock) {
- final int index = findCallbackRecord(callback);
+ final int index = findCallbackRecordIndex(callback);
if (index < 0) {
Log.w(TAG, "Ignore removing unknown callback. " + callback);
return;
@@ -148,7 +147,7 @@ public class MediaRouter2Manager {
}
}
- private int findCallbackRecord(Callback callback) {
+ private int findCallbackRecordIndex(Callback callback) {
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
if (mCallbacks.get(i).mCallback == callback) {
@@ -162,12 +161,12 @@ public class MediaRouter2Manager {
* Selects media route for the specified application uid.
*
* @param uid The uid of the application that should change it's media route.
- * @param routeId The id of the route to select
+ * @param route The route to select
*/
- public void selectRoute(int uid, String routeId) {
+ public void selectRoute(int uid, MediaRoute2Info route) {
if (mClient != null) {
try {
- mMediaRouterService.setRemoteRoute(mClient, uid, routeId, /* explicit= */true);
+ mMediaRouterService.selectClientRoute2(mClient, uid, route);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to select media route", ex);
}
@@ -182,7 +181,7 @@ public class MediaRouter2Manager {
public void unselectRoute(int uid) {
if (mClient != null) {
try {
- mMediaRouterService.setRemoteRoute(mClient, uid, null, /* explicit= */ true);
+ mMediaRouterService.selectClientRoute2(mClient, uid, null);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to select media route", ex);
}
@@ -220,15 +219,18 @@ public class MediaRouter2Manager {
if (prevRoute == null) {
notifyRouteAdded(routeInfo);
} else {
- //TODO: Notify only it's really changed.
- notifyRouteChanged(routeInfo);
+ if (!Objects.equals(prevRoute, routeInfo)) {
+ notifyRouteChanged(routeInfo);
+ }
updatedRouteIds.add(routeInfo.getId());
}
}
final Collection prevRoutes = prevProvider.getRoutes();
for (MediaRoute2Info prevRoute : prevRoutes) {
- notifyRouteRemoved(prevRoute);
+ if (!updatedRouteIds.contains(prevRoute.getId())) {
+ notifyRouteRemoved(prevRoute);
+ }
}
} else {
for (MediaRoute2Info routeInfo: routes) {
@@ -267,15 +269,15 @@ public class MediaRouter2Manager {
for (MediaRoute2ProviderInfo provider : providers) {
updateProvider(provider);
}
- //TODO: Call notifyProviderRemoved for removed providers.
+ //TODO: Call notifyRouteRemoved for the routes of the removed providers.
//TODO: Filter invalid providers.
mProviders = providers;
}
- void notifyRouteSelected(int uid, String routeId) {
+ void notifyRouteSelected(int uid, MediaRoute2Info route) {
for (CallbackRecord record : mCallbacks) {
- record.mExecutor.execute(() -> record.mCallback.onRouteSelected(uid, routeId));
+ record.mExecutor.execute(() -> record.mCallback.onRouteSelected(uid, route));
}
}
@@ -289,41 +291,35 @@ public class MediaRouter2Manager {
/**
* Interface for receiving events about media routing changes.
*/
- public abstract static class Callback {
+ public static class Callback {
/**
* Called when a route is added.
*/
- public void onRouteAdded(MediaRoute2Info routeInfo) {}
+ public void onRouteAdded(@NonNull MediaRoute2Info routeInfo) {}
/**
* Called when a route is changed.
*/
- public void onRouteChanged(MediaRoute2Info routeInfo) {}
+ public void onRouteChanged(@NonNull MediaRoute2Info routeInfo) {}
/**
* Called when a route is removed.
*/
- public void onRouteRemoved(MediaRoute2Info routeInfo) {}
+ public void onRouteRemoved(@NonNull MediaRoute2Info routeInfo) {}
/**
- * Called when a route is selected for some application uid.
- * @param uid
- * @param routeId
+ * Called when a route is selected for an application.
+ * @param uid uid of the application
+ * @param route selected route of the application.
*/
- public abstract void onRouteSelected(int uid, String routeId);
+ public void onRouteSelected(int uid, @Nullable MediaRoute2Info route) {}
/**
* Called when the control categories of an application is changed.
* @param uid the uid of the app that changed control categories
* @param categories the changed categories
*/
- public abstract void onControlCategoriesChanged(int uid, List categories);
-
- /**
- * Called when the provider updates its information
- * @param info the changed provider information
- */
- public void onProviderInfoUpdated(MediaRoute2ProviderInfo info) {}
+ public void onControlCategoriesChanged(int uid, @NonNull List categories) {}
}
final class CallbackRecord {
@@ -334,13 +330,22 @@ public class MediaRouter2Manager {
mExecutor = executor;
mCallback = callback;
}
+
+ void notifyRoutes() {
+ for (MediaRoute2ProviderInfo provider : mProviders) {
+ for (MediaRoute2Info routeInfo : provider.getRoutes()) {
+ mExecutor.execute(
+ () -> mCallback.onRouteAdded(routeInfo));
+ }
+ }
+ }
}
class Client extends IMediaRouter2Manager.Stub {
@Override
- public void notifyRouteSelected(int uid, String routeId) {
+ public void notifyRouteSelected(int uid, MediaRoute2Info route) {
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyRouteSelected,
- MediaRouter2Manager.this, uid, routeId));
+ MediaRouter2Manager.this, uid, route));
}
@Override
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 41a76bf9dda9e..aa062cd996ae8 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -17,7 +17,6 @@
package com.android.mediaroutertest;
import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.after;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -30,13 +29,16 @@ import android.media.MediaRouter2Manager;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
@@ -96,7 +98,7 @@ public class MediaRouterManagerTest {
mManager.removeCallback(mockCallback);
}
- @Test
+ //TODO: Recover this test when media router 2 is finalized.
public void testRouteRemoved() {
MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
mManager.addCallback(mExecutor, mockCallback);
@@ -129,9 +131,6 @@ public class MediaRouterManagerTest {
MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
- verify(mockCallback, after(AWAIT_MS).never()).onControlCategoriesChanged(uid,
- TEST_CONTROL_CATEGORIES);
-
InstrumentationRegistry.getInstrumentation().runOnMainSync(
(Runnable) () -> {
mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, mockRouterCallback);
@@ -143,4 +142,49 @@ public class MediaRouterManagerTest {
mManager.removeCallback(mockCallback);
}
+
+ @Test
+ public void selectRouteTest() throws Exception {
+ final int uid = android.os.Process.myUid();
+
+ CountDownLatch latch = new CountDownLatch(1);
+
+ MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ (Runnable) () -> {
+ mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, mockRouterCallback);
+ }
+ );
+
+ MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
+ MediaRoute2Info mSelectedRoute = null;
+
+ @Override
+ public void onRouteAdded(MediaRoute2Info routeInfo) {
+ if (mSelectedRoute == null) {
+ mSelectedRoute = routeInfo;
+ mManager.selectRoute(uid, mSelectedRoute);
+ }
+ }
+
+ @Override
+ public void onRouteSelected(int uid, MediaRoute2Info route) {
+ if (mSelectedRoute != null && route != null
+ && TextUtils.equals(route.getId(), mSelectedRoute.getId())) {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void onControlCategoriesChanged(int uid, List categories) {
+
+ }
+ };
+
+ mManager.addCallback(mExecutor, managerCallback);
+
+ Assert.assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ mManager.removeCallback(managerCallback);
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 2fd2d74f6e440..c13fcd61eeab6 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -17,6 +17,7 @@
package com.android.server.media;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -98,6 +99,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
+ @Nullable
public MediaRoute2ProviderInfo getProviderInfo() {
return mProviderInfo;
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 98fbf757662cb..0398658f18cde 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,8 @@
package com.android.server.media;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -32,6 +34,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -167,12 +170,24 @@ class MediaRouter2ServiceImpl {
}
}
- public void setRemoteRoute(@NonNull IMediaRouter2Manager manager,
- int uid, @Nullable String routeId, boolean explicit) {
+ public void selectRoute2(@NonNull IMediaRouter2Client client,
+ @Nullable MediaRoute2Info route) {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- setRemoteRouteLocked(manager, uid, routeId, explicit);
+ selectRoute2Locked(client, route);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ public void selectClientRoute2(@NonNull IMediaRouter2Manager manager,
+ int clientUid, @Nullable MediaRoute2Info route) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ selectClientRoute2Locked(manager, clientUid, route);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -252,6 +267,53 @@ class MediaRouter2ServiceImpl {
}
}
+ private void selectRoute2Locked(IMediaRouter2Client client,
+ MediaRoute2Info route) {
+ ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+ if (clientRecord != null) {
+ MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
+ clientRecord.mSelectedRoute = route;
+
+ UserHandler handler = clientRecord.mUserRecord.mHandler;
+ //TODO: Handle transfer instead of unselect and select
+ if (oldRoute != null) {
+ handler.sendMessage(
+ obtainMessage(UserHandler::unselectRoute, handler, clientRecord,
+ oldRoute));
+ }
+ if (route != null) {
+ handler.sendMessage(
+ obtainMessage(UserHandler::selectRoute, handler, clientRecord, route));
+ }
+ handler.sendMessage(
+ obtainMessage(UserHandler::updateClientUsage, handler, clientRecord));
+ }
+ }
+
+ private void setControlCategoriesLocked(IMediaRouter2Client client, List categories) {
+ final IBinder binder = client.asBinder();
+ ClientRecord clientRecord = mAllClientRecords.get(binder);
+
+ if (clientRecord != null) {
+ clientRecord.mControlCategories = categories;
+
+ clientRecord.mUserRecord.mHandler.obtainMessage(
+ UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget();
+ }
+ }
+
+ private void sendControlRequestLocked(IMediaRouter2Client client, MediaRoute2Info route,
+ Intent request) {
+ final IBinder binder = client.asBinder();
+ ClientRecord clientRecord = mAllClientRecords.get(binder);
+
+ if (clientRecord != null) {
+ Pair obj = new Pair<>(route, request);
+ clientRecord.mUserRecord.mHandler.obtainMessage(
+ UserHandler.MSG_SEND_CONTROL_REQUEST, obj).sendToTarget();
+ }
+ }
+
private void registerManagerLocked(IMediaRouter2Manager manager,
int uid, int pid, String packageName, int userId, boolean trusted) {
final IBinder binder = manager.asBinder();
@@ -301,38 +363,17 @@ class MediaRouter2ServiceImpl {
}
}
- private void setRemoteRouteLocked(IMediaRouter2Manager manager,
- int uid, String routeId, boolean explicit) {
+ private void selectClientRoute2Locked(IMediaRouter2Manager manager,
+ int clientUid, MediaRoute2Info route) {
ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
if (managerRecord != null) {
- if (explicit && managerRecord.mTrusted) {
- Pair obj = new Pair<>(uid, routeId);
- managerRecord.mUserRecord.mHandler.obtainMessage(
- UserHandler.MSG_SELECT_REMOTE_ROUTE, obj).sendToTarget();
+ ClientRecord clientRecord = managerRecord.mUserRecord.findClientRecordByUid(clientUid);
+ if (clientRecord == null) {
+ Slog.w(TAG, "Ignoring route selection for unknown client.");
+ }
+ if (clientRecord != null && managerRecord.mTrusted) {
+ selectRoute2Locked(clientRecord.mClient, route);
}
- }
- }
-
- private void setControlCategoriesLocked(IMediaRouter2Client client, List categories) {
- final IBinder binder = client.asBinder();
- ClientRecord clientRecord = mAllClientRecords.get(binder);
-
- if (clientRecord != null) {
- clientRecord.mControlCategories = categories;
- clientRecord.mUserRecord.mHandler.obtainMessage(
- UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget();
- }
- }
-
- private void sendControlRequestLocked(IMediaRouter2Client client, MediaRoute2Info route,
- Intent request) {
- final IBinder binder = client.asBinder();
- ClientRecord clientRecord = mAllClientRecords.get(binder);
-
- if (clientRecord != null) {
- Pair obj = new Pair<>(route, request);
- clientRecord.mUserRecord.mHandler.obtainMessage(
- UserHandler.MSG_SEND_CONTROL_REQUEST, obj).sendToTarget();
}
}
@@ -371,6 +412,13 @@ class MediaRouter2ServiceImpl {
mUserId = userId;
mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
}
+
+ ClientRecord findClientRecordByUid(int uid) {
+ for (ClientRecord clientRecord : mClientRecords) {
+ if (clientRecord.mUid == uid) return clientRecord;
+ }
+ return null;
+ }
}
final class ClientRecord implements IBinder.DeathRecipient {
@@ -381,6 +429,7 @@ class MediaRouter2ServiceImpl {
public final String mPackageName;
public final boolean mTrusted;
public List mControlCategories;
+ public MediaRoute2Info mSelectedRoute;
ClientRecord(UserRecord userRecord, IMediaRouter2Client client,
int uid, int pid, String packageName, boolean trusted) {
@@ -447,20 +496,20 @@ class MediaRouter2ServiceImpl {
MediaRoute2ProviderWatcher.Callback,
MediaRoute2ProviderProxy.Callback {
- //TODO: Should be rearranged
- public static final int MSG_START = 1;
- public static final int MSG_STOP = 2;
+ //TODO: Use PooledLambda instead.
+ static final int MSG_START = 1;
+ static final int MSG_STOP = 2;
- private static final int MSG_SELECT_REMOTE_ROUTE = 10;
- private static final int MSG_UPDATE_CLIENT_USAGE = 11;
- private static final int MSG_UPDATE_MANAGER_STATE = 12;
- private static final int MSG_SEND_CONTROL_REQUEST = 13;
+ static final int MSG_UPDATE_CLIENT_USAGE = 11;
+ static final int MSG_UPDATE_MANAGER_STATE = 12;
+ static final int MSG_SEND_CONTROL_REQUEST = 13;
private final WeakReference mServiceRef;
private final UserRecord mUserRecord;
private final MediaRoute2ProviderWatcher mWatcher;
private final ArrayList mTempManagers = new ArrayList<>();
+ //TODO: Make this thread-safe.
private final ArrayList mMediaProviders =
new ArrayList<>();
@@ -486,11 +535,6 @@ class MediaRouter2ServiceImpl {
stop();
break;
}
- case MSG_SELECT_REMOTE_ROUTE: {
- Pair obj = (Pair) msg.obj;
- selectRemoteRoute(obj.first, obj.second);
- break;
- }
case MSG_UPDATE_CLIENT_USAGE: {
updateClientUsage((ClientRecord) msg.obj);
break;
@@ -541,22 +585,28 @@ class MediaRouter2ServiceImpl {
scheduleUpdateManagerState();
}
+ private void unselectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+ if (route != null) {
+ MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ if (provider != null) {
+ provider.setSelectedRoute(clientRecord.mUid, null);
+ }
+ }
+ }
- private void selectRemoteRoute(int uid, String routeId) {
- if (routeId != null) {
- final int providerCount = mMediaProviders.size();
-
- //TODO: should find proper provider (currently assumes a single provider)
- for (int i = 0; i < providerCount; i++) {
- mMediaProviders.get(i).setSelectedRoute(uid, routeId);
+ private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+ if (route != null) {
+ MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ if (provider != null) {
+ provider.setSelectedRoute(clientRecord.mUid, route.getId());
}
}
}
private void sendControlRequest(MediaRoute2Info route, Intent request) {
- final int providerCount = mMediaProviders.size();
- for (int i = 0; i < providerCount; i++) {
- mMediaProviders.get(i).sendControlRequest(route, request);
+ final MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
+ if (provider != null) {
+ provider.sendControlRequest(route, request);
}
}
@@ -576,10 +626,9 @@ class MediaRouter2ServiceImpl {
}
//TODO: Consider using a member variable (like mTempManagers).
final List providers = new ArrayList<>();
- final int mediaCount = mMediaProviders.size();
- for (int i = 0; i < mediaCount; i++) {
+ for (MediaRoute2ProviderProxy mediaProvider : mMediaProviders) {
final MediaRoute2ProviderInfo providerInfo =
- mMediaProviders.get(i).getProviderInfo();
+ mediaProvider.getProviderInfo();
if (providerInfo == null || !providerInfo.isValid()) {
Log.w(TAG, "Ignoring invalid provider info : " + providerInfo);
} else {
@@ -594,16 +643,11 @@ class MediaRouter2ServiceImpl {
mTempManagers.add(mUserRecord.mManagerRecords.get(i).mManager);
}
}
- //TODO: Call !proper callbacks when provider descriptor is implemented.
- if (!providers.isEmpty()) {
- final int count = mTempManagers.size();
- for (int i = 0; i < count; i++) {
- try {
- mTempManagers.get(i).notifyProviderInfosUpdated(providers);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to call onStateChanged. Manager probably died.",
- ex);
- }
+ for (IMediaRouter2Manager tempManager : mTempManagers) {
+ try {
+ tempManager.notifyProviderInfosUpdated(providers);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to update manager state. Manager probably died.", ex);
}
}
} finally {
@@ -624,16 +668,26 @@ class MediaRouter2ServiceImpl {
managers.add(mUserRecord.mManagerRecords.get(i).mManager);
}
}
- final int count = managers.size();
- for (int i = 0; i < count; i++) {
+ for (IMediaRouter2Manager manager : managers) {
try {
- managers.get(i).notifyControlCategoriesChanged(clientRecord.mUid,
+ manager.notifyRouteSelected(clientRecord.mUid, clientRecord.mSelectedRoute);
+ manager.notifyControlCategoriesChanged(clientRecord.mUid,
clientRecord.mControlCategories);
} catch (RemoteException ex) {
- Slog.w(TAG, "Failed to call onControlCategoriesChanged. "
- + "Manager probably died.", ex);
+ Slog.w(TAG, "Failed to update client usage. Manager probably died.", ex);
}
}
}
+
+ private MediaRoute2ProviderProxy findProvider(String providerId) {
+ for (MediaRoute2ProviderProxy provider : mMediaProviders) {
+ final MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
+ if (providerInfo != null
+ && TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
+ return provider;
+ }
+ }
+ return null;
+ }
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index d820c62395753..4577365b6c3a0 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -449,6 +449,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub
mService2.unregisterClient(client);
}
+ // Binder call
+ @Override
+ public void selectRoute2(IMediaRouter2Client client, MediaRoute2Info route) {
+ mService2.selectRoute2(client, route);
+ }
+
// Binder call
@Override
public void sendControlRequest(IMediaRouter2Client client, MediaRoute2Info route,
@@ -475,9 +481,9 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
- public void setRemoteRoute(IMediaRouter2Manager manager,
- int uid, String routeId, boolean explicit) {
- mService2.setRemoteRoute(manager, uid, routeId, explicit);
+ public void selectClientRoute2(IMediaRouter2Manager manager,
+ int clientUid, MediaRoute2Info route) {
+ mService2.selectClientRoute2(manager, clientUid, route);
}
// Binder call