Merge "Media: Introduce MediaRouter2Service"
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
new file mode 100644
index 0000000..735df33
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.media.IMediaRouter2ManagerClient;
+import android.media.IMediaRouterClient;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TODO: Merge this to MediaRouterService once it's finished.
+ */
+class MediaRouter2ServiceImpl {
+    private static final String TAG = "MediaRouter2ServiceImpl";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private final Object mLock = new Object();
+    private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
+
+    private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
+    private int mCurrentUserId = -1;
+
+    MediaRouter2ServiceImpl(Context context) {
+        mContext = context;
+    }
+
+    public void registerManagerAsUser(IMediaRouter2ManagerClient client,
+            String packageName, int userId) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+        //TODO: should check permission
+        final boolean trusted = true;
+
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                false /*allowAll*/, true /*requireFull*/, "registerManagerAsUser", packageName);
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                registerManagerLocked(client, uid, pid, packageName, resolvedUserId, trusted);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    public void unregisterManager(IMediaRouter2ManagerClient client) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                unregisterManagerLocked(client, false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    public void setControlCategories(IMediaRouterClient client, List<String> categories) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                setControlCategoriesLocked(client, categories);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    public void setRemoteRoute(IMediaRouter2ManagerClient client,
+            int uid, String routeId, boolean explicit) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                setRemoteRouteLocked(client, uid, routeId, explicit);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    void clientDied(ManagerRecord managerRecord) {
+        synchronized (mLock) {
+            unregisterManagerLocked(managerRecord.mClient, true);
+        }
+    }
+
+    private void registerManagerLocked(IMediaRouter2ManagerClient client,
+            int uid, int pid, String packageName, int userId, boolean trusted) {
+        final IBinder binder = client.asBinder();
+        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+        if (managerRecord == null) {
+            boolean newUser = false;
+            UserRecord userRecord = mUserRecords.get(userId);
+            if (userRecord == null) {
+                userRecord = new UserRecord(userId);
+                newUser = true;
+            }
+            managerRecord = new ManagerRecord(userRecord, client, uid, pid, packageName, trusted);
+            try {
+                binder.linkToDeath(managerRecord, 0);
+            } catch (RemoteException ex) {
+                throw new RuntimeException("Media router client died prematurely.", ex);
+            }
+
+            if (newUser) {
+                mUserRecords.put(userId, userRecord);
+                initializeUserLocked(userRecord);
+            }
+
+            userRecord.mManagerRecords.add(managerRecord);
+            mAllManagerRecords.put(binder, managerRecord);
+
+            //TODO: send client's info to manager
+        }
+    }
+
+    private void unregisterManagerLocked(IMediaRouter2ManagerClient client, boolean died) {
+        ManagerRecord clientRecord = mAllManagerRecords.remove(client.asBinder());
+        if (clientRecord != null) {
+            UserRecord userRecord = clientRecord.mUserRecord;
+            userRecord.mManagerRecords.remove(clientRecord);
+            clientRecord.dispose();
+            disposeUserIfNeededLocked(userRecord); // since client removed from user
+        }
+    }
+
+    private void setRemoteRouteLocked(IMediaRouter2ManagerClient client,
+            int uid, String routeId, boolean explicit) {
+        ManagerRecord managerRecord = mAllManagerRecords.get(client.asBinder());
+        if (managerRecord != null) {
+            if (explicit && managerRecord.mTrusted) {
+                Pair<Integer, String> obj = new Pair<>(uid, routeId);
+                managerRecord.mUserRecord.mHandler.obtainMessage(
+                        UserHandler.MSG_SELECT_REMOTE_ROUTE, obj).sendToTarget();
+            }
+        }
+    }
+
+    private void setControlCategoriesLocked(IMediaRouterClient client, List<String> categories) {
+        //TODO: implement this when we have client record (MediaRouter2?)
+//        final IBinder binder = client.asBinder();
+//        ClientRecord clientRecord = mAllClientRecords.get(binder);
+//
+//        if (clientRecord != null) {
+//            clientRecord.mControlCategories = categories;
+//            clientRecord.mUserRecord.mHandler.obtainMessage(
+//                    UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget();
+//        }
+    }
+
+    private void initializeUserLocked(UserRecord userRecord) {
+        if (DEBUG) {
+            Slog.d(TAG, userRecord + ": Initialized");
+        }
+        if (userRecord.mUserId == mCurrentUserId) {
+            userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+        }
+    }
+
+    private void disposeUserIfNeededLocked(UserRecord userRecord) {
+        // If there are no records left and the user is no longer current then go ahead
+        // and purge the user record and all of its associated state.  If the user is current
+        // then leave it alone since we might be connected to a route or want to query
+        // the same route information again soon.
+        if (userRecord.mUserId != mCurrentUserId
+                && userRecord.mManagerRecords.isEmpty()) {
+            if (DEBUG) {
+                Slog.d(TAG, userRecord + ": Disposed");
+            }
+            mUserRecords.remove(userRecord.mUserId);
+            // Note: User already stopped (by switchUser) so no need to send stop message here.
+        }
+    }
+
+    final class UserRecord {
+        public final int mUserId;
+        final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
+        final UserHandler mHandler;
+
+        UserRecord(int userId) {
+            mUserId = userId;
+            mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
+        }
+    }
+
+    final class ManagerRecord implements IBinder.DeathRecipient {
+        public final UserRecord mUserRecord;
+        public final IMediaRouter2ManagerClient mClient;
+        public final int mUid;
+        public final int mPid;
+        public final String mPackageName;
+        public final boolean mTrusted;
+
+        ManagerRecord(UserRecord userRecord, IMediaRouter2ManagerClient client,
+                int uid, int pid, String packageName, boolean trusted) {
+            mUserRecord = userRecord;
+            mClient = client;
+            mUid = uid;
+            mPid = pid;
+            mPackageName = packageName;
+            mTrusted = trusted;
+        }
+
+        public void dispose() {
+            mClient.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            clientDied(this);
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + this);
+
+            final String indent = prefix + "  ";
+            pw.println(indent + "mTrusted=" + mTrusted);
+        }
+
+        @Override
+        public String toString() {
+            return "Client " + mPackageName + " (pid " + mPid + ")";
+        }
+    }
+
+    static final class UserHandler extends Handler implements
+            MediaRoute2ProviderWatcher.Callback,
+            MediaRoute2ProviderProxy.Callback {
+
+        //TODO: Should be rearranged
+        public static final int MSG_START = 1;
+        public static final int MSG_STOP = 2;
+
+        private static final int MSG_UPDATE_CLIENT_STATE = 8;
+
+        private static final int MSG_SELECT_REMOTE_ROUTE = 10;
+        private static final int MSG_UPDATE_CLIENT_USAGE = 11;
+
+        private final WeakReference<MediaRouter2ServiceImpl> mServiceRef;
+        private final UserRecord mUserRecord;
+        private final MediaRoute2ProviderWatcher mWatcher;
+        private final ArrayList<IMediaRouter2ManagerClient> mTempManagers = new ArrayList<>();
+
+        private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders =
+                new ArrayList<>();
+
+        private boolean mRunning;
+        private boolean mClientStateUpdateScheduled;
+
+        UserHandler(MediaRouter2ServiceImpl service, UserRecord userRecord) {
+            mServiceRef = new WeakReference<>(service);
+            mUserRecord = userRecord;
+            mWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
+                    this, mUserRecord.mUserId);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START: {
+                    start();
+                    break;
+                }
+                case MSG_STOP: {
+                    stop();
+                    break;
+                }
+                case MSG_UPDATE_CLIENT_STATE: {
+                    updateClientState();
+                    break;
+                }
+                case MSG_SELECT_REMOTE_ROUTE: {
+                    Pair<Integer, String> obj = (Pair<Integer, String>) msg.obj;
+                    selectRemoteRoute(obj.first, obj.second);
+                    break;
+                }
+                case MSG_UPDATE_CLIENT_USAGE: {
+                    updateClientUsage();
+                    break;
+                }
+            }
+        }
+
+        private void start() {
+            if (!mRunning) {
+                mRunning = true;
+                mWatcher.start();
+            }
+        }
+
+        private void stop() {
+            if (mRunning) {
+                mRunning = false;
+                //TODO: may unselect routes
+                mWatcher.stop(); // also stops all providers
+            }
+        }
+
+        @Override
+        public void addProvider(MediaRoute2ProviderProxy provider) {
+            provider.setCallback(this);
+            mMediaProviders.add(provider);
+        }
+
+        @Override
+        public void removeProvider(MediaRoute2ProviderProxy provider) {
+            mMediaProviders.remove(provider);
+        }
+
+        @Override
+        public void onProviderStateChanged(MediaRoute2ProviderProxy provider) {
+            updateProvider(provider);
+        }
+
+        private void updateProvider(MediaRoute2ProviderProxy provider) {
+            scheduleUpdateClientState();
+        }
+
+
+        private void selectRemoteRoute(int uid, String routeId) {
+            if (routeId != null) {
+                final int providerCount = mMediaProviders.size();
+
+                //TODO: should find proper provider (currently assumes a single provider)
+                for (int i = 0; i < providerCount; ++i) {
+                    mMediaProviders.get(i).setSelectedRoute(uid, routeId);
+                }
+            }
+        }
+
+        private void scheduleUpdateClientState() {
+            if (!mClientStateUpdateScheduled) {
+                mClientStateUpdateScheduled = true;
+                sendEmptyMessage(MSG_UPDATE_CLIENT_STATE);
+            }
+        }
+
+        private void updateClientState() {
+            mClientStateUpdateScheduled = false;
+
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return;
+            }
+
+            //TODO: send provider info
+            int selectedUid = 0;
+            String selectedRouteId = null;
+            final int mediaCount = mMediaProviders.size();
+            for (int i = 0; i < mediaCount; i++) {
+                selectedUid = mMediaProviders.get(i).mSelectedUid;
+                selectedRouteId = mMediaProviders.get(i).mSelectedRouteId;
+            }
+
+            try {
+                synchronized (service.mLock) {
+                    final int count = mUserRecord.mManagerRecords.size();
+                    for (int i = 0; i < count; i++) {
+                        mTempManagers.add(mUserRecord.mManagerRecords.get(i).mClient);
+                    }
+                }
+
+                //TODO: Call proper callbacks when provider descriptor is implemented.
+                final int count = mTempManagers.size();
+                for (int i = 0; i < count; i++) {
+                    try {
+                        mTempManagers.get(i).onRouteSelected(selectedUid, selectedRouteId);
+                    } catch (RemoteException ex) {
+                        Slog.w(TAG, "Failed to call onStateChanged. Manager probably died.", ex);
+                    }
+                }
+            } finally {
+                mTempManagers.clear();
+            }
+        }
+
+        private void updateClientUsage() {
+            //TODO: merge these code to updateClientState()
+
+//            List<IMediaRouter2ManagerClient> managers = new ArrayList<>();
+//            synchronized (mService.mLock) {
+//                final int count = mUserRecord.mManagerRecords.size();
+//                for (int i = 0; i < count; i++) {
+//                    managers.add(mUserRecord.mManagerRecords.get(i).mClient);
+//                }
+//            }
+//            final int count = managers.size();
+//            for (int i = 0; i < count; i++) {
+//                try {
+//                    managers.get(i).onControlCategoriesChanged(clientRecord.mUid,
+//                            clientRecord.mControlCategories);
+//                } catch (RemoteException ex) {
+//                    Slog.w(TAG, "Failed to call onControlCategoriesChanged. "
+//                            + "Manager probably died.", ex);
+//                }
+//            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index a43533f..05dae46 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -50,7 +50,6 @@
 import android.util.ArrayMap;
 import android.util.IntArray;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -98,7 +97,6 @@
     private final Object mLock = new Object();
     private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
     private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>();
-    private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
     private int mCurrentUserId = -1;
     private final IAudioService mAudioService;
     private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
@@ -111,7 +109,12 @@
     int mAudioRouteMainType = AudioRoutesInfo.MAIN_SPEAKER;
     boolean mGlobalBluetoothA2dpOn = false;
 
+    //TODO: remove this when it's finished
+    private final MediaRouter2ServiceImpl mService2;
+
     public MediaRouterService(Context context) {
+        mService2 = new MediaRouter2ServiceImpl(context);
+
         mContext = context;
         Watchdog.getInstance().addMonitor(this);
 
@@ -308,17 +311,7 @@
     // Binder call
     @Override
     public void setControlCategories(IMediaRouterClient client, List<String> categories) {
-        if (client == null) {
-            throw new IllegalArgumentException("client must not be null");
-        }
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                setControlCategoriesLocked(client, categories);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mService2.setControlCategories(client, categories);
     }
 
     // Binder call
@@ -425,59 +418,24 @@
     @Override
     public void registerManagerAsUser(IMediaRouter2ManagerClient client,
             String packageName, int userId) {
-        if (client == null) {
-            throw new IllegalArgumentException("client must not be null");
-        }
-        //TODO: should check permission
-        final boolean trusted = true;
-
         final int uid = Binder.getCallingUid();
         if (!validatePackageName(uid, packageName)) {
             throw new SecurityException("packageName must match the calling uid");
         }
-
-        final int pid = Binder.getCallingPid();
-        final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                false /*allowAll*/, true /*requireFull*/, "registerManagerAsUser", packageName);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                registerManagerLocked(client, uid, pid, packageName, resolvedUserId, trusted);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mService2.registerManagerAsUser(client, packageName, userId);
     }
 
     // Binder call
     @Override
     public void unregisterManager(IMediaRouter2ManagerClient client) {
-        if (client == null) {
-            throw new IllegalArgumentException("client must not be null");
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                unregisterManagerLocked(client, false);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mService2.unregisterManager(client);
     }
 
     // Binder call
     @Override
     public void setRemoteRoute(IMediaRouter2ManagerClient client,
             int uid, String routeId, boolean explicit) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                setRemoteRouteLocked(client, uid, routeId, explicit);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mService2.setRemoteRoute(client, uid, routeId, explicit);
     }
 
     void restoreBluetoothA2dp() {
@@ -551,12 +509,6 @@
         }
     }
 
