Merge "MediaRouter2: Revise MediaRouter2.Callback.onRoute**"

This commit is contained in:
Kyunglyul Hyun
2019-11-04 02:43:10 +00:00
committed by Android (Google) Code Review
7 changed files with 334 additions and 154 deletions

View File

@@ -16,12 +16,14 @@
package android.media;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2Info;
/**
* @hide
*/
oneway interface IMediaRouter2Client {
void notifyRestoreRoute();
void notifyProviderInfosUpdated(in List<MediaRoute2ProviderInfo> providers);
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
}

View File

@@ -314,7 +314,7 @@ public final class MediaRoute2Info implements Parcelable {
List<String> mSupportedCategories;
int mVolume;
int mVolumeMax;
int mVolumeHandling;
int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
Bundle mExtras;
public Builder(@NonNull String id, @NonNull String name) {

View File

@@ -33,7 +33,9 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
@@ -51,23 +53,23 @@ public class MediaRouter2 {
@GuardedBy("sLock")
private static MediaRouter2 sInstance;
private Context mContext;
private final Context mContext;
private final IMediaRouterService mMediaRouterService;
private final CopyOnWriteArrayList<CallbackRecord> mCallbackRecords =
new CopyOnWriteArrayList<>();
@GuardedBy("sLock")
private List<String> mControlCategories = Collections.emptyList();
private final String mPackageName;
private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
private volatile List<String> mControlCategories = Collections.emptyList();
private MediaRoute2Info mSelectedRoute;
@GuardedBy("sLock")
private Client mClient;
private final String mPackageName;
final Handler mHandler;
List<MediaRoute2ProviderInfo> mProviders = Collections.emptyList();
volatile List<MediaRoute2Info> mRoutes = Collections.emptyList();
MediaRoute2Info mSelectedRoute;
volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
/**
* Gets an instance of the media router associated with the context.
@@ -137,6 +139,7 @@ public class MediaRouter2 {
}
}
}
//TODO: Is it thread-safe?
record.notifyRoutes();
//TODO: Update discovery request here.
@@ -181,31 +184,22 @@ public class MediaRouter2 {
public void setControlCategories(@NonNull Collection<String> controlCategories) {
Objects.requireNonNull(controlCategories, "control categories must not be null");
Client client;
List<String> newControlCategories = new ArrayList<>(controlCategories);
synchronized (sLock) {
mControlCategories = newControlCategories;
client = mClient;
}
if (client != null) {
try {
mMediaRouterService.setControlCategories2(client, newControlCategories);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to set control categories.", ex);
}
}
mHandler.sendMessage(obtainMessage(MediaRouter2::refreshAndNotifyRoutes, this));
// To ensure invoking callbacks correctly according to control categories
mHandler.sendMessage(obtainMessage(MediaRouter2::setControlCategoriesOnHandler,
MediaRouter2.this, new ArrayList<>(controlCategories)));
}
/**
* Gets the list of {@link MediaRoute2Info routes} currently known to the media router.
* Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
* known to the media router.
*
* @return the list of routes that support at least one of the control categories set by
* the application
*/
@NonNull
public List<MediaRoute2Info> getRoutes() {
return mRoutes;
return mFilteredRoutes;
}
/**
@@ -326,102 +320,145 @@ public class MediaRouter2 {
return -1;
}
void onProviderInfosUpdated(List<MediaRoute2ProviderInfo> providers) {
if (providers == null) {
Log.w(TAG, "Providers info is null.");
return;
}
private void setControlCategoriesOnHandler(List<String> newControlCategories) {
List<String> prevControlCategories = mControlCategories;
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
mProviders = providers;
refreshAndNotifyRoutes();
}
void refreshAndNotifyRoutes() {
ArrayList<MediaRoute2Info> routes = new ArrayList<>();
List<String> controlCategories;
mControlCategories = newControlCategories;
Client client;
synchronized (sLock) {
controlCategories = mControlCategories;
client = mClient;
}
if (client != null) {
try {
mMediaRouterService.setControlCategories2(client, mControlCategories);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to set control categories.", ex);
}
}
for (MediaRoute2ProviderInfo provider : mProviders) {
updateProvider(provider, controlCategories, routes);
for (MediaRoute2Info route : mRoutes.values()) {
boolean preSupported = route.supportsControlCategory(prevControlCategories);
boolean postSupported = route.supportsControlCategory(newControlCategories);
if (postSupported) {
filteredRoutes.add(route);
}
if (preSupported == postSupported) {
continue;
}
if (preSupported) {
removedRoutes.add(route);
} else {
addedRoutes.add(route);
}
}
mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
//TODO: Can orders be changed?
if (!Objects.equals(mRoutes, routes)) {
mRoutes = Collections.unmodifiableList(routes);
notifyRouteListChanged(mRoutes);
if (removedRoutes.size() > 0) {
notifyRoutesRemoved(removedRoutes);
}
if (addedRoutes.size() > 0) {
notifyRoutesAdded(addedRoutes);
}
}
void updateProvider(MediaRoute2ProviderInfo provider, List<String> controlCategories,
List<MediaRoute2Info> outRoutes) {
if (provider == null || !provider.isValid()) {
Log.w(TAG, "Ignoring invalid provider : " + provider);
return;
}
final Collection<MediaRoute2Info> routes = provider.getRoutes();
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
for (MediaRoute2Info route : routes) {
if (!route.isValid()) {
Log.w(TAG, "Ignoring invalid route : " + route);
continue;
mRoutes.put(route.getUniqueId(), route);
if (route.supportsControlCategory(mControlCategories)) {
addedRoutes.add(route);
}
if (!route.supportsControlCategory(controlCategories)) {
continue;
}
MediaRoute2Info preRoute = findRouteById(route.getId());
if (!route.equals(preRoute)) {
notifyRouteChanged(route);
}
outRoutes.add(route);
}
if (addedRoutes.size() > 0) {
refreshFilteredRoutes();
notifyRoutesAdded(addedRoutes);
}
}
MediaRoute2Info findRouteById(String id) {
for (MediaRoute2Info route : mRoutes) {
if (route.getId().equals(id)) return route;
void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
for (MediaRoute2Info route : routes) {
mRoutes.remove(route.getUniqueId());
if (route.supportsControlCategory(mControlCategories)) {
removedRoutes.add(route);
}
}
if (removedRoutes.size() > 0) {
refreshFilteredRoutes();
notifyRoutesRemoved(removedRoutes);
}
return null;
}
void notifyRouteListChanged(List<MediaRoute2Info> routes) {
void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
for (MediaRoute2Info route : routes) {
mRoutes.put(route.getUniqueId(), route);
if (route.supportsControlCategory(mControlCategories)) {
changedRoutes.add(route);
}
}
if (changedRoutes.size() > 0) {
refreshFilteredRoutes();
notifyRoutesChanged(changedRoutes);
}
}
private void refreshFilteredRoutes() {
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
for (MediaRoute2Info route : mRoutes.values()) {
if (route.supportsControlCategory(mControlCategories)) {
filteredRoutes.add(route);
}
}
mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
}
private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
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));
}
}
void notifyRouteChanged(MediaRoute2Info route) {
for (CallbackRecord record: mCallbackRecords) {
record.mExecutor.execute(
() -> record.mCallback.onRouteChanged(route));
}
}
/**
* Interface for receiving events about media routing changes.
*/
public static class Callback {
//TODO: clean up these callbacks
/**
* Called when a route is added.
*/
public void onRouteAdded(MediaRoute2Info routeInfo) {}
/**
* Called when a route is changed.
* Called when routes are added.
* @param routes the list of routes that have been added. It's never empty.
*/
public void onRouteChanged(MediaRoute2Info routeInfo) {}
public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {}
/**
* Called when a route is removed.
* Called when routes are removed.
* @param routes the list of routes that have been removed. It's never empty.
*/
public void onRouteRemoved(MediaRoute2Info routeInfo) {}
public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}
/**
* Called when the list of routes is changed.
* Called when routes are changed.
* @param routes the list of routes that have been changed. It's never empty.
*/
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
}
@@ -436,11 +473,10 @@ public class MediaRouter2 {
}
void notifyRoutes() {
final List<MediaRoute2Info> routes = mRoutes;
final List<MediaRoute2Info> routes = mFilteredRoutes;
// notify only when bound to media router service.
//TODO: Correct the condition when control category, default route, .. are finalized.
if (routes.size() > 0) {
mExecutor.execute(() -> mCallback.onRoutesChanged(routes));
mExecutor.execute(() -> mCallback.onRoutesAdded(routes));
}
}
}
@@ -450,9 +486,21 @@ public class MediaRouter2 {
public void notifyRestoreRoute() throws RemoteException {}
@Override
public void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> info) {
mHandler.sendMessage(obtainMessage(MediaRouter2::onProviderInfosUpdated,
MediaRouter2.this, info));
public void notifyRoutesAdded(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));
}
}
}

