Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3eb4278 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "MediaRouter2: Updates callback for MediaRouter2Manager"

parents c3423e23 4ed68757
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -25,5 +25,7 @@ import android.media.MediaRoute2Info;
oneway interface IMediaRouter2Manager {
oneway interface IMediaRouter2Manager {
    void notifyRouteSelected(String packageName, in MediaRoute2Info route);
    void notifyRouteSelected(String packageName, in MediaRoute2Info route);
    void notifyControlCategoriesChanged(String packageName, in List<String> categories);
    void notifyControlCategoriesChanged(String packageName, in List<String> categories);
    void notifyProviderInfosUpdated(in List<MediaRoute2ProviderInfo> providers);
    void notifyRoutesAdded(in List<MediaRoute2Info> routes);
    void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
    void notifyRoutesChanged(in List<MediaRoute2Info> routes);
}
}
+5 −1
Original line number Original line Diff line number Diff line
@@ -95,6 +95,10 @@ public class MediaRouter2 {
    private final String mPackageName;
    private final String mPackageName;
    private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
    private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();


    //TODO: Use a lock for this to cover the below use case
    // mRouter.setControlCategories(...);
    // routes = mRouter.getRoutes();
    // The current implementation returns empty list
    private volatile List<String> mControlCategories = Collections.emptyList();
    private volatile List<String> mControlCategories = Collections.emptyList();


    private MediaRoute2Info mSelectedRoute;
    private MediaRoute2Info mSelectedRoute;
@@ -202,6 +206,7 @@ public class MediaRouter2 {
                    } catch (RemoteException ex) {
                    } catch (RemoteException ex) {
                        Log.e(TAG, "Unable to unregister media router.", ex);
                        Log.e(TAG, "Unable to unregister media router.", ex);
                    }
                    }
                    //TODO: Clean up mRoutes. (onHandler?)
                    mClient = null;
                    mClient = null;
                }
                }
            }
            }
@@ -222,7 +227,6 @@ public class MediaRouter2 {
                MediaRouter2.this, new ArrayList<>(controlCategories)));
                MediaRouter2.this, new ArrayList<>(controlCategories)));
    }
    }



    /**
    /**
     * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
     * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
     * known to the media router.
     * known to the media router.
+93 −120
Original line number Original line Diff line number Diff line
@@ -25,18 +25,16 @@ import android.content.Context;
import android.os.Handler;
import android.os.Handler;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -59,13 +57,11 @@ public class MediaRouter2Manager {
    private Client mClient;
    private Client mClient;
    private final IMediaRouterService mMediaRouterService;
    private final IMediaRouterService mMediaRouterService;
    final Handler mHandler;
    final Handler mHandler;
    final List<CallbackRecord> mCallbacks = new CopyOnWriteArrayList<>();
    final List<CallbackRecord> mCallbackRecords = new CopyOnWriteArrayList<>();


    @SuppressWarnings("WeakerAccess") /* synthetic access */
    private final Object mRoutesLock = new Object();
    @NonNull
    @GuardedBy("mRoutesLock")
    List<MediaRoute2ProviderInfo> mProviders = Collections.emptyList();
    private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
    @NonNull
    List<MediaRoute2Info> mRoutes = Collections.emptyList();
    @NonNull
    @NonNull
    final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
    final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();