-    void clientDied(ManagerRecord managerRecord) {
-        synchronized (mLock) {
-            unregisterManagerLocked(managerRecord.mClient, true);
-        }
-    }
-
     private void registerClientLocked(IMediaRouterClient client,
             int uid, int pid, String packageName, int userId, boolean trusted) {
         final IBinder binder = client.asBinder();
@@ -604,17 +556,6 @@
         return null;
     }
 
-    private void setControlCategoriesLocked(IMediaRouterClient client, List<String> categories) {
-        final IBinder binder = client.asBinder();
-        ClientRecord clientRecord = mAllClientRecords.get(binder);
-
-        if (clientRecord != null) {
-            clientRecord.mControlCategories = categories;
-            clientRecord.mUserRecord.mHandler.obtainMessage(
-                    UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget();
-        }
-    }
-
     private void setDiscoveryRequestLocked(IMediaRouterClient client,
             int routeTypes, boolean activeScan) {
         final IBinder binder = client.asBinder();
@@ -668,63 +609,6 @@
         }
     }
 
-    private void registerManagerLocked(IMediaRouter2ManagerClient client,
-            int uid, int pid, String packageName, int userId, boolean trusted) {
-        final IBinder binder = client.asBinder();
-        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
-        if (managerRecord == null) {
-            boolean newUser = false;
-            UserRecord userRecord = mUserRecords.get(userId);
-            if (userRecord == null) {
-                userRecord = new UserRecord(userId);
-                newUser = true;
-            }
-            managerRecord = new ManagerRecord(userRecord, client, uid, pid, packageName, trusted);
-            try {
-                binder.linkToDeath(managerRecord, 0);
-            } catch (RemoteException ex) {
-                throw new RuntimeException("Media router client died prematurely.", ex);
-            }
-
-            if (newUser) {
-                mUserRecords.put(userId, userRecord);
-                initializeUserLocked(userRecord);
-            }
-
-            userRecord.mManagerRecords.add(managerRecord);
-            mAllManagerRecords.put(binder, managerRecord);
-
-            // send client usage to manager
-            final int clientCount = userRecord.mClientRecords.size();
-            for (int i = 0; i < clientCount; i++) {
-                userRecord.mHandler.obtainMessage(UserHandler.MSG_UPDATE_CLIENT_USAGE,
-                        userRecord.mClientRecords.get(i)).sendToTarget();
-            }
-        }
-    }
-
-    private void unregisterManagerLocked(IMediaRouter2ManagerClient client, boolean died) {
-        ManagerRecord clientRecord = mAllManagerRecords.remove(client.asBinder());
-        if (clientRecord != null) {
-            UserRecord userRecord = clientRecord.mUserRecord;
-            userRecord.mManagerRecords.remove(clientRecord);
-            clientRecord.dispose();
-            disposeUserIfNeededLocked(userRecord); // since client removed from user
-        }
-    }
-
-    private void setRemoteRouteLocked(IMediaRouter2ManagerClient client,
-            int uid, String routeId, boolean explicit) {
-        ManagerRecord managerRecord = mAllManagerRecords.get(client.asBinder());
-        if (managerRecord != null) {
-            if (explicit && managerRecord.mTrusted) {
-                Pair<Integer, String> obj = new Pair<>(uid, routeId);
-                managerRecord.mUserRecord.mHandler.obtainMessage(
-                        UserHandler.MSG_SELECT_REMOTE_ROUTE, obj).sendToTarget();
-            }
-        }
-    }
-
     private void requestSetVolumeLocked(IMediaRouterClient client,
             String routeId, int volume) {
         final IBinder binder = client.asBinder();
@@ -817,46 +701,6 @@
         }
     }
 
