Merge "LeAudio: Set communication device when LeAudio is used" am: 59790a5b1d

Original change: https://android-review.googlesource.com/c/platform/packages/services/Telecomm/+/1927389

Change-Id: If1860a81a9e4c328e6bda20705644a75a211279c
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index a1a181c..50f75b1 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -23,6 +23,8 @@
 import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioDeviceInfo;
 import android.telecom.Log;
 import android.util.LocalLog;
 
@@ -142,8 +144,10 @@
     private BluetoothHeadset mBluetoothHeadset;
     private BluetoothHearingAid mBluetoothHearingAid;
     private BluetoothLeAudio mBluetoothLeAudioService;
+    private boolean mLeAudioSetAsCommunicationDevice = false;
     private BluetoothDevice mBluetoothHearingAidActiveDeviceCache;
     private BluetoothAdapter mBluetoothAdapter;
+    private AudioManager mAudioManager;
 
     public BluetoothDeviceManager(Context context, BluetoothAdapter bluetoothAdapter) {
         if (bluetoothAdapter != null) {
@@ -154,6 +158,7 @@
                     BluetoothProfile.HEARING_AID);
             bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
                     BluetoothProfile.LE_AUDIO);
+            mAudioManager = context.getSystemService(AudioManager.class);
         }
     }
 
@@ -377,6 +382,7 @@
                 }
             }
             disconnectSco();
+            clearLeAudioCommunicationDevice();
         }
     }
 
@@ -388,6 +394,67 @@
         }
     }
 
+    public boolean isLeAudioCommunicationDevice() {
+        return mLeAudioSetAsCommunicationDevice;
+    }
+
+    public void clearLeAudioCommunicationDevice() {
+        if (!mLeAudioSetAsCommunicationDevice) {
+            return;
+        }
+        mLeAudioSetAsCommunicationDevice = false;
+
+        if (mAudioManager == null) {
+            Log.i(this, " mAudioManager is null");
+            return;
+        }
+        mAudioManager.clearCommunicationDevice();
+    }
+
+    public boolean setLeAudioCommunicationDevice() {
+        Log.i(this, "setLeAudioCommunicationDevice");
+
+        if (mLeAudioSetAsCommunicationDevice) {
+            Log.i(this, "setLeAudioCommunicationDevice already set");
+            return true;
+        }
+
+        if (mAudioManager == null) {
+            Log.w(this, " mAudioManager is null");
+            return false;
+        }
+
+        AudioDeviceInfo bleHeadset = null;
+        List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices();
+        if (devices.size() == 0) {
+            Log.w(this, " No communication devices available.");
+            return false;
+        }
+
+        for (AudioDeviceInfo device : devices) {
+            Log.i(this, " Available device type:  " + device.getType());
+            if (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET) {
+                bleHeadset = device;
+                break;
+            }
+        }
+
+        if (bleHeadset == null) {
+            Log.w(this, " No bleHeadset device available");
+            return false;
+        }
+
+        // Turn BLE_OUT_HEADSET ON.
+        boolean result = mAudioManager.setCommunicationDevice(bleHeadset);
+        if (!result) {
+            Log.w(this, " Could not set bleHeadset device");
+        } else {
+            Log.i(this, " bleHeadset device set");
+            mLeAudioSetAsCommunicationDevice = true;
+        }
+        return result;
+    }
+
     // Connect audio to the bluetooth device at address, checking to see whether it's
     // le audio, hearing aid or a HFP device, and using the proper BT API.
     public boolean connectAudio(String address) {
@@ -397,8 +464,11 @@
                 return false;
             }
             BluetoothDevice device = mLeAudioDevicesByAddress.get(address);