@@ -104,13 +100,13 @@ public class MediaRouter2Manager {
        Objects.requireNonNull(callback, "callback must not be null");
        Objects.requireNonNull(callback, "callback must not be null");


        CallbackRecord callbackRecord;
        CallbackRecord callbackRecord;
        synchronized (mCallbacks) {
        synchronized (mCallbackRecords) {
            if (findCallbackRecordIndexLocked(callback) >= 0) {
            if (findCallbackRecordIndexLocked(callback) >= 0) {
                Log.w(TAG, "Ignoring to add the same callback twice.");
                Log.w(TAG, "Ignoring to add the same callback twice.");
                return;
                return;
            }
            }
            callbackRecord = new CallbackRecord(executor, callback);
            callbackRecord = new CallbackRecord(executor, callback);
            mCallbacks.add(callbackRecord);
            mCallbackRecords.add(callbackRecord);
        }
        }


        synchronized (sLock) {
        synchronized (sLock) {
@@ -136,32 +132,32 @@ public class MediaRouter2Manager {
    public void unregisterCallback(@NonNull Callback callback) {
    public void unregisterCallback(@NonNull Callback callback) {
        Objects.requireNonNull(callback, "callback must not be null");
        Objects.requireNonNull(callback, "callback must not be null");


        synchronized (mCallbacks) {
        synchronized (mCallbackRecords) {
            final int index = findCallbackRecordIndexLocked(callback);
            final int index = findCallbackRecordIndexLocked(callback);
            if (index < 0) {
            if (index < 0) {
                Log.w(TAG, "Ignore removing unknown callback. " + callback);
                Log.w(TAG, "Ignore removing unknown callback. " + callback);
                return;
                return;
            }
            }
            mCallbacks.remove(index);
            mCallbackRecords.remove(index);
            synchronized (sLock) {
            synchronized (sLock) {
                if (mCallbacks.size() == 0 && mClient != null) {
                if (mCallbackRecords.size() == 0 && mClient != null) {
                    try {
                    try {
                        mMediaRouterService.unregisterManager(mClient);
                        mMediaRouterService.unregisterManager(mClient);
                    } catch (RemoteException ex) {
                    } catch (RemoteException ex) {
                        Log.e(TAG, "Unable to unregister media router manager", ex);
                        Log.e(TAG, "Unable to unregister media router manager", ex);
                    }
                    }
                    mClient.notifyProviderInfosUpdated(Collections.emptyList());
                    //TODO: clear mRoutes?
                    mClient = null;
                    mClient = null;
                }
                }
            }
            }
        }
        }
    }
    }


    @GuardedBy("mCallbacks")
    @GuardedBy("mCallbackRecords")
    private int findCallbackRecordIndexLocked(Callback callback) {
    private int findCallbackRecordIndexLocked(Callback callback) {
        final int count = mCallbacks.size();
        final int count = mCallbackRecords.size();
        for (int i = 0; i < count; i++) {
        for (int i = 0; i < count; i++) {
            if (mCallbacks.get(i).mCallback == callback) {
            if (mCallbackRecords.get(i).mCallback == callback) {
                return i;
                return i;
            }
            }
        }
        }
@@ -184,11 +180,14 @@ public class MediaRouter2Manager {
            return Collections.emptyList();
            return Collections.emptyList();
        }
        }
        List<MediaRoute2Info> routes = new ArrayList<>();
        List<MediaRoute2Info> routes = new ArrayList<>();
        for (MediaRoute2Info route : mRoutes) {
        synchronized (mRoutesLock) {
            for (MediaRoute2Info route : mRoutes.values()) {
                if (route.supportsControlCategory(controlCategories)) {
                if (route.supportsControlCategory(controlCategories)) {
                    routes.add(route);
                    routes.add(route);
                }
                }
            }
            }
        }
        //TODO: Should we cache this?
        return routes;
        return routes;
    }
    }


@@ -282,136 +281,96 @@ public class MediaRouter2Manager {
        }
        }
    }
    }


    int findProviderIndex(MediaRoute2ProviderInfo provider) {
    void addRoutesOnHandler(List<MediaRoute2Info> routes) {
        final int count = mProviders.size();
        synchronized (mRoutesLock) {
        for (int i = 0; i < count; i++) {
            for (MediaRoute2Info route : routes) {
            if (TextUtils.equals(mProviders.get(i).getUniqueId(), provider.getUniqueId())) {
                mRoutes.put(route.getUniqueId(), route);
                return i;
            }
            }
        }
        }
        return -1;
        if (routes.size() > 0) {
            notifyRoutesAdded(routes);
        }
        }

    void updateProvider(@NonNull MediaRoute2ProviderInfo provider) {
        if (provider == null || !provider.isValid()) {
            Log.w(TAG, "Ignoring invalid provider : " + provider);
            return;
    }
    }


        final Collection<MediaRoute2Info> routes = provider.getRoutes();
    void removeRoutesOnHandler(List<MediaRoute2Info> routes) {

        synchronized (mRoutesLock) {
        final int index = findProviderIndex(provider);
            for (MediaRoute2Info route : routes) {
        if (index >= 0) {
                mRoutes.remove(route.getUniqueId());
            final MediaRoute2ProviderInfo prevProvider = mProviders.get(index);
            final Set<String> updatedRouteIds = new HashSet<>();
            for (MediaRoute2Info routeInfo : routes) {
                if (!routeInfo.isValid()) {
                    Log.w(TAG, "Ignoring invalid route : " + routeInfo);
                    continue;
            }
            }
                final MediaRoute2Info prevRoute = prevProvider.getRoute(routeInfo.getId());
                if (prevRoute == null) {
                    notifyRouteAdded(routeInfo);
                } else {
                    if (!Objects.equals(prevRoute, routeInfo)) {
                        notifyRouteChanged(routeInfo);
        }
        }
                    updatedRouteIds.add(routeInfo.getId());
        if (routes.size() > 0) {
            notifyRoutesRemoved(routes);
        }
        }
    }
    }
            final Collection<MediaRoute2Info> prevRoutes = prevProvider.getRoutes();


            for (MediaRoute2Info prevRoute : prevRoutes) {
    void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
                if (!updatedRouteIds.contains(prevRoute.getId())) {
        synchronized (mRoutesLock) {
                    notifyRouteRemoved(prevRoute);
            for (MediaRoute2Info route : routes) {
                mRoutes.put(route.getUniqueId(), route);
            }
            }
        }
        }
        } else {
        if (routes.size() > 0) {
            for (MediaRoute2Info routeInfo: routes) {
            notifyRoutesChanged(routes);
                notifyRouteAdded(routeInfo);
            }
        }
    }

    void notifyRouteAdded(MediaRoute2Info routeInfo) {
        for (CallbackRecord record : mCallbacks) {
            record.mExecutor.execute(
                    () -> record.mCallback.onRouteAdded(routeInfo));
        }
        }
    }
    }


    void notifyRouteChanged(MediaRoute2Info routeInfo) {
    private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
        for (CallbackRecord record : mCallbacks) {
        for (CallbackRecord record: mCallbackRecords) {
            record.mExecutor.execute(
            record.mExecutor.execute(
                    () -> record.mCallback.onRouteChanged(routeInfo));
                    () -> record.mCallback.onRoutesAdded(routes));
        }
        }
    }
    }


    void notifyRouteRemoved(MediaRoute2Info routeInfo) {
    private void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
        for (CallbackRecord record : mCallbacks) {
        for (CallbackRecord record: mCallbackRecords) {
            record.mExecutor.execute(
            record.mExecutor.execute(
                    () -> record.mCallback.onRouteRemoved(routeInfo));
                    () -> record.mCallback.onRoutesRemoved(routes));
        }
        }
    }
    }


    void notifyRouteListChanged() {
    private void notifyRoutesChanged(List<MediaRoute2Info> routes) {
        for (CallbackRecord record: mCallbacks) {
        for (CallbackRecord record: mCallbackRecords) {
            record.mExecutor.execute(
            record.mExecutor.execute(
                    () -> record.mCallback.onRoutesChanged(mRoutes));
                    () -> record.mCallback.onRoutesChanged(routes));
        }
        }
    }
    }


    void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> providers) {
        if (providers == null) {
            Log.w(TAG, "Providers info is null.");
            return;
        }

        ArrayList<MediaRoute2Info> routes = new ArrayList<>();

        for (MediaRoute2ProviderInfo provider : providers) {
            updateProvider(provider);
            //TODO: Should we do this in updateProvider()?
            routes.addAll(provider.getRoutes());
        }
        //TODO: Call notifyRouteRemoved for the routes of the removed providers.

        //TODO: Filter invalid providers and invalid routes.
        mProviders = providers;
        mRoutes = routes;

        //TODO: Call this when only the list is modified.
        notifyRouteListChanged();
    }

    void notifyRouteSelected(String packageName, MediaRoute2Info route) {
    void notifyRouteSelected(String packageName, MediaRoute2Info route) {
        for (CallbackRecord record : mCallbacks) {
        for (CallbackRecord record : mCallbackRecords) {
            record.mExecutor.execute(() -> record.mCallback.onRouteSelected(packageName, route));
            record.mExecutor.execute(() -> record.mCallback.onRouteSelected(packageName, route));
        }
        }
    }
    }


    void updateControlCategories(String packageName, List<String> categories) {
    void updateControlCategories(String packageName, List<String> categories) {
        mControlCategoryMap.put(packageName, categories);
        mControlCategoryMap.put(packageName, categories);
        for (CallbackRecord record : mCallbackRecords) {
            record.mExecutor.execute(
                    () -> record.mCallback.onControlCategoriesChanged(packageName));
        }
    }
    }


    /**
    /**
     * Interface for receiving events about media routing changes.
     * Interface for receiving events about media routing changes.
     */
     */
    public static class Callback {
    public static class Callback {

        /**
        /**
         * Called when a route is added.
         * Called when routes are added.
         * @param routes the list of routes that have been added. It's never empty.
         */
         */
        public void onRouteAdded(@NonNull MediaRoute2Info routeInfo) {}
        public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {}


        /**
        /**
         * Called when a route is changed.
         * Called when routes are removed.
         * @param routes the list of routes that have been removed. It's never empty.
         */
         */
        public void onRouteChanged(@NonNull MediaRoute2Info routeInfo) {}
        public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}


        /**
        /**
         * Called when a route is removed.
         * Called when routes are changed.
         * @param routes the list of routes that have been changed. It's never empty.
         */
         */
        public void onRouteRemoved(@NonNull MediaRoute2Info routeInfo) {}
        public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}


        /**
        /**
         * Called when a route is selected for an application.
         * Called when a route is selected for an application.
@@ -422,13 +381,13 @@ public class MediaRouter2Manager {
         */
         */
        public void onRouteSelected(@NonNull String packageName, @Nullable MediaRoute2Info route) {}
        public void onRouteSelected(@NonNull String packageName, @Nullable MediaRoute2Info route) {}



        /**
        /**
         * Called when the list of routes is changed.
         * Called when the control categories of an app is changed.
         * A client may refresh available routes for each application.
         *
         * @param packageName the package name of the application
         */
         */
        public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
        public void onControlCategoriesChanged(@NonNull String packageName) {}

        //TODO: add onControlCategoriesChanged to notify available routes are changed
    }
    }


    final class CallbackRecord {
    final class CallbackRecord {
@@ -441,10 +400,12 @@ public class MediaRouter2Manager {
        }
        }


        void notifyRoutes() {
        void notifyRoutes() {
            mExecutor.execute(() -> mCallback.onRoutesChanged(mRoutes));
            List<MediaRoute2Info> routes;
            for (MediaRoute2Info routeInfo : mRoutes) {
            synchronized (mRoutesLock) {
                mExecutor.execute(
                routes = new ArrayList<>(mRoutes.values());
                        () -> mCallback.onRouteAdded(routeInfo));
            }
            if (routes.size() > 0) {
                mExecutor.execute(() -> mCallback.onRoutesAdded(routes));
            }
            }
        }
        }
    }
    }