-    final class ManagerRecord implements DeathRecipient {
-        public final UserRecord mUserRecord;
-        public final IMediaRouter2ManagerClient mClient;
-        public final int mUid;
-        public final int mPid;
-        public final String mPackageName;
-        public final boolean mTrusted;
-
-        ManagerRecord(UserRecord userRecord, IMediaRouter2ManagerClient client,
-                int uid, int pid, String packageName, boolean trusted) {
-            mUserRecord = userRecord;
-            mClient = client;
-            mUid = uid;
-            mPid = pid;
-            mPackageName = packageName;
-            mTrusted = trusted;
-        }
-
-        public void dispose() {
-            mClient.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            clientDied(this);
-        }
-
-        public void dump(PrintWriter pw, String prefix) {
-            pw.println(prefix + this);
-
-            final String indent = prefix + "  ";
-            pw.println(indent + "mTrusted=" + mTrusted);
-        }
-
-        @Override
-        public String toString() {
-            return "Client " + mPackageName + " (pid " + mPid + ")";
-        }
-    }
-
     /**
      * Information about a particular client of the media router.
      * The contents of this object is guarded by mLock.
@@ -920,7 +764,6 @@
     final class UserRecord {
         public final int mUserId;
         public final ArrayList<ClientRecord> mClientRecords = new ArrayList<>();
-        public final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
         public final UserHandler mHandler;
         public MediaRouterClientState mRouterState;
 
@@ -975,9 +818,7 @@
      */
     static final class UserHandler extends Handler
             implements RemoteDisplayProviderWatcher.Callback,