View File

@@ -67,7 +67,7 @@ public class MediaRouter2Manager {
@NonNull
List<MediaRoute2Info> mRoutes = Collections.emptyList();
@NonNull
ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
/**
* Gets an instance of media router manager that controls media route of other applications.
@@ -427,6 +427,8 @@ public class MediaRouter2Manager {
* A client may refresh available routes for each application.
*/
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
//TODO: add onControlCategoriesChanged to notify available routes are changed
}
final class CallbackRecord {

View File

@@ -22,6 +22,7 @@ import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
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.Mockito.mock;
import static org.mockito.Mockito.timeout;
@@ -272,29 +273,28 @@ public class MediaRouterManagerTest {
@Test
public void testControlVolumeWithRouter() throws Exception {
MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_ALL);
mRouter2.registerCallback(mExecutor, mockCallback);
MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
int targetVolume = originalVolume + deltaVolume;
mRouter2.requestSetVolume(volRoute, targetVolume);
verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
.onRouteChanged(argThat(route ->
route.getId().equals(volRoute.getId())
&& route.getVolume() == targetVolume));
CountDownLatch latch1 = new CountDownLatch(1);
MediaRouter2.Callback callback1 =
createVolumeChangeCallback(ROUTE_ID_VARIABLE_VOLUME,
originalVolume + deltaVolume, latch1);
mRouter2.registerCallback(mExecutor, callback1);
mRouter2.requestUpdateVolume(volRoute, deltaVolume);
assertTrue(latch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
mRouter2.unregisterCallback(callback1);
mRouter2.requestUpdateVolume(volRoute, -deltaVolume);
verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
.onRouteChanged(argThat(route ->
route.getId().equals(volRoute.getId())
&& route.getVolume() == originalVolume));
mRouter2.unregisterCallback(mockCallback);
CountDownLatch latch2 = new CountDownLatch(1);
MediaRouter2.Callback callback2 =
createVolumeChangeCallback(ROUTE_ID_VARIABLE_VOLUME, originalVolume, latch2);
mRouter2.registerCallback(mExecutor, callback2);
mRouter2.requestSetVolume(volRoute, originalVolume);
assertTrue(latch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
mRouter2.unregisterCallback(callback1);
}
@Test
@@ -312,13 +312,13 @@ public class MediaRouterManagerTest {
int targetVolume = originalVolume + deltaVolume;
mManager.requestSetVolume(volRoute, targetVolume);
verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
verify(managerCallback, timeout(TIMEOUT_MS).atLeastOnce())
.onRouteChanged(argThat(route ->
route.getId().equals(volRoute.getId())
&& route.getVolume() == targetVolume));
mManager.requestUpdateVolume(volRoute, -deltaVolume);
verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
verify(managerCallback, timeout(TIMEOUT_MS).atLeastOnce())
.onRouteChanged(argThat(route ->
route.getId().equals(volRoute.getId())
&& route.getVolume() == originalVolume));
@@ -347,14 +347,14 @@ public class MediaRouterManagerTest {
CountDownLatch latch = new CountDownLatch(1);
MediaRouter2.Callback callback = new MediaRouter2.Callback() {
@Override
public void onRoutesChanged(List<MediaRoute2Info> routes) {
if (routes.size() > 0) latch.countDown();
public void onRoutesAdded(List<MediaRoute2Info> added) {
if (added.size() > 0) latch.countDown();
}
};
mRouter2.setControlCategories(controlCategories);
mRouter2.registerCallback(mExecutor, callback);
try {
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
return createRouteMap(mRouter2.getRoutes());
} finally {
mRouter2.unregisterCallback(callback);
@@ -370,14 +370,18 @@ public class MediaRouterManagerTest {
MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
@Override
public void onRoutesChanged(List<MediaRoute2Info> routes) {
if (routes.size() > 0) latch.countDown();
if (routes.size() > 0) {
latch.countDown();
}
}
};
mManager.registerCallback(mExecutor, managerCallback);
mRouter2.setControlCategories(controlCategories);
mRouter2.registerCallback(mExecutor, routerCallback);
try {
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
//TODO: currently this returns empty list occasionally.
//Maybe due to control category is not set yet
return createRouteMap(mManager.getAvailableRoutes(mPackageName));
} finally {
mRouter2.unregisterCallback(routerCallback);
@@ -385,6 +389,20 @@ public class MediaRouterManagerTest {
}
}
MediaRouter2.Callback createVolumeChangeCallback(String routeId,
int targetVolume, CountDownLatch latch) {
MediaRouter2.Callback callback = new MediaRouter2.Callback() {
@Override
public void onRoutesChanged(List<MediaRoute2Info> changed) {
MediaRoute2Info volRoute = createRouteMap(changed).get(routeId);
if (volRoute != null && volRoute.getVolume() == targetVolume) {
latch.countDown();
}
}
};
return callback;
}
// Helper for getting routes easily
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();

View File

@@ -119,6 +119,11 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
@NonNull
public String getUniqueId() {
return mUniqueId;
}
@Nullable
public MediaRoute2ProviderInfo getProviderInfo() {
return mProviderInfo;
@@ -294,7 +299,7 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
public interface Callback {
void onProviderStateChanged(MediaRoute2ProviderProxy provider);
void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider);
}
private final class Connection implements DeathRecipient {

View File

@@ -47,9 +47,12 @@ import com.android.internal.util.function.pooled.PooledLambda;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* TODO: Merge this to MediaRouterService once it's finished.
@@ -357,8 +360,7 @@ class MediaRouter2ServiceImpl {
mAllClientRecords.put(binder, clientRecord);
userRecord.mHandler.sendMessage(
obtainMessage(UserHandler::notifyProviderInfosUpdatedToClient,
userRecord.mHandler, client));
obtainMessage(UserHandler::notifyRoutesToClient, userRecord.mHandler, client));
}
}
@@ -586,6 +588,7 @@ class MediaRouter2ServiceImpl {
final class UserRecord {
public final int mUserId;
//TODO: make records private for thread-safety
final ArrayList<ClientRecord> mClientRecords = new ArrayList<>();
final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
final UserHandler mHandler;
@@ -705,7 +708,7 @@ class MediaRouter2ServiceImpl {
//TODO: Make this thread-safe.
private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders =
new ArrayList<>();
private List<MediaRoute2ProviderInfo> mProviderInfos;
private final List<MediaRoute2ProviderInfo> mProviderInfos = new ArrayList<>();
private boolean mRunning;
private boolean mProviderInfosUpdateScheduled;
@@ -745,14 +748,89 @@ class MediaRouter2ServiceImpl {
}
@Override
public void onProviderStateChanged(MediaRoute2ProviderProxy provider) {
updateProvider(provider);
public void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider) {
sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
}
private void updateProvider(MediaRoute2ProviderProxy provider) {
int providerIndex = getProviderInfoIndex(provider.getUniqueId());
MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
MediaRoute2ProviderInfo prevInfo =
(providerIndex < 0) ? null : mProviderInfos.get(providerIndex);
if (Objects.equals(prevInfo, providerInfo)) return;
if (prevInfo == null) {
mProviderInfos.add(providerInfo);
Collection<MediaRoute2Info> addedRoutes = providerInfo.getRoutes();
if (addedRoutes.size() > 0) {
sendMessage(PooledLambda.obtainMessage(UserHandler::notifyRoutesAddedToClients,
this, getClients(), new ArrayList<>(addedRoutes)));
}
} else if (providerInfo == null) {
mProviderInfos.remove(prevInfo);
Collection<MediaRoute2Info> removedRoutes = prevInfo.getRoutes();
if (removedRoutes.size() > 0) {
sendMessage(PooledLambda.obtainMessage(
UserHandler::notifyRoutesRemovedToClients,
this, getClients(), new ArrayList<>(removedRoutes)));
}
} else {
mProviderInfos.set(providerIndex, providerInfo);
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
List<MediaRoute2Info> removedRoutes = new ArrayList<>();
List<MediaRoute2Info> changedRoutes = new ArrayList<>();
final Collection<MediaRoute2Info> currentRoutes = providerInfo.getRoutes();
final Set<String> updatedRouteIds = new HashSet<>();
for (MediaRoute2Info route : currentRoutes) {
if (!route.isValid()) {
Slog.w(TAG, "Ignoring invalid route : " + route);
continue;
}
MediaRoute2Info prevRoute = prevInfo.getRoute(route.getId());
if (prevRoute != null) {
if (!Objects.equals(prevRoute, route)) {
changedRoutes.add(route);
}
updatedRouteIds.add(route.getId());
} else {
addedRoutes.add(route);
}
}
for (MediaRoute2Info prevRoute : prevInfo.getRoutes()) {
if (!updatedRouteIds.contains(prevRoute.getId())) {
removedRoutes.add(prevRoute);
}
}
List<IMediaRouter2Client> clients = getClients();
if (addedRoutes.size() > 0) {
notifyRoutesAddedToClients(clients, addedRoutes);
}
if (removedRoutes.size() > 0) {
notifyRoutesRemovedToClients(clients, removedRoutes);
}
if (changedRoutes.size() > 0) {
notifyRoutesChangedToClients(clients, changedRoutes);
}
}
scheduleUpdateProviderInfos();
}
private int getProviderInfoIndex(String providerId) {
for (int i = 0; i < mProviderInfos.size(); i++) {
MediaRoute2ProviderInfo providerInfo = mProviderInfos.get(i);
if (TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
return i;
}
}
return -1;
}
private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
if (route != null) {
MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
@@ -803,6 +881,7 @@ class MediaRouter2ServiceImpl {
}
}
//TODO: should be replaced into notifyRoutes...ToManagers
private void updateProviderInfos() {
mProviderInfosUpdateScheduled = false;
@@ -810,55 +889,83 @@ class MediaRouter2ServiceImpl {
if (service == null) {
return;
}
final List<MediaRoute2ProviderInfo> providers = new ArrayList<>();
for (MediaRoute2ProviderProxy mediaProvider : mMediaProviders) {
final MediaRoute2ProviderInfo providerInfo =
mediaProvider.getProviderInfo();
if (providerInfo == null || !providerInfo.isValid()) {
Slog.w(TAG, "Ignoring invalid provider info : " + providerInfo);
} else {
providers.add(providerInfo);
}
}
mProviderInfos = providers;
final List<IMediaRouter2Manager> managers = new ArrayList<>();
final List<IMediaRouter2Client> clients = new ArrayList<>();
synchronized (service.mLock) {
for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
managers.add(managerRecord.mManager);
}
}
for (IMediaRouter2Manager manager : managers) {
notifyProviderInfosUpdatedToManager(manager);
}
}
private List<IMediaRouter2Client> getClients() {
final List<IMediaRouter2Client> clients = new ArrayList<>();
MediaRouter2ServiceImpl service = mServiceRef.get();
if (service == null) {
return clients;
}
synchronized (service.mLock) {
for (ClientRecord clientRecord : mUserRecord.mClientRecords) {
if (clientRecord instanceof Client2Record) {
clients.add(((Client2Record) clientRecord).mClient);
}
}
}
for (IMediaRouter2Manager manager : managers) {
notifyProviderInfosUpdatedToManager(manager);
}
for (IMediaRouter2Client client : clients) {
notifyProviderInfosUpdatedToClient(client);
}
return clients;
}
private void notifyProviderInfosUpdatedToClient(IMediaRouter2Client client) {
if (mProviderInfos == null) {
scheduleUpdateProviderInfos();
private void notifyRoutesToClient(IMediaRouter2Client client) {
List<MediaRoute2Info> routes = new ArrayList<>();
for (MediaRoute2ProviderInfo providerInfo : mProviderInfos) {
routes.addAll(providerInfo.getRoutes());
}
if (routes.size() == 0) {
return;
}
try {
client.notifyProviderInfosUpdated(mProviderInfos);
client.notifyRoutesAdded(routes);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify provider infos updated. Client probably died.");
Slog.w(TAG, "Failed to notify all routes. Client probably died.", ex);
}
}
private void notifyRoutesAddedToClients(List<IMediaRouter2Client> clients,
List<MediaRoute2Info> routes) {
for (IMediaRouter2Client client : clients) {
try {
client.notifyRoutesAdded(routes);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify routes added. Client probably died.", ex);
}
}
}
private void notifyRoutesRemovedToClients(List<IMediaRouter2Client> clients,
List<MediaRoute2Info> routes) {
for (IMediaRouter2Client client : clients) {
try {
client.notifyRoutesRemoved(routes);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify routes removed. Client probably died.", ex);
}
}
}
private void notifyRoutesChangedToClients(List<IMediaRouter2Client> clients,
List<MediaRoute2Info> routes) {
for (IMediaRouter2Client client : clients) {
try {
client.notifyRoutesChanged(routes);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify routes changed. Client probably died.", ex);
}
}
}
private void notifyProviderInfosUpdatedToManager(IMediaRouter2Manager manager) {
if (mProviderInfos == null) {
scheduleUpdateProviderInfos();
return;
}
try {
manager.notifyProviderInfosUpdated(mProviderInfos);
} catch (RemoteException ex) {
@@ -891,9 +998,7 @@ class MediaRouter2ServiceImpl {
private MediaRoute2ProviderProxy findProvider(String providerId) {
for (MediaRoute2ProviderProxy provider : mMediaProviders) {
final MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
if (providerInfo != null
&& TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
if (TextUtils.equals(provider.getUniqueId(), providerId)) {
return provider;
}
}