Merge "Remove code duplications"
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 8379614..33e01bd 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -166,6 +166,20 @@
         }
     }
 
+    @Nullable
+    MediaRoute2Info getSelectedRoute() {
+        return (mSelectedRoute == null) ? null : mSelectedRoute.route;
+    }
+
+    @NonNull
+    List<MediaRoute2Info> getTransferableRoutes() {
+        List<MediaRoute2Info> routes = getAllBluetoothRoutes();
+        if (mSelectedRoute != null) {
+            routes.remove(mSelectedRoute.route);
+        }
+        return routes;
+    }
+
     @NonNull
     List<MediaRoute2Info> getAllBluetoothRoutes() {
         ArrayList<MediaRoute2Info> routes = new ArrayList<>();
@@ -175,9 +189,12 @@
         return routes;
     }
 
-    @Nullable
-    String getSelectedRouteId() {
-        return mSelectedRoute == null ? null : mSelectedRoute.route.getId();
+    boolean setSelectedRouteVolume(int volume) {
+        if (mSelectedRoute == null) return false;
+        mSelectedRoute.route = new MediaRoute2Info.Builder(mSelectedRoute.route)
+                .setVolume(volume)
+                .build();
+        return true;
     }
 
     private void notifyBluetoothRoutesUpdated() {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 777a8fe..8e38114 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -19,7 +19,6 @@
 import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
 import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO;
 
-import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -42,15 +41,13 @@
 import android.util.Log;
 
 import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
 
-import java.util.Collections;
-import java.util.List;
 import java.util.Objects;
 
 /**
  * Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers.
  */
+// TODO: check thread safety. We may need to use lock to protect variables.
 class SystemMediaRoute2Provider extends MediaRoute2Provider {
     private static final String TAG = "MR2SystemProvider";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -68,19 +65,16 @@
             SystemMediaRoute2Provider.class.getPackageName$(),
             SystemMediaRoute2Provider.class.getName());
 
-    @GuardedBy("mLock")
     private String mSelectedRouteId;
     MediaRoute2Info mDefaultRoute;
-    @NonNull List<MediaRoute2Info> mBluetoothRoutes = Collections.EMPTY_LIST;
     final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
 
     final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() {
         @Override
         public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
-            mHandler.post(new Runnable() {
-                @Override public void run() {
-                    updateAudioRoutes(newRoutes);
-                }
+            mHandler.post(() -> {
+                updateDefaultRoute(newRoutes);
+                notifyProviderState();
             });
         }
     };
@@ -97,11 +91,15 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mAudioService = IAudioService.Stub.asInterface(
                 ServiceManager.getService(Context.AUDIO_SERVICE));
+        AudioRoutesInfo newAudioRoutes = null;
+        try {
+            newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
+        } catch (RemoteException e) {
+        }
+        updateDefaultRoute(newAudioRoutes);
 
-        initializeDefaultRoute();
         mBtRouteProvider = BluetoothRouteProvider.getInstance(context, (routes) -> {
-            mBluetoothRoutes = routes;
-            publishRoutes();
+            publishProviderState();
 
             boolean sessionInfoChanged;
             synchronized (mLock) {
@@ -111,7 +109,15 @@
                 notifySessionInfoUpdated();
             }
         });
-        initializeSessionInfo();
+
+        mHandler.post(() -> notifyProviderState());
+
+        //TODO: clean up this
+        // This is required because it is not instantiated in the main thread and
+        // BluetoothRoutesUpdatedListener can be called before here
+        synchronized (mLock) {
+            updateSessionInfosIfNeededLocked();
+        }
 
         mContext.registerReceiver(new VolumeChangeReceiver(),
                 new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));
@@ -164,65 +170,21 @@
         // Do nothing since we don't support grouping volume yet.
     }
 
-    private void initializeDefaultRoute() {
-        mDefaultRoute = new MediaRoute2Info.Builder(
-                DEFAULT_ROUTE_ID,
-                mContext.getResources().getText(R.string.default_audio_route_name).toString())
-                .setVolumeHandling(mAudioManager.isVolumeFixed()
-                        ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
-                        : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
-                .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
-                .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
-                .addFeature(FEATURE_LIVE_AUDIO)
-                .addFeature(FEATURE_LIVE_VIDEO)
-                .build();
-
-        AudioRoutesInfo newAudioRoutes = null;
-        try {
-            newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
-        } catch (RemoteException e) {
-        }
-        if (newAudioRoutes != null) {
-            // This will select the active BT route if there is one and the current
-            // selected route is the default system route, or if there is no selected
-            // route yet.
-            updateAudioRoutes(newAudioRoutes);
-        }
-    }
-
-    private void initializeSessionInfo() {
-        mBluetoothRoutes = mBtRouteProvider.getAllBluetoothRoutes();
-
-        MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder();
-        builder.addRoute(mDefaultRoute);
-        for (MediaRoute2Info route : mBluetoothRoutes) {
-            builder.addRoute(route);
-        }
-        setProviderState(builder.build());
-        mHandler.post(() -> notifyProviderState());
-
-        //TODO: clean up this
-        // This is required because it is not instantiated in the main thread and
-        // BluetoothRoutesUpdatedListener can be called before this function
-        synchronized (mLock) {
-            updateSessionInfosIfNeededLocked();
-        }
-    }
-
-    private void updateAudioRoutes(AudioRoutesInfo newRoutes) {
+    private void updateDefaultRoute(AudioRoutesInfo newRoutes) {
         int name = R.string.default_audio_route_name;
-        mCurAudioRoutesInfo.mainType = newRoutes.mainType;
-        if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0
-                || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
-            name = com.android.internal.R.string.default_audio_route_name_headphones;
-        } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
-            name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
-        } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
-            name = com.android.internal.R.string.default_audio_route_name_hdmi;
-        } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
-            name = com.android.internal.R.string.default_audio_route_name_usb;
+        if (newRoutes != null) {
+            mCurAudioRoutesInfo.mainType = newRoutes.mainType;
+            if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0
+                    || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
+                name = com.android.internal.R.string.default_audio_route_name_headphones;
+            } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
+                name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
+            } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
+                name = com.android.internal.R.string.default_audio_route_name_hdmi;
+            } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
+                name = com.android.internal.R.string.default_audio_route_name_usb;
+            }
         }