-            RemoteDisplayProviderProxy.Callback,
-            MediaRoute2ProviderWatcher.Callback,
-            MediaRoute2ProviderProxy.Callback {
+            RemoteDisplayProviderProxy.Callback {
         public static final int MSG_START = 1;
         public static final int MSG_STOP = 2;
         public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3;
@@ -988,9 +829,6 @@
         private static final int MSG_UPDATE_CLIENT_STATE = 8;
         private static final int MSG_CONNECTION_TIMED_OUT = 9;
 
-        private static final int MSG_SELECT_REMOTE_ROUTE = 10;
-        private static final int MSG_UPDATE_CLIENT_USAGE = 11;
-
         private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1;
         private static final int TIMEOUT_REASON_CONNECTION_LOST = 2;
         private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 3;
@@ -1006,17 +844,11 @@
         private final MediaRouterService mService;
         private final UserRecord mUserRecord;
         private final RemoteDisplayProviderWatcher mWatcher;
-        private final MediaRoute2ProviderWatcher mMediaWatcher;
-
         private final ArrayList<ProviderRecord> mProviderRecords =
                 new ArrayList<ProviderRecord>();
         private final ArrayList<IMediaRouterClient> mTempClients =
                 new ArrayList<IMediaRouterClient>();
 
-        private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders =
-                new ArrayList<>();
-        private final ArrayList<IMediaRouter2ManagerClient> mTempManagers = new ArrayList<>();
-
         private boolean mRunning;
         private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE;
         private RouteRecord mSelectedRouteRecord;
@@ -1031,8 +863,6 @@
             mUserRecord = userRecord;
             mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this,
                     this, mUserRecord.mUserId);
-            mMediaWatcher = new MediaRoute2ProviderWatcher(service.mContext, this,
-                    this, mUserRecord.mUserId);
         }
 
         @Override
