Refactoring: Audio Routing Handler (Step 3)

This CL refactors connection and activation events to be handled in
the AudioRoutingHandler. This will remove the mLock and migrate the
variables guarded by the mLock into the handler.

It will also remove the priority of hearing aid devices so that they
are activated at the same level as other BT devices.

This CL refactors the connection events of hearing aid, and more CLs
will follow.

Bug: 299023147
Test: atest BluetoothInstrumentationTests
Change-Id: I60a21b601676294a2bd6eb27473286f37323517a
diff --git a/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java b/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java
index 42cf6e4..ae92fb1 100644
--- a/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/AudioRoutingManager.java
@@ -50,7 +50,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -131,17 +130,10 @@
                 case BluetoothProfile.A2DP:
                 case BluetoothProfile.HEADSET:
                 case BluetoothProfile.LE_AUDIO:
+                case BluetoothProfile.HEARING_AID:
                     mHandler.post(() -> mHandler.handleDeviceConnected(device, profile));
                     break;
-                case BluetoothProfile.HEARING_AID:
-                    mHandler.post(
-                            () -> {
-                                AudioRoutingHandler.AudioRoutingDevice arDevice =
-                                        mHandler.getAudioRoutingDevice(device);
-                                arDevice.connectedProfiles.add(profile);
-                                handleHearingAidConnected(device);
-                            });
-                    break;
+
                 case BluetoothProfile.HAP_CLIENT:
                     mHandler.post(
                             () -> {
@@ -157,16 +149,8 @@
                 case BluetoothProfile.A2DP:
                 case BluetoothProfile.HEADSET:
                 case BluetoothProfile.LE_AUDIO:
-                    mHandler.post(() -> mHandler.handleDeviceDisconnected(device, profile));
-                    break;
                 case BluetoothProfile.HEARING_AID:
-                    mHandler.post(
-                            () -> {
-                                AudioRoutingHandler.AudioRoutingDevice arDevice =
-                                        mHandler.getAudioRoutingDevice(device);
-                                arDevice.connectedProfiles.remove(profile);
-                                handleHearingAidDisconnected(device);
-                            });
+                    mHandler.post(() -> mHandler.handleDeviceDisconnected(device, profile));
                     break;
                 case BluetoothProfile.HAP_CLIENT:
                     mHandler.post(
@@ -194,7 +178,9 @@
                 mHandler.post(
                         () -> {
                             if (device != null) {
-                                mHandler.mActiveDevices.put(profile, Arrays.asList(device));
+                                ArrayList<BluetoothDevice> devices = new ArrayList<>();
+                                devices.add(device);
+                                mHandler.mActiveDevices.put(profile, devices);
                             } else {
                                 mHandler.mActiveDevices.remove(profile);
                             }
@@ -205,7 +191,9 @@
                 mHandler.post(
                         () -> {
                             if (device != null) {
-                                mHandler.mActiveDevices.put(profile, Arrays.asList(device));
+                                ArrayList<BluetoothDevice> devices = new ArrayList<>();
+                                devices.add(device);
+                                mHandler.mActiveDevices.put(profile, devices);
                             } else {
                                 mHandler.mActiveDevices.remove(profile);
                             }
@@ -216,7 +204,9 @@
                 mHandler.post(
                         () -> {
                             if (device != null) {
-                                mHandler.mActiveDevices.put(profile, Arrays.asList(device));
+                                ArrayList<BluetoothDevice> devices = new ArrayList<>();
+                                devices.add(device);
+                                mHandler.mActiveDevices.put(profile, devices);
                             } else {
                                 mHandler.mActiveDevices.remove(profile);
                             }
@@ -227,7 +217,9 @@
                 mHandler.post(
                         () -> {
                             if (device != null) {
-                                mHandler.mActiveDevices.put(profile, Arrays.asList(device));
+                                ArrayList<BluetoothDevice> devices = new ArrayList<>();
+                                devices.add(device);
+                                mHandler.mActiveDevices.put(profile, devices);
                             } else {
                                 mHandler.mActiveDevices.remove(profile);
                             }
@@ -246,27 +238,6 @@
         }
     }
 
-    private void handleHearingAidConnected(BluetoothDevice device) {
-        synchronized (mLock) {
-            if (DBG) {
-                Log.d(TAG, "handleHearingAidConnected: " + device);
-            }
-            if (mHearingAidConnectedDevices.contains(device)) {
-                if (DBG) {
-                    Log.d(TAG, "This device is already connected: " + device);
-                }
-                return;
-            }
-            mHearingAidConnectedDevices.add(device);
-        }
-        // New connected device: select it as active
-        if (setHearingAidActiveDevice(device)) {
-            setA2dpActiveDevice(null, true);
-            setHfpActiveDevice(null);
-            setLeAudioActiveDevice(null, true);
-        }
-    }
-
     private void handleHapConnected(BluetoothDevice device) {
         synchronized (mLock) {
             if (DBG) {
@@ -294,25 +265,6 @@
         }
     }
 
-    private void handleHearingAidDisconnected(BluetoothDevice device) {
-        synchronized (mLock) {
-            if (DBG) {
-                Log.d(
-                        TAG,
-                        "handleHearingAidDisconnected: "
-                                + device
-                                + ", mHearingAidActiveDevices="
-                                + mHearingAidActiveDevices);
-            }
-            mHearingAidConnectedDevices.remove(device);
-            if (mHearingAidActiveDevices.remove(device) && mHearingAidActiveDevices.isEmpty()) {
-                if (!setFallbackDeviceActiveLocked()) {
-                    setHearingAidActiveDevice(null, false);
-                }
-            }
-        }
-    }
-
     private void handleHapDisconnected(BluetoothDevice device) {
         synchronized (mLock) {
             if (DBG) {
@@ -740,7 +692,6 @@
             mHearingAidActiveDevices.clear();
             mHearingAidActiveDevices.addAll(hearingAidService.getConnectedPeerDevices(hiSyncId));
         }
-        mHandler.mActiveDevices.put(BluetoothProfile.HEARING_AID, Arrays.asList(device));
         return true;
     }
 
@@ -1094,6 +1045,7 @@
                     case BluetoothProfile.HEADSET -> mHfpConnectedDevices.add(device);
                     case BluetoothProfile.A2DP -> mA2dpConnectedDevices.add(device);
                     case BluetoothProfile.LE_AUDIO -> mLeAudioConnectedDevices.add(device);
+                    case BluetoothProfile.HEARING_AID -> mHearingAidConnectedDevices.add(device);
                 }
             }
             if (isWatch(device)) {
@@ -1132,6 +1084,7 @@
                     case BluetoothProfile.HEADSET -> mHfpConnectedDevices.remove(device);
                     case BluetoothProfile.A2DP -> mA2dpConnectedDevices.remove(device);
                     case BluetoothProfile.LE_AUDIO -> mLeAudioConnectedDevices.remove(device);
+                    case BluetoothProfile.HEARING_AID -> mHearingAidConnectedDevices.remove(device);
                 }
             }
             List<BluetoothDevice> activeDevices = mActiveDevices.get(profile);
@@ -1338,14 +1291,14 @@
 
             private boolean canActivateTogether(
                     int profile, BluetoothDevice device, List<BluetoothDevice> group) {
-                if (group == null || group.isEmpty()) {
+                if (device == null || group == null || group.isEmpty()) {
                     return false;
                 }
                 switch (profile) {
-                    // TODO: handle HAP_CLIENT and HEARING_AID
-                    case BluetoothProfile.LE_AUDIO:
+                    // TODO: handle HAP_CLIENT
+                    case BluetoothProfile.LE_AUDIO: {
                         final LeAudioService leAudioService = mFactory.getLeAudioService();
-                        if (leAudioService == null || device == null) {
+                        if (leAudioService == null) {
                             return false;
                         }
                         int groupId = leAudioService.getGroupId(device);
@@ -1353,6 +1306,20 @@
                                 && groupId == leAudioService.getGroupId(group.get(0))) {
                             return true;
                         }
+                        break;
+                    }
+                    case BluetoothProfile.HEARING_AID: {
+                        final HearingAidService hearingAidService = mFactory.getHearingAidService();
+                        if (hearingAidService == null) {
+                            return false;
+                        }
+                        long hiSyncId = hearingAidService.getHiSyncId(device);
+                        if (hiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID
+                                && hiSyncId == hearingAidService.getHiSyncId(group.get(0))) {
+                            return true;
+                        }
+                        break;
+                    }
                 }
                 return false;
             }
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/AudioRoutingManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/AudioRoutingManagerTest.java
index 042f559..e9258bc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/AudioRoutingManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/AudioRoutingManagerTest.java
@@ -87,7 +87,7 @@
     private ArrayList<BluetoothDevice> mDeviceConnectionStack;
     private BluetoothDevice mMostRecentDevice;
     private AudioRoutingManager mAudioRoutingManager;
-    private long mHearingAidHiSyncId = 1010;
+    private static final long HEARING_AID_HISYNC_ID = 1010;
 
     private static final int TIMEOUT_MS = 1_000;
     private static final int A2DP_HFP_SYNC_CONNECTION_TIMEOUT_MS =
@@ -156,8 +156,8 @@
 
         List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
         connectedHearingAidDevices.add(mHearingAidDevice);
-        when(mHearingAidService.getHiSyncId(mHearingAidDevice)).thenReturn(mHearingAidHiSyncId);
-        when(mHearingAidService.getConnectedPeerDevices(mHearingAidHiSyncId))
+        when(mHearingAidService.getHiSyncId(mHearingAidDevice)).thenReturn(HEARING_AID_HISYNC_ID);
+        when(mHearingAidService.getConnectedPeerDevices(HEARING_AID_HISYNC_ID))
                 .thenReturn(connectedHearingAidDevices);
     }
 
@@ -557,8 +557,9 @@
         List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
         connectedHearingAidDevices.add(mHearingAidDevice);
         connectedHearingAidDevices.add(mSecondaryAudioDevice);
-        when(mHearingAidService.getHiSyncId(mSecondaryAudioDevice)).thenReturn(mHearingAidHiSyncId);
-        when(mHearingAidService.getConnectedPeerDevices(mHearingAidHiSyncId))
+        when(mHearingAidService.getHiSyncId(mSecondaryAudioDevice))
+                .thenReturn(HEARING_AID_HISYNC_ID);
+        when(mHearingAidService.getConnectedPeerDevices(HEARING_AID_HISYNC_ID))
                 .thenReturn(connectedHearingAidDevices);
 
         hearingAidConnected(mHearingAidDevice);
@@ -867,8 +868,8 @@
         List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
         connectedHearingAidDevices.add(mSecondaryAudioDevice);
         when(mHearingAidService.getHiSyncId(mSecondaryAudioDevice))
-                .thenReturn(mHearingAidHiSyncId + 1);
-        when(mHearingAidService.getConnectedPeerDevices(mHearingAidHiSyncId + 1))
+                .thenReturn(HEARING_AID_HISYNC_ID + 1);
+        when(mHearingAidService.getConnectedPeerDevices(HEARING_AID_HISYNC_ID + 1))
                 .thenReturn(connectedHearingAidDevices);
 
         hearingAidConnected(mSecondaryAudioDevice);