Merge "MediaRouter: send control hints from provider to client"

This commit is contained in:
Kyunglyul Hyun
2019-12-02 09:13:17 +00:00
committed by Android (Google) Code Review
9 changed files with 233 additions and 107 deletions

View File

@@ -17,10 +17,13 @@
package android.media;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2Info;
import android.os.Bundle;
/**
* @hide
*/
oneway interface IMediaRoute2ProviderClient {
void updateProviderInfo(in MediaRoute2ProviderInfo info);
void notifyRouteSelected(String packageName, String routeId, in Bundle controlHints, int seq);
}

View File

@@ -18,14 +18,19 @@ package android.media;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import java.util.Objects;
/**
* @hide
*/
@@ -44,7 +49,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
public IBinder onBind(Intent intent) {
public IBinder onBind(@NonNull Intent intent) {
//TODO: Allow binding from media router service only?
if (SERVICE_INTERFACE.equals(intent.getAction())) {
if (mStub == null) {
@@ -57,11 +62,17 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Called when selectRoute is called on a route of the provider.
* Once the route is ready to be used , call {@link #notifyRouteSelected(SelectToken, Bundle)}
* to notify that.
*
* @param packageName the package name of the application that selected the route
* @param routeId the id of the route being selected
* @param token token that contains select info
*
* @see #notifyRouteSelected
*/
public abstract void onSelectRoute(String packageName, String routeId);
public abstract void onSelectRoute(@NonNull String packageName, @NonNull String routeId,
@NonNull SelectToken token);
/**
* Called when unselectRoute is called on a route of the provider.
@@ -69,7 +80,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* @param packageName the package name of the application that has selected the route.
* @param routeId the id of the route being unselected
*/
public abstract void onUnselectRoute(String packageName, String routeId);
public abstract void onUnselectRoute(@NonNull String packageName, @NonNull String routeId);
/**
* Called when sendControlRequest is called on a route of the provider
@@ -78,21 +89,21 @@ public abstract class MediaRoute2ProviderService extends Service {
* @param request the media control request intent
*/
//TODO: Discuss what to use for request (e.g., Intent? Request class?)
public abstract void onControlRequest(String routeId, Intent request);
public abstract void onControlRequest(@NonNull String routeId, @NonNull Intent request);
/**
* Called when requestSetVolume is called on a route of the provider
* @param routeId the id of the route
* @param volume the target volume
*/
public abstract void onSetVolume(String routeId, int volume);
public abstract void onSetVolume(@NonNull String routeId, int volume);
/**
* Called when requestUpdateVolume is called on a route of the provider
* @param routeId id of the route
* @param delta the delta to add to the current volume
*/
public abstract void onUpdateVolume(String routeId, int delta);
public abstract void onUpdateVolume(@NonNull String routeId, int delta);
/**
* Updates provider info and publishes routes
@@ -102,6 +113,29 @@ public abstract class MediaRoute2ProviderService extends Service {
publishState();
}
/**
* Notifies the client of that the selected route is ready for use. If the selected route can be
* controlled, pass a {@link Bundle} that contains how to control it.
*
* @param token token passed in {@link #onSelectRoute}
* @param controlHints a {@link Bundle} that contains how to control the given route.
* Pass {@code null} if the route is not available.
*/
public final void notifyRouteSelected(@NonNull SelectToken token,
@Nullable Bundle controlHints) {
Objects.requireNonNull(token, "token must not be null");
if (mClient == null) {
return;
}
try {
mClient.notifyRouteSelected(token.mPackageName, token.mRouteId,
controlHints, token.mSeq);
} catch (RemoteException ex) {
Log.w(TAG, "Failed to notify route selected");
}
}
void setClient(IMediaRoute2ProviderClient client) {
mClient = client;
publishState();
@@ -118,6 +152,23 @@ public abstract class MediaRoute2ProviderService extends Service {
}
}
/**
* Route selection information.
*
* @see #notifyRouteSelected
*/
public final class SelectToken {
final String mPackageName;
final String mRouteId;
final int mSeq;
SelectToken(String packageName, String routeId, int seq) {
mPackageName = packageName;
mRouteId = routeId;
mSeq = seq;
}
}
final class ProviderStub extends IMediaRoute2Provider.Stub {
ProviderStub() { }
@@ -129,10 +180,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void requestSelectRoute(String packageName, String id, int seq) {
// TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
// use the sequence number here properly.
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
MediaRoute2ProviderService.this, packageName, id));
MediaRoute2ProviderService.this, packageName, id,
new SelectToken(packageName, id, seq)));
}
@Override

View File

@@ -1318,6 +1318,7 @@ public class MediaRouter {
sStatic.rebindAsUser(userId);
}
//TODO: remove this and Client1Record in MediaRouter2ServiceImpl.
/**
* Sets the control categories of the application.
* Routes that support at least one of the given control categories only exists and are handled

View File

@@ -57,7 +57,8 @@ public class MediaRouter2 {
@IntDef(value = {
SELECT_REASON_UNKNOWN,
SELECT_REASON_USER_SELECTED,
SELECT_REASON_FALLBACK})
SELECT_REASON_FALLBACK,
SELECT_REASON_SYSTEM_SELECTED})
public @interface SelectReason {}
/**
@@ -80,6 +81,13 @@ public class MediaRouter2 {
*/
public static final int SELECT_REASON_FALLBACK = 2;
/**
* This is passed from {@link com.android.server.media.MediaRouterService} when the route
* is selected in response to a request from other apps (e.g. System UI).
* @hide
*/
public static final int SELECT_REASON_SYSTEM_SELECTED = 3;
private static final String TAG = "MR2";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final Object sLock = new Object();
@@ -485,6 +493,9 @@ public class MediaRouter2 {
}
mSelectingRoute = null;
}
if (reason == SELECT_REASON_SYSTEM_SELECTED) {
reason = SELECT_REASON_USER_SELECTED;
}
mSelectedRoute = route;
notifyRouteSelected(route, reason, controlHints);
}