@@ -1074,15 +904,6 @@
                     connectionTimedOut();
                     break;
                 }
-                case MSG_SELECT_REMOTE_ROUTE: {
-                    Pair<Integer, String> obj = (Pair<Integer, String>) msg.obj;
-                    selectRemoteRoute(obj.first, obj.second);
-                    break;
-                }
-                case MSG_UPDATE_CLIENT_USAGE: {
-                    updateClientUsage((ClientRecord) msg.obj);
-                    break;
-                }
             }
         }
 
@@ -1114,7 +935,6 @@
             if (!mRunning) {
                 mRunning = true;
                 mWatcher.start(); // also starts all providers
-                mMediaWatcher.start();
             }
         }
 
@@ -1123,7 +943,6 @@
                 mRunning = false;
                 unselectSelectedRoute();
                 mWatcher.stop(); // also stops all providers
-                mMediaWatcher.stop();
             }
         }
 
@@ -1255,26 +1074,6 @@
             }
         }
 
-        @Override
-        public void addProvider(MediaRoute2ProviderProxy provider) {
-            provider.setCallback(this);
-            mMediaProviders.add(provider);
-        }
-
-        @Override
-        public void removeProvider(MediaRoute2ProviderProxy provider) {
-            mMediaProviders.remove(provider);
-        }
-
-        @Override
-        public void onProviderStateChanged(MediaRoute2ProviderProxy provider) {
-            updateProvider(provider);
-        }
-
-        private void updateProvider(MediaRoute2ProviderProxy provider) {
-            scheduleUpdateClientState();
-        }
-
         /**
          * This function is called whenever the state of the selected route may have changed.
          * It checks the state and updates timeouts or unselects the route as appropriate.
@@ -1385,17 +1184,6 @@
             unselectSelectedRoute();
         }
 
-        private void selectRemoteRoute(int uid, String routeId) {
-            if (routeId != null) {
-                final int providerCount = mMediaProviders.size();
-
-                //TODO: should find proper provider (currently assumes a single provider)
-                for (int i = 0; i < providerCount; ++i) {
-                    mMediaProviders.get(i).setSelectedRoute(uid, routeId);
-                }
-            }
-        }
-
         private void scheduleUpdateClientState() {
             if (!mClientStateUpdateScheduled) {
                 mClientStateUpdateScheduled = true;
@@ -1412,16 +1200,6 @@
             for (int i = 0; i < providerCount; i++) {
                 mProviderRecords.get(i).appendClientState(routerState);
             }
-
-            //TODO: send provider info
-            int selectedUid = 0;
-            String selectedRouteId = null;
-            final int mediaCount = mMediaProviders.size();
-            for (int i = 0; i < mediaCount; i++) {
-                selectedUid = mMediaProviders.get(i).mSelectedUid;
-                selectedRouteId = mMediaProviders.get(i).mSelectedRouteId;
-            }
-
             try {
                 synchronized (mService.mLock) {
                     // Update the UserRecord.
@@ -1432,11 +1210,6 @@
                     for (int i = 0; i < count; i++) {
                         mTempClients.add(mUserRecord.mClientRecords.get(i).mClient);
                     }
-
-                    final int count2 = mUserRecord.mManagerRecords.size();
-                    for (int i = 0; i < count2; i++) {
-                        mTempManagers.add(mUserRecord.mManagerRecords.get(i).mClient);
-                    }
                 }
 
                 // Notify all clients (outside of the lock).
@@ -1448,39 +1221,9 @@
                         Slog.w(TAG, "Failed to call onStateChanged. Client probably died.");
                     }
                 }
-                //TODO: Call proper callbacks when provider descriptor is implemented.
-                final int count2 = mTempManagers.size();
-                for (int i = 0; i < count2; i++) {
-                    try {
-                        mTempManagers.get(i).onRouteSelected(selectedUid, selectedRouteId);
-                    } catch (RemoteException ex) {
-                        Slog.w(TAG, "Failed to call onStateChanged. Manager probably died.", ex);
-                    }
-                }
             } finally {
                 // Clear the list in preparation for the next time.
                 mTempClients.clear();
-                mTempManagers.clear();
-            }
-        }
-
-        private void updateClientUsage(ClientRecord clientRecord) {
-            List<IMediaRouter2ManagerClient> managers = new ArrayList<>();
-            synchronized (mService.mLock) {
-                final int count = mUserRecord.mManagerRecords.size();
-                for (int i = 0; i < count; i++) {
-                    managers.add(mUserRecord.mManagerRecords.get(i).mClient);
-                }
-            }
-            final int count = managers.size();
-            for (int i = 0; i < count; i++) {
-                try {
-                    managers.get(i).onControlCategoriesChanged(clientRecord.mUid,
-                            clientRecord.mControlCategories);
-                } catch (RemoteException ex) {
-                    Slog.w(TAG, "Failed to call onControlCategoriesChanged. "
-                            + "Manager probably died.", ex);
-                }
             }
         }
 
@@ -1867,5 +1610,4 @@
             }
         }
     }
-
 }