Merge "Add MediaRouter2 API atomic route callbacks"
This commit is contained in:
@@ -23189,9 +23189,10 @@ package android.media {
|
||||
|
||||
public abstract static class MediaRouter2.RouteCallback {
|
||||
ctor public MediaRouter2.RouteCallback();
|
||||
method public void onRoutesAdded(@NonNull java.util.List<android.media.MediaRoute2Info>);
|
||||
method public void onRoutesChanged(@NonNull java.util.List<android.media.MediaRoute2Info>);
|
||||
method public void onRoutesRemoved(@NonNull java.util.List<android.media.MediaRoute2Info>);
|
||||
method @Deprecated public void onRoutesAdded(@NonNull java.util.List<android.media.MediaRoute2Info>);
|
||||
method @Deprecated public void onRoutesChanged(@NonNull java.util.List<android.media.MediaRoute2Info>);
|
||||
method @Deprecated public void onRoutesRemoved(@NonNull java.util.List<android.media.MediaRoute2Info>);
|
||||
method public void onRoutesUpdated(@NonNull java.util.List<android.media.MediaRoute2Info>);
|
||||
}
|
||||
|
||||
public class MediaRouter2.RoutingController {
|
||||
|
||||
@@ -26,9 +26,7 @@ import android.os.Bundle;
|
||||
oneway interface IMediaRouter2 {
|
||||
void notifyRouterRegistered(in List<MediaRoute2Info> currentRoutes,
|
||||
in RoutingSessionInfo currentSystemSessionInfo);
|
||||
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
|
||||
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
|
||||
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
|
||||
void notifyRoutesUpdated(in List<MediaRoute2Info> routes);
|
||||
void notifySessionCreated(int requestId, in @nullable RoutingSessionInfo sessionInfo);
|
||||
void notifySessionInfoChanged(in RoutingSessionInfo sessionInfo);
|
||||
void notifySessionReleased(in RoutingSessionInfo sessionInfo);
|
||||
|
||||
@@ -30,8 +30,6 @@ oneway interface IMediaRouter2Manager {
|
||||
void notifySessionReleased(in RoutingSessionInfo session);
|
||||
void notifyDiscoveryPreferenceChanged(String packageName,
|
||||
in RouteDiscoveryPreference discoveryPreference);
|
||||
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
|
||||
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
|
||||
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
|
||||
void notifyRoutesUpdated(in List<MediaRoute2Info> routes);
|
||||
void notifyRequestFailed(int requestId, int reason);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ public final class MediaRouter2 {
|
||||
/**
|
||||
* Stores an auxiliary copy of {@link #mFilteredRoutes} at the time of the last route callback
|
||||
* dispatch. This is only used to determine what callback a route should be assigned to (added,
|
||||
* removed, changed) in {@link #dispatchFilteredRoutesChangedLocked(List)}.
|
||||
* removed, changed) in {@link #dispatchFilteredRoutesUpdatedOnHandler(List)}.
|
||||
*/
|
||||
private volatile ArrayMap<String, MediaRoute2Info> mPreviousRoutes = new ArrayMap<>();
|
||||
|
||||
@@ -820,7 +820,7 @@ public final class MediaRouter2 {
|
||||
}
|
||||
}
|
||||
|
||||
void dispatchFilteredRoutesChangedLocked(List<MediaRoute2Info> newRoutes) {
|
||||
void dispatchFilteredRoutesUpdatedOnHandler(List<MediaRoute2Info> newRoutes) {
|
||||
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
|
||||
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
|
||||
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
|
||||
@@ -863,29 +863,16 @@ public final class MediaRouter2 {
|
||||
if (!changedRoutes.isEmpty()) {
|
||||
notifyRoutesChanged(changedRoutes);
|
||||
}
|
||||
}
|
||||
|
||||
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
|
||||
synchronized (mLock) {
|
||||
for (MediaRoute2Info route : routes) {
|
||||
mRoutes.put(route.getId(), route);
|
||||
}
|
||||
updateFilteredRoutesLocked();
|
||||
// Note: We don't notify clients of changes in route ordering.
|
||||
if (!addedRoutes.isEmpty() || !removedRoutes.isEmpty() || !changedRoutes.isEmpty()) {
|
||||
notifyRoutesUpdated(newRoutes);
|
||||
}
|
||||
}
|
||||
|
||||
void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
|
||||
synchronized (mLock) {
|
||||
for (MediaRoute2Info route : routes) {
|
||||
mRoutes.remove(route.getId());
|
||||
}
|
||||
updateFilteredRoutesLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
|
||||
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
|
||||
void updateRoutesOnHandler(List<MediaRoute2Info> routes) {
|
||||
synchronized (mLock) {
|
||||
mRoutes.clear();
|
||||
for (MediaRoute2Info route : routes) {
|
||||
mRoutes.put(route.getId(), route);
|
||||
}
|
||||
@@ -900,8 +887,10 @@ public final class MediaRouter2 {
|
||||
Collections.unmodifiableList(
|
||||
filterRoutesWithCompositePreferenceLocked(List.copyOf(mRoutes.values())));
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(MediaRouter2::dispatchFilteredRoutesChangedLocked,
|
||||
this, mFilteredRoutes));
|
||||
obtainMessage(
|
||||
MediaRouter2::dispatchFilteredRoutesUpdatedOnHandler,
|
||||
this,
|
||||
mFilteredRoutes));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1211,6 +1200,14 @@ public final class MediaRouter2 {
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesUpdated(List<MediaRoute2Info> routes) {
|
||||
for (RouteCallbackRecord record : mRouteCallbackRecords) {
|
||||
List<MediaRoute2Info> filteredRoutes =
|
||||
filterRoutesWithIndividualPreference(routes, record.mPreference);
|
||||
record.mExecutor.execute(() -> record.mRouteCallback.onRoutesUpdated(filteredRoutes));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyPreferredFeaturesChanged(List<String> features) {
|
||||
for (RouteCallbackRecord record : mRouteCallbackRecords) {
|
||||
record.mExecutor.execute(
|
||||
@@ -1246,28 +1243,43 @@ public final class MediaRouter2 {
|
||||
/** Callback for receiving events about media route discovery. */
|
||||
public abstract static class RouteCallback {
|
||||
/**
|
||||
* Called when routes are added. Whenever you registers a callback, this will be invoked
|
||||
* with known routes.
|
||||
* Called when routes are added. Whenever you register a callback, this will be invoked with
|
||||
* known routes.
|
||||
*
|
||||
* @param routes the list of routes that have been added. It's never empty.
|
||||
* @deprecated Use {@link #onRoutesUpdated(List)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {}
|
||||
|
||||
/**
|
||||
* Called when routes are removed.
|
||||
*
|
||||
* @param routes the list of routes that have been removed. It's never empty.
|
||||
* @deprecated Use {@link #onRoutesUpdated(List)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}
|
||||
|
||||
/**
|
||||
* Called when routes are changed. For example, it is called when the route's name or volume
|
||||
* have been changed.
|
||||
* Called when the properties of one or more existing routes are changed. For example, it is
|
||||
* called when a route's name or volume have changed.
|
||||
*
|
||||
* @param routes the list of routes that have been changed. It's never empty.
|
||||
* @deprecated Use {@link #onRoutesUpdated(List)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
|
||||
|
||||
/**
|
||||
* Called when the route list is updated, which can happen when routes are added, removed,
|
||||
* or modified. It will also be called when a route callback is registered.
|
||||
*
|
||||
* @param routes the updated list of routes filtered by the callback's individual discovery
|
||||
* preferences.
|
||||
*/
|
||||
public void onRoutesUpdated(@NonNull List<MediaRoute2Info> routes) {}
|
||||
|
||||
/**
|
||||
* Called when the client app's preferred features are changed. When this is called, it is
|
||||
* recommended to {@link #getRoutes()} to get the routes that are currently available to the
|
||||
@@ -1985,21 +1997,9 @@ public final class MediaRouter2 {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
|
||||
public void notifyRoutesUpdated(List<MediaRoute2Info> routes) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(MediaRouter2::addRoutesOnHandler, MediaRouter2.this, routes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(MediaRouter2::removeRoutesOnHandler, MediaRouter2.this, routes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRoutesChanged(List<MediaRoute2Info> routes) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(MediaRouter2::changeRoutesOnHandler, MediaRouter2.this, routes));
|
||||
obtainMessage(MediaRouter2::updateRoutesOnHandler, MediaRouter2.this, routes));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2047,17 +2047,7 @@ public final class MediaRouter2 {
|
||||
class ManagerCallback implements MediaRouter2Manager.Callback {
|
||||
|
||||
@Override
|
||||
public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {
|
||||
updateAllRoutesFromManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {
|
||||
updateAllRoutesFromManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {
|
||||
public void onRoutesUpdated() {
|
||||
updateAllRoutesFromManager();
|
||||
}
|
||||
|
||||
|
||||
@@ -546,37 +546,15 @@ public final class MediaRouter2Manager {
|
||||
}
|
||||
}
|
||||
|
||||
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
|
||||
void updateRoutesOnHandler(@NonNull List<MediaRoute2Info> routes) {
|
||||
synchronized (mRoutesLock) {
|
||||
mRoutes.clear();
|
||||
for (MediaRoute2Info route : routes) {
|
||||
mRoutes.put(route.getId(), route);
|
||||
}
|
||||
}
|
||||
if (routes.size() > 0) {
|
||||
notifyRoutesAdded(routes);
|
||||
}
|
||||
}
|
||||
|
||||
void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
|
||||
synchronized (mRoutesLock) {
|
||||
for (MediaRoute2Info route : routes) {
|
||||
mRoutes.remove(route.getId());
|
||||
}
|
||||
}
|
||||
if (routes.size() > 0) {
|
||||
notifyRoutesRemoved(routes);
|
||||
}
|
||||
}
|
||||
|
||||
void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
|
||||
synchronized (mRoutesLock) {
|
||||
for (MediaRoute2Info route : routes) {
|
||||
mRoutes.put(route.getId(), route);
|
||||
}
|
||||
}
|
||||
if (routes.size() > 0) {
|
||||
notifyRoutesChanged(routes);
|
||||
}
|
||||
notifyRoutesUpdated();
|
||||
}
|
||||
|
||||
void createSessionOnHandler(int requestId, RoutingSessionInfo sessionInfo) {
|
||||
@@ -650,24 +628,9 @@ public final class MediaRouter2Manager {
|
||||
notifySessionUpdated(sessionInfo);
|
||||
}
|
||||
|
||||
private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
|
||||
private void notifyRoutesUpdated() {
|
||||
for (CallbackRecord record: mCallbackRecords) {
|
||||
record.mExecutor.execute(
|
||||
() -> record.mCallback.onRoutesAdded(routes));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
|
||||
for (CallbackRecord record: mCallbackRecords) {
|
||||
record.mExecutor.execute(
|
||||
() -> record.mCallback.onRoutesRemoved(routes));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesChanged(List<MediaRoute2Info> routes) {
|
||||
for (CallbackRecord record: mCallbackRecords) {
|
||||
record.mExecutor.execute(
|
||||
() -> record.mCallback.onRoutesChanged(routes));
|
||||
record.mExecutor.execute(() -> record.mCallback.onRoutesUpdated());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,23 +926,12 @@ public final class MediaRouter2Manager {
|
||||
* Interface for receiving events about media routing changes.
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when routes are added.
|
||||
* @param routes the list of routes that have been added. It's never empty.
|
||||
*/
|
||||
default void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {}
|
||||
|
||||
/**
|
||||
* Called when routes are removed.
|
||||
* @param routes the list of routes that have been removed. It's never empty.
|
||||
* Called when the routes list changes. This includes adding, modifying, or removing
|
||||
* individual routes.
|
||||
*/
|
||||
default void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}
|
||||
|
||||
/**
|
||||
* Called when routes are changed.
|
||||
* @param routes the list of routes that have been changed. It's never empty.
|
||||
*/
|
||||
default void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
|
||||
default void onRoutesUpdated() {}
|
||||
|
||||
/**
|
||||
* Called when a session is changed.
|
||||
@@ -1115,21 +1067,12 @@ public final class MediaRouter2Manager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
|
||||
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::addRoutesOnHandler,
|
||||
MediaRouter2Manager.this, routes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
|
||||
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::removeRoutesOnHandler,
|
||||
MediaRouter2Manager.this, routes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRoutesChanged(List<MediaRoute2Info> routes) {
|
||||
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::changeRoutesOnHandler,
|
||||
MediaRouter2Manager.this, routes));
|
||||
public void notifyRoutesUpdated(List<MediaRoute2Info> routes) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(
|
||||
MediaRouter2Manager::updateRoutesOnHandler,
|
||||
MediaRouter2Manager.this,
|
||||
routes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_I
|
||||
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_FIXED_VOLUME;
|
||||
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
|
||||
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
|
||||
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_NAME2;
|
||||
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.VOLUME_MAX;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -56,10 +55,10 @@ import android.media.RoutingSessionInfo;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.compatibility.common.util.PollingCheck;
|
||||
|
||||
@@ -69,6 +68,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -115,7 +115,7 @@ public class MediaRouter2ManagerTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
||||
mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.MEDIA_CONTENT_CONTROL,
|
||||
Manifest.permission.MODIFY_AUDIO_ROUTING);
|
||||
@@ -170,51 +170,95 @@ public class MediaRouter2ManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRoutesRemovedAndAdded() throws Exception {
|
||||
RouteCallback routeCallback = new RouteCallback() {};
|
||||
mRouteCallbacks.add(routeCallback);
|
||||
mRouter2.registerRouteCallback(mExecutor, routeCallback,
|
||||
new RouteDiscoveryPreference.Builder(FEATURES_ALL, true).build());
|
||||
public void testOnRoutesUpdated() throws Exception {
|
||||
final String routeId0 = "routeId0";
|
||||
final String routeName0 = "routeName0";
|
||||
final String routeId1 = "routeId1";
|
||||
final String routeName1 = "routeName1";
|
||||
final List<String> features = Collections.singletonList("customFeature");
|
||||
|
||||
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
|
||||
final int newConnectionState = MediaRoute2Info.CONNECTION_STATE_CONNECTED;
|
||||
|
||||
final List<MediaRoute2Info> routes = new ArrayList<>();
|
||||
routes.add(new MediaRoute2Info.Builder(routeId0, routeName0).addFeatures(features).build());
|
||||
routes.add(new MediaRoute2Info.Builder(routeId1, routeName1).addFeatures(features).build());
|
||||
|
||||
CountDownLatch removedLatch = new CountDownLatch(1);
|
||||
CountDownLatch addedLatch = new CountDownLatch(1);
|
||||
CountDownLatch changedLatch = new CountDownLatch(1);
|
||||
CountDownLatch removedLatch = new CountDownLatch(1);
|
||||
|
||||
addManagerCallback(new MediaRouter2Manager.Callback() {
|
||||
@Override
|
||||
public void onRoutesRemoved(List<MediaRoute2Info> routes) {
|
||||
assertTrue(routes.size() > 0);
|
||||
for (MediaRoute2Info route : routes) {
|
||||
if (route.getOriginalId().equals(ROUTE_ID2)
|
||||
&& route.getName().equals(ROUTE_NAME2)) {
|
||||
removedLatch.countDown();
|
||||
addManagerCallback(
|
||||
new MediaRouter2Manager.Callback() {
|
||||
@Override
|
||||
public void onRoutesUpdated() {
|
||||
if (addedLatch.getCount() == 1
|
||||
&& checkRoutesMatch(mManager.getAllRoutes(), routes)) {
|
||||
addedLatch.countDown();
|
||||
} else if (changedLatch.getCount() == 1
|
||||
&& checkRoutesMatch(
|
||||
mManager.getAllRoutes(), routes.subList(1, 2))) {
|
||||
changedLatch.countDown();
|
||||
} else if (removedLatch.getCount() == 1
|
||||
&& checkRoutesRemoved(mManager.getAllRoutes(), routes)) {
|
||||
removedLatch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mService.addRoutes(routes);
|
||||
assertTrue(
|
||||
"Added routes not found or onRoutesUpdated() never called.",
|
||||
addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||
|
||||
MediaRoute2Info newRoute2 =
|
||||
new MediaRoute2Info.Builder(routes.get(1))
|
||||
.setConnectionState(newConnectionState)
|
||||
.build();
|
||||
routes.set(1, newRoute2);
|
||||
mService.addRoute(routes.get(1));
|
||||
assertTrue(
|
||||
"Modified route not found or onRoutesUpdated() never called.",
|
||||
changedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||
|
||||
List<String> routeIds = new ArrayList<>();
|
||||
routeIds.add(routeId0);
|
||||
routeIds.add(routeId1);
|
||||
|
||||
mService.removeRoutes(routeIds);
|
||||
assertTrue(
|
||||
"Removed routes not found or onRoutesUpdated() never called.",
|
||||
removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
private static boolean checkRoutesMatch(
|
||||
List<MediaRoute2Info> routesReceived, List<MediaRoute2Info> expectedRoutes) {
|
||||
for (MediaRoute2Info expectedRoute : expectedRoutes) {
|
||||
MediaRoute2Info matchingRoute =
|
||||
routesReceived.stream()
|
||||
.filter(r -> r.getOriginalId().equals(expectedRoute.getOriginalId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (matchingRoute == null) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void onRoutesAdded(List<MediaRoute2Info> routes) {
|
||||
assertTrue(routes.size() > 0);
|
||||
if (removedLatch.getCount() > 0) {
|
||||
return;
|
||||
}
|
||||
for (MediaRoute2Info route : routes) {
|
||||
if (route.getOriginalId().equals(ROUTE_ID2)
|
||||
&& route.getName().equals(ROUTE_NAME2)) {
|
||||
addedLatch.countDown();
|
||||
}
|
||||
}
|
||||
assertTrue(TextUtils.equals(expectedRoute.getName(), matchingRoute.getName()));
|
||||
assertEquals(expectedRoute.getFeatures(), matchingRoute.getFeatures());
|
||||
assertEquals(expectedRoute.getConnectionState(), matchingRoute.getConnectionState());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkRoutesRemoved(
|
||||
List<MediaRoute2Info> routesReceived, List<MediaRoute2Info> routesRemoved) {
|
||||
for (MediaRoute2Info removedRoute : routesRemoved) {
|
||||
if (routesReceived.stream()
|
||||
.anyMatch(r -> r.getOriginalId().equals(removedRoute.getOriginalId()))) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
MediaRoute2Info routeToRemove = routes.get(ROUTE_ID2);
|
||||
assertNotNull(routeToRemove);
|
||||
|
||||
mService.removeRoute(ROUTE_ID2);
|
||||
assertTrue(removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||
|
||||
mService.addRoute(routeToRemove);
|
||||
assertTrue(addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -874,28 +918,31 @@ public class MediaRouter2ManagerTest {
|
||||
|
||||
// A dummy callback is required to send route feature info.
|
||||
RouteCallback routeCallback = new RouteCallback() {};
|
||||
MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
|
||||
@Override
|
||||
public void onRoutesAdded(List<MediaRoute2Info> routes) {
|
||||
for (MediaRoute2Info route : routes) {
|
||||
if (!route.isSystemRoute()
|
||||
&& hasMatchingFeature(route.getFeatures(), preference
|
||||
.getPreferredFeatures())) {
|
||||
addedLatch.countDown();
|
||||
break;
|
||||
MediaRouter2Manager.Callback managerCallback =
|
||||
new MediaRouter2Manager.Callback() {
|
||||
@Override
|
||||
public void onRoutesUpdated() {
|
||||
List<MediaRoute2Info> routes = mManager.getAllRoutes();
|
||||
for (MediaRoute2Info route : routes) {
|
||||
if (!route.isSystemRoute()
|
||||
&& hasMatchingFeature(
|
||||
route.getFeatures(),
|
||||
preference.getPreferredFeatures())) {
|
||||
addedLatch.countDown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDiscoveryPreferenceChanged(String packageName,
|
||||
RouteDiscoveryPreference discoveryPreference) {
|
||||
if (TextUtils.equals(mPackageName, packageName)
|
||||
&& Objects.equals(preference, discoveryPreference)) {
|
||||
preferenceLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void onDiscoveryPreferenceChanged(
|
||||
String packageName, RouteDiscoveryPreference discoveryPreference) {
|
||||
if (TextUtils.equals(mPackageName, packageName)
|
||||
&& Objects.equals(preference, discoveryPreference)) {
|
||||
preferenceLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
mManager.registerCallback(mExecutor, managerCallback);
|
||||
mRouter2.registerRouteCallback(mExecutor, routeCallback, preference);
|
||||
|
||||
@@ -923,15 +970,17 @@ public class MediaRouter2ManagerTest {
|
||||
void awaitOnRouteChangedManager(Runnable task, String routeId,
|
||||
Predicate<MediaRoute2Info> predicate) throws Exception {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
|
||||
@Override
|
||||
public void onRoutesChanged(List<MediaRoute2Info> changed) {
|
||||
MediaRoute2Info route = createRouteMap(changed).get(routeId);
|
||||
if (route != null && predicate.test(route)) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
MediaRouter2Manager.Callback callback =
|
||||
new MediaRouter2Manager.Callback() {
|
||||
@Override
|
||||
public void onRoutesUpdated() {
|
||||
MediaRoute2Info route =
|
||||
createRouteMap(mManager.getAllRoutes()).get(routeId);
|
||||
if (route != null && predicate.test(route)) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
mManager.registerCallback(mExecutor, callback);
|
||||
try {
|
||||
task.run();
|
||||
|
||||
@@ -30,7 +30,9 @@ import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -146,19 +148,44 @@ public class StubMediaRoute2ProviderService extends MediaRoute2ProviderService {
|
||||
* they have the same route id.
|
||||
*/
|
||||
public void addRoute(@NonNull MediaRoute2Info route) {
|
||||
Objects.requireNonNull(route, "route must not be null");
|
||||
mRoutes.put(route.getOriginalId(), route);
|
||||
publishRoutes();
|
||||
addRoutes(Collections.singletonList(route));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a route and publishes it.
|
||||
* Adds a list of routes and publishes it. It will replace existing routes with matching ids.
|
||||
*
|
||||
* @param routes list of routes to be added.
|
||||
*/
|
||||
public void addRoutes(@NonNull List<MediaRoute2Info> routes) {
|
||||
Objects.requireNonNull(routes, "Routes must not be null.");
|
||||
for (MediaRoute2Info route : routes) {
|
||||
Objects.requireNonNull(route, "Route must not be null");
|
||||
mRoutes.put(route.getOriginalId(), route);
|
||||
}
|
||||
publishRoutes();
|
||||
}
|
||||
|
||||
/** Removes a route and publishes it. */
|
||||
public void removeRoute(@NonNull String routeId) {
|
||||
Objects.requireNonNull(routeId, "routeId must not be null");
|
||||
MediaRoute2Info route = mRoutes.get(routeId);
|
||||
if (route != null) {
|
||||
mRoutes.remove(routeId);
|
||||
removeRoutes(Collections.singletonList(routeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a list of routes and publishes the changes.
|
||||
*
|
||||
* @param routes list of route ids to be removed.
|
||||
*/
|
||||
public void removeRoutes(@NonNull List<String> routes) {
|
||||
Objects.requireNonNull(routes, "Routes must not be null");
|
||||
boolean hasRemovedRoutes = false;
|
||||
for (String routeId : routes) {
|
||||
MediaRoute2Info route = mRoutes.get(routeId);
|
||||
if (route != null) {
|
||||
mRoutes.remove(routeId);
|
||||
hasRemovedRoutes = true;
|
||||
}
|
||||
}
|
||||
if (hasRemovedRoutes) {
|
||||
publishRoutes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +528,7 @@ public class InfoMediaManager extends MediaManager {
|
||||
class RouterManagerCallback implements MediaRouter2Manager.Callback {
|
||||
|
||||
@Override
|
||||
public void onRoutesAdded(List<MediaRoute2Info> routes) {
|
||||
public void onRoutesUpdated() {
|
||||
refreshDevices();
|
||||
}
|
||||
|
||||
@@ -539,16 +539,6 @@ public class InfoMediaManager extends MediaManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRoutesChanged(List<MediaRoute2Info> routes) {
|
||||
refreshDevices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRoutesRemoved(List<MediaRoute2Info> routes) {
|
||||
refreshDevices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransferred(RoutingSessionInfo oldSession, RoutingSessionInfo newSession) {
|
||||
if (DEBUG) {
|
||||
|
||||
@@ -112,7 +112,7 @@ public class InfoMediaManagerTest {
|
||||
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
|
||||
assertThat(mediaDevice).isNull();
|
||||
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesAdded(routes);
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
|
||||
|
||||
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
|
||||
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
|
||||
@@ -135,7 +135,7 @@ public class InfoMediaManagerTest {
|
||||
assertThat(mediaDevice).isNull();
|
||||
|
||||
mInfoMediaManager.mPackageName = "";
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesAdded(routes);
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
|
||||
|
||||
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
|
||||
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
|
||||
@@ -199,7 +199,7 @@ public class InfoMediaManagerTest {
|
||||
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
|
||||
assertThat(mediaDevice).isNull();
|
||||
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesChanged(routes);
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
|
||||
|
||||
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
|
||||
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
|
||||
@@ -222,7 +222,7 @@ public class InfoMediaManagerTest {
|
||||
assertThat(mediaDevice).isNull();
|
||||
|
||||
mInfoMediaManager.mPackageName = "";
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesChanged(routes);
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
|
||||
|
||||
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
|
||||
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
|
||||
@@ -263,7 +263,7 @@ public class InfoMediaManagerTest {
|
||||
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
|
||||
assertThat(mediaDevice).isNull();
|
||||
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesRemoved(routes);
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
|
||||
|
||||
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
|
||||
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
|
||||
@@ -286,7 +286,7 @@ public class InfoMediaManagerTest {
|
||||
assertThat(mediaDevice).isNull();
|
||||
|
||||
mInfoMediaManager.mPackageName = "";
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesRemoved(routes);
|
||||
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
|
||||
|
||||
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
|
||||
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
|
||||
|
||||
@@ -927,8 +927,9 @@ class MediaRouter2ServiceImpl {
|
||||
routerRecord.mUserRecord.mHandler, routerRecord, manager));
|
||||
}
|
||||
|
||||
userRecord.mHandler.sendMessage(obtainMessage(UserHandler::notifyRoutesToManager,
|
||||
userRecord.mHandler, manager));
|
||||
userRecord.mHandler.sendMessage(
|
||||
obtainMessage(
|
||||
UserHandler::notifyInitialRoutesToManager, userRecord.mHandler, manager));
|
||||
}
|
||||
|
||||
private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) {
|
||||
@@ -1311,6 +1312,36 @@ class MediaRouter2ServiceImpl {
|
||||
new CopyOnWriteArrayList<>();
|
||||
private final Map<String, RouterRecord> mSessionToRouterMap = new ArrayMap<>();
|
||||
|
||||
/**
|
||||
* Latest list of routes sent to privileged {@link android.media.MediaRouter2 routers} and
|
||||
* {@link android.media.MediaRouter2Manager managers}.
|
||||
*
|
||||
* <p>Privileged routers are instances of {@link android.media.MediaRouter2 MediaRouter2}
|
||||
* that have {@code MODIFY_AUDIO_ROUTING} permission.
|
||||
*
|
||||
* <p>This list contains all routes exposed by route providers. This includes routes from
|
||||
* both system route providers and user route providers.
|
||||
*
|
||||
* <p>See {@link #getRouters(boolean hasModifyAudioRoutingPermission)}.
|
||||
*/
|
||||
private final Map<String, MediaRoute2Info> mLastNotifiedRoutesToPrivilegedRouters =
|
||||
new ArrayMap<>();
|
||||
|
||||
/**
|
||||
* Latest list of routes sent to non-privileged {@link android.media.MediaRouter2 routers}.
|
||||
*
|
||||
* <p>Non-privileged routers are instances of {@link android.media.MediaRouter2
|
||||
* MediaRouter2} that do <i><b>not</b></i> have {@code MODIFY_AUDIO_ROUTING} permission.
|
||||
*
|
||||
* <p>This list contains all routes exposed by user route providers. It might also include
|
||||
* the current default route from {@link #mSystemProvider} to expose local route updates
|
||||
* (e.g. volume changes) to non-privileged routers.
|
||||
*
|
||||
* <p>See {@link SystemMediaRoute2Provider#mDefaultRoute}.
|
||||
*/
|
||||
private final Map<String, MediaRoute2Info> mLastNotifiedRoutesToNonPrivilegedRouters =
|
||||
new ArrayMap<>();
|
||||
|
||||
private boolean mRunning;
|
||||
|
||||
// TODO: (In Android S+) Pull out SystemMediaRoute2Provider out of UserHandler.
|
||||
@@ -1425,91 +1456,182 @@ class MediaRouter2ServiceImpl {
|
||||
}
|
||||
|
||||
private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
|
||||
int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
|
||||
MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
|
||||
MediaRoute2ProviderInfo prevInfo =
|
||||
(providerInfoIndex < 0) ? null : mLastProviderInfos.get(providerInfoIndex);
|
||||
if (Objects.equals(prevInfo, currentInfo)) return;
|
||||
|
||||
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
|
||||
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
|
||||
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
|
||||
int providerInfoIndex =
|
||||
indexOfRouteProviderInfoByUniqueId(provider.getUniqueId(), mLastProviderInfos);
|
||||
|
||||
MediaRoute2ProviderInfo prevInfo =
|
||||
providerInfoIndex == -1 ? null : mLastProviderInfos.get(providerInfoIndex);
|
||||
|
||||
// Ignore if no changes
|
||||
if (Objects.equals(prevInfo, currentInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasAddedOrModifiedRoutes = false;
|
||||
boolean hasRemovedRoutes = false;
|
||||
|
||||
boolean isSystemProvider = provider.mIsSystemRouteProvider;
|
||||
|
||||
if (prevInfo == null) {
|
||||
// Provider is being added.
|
||||
mLastProviderInfos.add(currentInfo);
|
||||
addedRoutes.addAll(currentInfo.getRoutes());
|
||||
addToRoutesMap(currentInfo.getRoutes(), isSystemProvider);
|
||||
// Check if new provider exposes routes.
|
||||
hasAddedOrModifiedRoutes = !currentInfo.getRoutes().isEmpty();
|
||||
} else if (currentInfo == null) {
|
||||
// Provider is being removed.
|
||||
hasRemovedRoutes = true;
|
||||
mLastProviderInfos.remove(prevInfo);
|
||||
removedRoutes.addAll(prevInfo.getRoutes());
|
||||
removeFromRoutesMap(prevInfo.getRoutes(), isSystemProvider);
|
||||
} else {
|
||||
// Provider is being updated.
|
||||
mLastProviderInfos.set(providerInfoIndex, currentInfo);
|
||||
final Collection<MediaRoute2Info> prevRoutes = prevInfo.getRoutes();
|
||||
final Collection<MediaRoute2Info> currentRoutes = currentInfo.getRoutes();
|
||||
|
||||
// Checking for individual routes.
|
||||
for (MediaRoute2Info route : currentRoutes) {
|
||||
if (!route.isValid()) {
|
||||
Slog.w(TAG, "onProviderStateChangedOnHandler: Ignoring invalid route : "
|
||||
+ route);
|
||||
Slog.w(
|
||||
TAG,
|
||||
"onProviderStateChangedOnHandler: Ignoring invalid route : "
|
||||
+ route);
|
||||
continue;
|
||||
}
|
||||
|
||||
MediaRoute2Info prevRoute = prevInfo.getRoute(route.getOriginalId());
|
||||
if (prevRoute == null) {
|
||||
addedRoutes.add(route);
|
||||
} else if (!Objects.equals(prevRoute, route)) {
|
||||
changedRoutes.add(route);
|
||||
if (prevRoute == null || !Objects.equals(prevRoute, route)) {
|
||||
hasAddedOrModifiedRoutes = true;
|
||||
mLastNotifiedRoutesToPrivilegedRouters.put(route.getId(), route);
|
||||
if (!isSystemProvider) {
|
||||
mLastNotifiedRoutesToNonPrivilegedRouters.put(route.getId(), route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking for individual removals
|
||||
for (MediaRoute2Info prevRoute : prevInfo.getRoutes()) {
|
||||
if (currentInfo.getRoute(prevRoute.getOriginalId()) == null) {
|
||||
removedRoutes.add(prevRoute);
|
||||
hasRemovedRoutes = true;
|
||||
mLastNotifiedRoutesToPrivilegedRouters.remove(prevRoute.getId());
|
||||
if (!isSystemProvider) {
|
||||
mLastNotifiedRoutesToNonPrivilegedRouters.remove(prevRoute.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatchUpdates(
|
||||
hasAddedOrModifiedRoutes,
|
||||
hasRemovedRoutes,
|
||||
isSystemProvider,
|
||||
mSystemProvider.getDefaultRoute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds provided routes to {@link #mLastNotifiedRoutesToPrivilegedRouters}. Also adds them
|
||||
* to {@link #mLastNotifiedRoutesToNonPrivilegedRouters} if they were provided by a
|
||||
* non-system route provider. Overwrites any route with matching id that already exists.
|
||||
*
|
||||
* @param routes list of routes to be added.
|
||||
* @param isSystemRoutes indicates whether routes come from a system route provider.
|
||||
*/
|
||||
private void addToRoutesMap(
|
||||
@NonNull Collection<MediaRoute2Info> routes, boolean isSystemRoutes) {
|
||||
for (MediaRoute2Info route : routes) {
|
||||
if (!isSystemRoutes) {
|
||||
mLastNotifiedRoutesToNonPrivilegedRouters.put(route.getId(), route);
|
||||
}
|
||||
mLastNotifiedRoutesToPrivilegedRouters.put(route.getId(), route);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes provided routes from {@link #mLastNotifiedRoutesToPrivilegedRouters}. Also
|
||||
* removes them from {@link #mLastNotifiedRoutesToNonPrivilegedRouters} if they were
|
||||
* provided by a non-system route provider.
|
||||
*
|
||||
* @param routes list of routes to be removed.
|
||||
* @param isSystemRoutes whether routes come from a system route provider.
|
||||
*/
|
||||
private void removeFromRoutesMap(
|
||||
@NonNull Collection<MediaRoute2Info> routes, boolean isSystemRoutes) {
|
||||
for (MediaRoute2Info route : routes) {
|
||||
if (!isSystemRoutes) {
|
||||
mLastNotifiedRoutesToNonPrivilegedRouters.remove(route.getId());
|
||||
}
|
||||
mLastNotifiedRoutesToPrivilegedRouters.remove(route.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the latest route updates in {@link #mLastNotifiedRoutesToPrivilegedRouters}
|
||||
* and {@link #mLastNotifiedRoutesToNonPrivilegedRouters} to registered {@link
|
||||
* android.media.MediaRouter2 routers} and {@link MediaRouter2Manager managers} after a call
|
||||
* to {@link #onProviderStateChangedOnHandler(MediaRoute2Provider)}. Ignores if no changes
|
||||
* were made.
|
||||
*
|
||||
* @param hasAddedOrModifiedRoutes whether routes were added or modified.
|
||||
* @param hasRemovedRoutes whether routes were removed.
|
||||
* @param isSystemProvider whether the latest update was caused by a system provider.
|
||||
* @param defaultRoute the current default route in {@link #mSystemProvider}.
|
||||
*/
|
||||
private void dispatchUpdates(
|
||||
boolean hasAddedOrModifiedRoutes,
|
||||
boolean hasRemovedRoutes,
|
||||
boolean isSystemProvider,
|
||||
MediaRoute2Info defaultRoute) {
|
||||
|
||||
// Ignore if no changes.
|
||||
if (!hasAddedOrModifiedRoutes && !hasRemovedRoutes) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true);
|
||||
List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false);
|
||||
List<IMediaRouter2Manager> managers = getManagers();
|
||||
List<MediaRoute2Info> defaultRoute = new ArrayList<>();
|
||||
defaultRoute.add(mSystemProvider.getDefaultRoute());
|
||||
|
||||
if (addedRoutes.size() > 0) {
|
||||
notifyRoutesAddedToRouters(routersWithModifyAudioRoutingPermission, addedRoutes);
|
||||
if (!provider.mIsSystemRouteProvider) {
|
||||
notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
|
||||
addedRoutes);
|
||||
} else if (prevInfo == null) {
|
||||
notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission,
|
||||
defaultRoute);
|
||||
} // 'else' is handled as changed routes
|
||||
notifyRoutesAddedToManagers(managers, addedRoutes);
|
||||
}
|
||||
if (removedRoutes.size() > 0) {
|
||||
notifyRoutesRemovedToRouters(routersWithModifyAudioRoutingPermission,
|
||||
removedRoutes);
|
||||
if (!provider.mIsSystemRouteProvider) {
|
||||
notifyRoutesRemovedToRouters(routersWithoutModifyAudioRoutingPermission,
|
||||
removedRoutes);
|
||||
}
|
||||
notifyRoutesRemovedToManagers(managers, removedRoutes);
|
||||
}
|
||||
if (changedRoutes.size() > 0) {
|
||||
notifyRoutesChangedToRouters(routersWithModifyAudioRoutingPermission,
|
||||
changedRoutes);
|
||||
if (!provider.mIsSystemRouteProvider) {
|
||||
notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
|
||||
changedRoutes);
|
||||
} else if (prevInfo != null) {
|
||||
notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission,
|
||||
defaultRoute);
|
||||
} // 'else' is handled as added routes
|
||||
notifyRoutesChangedToManagers(managers, changedRoutes);
|
||||
// Managers receive all provider updates with all routes.
|
||||
notifyRoutesUpdatedToManagers(
|
||||
managers, new ArrayList<>(mLastNotifiedRoutesToPrivilegedRouters.values()));
|
||||
|
||||
// Routers with modify audio permission (usually system routers) receive all provider
|
||||
// updates with all routes.
|
||||
notifyRoutesUpdatedToRouters(
|
||||
routersWithModifyAudioRoutingPermission,
|
||||
new ArrayList<>(mLastNotifiedRoutesToPrivilegedRouters.values()));
|
||||
|
||||
if (!isSystemProvider) {
|
||||
// Regular routers receive updates from all non-system providers with all non-system
|
||||
// routes.
|
||||
notifyRoutesUpdatedToRouters(
|
||||
routersWithoutModifyAudioRoutingPermission,
|
||||
new ArrayList<>(mLastNotifiedRoutesToNonPrivilegedRouters.values()));
|
||||
} else if (hasAddedOrModifiedRoutes) {
|
||||
// On system provider updates, regular routers receive the updated default route.
|
||||
// This is the only system route they should receive.
|
||||
mLastNotifiedRoutesToNonPrivilegedRouters.put(defaultRoute.getId(), defaultRoute);
|
||||
notifyRoutesUpdatedToRouters(
|
||||
routersWithoutModifyAudioRoutingPermission,
|
||||
new ArrayList<>(mLastNotifiedRoutesToNonPrivilegedRouters.values()));
|
||||
}
|
||||
}
|
||||
|
||||
private int getLastProviderInfoIndex(@NonNull String providerId) {
|
||||
for (int i = 0; i < mLastProviderInfos.size(); i++) {
|
||||
MediaRoute2ProviderInfo providerInfo = mLastProviderInfos.get(i);
|
||||
if (TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
|
||||
/**
|
||||
* Returns the index of the first element in {@code lastProviderInfos} that matches the
|
||||
* specified unique id.
|
||||
*
|
||||
* @param uniqueId unique id of {@link MediaRoute2ProviderInfo} to be found.
|
||||
* @param lastProviderInfos list of {@link MediaRoute2ProviderInfo}.
|
||||
* @return index of found element, or -1 if not found.
|
||||
*/
|
||||
private static int indexOfRouteProviderInfoByUniqueId(
|
||||
@NonNull String uniqueId,
|
||||
@NonNull List<MediaRoute2ProviderInfo> lastProviderInfos) {
|
||||
for (int i = 0; i < lastProviderInfos.size(); i++) {
|
||||
MediaRoute2ProviderInfo providerInfo = lastProviderInfos.get(i);
|
||||
if (TextUtils.equals(providerInfo.getUniqueId(), uniqueId)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -1989,41 +2111,19 @@ class MediaRouter2ServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesAddedToRouters(@NonNull List<IMediaRouter2> routers,
|
||||
@NonNull List<MediaRoute2Info> routes) {
|
||||
private void notifyRoutesUpdatedToRouters(
|
||||
@NonNull List<IMediaRouter2> routers, @NonNull List<MediaRoute2Info> routes) {
|
||||
for (IMediaRouter2 router : routers) {
|
||||
try {
|
||||
router.notifyRoutesAdded(routes);
|
||||
router.notifyRoutesUpdated(routes);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify routes added. Router probably died.", ex);
|
||||
Slog.w(TAG, "Failed to notify routes updated. Router probably died.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesRemovedToRouters(@NonNull List<IMediaRouter2> routers,
|
||||
@NonNull List<MediaRoute2Info> routes) {
|
||||
for (IMediaRouter2 router : routers) {
|
||||
try {
|
||||
router.notifyRoutesRemoved(routes);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify routes removed. Router probably died.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesChangedToRouters(@NonNull List<IMediaRouter2> routers,
|
||||
@NonNull List<MediaRoute2Info> routes) {
|
||||
for (IMediaRouter2 router : routers) {
|
||||
try {
|
||||
router.notifyRoutesChanged(routes);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify routes changed. Router probably died.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifySessionInfoChangedToRouters(@NonNull List<IMediaRouter2> routers,
|
||||
@NonNull RoutingSessionInfo sessionInfo) {
|
||||
private void notifySessionInfoChangedToRouters(
|
||||
@NonNull List<IMediaRouter2> routers, @NonNull RoutingSessionInfo sessionInfo) {
|
||||
for (IMediaRouter2 router : routers) {
|
||||
try {
|
||||
router.notifySessionInfoChanged(sessionInfo);
|
||||
@@ -2033,48 +2133,31 @@ class MediaRouter2ServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesToManager(@NonNull IMediaRouter2Manager manager) {
|
||||
List<MediaRoute2Info> routes = new ArrayList<>();
|
||||
for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
|
||||
routes.addAll(providerInfo.getRoutes());
|
||||
}
|
||||
if (routes.size() == 0) {
|
||||
/**
|
||||
* Notifies {@code manager} with all known routes. This only happens once after {@code
|
||||
* manager} is registered through {@link #registerManager(IMediaRouter2Manager, String)
|
||||
* registerManager()}.
|
||||
*
|
||||
* @param manager {@link IMediaRouter2Manager} to be notified.
|
||||
*/
|
||||
private void notifyInitialRoutesToManager(@NonNull IMediaRouter2Manager manager) {
|
||||
if (mLastNotifiedRoutesToPrivilegedRouters.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
manager.notifyRoutesAdded(routes);
|
||||
manager.notifyRoutesUpdated(
|
||||
new ArrayList<>(mLastNotifiedRoutesToPrivilegedRouters.values()));
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify all routes. Manager probably died.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesAddedToManagers(@NonNull List<IMediaRouter2Manager> managers,
|
||||
private void notifyRoutesUpdatedToManagers(
|
||||
@NonNull List<IMediaRouter2Manager> managers,
|
||||
@NonNull List<MediaRoute2Info> routes) {
|
||||
for (IMediaRouter2Manager manager : managers) {
|
||||
try {
|
||||
manager.notifyRoutesAdded(routes);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify routes added. Manager probably died.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesRemovedToManagers(@NonNull List<IMediaRouter2Manager> managers,
|
||||
@NonNull List<MediaRoute2Info> routes) {
|
||||
for (IMediaRouter2Manager manager : managers) {
|
||||
try {
|
||||
manager.notifyRoutesRemoved(routes);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify routes removed. Manager probably died.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyRoutesChangedToManagers(@NonNull List<IMediaRouter2Manager> managers,
|
||||
@NonNull List<MediaRoute2Info> routes) {
|
||||
for (IMediaRouter2Manager manager : managers) {
|
||||
try {
|
||||
manager.notifyRoutesChanged(routes);
|
||||
manager.notifyRoutesUpdated(routes);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify routes changed. Manager probably died.", ex);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user