View File

@@ -20,6 +20,7 @@ import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
import android.os.Bundle;
import android.os.IBinder;
import java.util.HashMap;
@@ -95,7 +96,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
public void onSelectRoute(String packageName, String routeId) {
public void onSelectRoute(String packageName, String routeId, SelectToken token) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null) {
return;
@@ -104,6 +105,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
.setClientPackageName(packageName)
.build());
publishRoutes();
notifyRouteSelected(token, Bundle.EMPTY);
}
@Override

View File

@@ -23,23 +23,19 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.media.MediaRouter2Manager;
import android.os.Bundle;
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.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -95,9 +91,14 @@ public class MediaRouterManagerTest {
private Executor mExecutor;
private String mPackageName;
private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
private final List<MediaRouter2.Callback> mRouterCallbacks = new ArrayList<>();
private Map<String, MediaRoute2Info> mRoutes;
private static final List<String> CATEGORIES_ALL = new ArrayList();
private static final List<String> CATEGORIES_SPECIAL = new ArrayList();
private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
static {
CATEGORIES_ALL.add(CATEGORY_SAMPLE);
CATEGORIES_ALL.add(CATEGORY_SPECIAL);
@@ -108,6 +109,7 @@ public class MediaRouterManagerTest {
CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
}
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
@@ -116,6 +118,16 @@ public class MediaRouterManagerTest {
//TODO: If we need to support thread pool executors, change this to thread pool executor.
mExecutor = Executors.newSingleThreadExecutor();
mPackageName = mContext.getPackageName();
// ensure media router 2 client
addRouterCallback(new MediaRouter2.Callback());
mRoutes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
}
@After
public void tearDown() {
// unregister callbacks
clearCallbacks();
}
//TODO: Move to a separate file
@@ -132,10 +144,13 @@ public class MediaRouterManagerTest {
assertNotEquals(routeInfo1, routeInfo3);
}
/**
* Tests if routes are added correctly when a new callback is registered.
*/
@Test
public void testOnRoutesAdded() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onRoutesAdded(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
@@ -145,27 +160,15 @@ public class MediaRouterManagerTest {
}
}
}
};
mManager.registerCallback(mExecutor, callback);
});
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
mManager.unregisterCallback(callback);
}
@Test
public void testOnRoutesRemoved() throws Exception {
MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
mManager.registerCallback(mExecutor, mockCallback);
MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
mRouter2.registerCallback(mExecutor, routerCallback);
Map<String, MediaRoute2Info> routes =
waitAndGetRoutesWithManager(CATEGORIES_ALL);
CountDownLatch latch = new CountDownLatch(1);
MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onRoutesRemoved(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
@@ -175,16 +178,12 @@ public class MediaRouterManagerTest {
}
}
}
};
mManager.registerCallback(mExecutor, callback);
});
//TODO: Figure out a more proper way to test.
// (Control requests shouldn't be used in this way.)
mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
mRouter2.sendControlRequest(mRoutes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
mRouter2.unregisterCallback(routerCallback);
mManager.unregisterCallback(mockCallback);
}
/**
@@ -192,16 +191,10 @@ public class MediaRouterManagerTest {
*/
@Test
public void testControlCategory() throws Exception {
MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
mManager.registerCallback(mExecutor, mockCallback);
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
Map<String, MediaRoute2Info> routes =
waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
Assert.assertEquals(1, routes.size());
Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
mManager.unregisterCallback(mockCallback);
assertEquals(1, routes.size());
assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
}
/**
@@ -209,37 +202,60 @@ public class MediaRouterManagerTest {
*/
@Test
public void testGetRoutes() throws Exception {
MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
mRouter2.registerCallback(mExecutor, mockCallback);
Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
Assert.assertEquals(1, routes.size());
Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
mRouter2.unregisterCallback(mockCallback);
assertEquals(1, routes.size());
assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
}
/**
* Tests if MR2.Callback.onRouteSelected is called when a route is selected from MR2Manager.
*/
@Test
public void testOnRouteSelected() throws Exception {
MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
public void testRouterOnRouteSelected() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
mManager.registerCallback(mExecutor, managerCallback);
mRouter2.registerCallback(mExecutor, routerCallback);
addRouterCallback(new MediaRouter2.Callback() {
@Override
public void onRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
if (route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
latch.countDown();
}
}
});
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
assertNotNull(routeToSelect);
mManager.selectRoute(mPackageName, routeToSelect);
verify(managerCallback, timeout(TIMEOUT_MS))
.onRouteSelected(eq(mPackageName),
argThat(route -> route != null && route.equals(routeToSelect)));
mRouter2.unregisterCallback(routerCallback);
mManager.unregisterCallback(managerCallback);
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
/**
* Tests if MR2Manager.Callback.onRouteSelected is called
* when a route is selected by MR2Manager.
*/
@Test
public void testManagerOnRouteSelected() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onRouteSelected(String packageName, MediaRoute2Info route) {
if (TextUtils.equals(mPackageName, packageName)
&& route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
latch.countDown();
}
}
});
MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
assertNotNull(routeToSelect);
mManager.selectRoute(mPackageName, routeToSelect);
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
/**
@@ -247,19 +263,13 @@ public class MediaRouterManagerTest {
*/
@Test
public void testSingleProviderSelect() throws Exception {
MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
mRouter2.registerCallback(mExecutor, routerCallback);
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
awaitOnRouteChangedManager(
() -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
() -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID1)),
ROUTE_ID1,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
awaitOnRouteChangedManager(
() -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2)),
() -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID2)),
ROUTE_ID2,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
@@ -267,8 +277,6 @@ public class MediaRouterManagerTest {
() -> mManager.unselectRoute(mPackageName),
ROUTE_ID2,
route -> TextUtils.equals(route.getClientPackageName(), null));
mRouter2.unregisterCallback(routerCallback);
}
@Test
@@ -292,12 +300,7 @@ public class MediaRouterManagerTest {
@Test
public void testControlVolumeWithManager() throws Exception {
MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
mRouter2.registerCallback(mExecutor, mockCallback);
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
MediaRoute2Info volRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
@@ -310,24 +313,16 @@ public class MediaRouterManagerTest {
() -> mManager.requestSetVolume(volRoute, originalVolume),
ROUTE_ID_VARIABLE_VOLUME,
(route -> route.getVolume() == originalVolume));
mRouter2.unregisterCallback(mockCallback);
}
@Test
public void testVolumeHandling() throws Exception {
MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
mRouter2.registerCallback(mExecutor, mockCallback);
Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
MediaRoute2Info fixedVolumeRoute = mRoutes.get(ROUTE_ID_FIXED_VOLUME);
MediaRoute2Info variableVolumeRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
mRouter2.unregisterCallback(mockCallback);
}
@Test
@@ -368,6 +363,7 @@ public class MediaRouterManagerTest {
latch.countDown();
}
}
@Override
public void onControlCategoriesChanged(String packageName) {
if (TextUtils.equals(mPackageName, packageName)) {
@@ -401,7 +397,7 @@ public class MediaRouterManagerTest {
};
mRouter2.registerCallback(mExecutor, callback);
try {
new Thread(task).start();
task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
} finally {
mRouter2.unregisterCallback(callback);
@@ -422,7 +418,7 @@ public class MediaRouterManagerTest {
};
mManager.registerCallback(mExecutor, callback);
try {
new Thread(task).start();
task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
} finally {
mManager.unregisterCallback(callback);
@@ -433,9 +429,31 @@ public class MediaRouterManagerTest {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
// intentionally not route.getUniqueId() for convenience.
// intentionally not using route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
}
private void addManagerCallback(MediaRouter2Manager.Callback callback) {
mManagerCallbacks.add(callback);
mManager.registerCallback(mExecutor, callback);
}
private void addRouterCallback(MediaRouter2.Callback callback) {
mRouterCallbacks.add(callback);
mRouter2.registerCallback(mExecutor, callback);
}
private void clearCallbacks() {
for (MediaRouter2Manager.Callback callback : mManagerCallbacks) {
mManager.unregisterCallback(callback);
}
mManagerCallbacks.clear();
for (MediaRouter2.Callback callback : mRouterCallbacks) {
mRouter2.unregisterCallback(callback);
}
mRouterCallbacks.clear();
}
}

View File

@@ -22,6 +22,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.os.Bundle;
import java.util.Objects;
@@ -29,7 +30,7 @@ abstract class MediaRoute2Provider {
final ComponentName mComponentName;
final String mUniqueId;
private Callback mCallback;
Callback mCallback;
private MediaRoute2ProviderInfo mProviderInfo;
MediaRoute2Provider(@NonNull ComponentName componentName) {
@@ -77,6 +78,9 @@ abstract class MediaRoute2Provider {
}
public interface Callback {
void onProviderStateChanged(MediaRoute2Provider provider);
void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
@NonNull String clientPackageName, @NonNull MediaRoute2Info route,
@Nullable Bundle controlHints, int seq);
}
}

View File

@@ -26,6 +26,7 @@ import android.media.IMediaRoute2ProviderClient;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@@ -253,6 +254,20 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
setAndNotifyProviderInfo(info);
}
private void onRouteSelected(Connection connection,
String packageName, String routeId, Bundle controlHints, int seq) {
if (mActiveConnection != connection) {
return;
}
MediaRoute2ProviderInfo providerInfo = getProviderInfo();
MediaRoute2Info route = (providerInfo == null) ? null : providerInfo.getRoute(routeId);
if (route == null) {
Slog.w(TAG, this + ": Unknown route " + routeId + " is selected from remove provider");
return;
}
mCallback.onRouteSelected(this, packageName, route, controlHints, seq);
}
private void disconnect() {
if (mActiveConnection != null) {
mConnectionReady = false;
@@ -341,6 +356,11 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
void postProviderInfoUpdated(MediaRoute2ProviderInfo info) {
mHandler.post(() -> onProviderInfoUpdated(Connection.this, info));
}
void postRouteSelected(String packageName, String routeId, Bundle controlHints, int seq) {
mHandler.post(() -> onRouteSelected(Connection.this,
packageName, routeId, controlHints, seq));
}
}
private static final class ProviderClient extends IMediaRoute2ProviderClient.Stub {
@@ -361,5 +381,15 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
connection.postProviderInfoUpdated(info);
}
}
@Override
public void notifyRouteSelected(String packageName, String routeId,
Bundle controlHints, int seq) {
Connection connection = mConnectionRef.get();
if (connection != null) {
connection.postRouteSelected(packageName, routeId, controlHints, seq);
}
}
}
}