-            return mBluetoothAdapter.setActiveDevice(
-                    device, BluetoothAdapter.ACTIVE_DEVICE_ALL);
+            if (mBluetoothAdapter.setActiveDevice(
+                    device, BluetoothAdapter.ACTIVE_DEVICE_ALL)) {
+                return setLeAudioCommunicationDevice();
+            }
+            return false;
         } else if (mHearingAidDevicesByAddress.containsKey(address)) {
             if (mBluetoothHearingAid == null) {
                 Log.w(this, "Attempting to turn on audio when the hearing aid service is null");
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index dba2c36..44a60c4 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -606,6 +606,9 @@
         boolean wasActiveDevicePresent = hasBtActiveDevice();
         if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) {
             mLeAudioActiveDeviceCache = device;
+            if (device == null) {
+                mDeviceManager.clearLeAudioCommunicationDevice();
+            }
         } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID) {
             mHearingAidActiveDeviceCache = device;
         } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET) {
@@ -774,11 +777,13 @@
         }
 
         if (bluetoothLeAudio != null) {
-            for (BluetoothDevice device : bluetoothLeAudio.getActiveDevices()) {
-                if (device != null) {
-                    leAudioActiveDevice = device;
-                    activeDevices++;
-                    break;
+            if (mDeviceManager.isLeAudioCommunicationDevice()) {
+                for (BluetoothDevice device : bluetoothLeAudio.getActiveDevices()) {
+                    if (device != null) {
+                        leAudioActiveDevice = device;
+                        activeDevices++;
+                        break;
+                    }
                 }
             }
         }
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index cfd3b37..7bd0d0b 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -24,6 +24,8 @@
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Intent;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -44,12 +46,15 @@
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
 
 @RunWith(JUnit4.class)
 public class BluetoothDeviceManagerTest extends TelecomTestCase {
@@ -58,6 +63,7 @@
     @Mock BluetoothAdapter mAdapter;
     @Mock BluetoothHearingAid mBluetoothHearingAid;
     @Mock BluetoothLeAudio mBluetoothLeAudio;
+    @Mock AudioManager mockAudioManager;
 
     BluetoothDeviceManager mBluetoothDeviceManager;
     BluetoothProfile.ServiceListener serviceListenerUnderTest;
@@ -91,6 +97,8 @@
         mBluetoothDeviceManager = new BluetoothDeviceManager(mContext, mAdapter);
         mBluetoothDeviceManager.setBluetoothRouteManager(mRouteManager);
 
+        mockAudioManager = mContext.getSystemService(AudioManager.class);
+
         ArgumentCaptor<BluetoothProfile.ServiceListener> serviceCaptor =
                 ArgumentCaptor.forClass(BluetoothProfile.ServiceListener.class);
         verify(mAdapter).getProfileProxy(eq(mContext),
@@ -368,6 +376,17 @@
                 buildGroupNodeStatusChangedIntent(1, device5, BluetoothLeAudio.GROUP_NODE_ADDED));
         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
+
+        AudioDeviceInfo mockAudioDeviceInfo = mock(AudioDeviceInfo.class);
+        when(mockAudioDeviceInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_BLE_HEADSET);
+        List<AudioDeviceInfo> devices = new ArrayList<>();
+        devices.add(mockAudioDeviceInfo);
+
+        when(mockAudioManager.getAvailableCommunicationDevices())
+                        .thenReturn(devices);
+        when(mockAudioManager.setCommunicationDevice(mockAudioDeviceInfo))
+                       .thenReturn(true);
+
         mBluetoothDeviceManager.connectAudio(device5.getAddress());
         verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
         verify(mBluetoothHeadset, never()).connectAudio();
@@ -375,8 +394,7 @@
                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
 
         mBluetoothDeviceManager.disconnectAudio();
-        // TODO: Add a test here to verify that LE audio is de-selected
-        // verify(mAdapter).removeActiveDevice(BluetoothAdapter.ACTIVE_DEVICE_ALL);
+        verify(mockAudioManager).clearCommunicationDevice();
     }
 
     @SmallTest
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 2463847..94c4321 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -53,6 +53,7 @@
 import android.hardware.SensorPrivacyManager;
 import android.location.Country;
 import android.location.CountryDetector;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.os.Bundle;
 import android.os.Handler;
@@ -489,6 +490,11 @@
         public int getStreamVolume(int streamValueUnused) {
             return mAudioStreamValue;
         }
+
+        @Override
+        public boolean setCommunicationDevice(AudioDeviceInfo device) {
+            return true;
+        }
     }
 
     private static final String PACKAGE_NAME = "com.android.server.telecom.tests";