@@ -463,9 +424,21 @@ public class MediaRouter2Manager {
        }
        }


        @Override
        @Override
        public void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> info) {
        public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyProviderInfosUpdated,
            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::addRoutesOnHandler,
                    MediaRouter2Manager.this, info));
                    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));
        }
        }
    }
    }
}
}
+114 −104

File changed.

Preview size limit exceeded, changes collapsed.

+62 −32
Original line number Original line Diff line number Diff line
@@ -469,7 +469,7 @@ class MediaRouter2ServiceImpl {
            mAllManagerRecords.put(binder, managerRecord);
            mAllManagerRecords.put(binder, managerRecord);


            userRecord.mHandler.sendMessage(
            userRecord.mHandler.sendMessage(
                    obtainMessage(UserHandler::notifyProviderInfosUpdatedToManager,
                    obtainMessage(UserHandler::notifyRoutesToManager,
                            userRecord.mHandler, manager));
                            userRecord.mHandler, manager));


            for (ClientRecord clientRecord : userRecord.mClientRecords) {
            for (ClientRecord clientRecord : userRecord.mClientRecords) {
@@ -808,17 +808,20 @@ class MediaRouter2ServiceImpl {
                }
                }


                List<IMediaRouter2Client> clients = getClients();
                List<IMediaRouter2Client> clients = getClients();
                List<IMediaRouter2Manager> managers = getManagers();
                if (addedRoutes.size() > 0) {
                if (addedRoutes.size() > 0) {
                    notifyRoutesAddedToClients(clients, addedRoutes);
                    notifyRoutesAddedToClients(clients, addedRoutes);
                    notifyRoutesAddedToManagers(managers, addedRoutes);
                }
                }
                if (removedRoutes.size() > 0) {
                if (removedRoutes.size() > 0) {
                    notifyRoutesRemovedToClients(clients, removedRoutes);
                    notifyRoutesRemovedToClients(clients, removedRoutes);
                    notifyRoutesRemovedToManagers(managers, removedRoutes);
                }
                }
                if (changedRoutes.size() > 0) {
                if (changedRoutes.size() > 0) {
                    notifyRoutesChangedToClients(clients, changedRoutes);
                    notifyRoutesChangedToClients(clients, changedRoutes);
                    notifyRoutesChangedToManagers(managers, changedRoutes);
                }
                }
            }
            }
            scheduleUpdateProviderInfos();
        }
        }


        private int getProviderInfoIndex(String providerId) {
        private int getProviderInfoIndex(String providerId) {
@@ -874,47 +877,34 @@ class MediaRouter2ServiceImpl {
            }
            }
        }
        }


        private void scheduleUpdateProviderInfos() {
        private List<IMediaRouter2Client> getClients() {
            if (!mProviderInfosUpdateScheduled) {
            final List<IMediaRouter2Client> clients = new ArrayList<>();
                mProviderInfosUpdateScheduled = true;
                sendMessage(PooledLambda.obtainMessage(UserHandler::updateProviderInfos, this));
            }
        }

        //TODO: should be replaced into notifyRoutes...ToManagers
        private void updateProviderInfos() {
            mProviderInfosUpdateScheduled = false;

            MediaRouter2ServiceImpl service = mServiceRef.get();
            MediaRouter2ServiceImpl service = mServiceRef.get();
            if (service == null) {
            if (service == null) {
                return;
                return clients;
            }
            }

            final List<IMediaRouter2Manager> managers = new ArrayList<>();
            synchronized (service.mLock) {
            synchronized (service.mLock) {
                for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
                for (ClientRecord clientRecord : mUserRecord.mClientRecords) {
                    managers.add(managerRecord.mManager);
                    if (clientRecord instanceof Client2Record) {
                        clients.add(((Client2Record) clientRecord).mClient);
                    }
                    }
                }
                }
            for (IMediaRouter2Manager manager : managers) {
                notifyProviderInfosUpdatedToManager(manager);
            }
            }
            return clients;
        }
        }


        private List<IMediaRouter2Client> getClients() {
        private List<IMediaRouter2Manager> getManagers() {
            final List<IMediaRouter2Client> clients = new ArrayList<>();
            final List<IMediaRouter2Manager> managers = new ArrayList<>();
            MediaRouter2ServiceImpl service = mServiceRef.get();
            MediaRouter2ServiceImpl service = mServiceRef.get();
            if (service == null) {
            if (service == null) {
                return clients;
                return managers;
            }
            }
            synchronized (service.mLock) {
            synchronized (service.mLock) {
                for (ClientRecord clientRecord : mUserRecord.mClientRecords) {
                for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
                    if (clientRecord instanceof Client2Record) {
                    managers.add(managerRecord.mManager);
                        clients.add(((Client2Record) clientRecord).mClient);
                }
                }
            }
            }
            }
            return managers;
            return clients;
        }
        }


        private void notifyRoutesToClient(IMediaRouter2Client client) {
        private void notifyRoutesToClient(IMediaRouter2Client client) {
@@ -965,11 +955,51 @@ class MediaRouter2ServiceImpl {
            }
            }
        }
        }


        private void notifyProviderInfosUpdatedToManager(IMediaRouter2Manager manager) {
        private void notifyRoutesToManager(IMediaRouter2Manager manager) {
            List<MediaRoute2Info> routes = new ArrayList<>();
            for (MediaRoute2ProviderInfo providerInfo : mProviderInfos) {
                routes.addAll(providerInfo.getRoutes());
            }
            if (routes.size() == 0) {
                return;
            }
            try {
            try {
                manager.notifyProviderInfosUpdated(mProviderInfos);
                manager.notifyRoutesAdded(routes);
            } catch (RemoteException ex) {
            } catch (RemoteException ex) {
                Slog.w(TAG, "Failed to notify provider infos updated. Manager probably died.");
                Slog.w(TAG, "Failed to notify all routes. Manager probably died.", ex);
            }
        }

        private void notifyRoutesAddedToManagers(List<IMediaRouter2Manager> managers,
                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(List<IMediaRouter2Manager> managers,
                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(List<IMediaRouter2Manager> managers,
                List<MediaRoute2Info> routes) {
            for (IMediaRouter2Manager manager : managers) {
                try {
                    manager.notifyRoutesChanged(routes);
                } catch (RemoteException ex) {
                    Slog.w(TAG, "Failed to notify routes changed. Manager probably died.", ex);
                }
            }
            }
        }
        }