View File

@@ -77,7 +77,7 @@ class MediaRouter2ServiceImpl {
@GuardedBy("mLock")
private int mCurrentUserId = -1;
@GuardedBy("mLock")
private int mSelectRouteRequestSequenceNumber = 0;
private int mSelectRouteRequestSequenceNumber = 1;
MediaRouter2ServiceImpl(Context context) {
mContext = context;
@@ -218,7 +218,7 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), false, route);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -399,10 +399,12 @@ class MediaRouter2ServiceImpl {
}
}
private void requestSelectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
private void requestSelectRoute2Locked(ClientRecord clientRecord, boolean selectedByManager,
MediaRoute2Info route) {
if (clientRecord != null) {
MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
clientRecord.mSelectingRoute = route;
clientRecord.mIsManagerSelecting = selectedByManager;
UserHandler handler = clientRecord.mUserRecord.mHandler;
//TODO: Handle transfer instead of unselect and select
@@ -417,7 +419,6 @@ class MediaRouter2ServiceImpl {
handler.sendMessage(obtainMessage(
UserHandler::requestSelectRoute, handler, clientRecord.mPackageName,
route, seq));
// Remove all previous timeout messages
for (int previousSeq : clientRecord.mSelectRouteSequenceNumbers) {
clientRecord.mUserRecord.mHandler.removeMessages(previousSeq);
@@ -543,7 +544,7 @@ class MediaRouter2ServiceImpl {
Slog.w(TAG, "Ignoring route selection for unknown client.");
}
if (clientRecord != null && managerRecord.mTrusted) {
requestSelectRoute2Locked(clientRecord, route);
requestSelectRoute2Locked(clientRecord, true, route);
}
}
}
@@ -656,7 +657,9 @@ class MediaRouter2ServiceImpl {
public final UserRecord mUserRecord;
public final String mPackageName;
public final List<Integer> mSelectRouteSequenceNumbers;
public List<String> mControlCategories;
public boolean mIsManagerSelecting;
public MediaRoute2Info mSelectingRoute;
public MediaRoute2Info mSelectedRoute;
@@ -802,9 +805,8 @@ class MediaRouter2ServiceImpl {
sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
}
// TODO: When introducing MediaRoute2ProviderService#sendControlHints(),
// Make this method to be called.
public void onRouteSelectionRequestHandled(@NonNull MediaRoute2ProviderProxy provider,
@Override
public void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
String clientPackageName, MediaRoute2Info route, Bundle controlHints, int seq) {
sendMessage(PooledLambda.obtainMessage(
UserHandler::updateSelectedRoute, this, provider, clientPackageName, route,
@@ -917,6 +919,8 @@ class MediaRouter2ServiceImpl {
return;
}
//TODO: handle a case such that controlHints is null. (How should we notify MR2?)
if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
clientRecord.mSelectingRoute.getUniqueId(), selectedRoute.getUniqueId())) {
Log.w(TAG, "Ignoring invalid updateSelectedRoute call. selectingRoute="
@@ -929,7 +933,9 @@ class MediaRouter2ServiceImpl {
notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
selectedRoute,
MediaRouter2.SELECT_REASON_USER_SELECTED,
clientRecord.mIsManagerSelecting
? MediaRouter2.SELECT_REASON_SYSTEM_SELECTED :
MediaRouter2.SELECT_REASON_USER_SELECTED,
controlHints);
updateClientUsage(clientRecord);