-
         mDefaultRoute = new MediaRoute2Info.Builder(
                 DEFAULT_ROUTE_ID, mContext.getResources().getText(name).toString())
                 .setVolumeHandling(mAudioManager.isVolumeFixed()
@@ -232,9 +194,20 @@
                 .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC))
                 .addFeature(FEATURE_LIVE_AUDIO)
                 .addFeature(FEATURE_LIVE_VIDEO)
+                .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED)
                 .build();
+        updateProviderState();
+    }
 
-        publishRoutes();
+    private void updateProviderState() {
+        MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder();
+        builder.addRoute(mDefaultRoute);
+        if (mBtRouteProvider != null) {
+            for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) {
+                builder.addRoute(route);
+            }
+        }
+        setProviderState(builder.build());
     }
 
     /**
@@ -246,21 +219,21 @@
         RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
                 SYSTEM_SESSION_ID, "" /* clientPackageName */)
                 .setSystemSession(true);
-        String activeBtDeviceAddress = mBtRouteProvider.getSelectedRouteId();
-        mSelectedRouteId = TextUtils.isEmpty(activeBtDeviceAddress) ? mDefaultRoute.getId()
-                : activeBtDeviceAddress;
-        builder.addSelectedRoute(mSelectedRouteId);
 
-        if (!TextUtils.isEmpty(activeBtDeviceAddress)) {
+        MediaRoute2Info selectedRoute = mBtRouteProvider.getSelectedRoute();
+        if (selectedRoute == null) {
+            selectedRoute = mDefaultRoute;
+        } else {
             builder.addTransferableRoute(mDefaultRoute.getId());
         }
+        mSelectedRouteId = selectedRoute.getId();
+        builder.addSelectedRoute(mSelectedRouteId);
 
-        for (MediaRoute2Info route : mBluetoothRoutes) {
-            if (!TextUtils.equals(mSelectedRouteId, route.getId())) {
-                builder.addTransferableRoute(route.getId());
-            }
+        for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) {
+            builder.addTransferableRoute(route.getId());
         }
 
+
         RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build();
         if (Objects.equals(oldSessionInfo, newSessionInfo)) {
             return false;
@@ -271,13 +244,9 @@
         }
     }
 
-    void publishRoutes() {
-        MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder();
-        builder.addRoute(mDefaultRoute);
-        for (MediaRoute2Info route : mBluetoothRoutes) {
-            builder.addRoute(route);
-        }
-        setAndNotifyProviderState(builder.build());
+    void publishProviderState() {
+        updateProviderState();
+        notifyProviderState();
     }
 
     void notifySessionInfoUpdated() {
@@ -306,24 +275,14 @@
                     AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0);
 
             if (newVolume != oldVolume) {
-                String activeBtDeviceAddress = mBtRouteProvider.getSelectedRouteId();
-                if (!TextUtils.isEmpty(activeBtDeviceAddress)) {
-                    for (int i = mBluetoothRoutes.size() - 1; i >= 0; i--) {
-                        MediaRoute2Info route = mBluetoothRoutes.get(i);
-                        if (TextUtils.equals(activeBtDeviceAddress, route.getId())) {
-                            mBluetoothRoutes.set(i,
-                                    new MediaRoute2Info.Builder(route)
-                                            .setVolume(newVolume)
-                                            .build());
-                            break;
-                        }
-                    }
-                } else {
+                if (TextUtils.equals(mDefaultRoute.getId(), mSelectedRouteId)) {
                     mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute)
                             .setVolume(newVolume)
                             .build();
+                } else {
+                    mBtRouteProvider.setSelectedRouteVolume(newVolume);
                 }
-                publishRoutes();
+                publishProviderState();
             }
         }
     }