diff --git a/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java
new file mode 100644
index 0000000000000..0d81611ddd583
--- /dev/null
+++ b/services/core/java/com/android/server/media/AudioPoliciesBluetoothRouteController.java
@@ -0,0 +1,579 @@
+/*
+ * Copyright 2020 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 static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO;
+import static android.bluetooth.BluetoothAdapter.STATE_CONNECTED;
+import static android.bluetooth.BluetoothAdapter.STATE_DISCONNECTED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.MediaRoute2Info;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Controls bluetooth routes and provides selected route override.
+ *
+ *
The controller offers similar functionality to {@link LegacyBluetoothRouteController} but does
+ * not support routes selection logic. Instead, relies on external clients to make a decision
+ * about currently selected route.
+ *
+ *
Selected route override should be used by {@link AudioManager} which is aware of Audio
+ * Policies.
+ */
+class AudioPoliciesBluetoothRouteController implements BluetoothRouteController {
+ private static final String TAG = "APBtRouteController";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
+ private static final String LE_AUDIO_ROUTE_ID_PREFIX = "LE_AUDIO_";
+
+ // Maps hardware address to BluetoothRouteInfo
+ private final Map mBluetoothRoutes = new HashMap<>();
+ private final List mActiveRoutes = new ArrayList<>();
+
+ // Route type -> volume map
+ private final SparseIntArray mVolumeMap = new SparseIntArray();
+
+ private final Context mContext;
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final BluetoothRoutesUpdatedListener mListener;
+ private final AudioManager mAudioManager;
+ private final BluetoothProfileListener mProfileListener = new BluetoothProfileListener();
+
+ private final AdapterStateChangedReceiver mAdapterStateChangedReceiver =
+ new AdapterStateChangedReceiver();
+ private final DeviceStateChangedReceiver mDeviceStateChangedReceiver =
+ new DeviceStateChangedReceiver();
+
+ private BluetoothA2dp mA2dpProfile;
+ private BluetoothHearingAid mHearingAidProfile;
+ private BluetoothLeAudio mLeAudioProfile;
+
+ AudioPoliciesBluetoothRouteController(Context context, BluetoothAdapter btAdapter,
+ BluetoothRoutesUpdatedListener listener) {
+ mContext = context;
+ mBluetoothAdapter = btAdapter;
+ mListener = listener;
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ buildBluetoothRoutes();
+ }
+
+ /**
+ * Registers listener to bluetooth status changes as the provided user.
+ *
+ * The registered receiver listens to {@link BluetoothA2dp#ACTION_ACTIVE_DEVICE_CHANGED} and
+ * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED } events for {@link BluetoothProfile#A2DP},
+ * {@link BluetoothProfile#HEARING_AID}, and {@link BluetoothProfile#LE_AUDIO} bluetooth profiles.
+ *
+ * @param user {@code UserHandle} as which receiver is registered
+ */
+ @Override
+ public void start(UserHandle user) {
+ mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
+ mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);
+ mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.LE_AUDIO);
+
+ IntentFilter adapterStateChangedIntentFilter = new IntentFilter();
+
+ adapterStateChangedIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ mContext.registerReceiverAsUser(mAdapterStateChangedReceiver, user,
+ adapterStateChangedIntentFilter, null, null);
+
+ IntentFilter deviceStateChangedIntentFilter = new IntentFilter();
+
+ deviceStateChangedIntentFilter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
+ deviceStateChangedIntentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+ deviceStateChangedIntentFilter.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
+ deviceStateChangedIntentFilter.addAction(
+ BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+ deviceStateChangedIntentFilter.addAction(
+ BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
+ deviceStateChangedIntentFilter.addAction(
+ BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
+
+ mContext.registerReceiverAsUser(mDeviceStateChangedReceiver, user,
+ deviceStateChangedIntentFilter, null, null);
+ }
+
+ @Override
+ public void stop() {
+ mContext.unregisterReceiver(mAdapterStateChangedReceiver);
+ mContext.unregisterReceiver(mDeviceStateChangedReceiver);
+ }
+
+ /**
+ * Transfers to a given bluetooth route.
+ * The dedicated BT device with the route would be activated.
+ *
+ * @param routeId the id of the Bluetooth device. {@code null} denotes to clear the use of
+ * BT routes.
+ */
+ @Override
+ public void transferTo(@Nullable String routeId) {
+ if (routeId == null) {
+ clearActiveDevices();
+ return;
+ }
+
+ BluetoothRouteInfo btRouteInfo = findBluetoothRouteWithRouteId(routeId);
+
+ if (btRouteInfo == null) {
+ Slog.w(TAG, "transferTo: Unknown route. ID=" + routeId);
+ return;
+ }
+
+ if (mBluetoothAdapter != null) {
+ mBluetoothAdapter.setActiveDevice(btRouteInfo.mBtDevice, ACTIVE_DEVICE_AUDIO);
+ }
+ }
+
+ private BluetoothRouteInfo findBluetoothRouteWithRouteId(String routeId) {
+ if (routeId == null) {
+ return null;
+ }
+ for (BluetoothRouteInfo btRouteInfo : mBluetoothRoutes.values()) {
+ if (TextUtils.equals(btRouteInfo.mRoute.getId(), routeId)) {
+ return btRouteInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Clears the active device for all known profiles.
+ */
+ private void clearActiveDevices() {
+ if (mBluetoothAdapter != null) {
+ mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_AUDIO);
+ }
+ }
+
+ private void buildBluetoothRoutes() {
+ mBluetoothRoutes.clear();
+ Set bondedDevices = mBluetoothAdapter.getBondedDevices();
+ if (bondedDevices != null) {
+ for (BluetoothDevice device : bondedDevices) {
+ if (device.isConnected()) {
+ BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
+ if (newBtRoute.mConnectedProfiles.size() > 0) {
+ mBluetoothRoutes.put(device.getAddress(), newBtRoute);
+ }
+ }
+ }
+ }
+ }
+
+ @Nullable
+ @Override
+ public MediaRoute2Info getSelectedRoute() {
+ // For now, active routes can be multiple only when a pair of hearing aid devices is active.
+ // Let the first active device represent them.
+ return (mActiveRoutes.isEmpty() ? null : mActiveRoutes.get(0).mRoute);
+ }
+
+ @NonNull
+ @Override
+ public List getTransferableRoutes() {
+ List routes = getAllBluetoothRoutes();
+ for (BluetoothRouteInfo btRoute : mActiveRoutes) {
+ routes.remove(btRoute.mRoute);
+ }
+ return routes;
+ }
+
+ @NonNull
+ @Override
+ public List getAllBluetoothRoutes() {
+ List routes = new ArrayList<>();
+ List routeIds = new ArrayList<>();
+
+ MediaRoute2Info selectedRoute = getSelectedRoute();
+ if (selectedRoute != null) {
+ routes.add(selectedRoute);
+ routeIds.add(selectedRoute.getId());
+ }
+
+ for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
+ // A pair of hearing aid devices or having the same hardware address
+ if (routeIds.contains(btRoute.mRoute.getId())) {
+ continue;
+ }
+ routes.add(btRoute.mRoute);
+ routeIds.add(btRoute.mRoute.getId());
+ }
+ return routes;
+ }
+
+ /**
+ * Updates the volume for {@link AudioManager#getDevicesForStream(int) devices}.
+ *
+ * @return true if devices can be handled by the provider.
+ */
+ @Override
+ public boolean updateVolumeForDevices(int devices, int volume) {
+ int routeType;
+ if ((devices & (AudioSystem.DEVICE_OUT_HEARING_AID)) != 0) {
+ routeType = MediaRoute2Info.TYPE_HEARING_AID;
+ } else if ((devices & (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP
+ | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
+ | AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
+ routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+ } else if ((devices & (AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0) {
+ routeType = MediaRoute2Info.TYPE_BLE_HEADSET;
+ } else {
+ return false;
+ }
+ mVolumeMap.put(routeType, volume);
+
+ boolean shouldNotify = false;
+ for (BluetoothRouteInfo btRoute : mActiveRoutes) {
+ if (btRoute.mRoute.getType() != routeType) {
+ continue;
+ }
+ btRoute.mRoute = new MediaRoute2Info.Builder(btRoute.mRoute)
+ .setVolume(volume)
+ .build();
+ shouldNotify = true;
+ }
+ if (shouldNotify) {
+ notifyBluetoothRoutesUpdated();
+ }
+ return true;
+ }
+
+ private void notifyBluetoothRoutesUpdated() {
+ if (mListener != null) {
+ mListener.onBluetoothRoutesUpdated(getAllBluetoothRoutes());
+ }
+ }
+
+ private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) {
+ BluetoothRouteInfo newBtRoute = new BluetoothRouteInfo();
+ newBtRoute.mBtDevice = device;
+
+ String routeId = device.getAddress();
+ String deviceName = device.getName();
+ if (TextUtils.isEmpty(deviceName)) {
+ deviceName = mContext.getResources().getText(R.string.unknownName).toString();
+ }
+ int type = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+ newBtRoute.mConnectedProfiles = new SparseBooleanArray();
+ if (mA2dpProfile != null && mA2dpProfile.getConnectedDevices().contains(device)) {
+ newBtRoute.mConnectedProfiles.put(BluetoothProfile.A2DP, true);
+ }
+ if (mHearingAidProfile != null
+ && mHearingAidProfile.getConnectedDevices().contains(device)) {
+ newBtRoute.mConnectedProfiles.put(BluetoothProfile.HEARING_AID, true);
+ // Intentionally assign the same ID for a pair of devices to publish only one of them.
+ routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device);
+ type = MediaRoute2Info.TYPE_HEARING_AID;
+ }
+ if (mLeAudioProfile != null
+ && mLeAudioProfile.getConnectedDevices().contains(device)) {
+ newBtRoute.mConnectedProfiles.put(BluetoothProfile.LE_AUDIO, true);
+ routeId = LE_AUDIO_ROUTE_ID_PREFIX + mLeAudioProfile.getGroupId(device);
+ type = MediaRoute2Info.TYPE_BLE_HEADSET;
+ }
+
+ // Current volume will be set when connected.
+ newBtRoute.mRoute = new MediaRoute2Info.Builder(routeId, deviceName)
+ .addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
+ .addFeature(MediaRoute2Info.FEATURE_LOCAL_PLAYBACK)
+ .setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
+ .setDescription(mContext.getResources().getText(
+ R.string.bluetooth_a2dp_audio_route_name).toString())
+ .setType(type)
+ .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+ .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
+ .setAddress(device.getAddress())
+ .build();
+ return newBtRoute;
+ }
+
+ private void setRouteConnectionState(@NonNull BluetoothRouteInfo btRoute,
+ @MediaRoute2Info.ConnectionState int state) {
+ if (btRoute == null) {
+ Slog.w(TAG, "setRouteConnectionState: route shouldn't be null");
+ return;
+ }
+ if (btRoute.mRoute.getConnectionState() == state) {
+ return;
+ }
+
+ MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(btRoute.mRoute)
+ .setConnectionState(state);
+ builder.setType(btRoute.getRouteType());
+
+ if (state == MediaRoute2Info.CONNECTION_STATE_CONNECTED) {
+ builder.setVolume(mVolumeMap.get(btRoute.getRouteType(), 0));
+ }
+ btRoute.mRoute = builder.build();
+ }
+
+ private void addActiveRoute(BluetoothRouteInfo btRoute) {
+ if (btRoute == null) {
+ Slog.w(TAG, "addActiveRoute: btRoute is null");
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Adding active route: " + btRoute.mRoute);
+ }
+ if (mActiveRoutes.contains(btRoute)) {
+ Slog.w(TAG, "addActiveRoute: btRoute is already added.");
+ return;
+ }
+ setRouteConnectionState(btRoute, STATE_CONNECTED);
+ mActiveRoutes.add(btRoute);
+ }
+
+ private void removeActiveRoute(BluetoothRouteInfo btRoute) {
+ if (DEBUG) {
+ Log.d(TAG, "Removing active route: " + btRoute.mRoute);
+ }
+ if (mActiveRoutes.remove(btRoute)) {
+ setRouteConnectionState(btRoute, STATE_DISCONNECTED);
+ }
+ }
+
+ private void clearActiveRoutesWithType(int type) {
+ if (DEBUG) {
+ Log.d(TAG, "Clearing active routes with type. type=" + type);
+ }
+ Iterator iter = mActiveRoutes.iterator();
+ while (iter.hasNext()) {
+ BluetoothRouteInfo btRoute = iter.next();
+ if (btRoute.mRoute.getType() == type) {
+ iter.remove();
+ setRouteConnectionState(btRoute, STATE_DISCONNECTED);
+ }
+ }
+ }
+
+ private void addActiveDevices(BluetoothDevice device) {
+ // Let the given device be the first active device
+ BluetoothRouteInfo activeBtRoute = mBluetoothRoutes.get(device.getAddress());
+ // This could happen if ACTION_ACTIVE_DEVICE_CHANGED is sent before
+ // ACTION_CONNECTION_STATE_CHANGED is sent.
+ if (activeBtRoute == null) {
+ activeBtRoute = createBluetoothRoute(device);
+ mBluetoothRoutes.put(device.getAddress(), activeBtRoute);
+ }
+ addActiveRoute(activeBtRoute);
+
+ // A bluetooth route with the same route ID should be added.
+ for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
+ if (TextUtils.equals(btRoute.mRoute.getId(), activeBtRoute.mRoute.getId())
+ && !TextUtils.equals(btRoute.mBtDevice.getAddress(),
+ activeBtRoute.mBtDevice.getAddress())) {
+ addActiveRoute(btRoute);
+ }
+ }
+ }
+
+ private static class BluetoothRouteInfo {
+ private BluetoothDevice mBtDevice;
+ private MediaRoute2Info mRoute;
+ private SparseBooleanArray mConnectedProfiles;
+
+ @MediaRoute2Info.Type
+ int getRouteType() {
+ // Let hearing aid profile have a priority.
+ if (mConnectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
+ return MediaRoute2Info.TYPE_HEARING_AID;
+ }
+
+ if (mConnectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) {
+ return MediaRoute2Info.TYPE_BLE_HEADSET;
+ }
+
+ return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+ }
+ }
+
+ // These callbacks run on the main thread.
+ private final class BluetoothProfileListener implements BluetoothProfile.ServiceListener {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ List activeDevices;
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ mA2dpProfile = (BluetoothA2dp) proxy;
+ // It may contain null.
+ activeDevices = mBluetoothAdapter.getActiveDevices(BluetoothProfile.A2DP);
+ break;
+ case BluetoothProfile.HEARING_AID:
+ mHearingAidProfile = (BluetoothHearingAid) proxy;
+ activeDevices = mBluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEARING_AID);
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudioProfile = (BluetoothLeAudio) proxy;
+ activeDevices = mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
+ break;
+ default:
+ return;
+ }
+ for (BluetoothDevice device : proxy.getConnectedDevices()) {
+ BluetoothRouteInfo btRoute = mBluetoothRoutes.get(device.getAddress());
+ if (btRoute == null) {
+ btRoute = createBluetoothRoute(device);
+ mBluetoothRoutes.put(device.getAddress(), btRoute);
+ }
+ if (activeDevices.contains(device)) {
+ addActiveRoute(btRoute);
+ }
+ }
+ notifyBluetoothRoutesUpdated();
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ mA2dpProfile = null;
+ break;
+ case BluetoothProfile.HEARING_AID:
+ mHearingAidProfile = null;
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudioProfile = null;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+ private class AdapterStateChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ if (state == BluetoothAdapter.STATE_OFF
+ || state == BluetoothAdapter.STATE_TURNING_OFF) {
+ mBluetoothRoutes.clear();
+ notifyBluetoothRoutesUpdated();
+ } else if (state == BluetoothAdapter.STATE_ON) {
+ buildBluetoothRoutes();
+ if (!mBluetoothRoutes.isEmpty()) {
+ notifyBluetoothRoutesUpdated();
+ }
+ }
+ }
+ }
+
+ private class DeviceStateChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ BluetoothDevice device = intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE, BluetoothDevice.class);
+
+ switch (intent.getAction()) {
+ case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
+ clearActiveRoutesWithType(MediaRoute2Info.TYPE_BLUETOOTH_A2DP);
+ if (device != null) {
+ addActiveRoute(mBluetoothRoutes.get(device.getAddress()));
+ }
+ notifyBluetoothRoutesUpdated();
+ break;
+ case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
+ clearActiveRoutesWithType(MediaRoute2Info.TYPE_HEARING_AID);
+ if (device != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Setting active hearing aid devices. device=" + device);
+ }
+
+ addActiveDevices(device);
+ }
+ notifyBluetoothRoutesUpdated();
+ break;
+ case BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED:
+ clearActiveRoutesWithType(MediaRoute2Info.TYPE_BLE_HEADSET);
+ if (device != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Setting active le audio devices. device=" + device);
+ }
+
+ addActiveDevices(device);
+ }
+ notifyBluetoothRoutesUpdated();
+ break;
+ case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
+ handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
+ break;
+ case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
+ handleConnectionStateChanged(BluetoothProfile.HEARING_AID, intent, device);
+ break;
+ case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
+ handleConnectionStateChanged(BluetoothProfile.LE_AUDIO, intent, device);
+ break;
+ }
+ }
+
+ private void handleConnectionStateChanged(int profile, Intent intent,
+ BluetoothDevice device) {
+ int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
+ BluetoothRouteInfo btRoute = mBluetoothRoutes.get(device.getAddress());
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ if (btRoute == null) {
+ btRoute = createBluetoothRoute(device);
+ if (btRoute.mConnectedProfiles.size() > 0) {
+ mBluetoothRoutes.put(device.getAddress(), btRoute);
+ notifyBluetoothRoutesUpdated();
+ }
+ } else {
+ btRoute.mConnectedProfiles.put(profile, true);
+ }
+ } else if (state == BluetoothProfile.STATE_DISCONNECTING
+ || state == BluetoothProfile.STATE_DISCONNECTED) {
+ if (btRoute != null) {
+ btRoute.mConnectedProfiles.delete(profile);
+ if (btRoute.mConnectedProfiles.size() == 0) {
+ removeActiveRoute(mBluetoothRoutes.remove(device.getAddress()));
+ notifyBluetoothRoutesUpdated();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java b/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java
index 7979d2a3fb3bd..64a76eab4d01c 100644
--- a/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java
+++ b/services/core/java/com/android/server/media/LegacyBluetoothRouteController.java
@@ -52,7 +52,7 @@ import java.util.Map;
import java.util.Set;
class LegacyBluetoothRouteController implements BluetoothRouteController {
- private static final String TAG = "BTRouteProvider";
+ private static final String TAG = "LBtRouteProvider";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";