Loading src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java +72 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import android.bluetooth.BluetoothHearingAid; 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; Loading Loading @@ -142,8 +144,10 @@ public class BluetoothDeviceManager { 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) { Loading @@ -154,6 +158,7 @@ public class BluetoothDeviceManager { BluetoothProfile.HEARING_AID); bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener, BluetoothProfile.LE_AUDIO); mAudioManager = context.getSystemService(AudioManager.class); } } Loading Loading @@ -377,6 +382,7 @@ public class BluetoothDeviceManager { } } disconnectSco(); clearLeAudioCommunicationDevice(); } } Loading @@ -388,6 +394,67 @@ public class BluetoothDeviceManager { } } 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) { Loading @@ -397,8 +464,11 @@ public class BluetoothDeviceManager { 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"); Loading src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java +10 −5 Original line number Diff line number Diff line Loading @@ -606,6 +606,9 @@ public class BluetoothRouteManager extends StateMachine { 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) { Loading Loading @@ -774,6 +777,7 @@ public class BluetoothRouteManager extends StateMachine { } if (bluetoothLeAudio != null) { if (mDeviceManager.isLeAudioCommunicationDevice()) { for (BluetoothDevice device : bluetoothLeAudio.getActiveDevices()) { if (device != null) { leAudioActiveDevice = device; Loading @@ -782,6 +786,7 @@ public class BluetoothRouteManager extends StateMachine { } } } } // Return the active device reported by either HFP, hearing aid or le audio. If more than // one is reporting active devices, go with the most recent one as reported by the receiver. Loading tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java +20 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.bluetooth.BluetoothLeAudio; 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; Loading @@ -44,12 +46,15 @@ import static org.junit.Assert.assertNull; 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 { Loading @@ -58,6 +63,7 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { @Mock BluetoothAdapter mAdapter; @Mock BluetoothHearingAid mBluetoothHearingAid; @Mock BluetoothLeAudio mBluetoothLeAudio; @Mock AudioManager mockAudioManager; BluetoothDeviceManager mBluetoothDeviceManager; BluetoothProfile.ServiceListener serviceListenerUnderTest; Loading Loading @@ -91,6 +97,8 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { 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), Loading Loading @@ -368,6 +376,17 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { 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(); Loading @@ -375,8 +394,7 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { 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 Loading tests/src/com/android/server/telecom/tests/ComponentContextFixture.java +6 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.content.res.Resources; 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; Loading Loading @@ -489,6 +490,11 @@ public class ComponentContextFixture implements TestFixture<Context> { 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"; Loading Loading
src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java +72 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import android.bluetooth.BluetoothHearingAid; 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; Loading Loading @@ -142,8 +144,10 @@ public class BluetoothDeviceManager { 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) { Loading @@ -154,6 +158,7 @@ public class BluetoothDeviceManager { BluetoothProfile.HEARING_AID); bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener, BluetoothProfile.LE_AUDIO); mAudioManager = context.getSystemService(AudioManager.class); } } Loading Loading @@ -377,6 +382,7 @@ public class BluetoothDeviceManager { } } disconnectSco(); clearLeAudioCommunicationDevice(); } } Loading @@ -388,6 +394,67 @@ public class BluetoothDeviceManager { } } 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) { Loading @@ -397,8 +464,11 @@ public class BluetoothDeviceManager { 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"); Loading
src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java +10 −5 Original line number Diff line number Diff line Loading @@ -606,6 +606,9 @@ public class BluetoothRouteManager extends StateMachine { 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) { Loading Loading @@ -774,6 +777,7 @@ public class BluetoothRouteManager extends StateMachine { } if (bluetoothLeAudio != null) { if (mDeviceManager.isLeAudioCommunicationDevice()) { for (BluetoothDevice device : bluetoothLeAudio.getActiveDevices()) { if (device != null) { leAudioActiveDevice = device; Loading @@ -782,6 +786,7 @@ public class BluetoothRouteManager extends StateMachine { } } } } // Return the active device reported by either HFP, hearing aid or le audio. If more than // one is reporting active devices, go with the most recent one as reported by the receiver. Loading
tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java +20 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.bluetooth.BluetoothLeAudio; 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; Loading @@ -44,12 +46,15 @@ import static org.junit.Assert.assertNull; 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 { Loading @@ -58,6 +63,7 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { @Mock BluetoothAdapter mAdapter; @Mock BluetoothHearingAid mBluetoothHearingAid; @Mock BluetoothLeAudio mBluetoothLeAudio; @Mock AudioManager mockAudioManager; BluetoothDeviceManager mBluetoothDeviceManager; BluetoothProfile.ServiceListener serviceListenerUnderTest; Loading Loading @@ -91,6 +97,8 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { 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), Loading Loading @@ -368,6 +376,17 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { 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(); Loading @@ -375,8 +394,7 @@ public class BluetoothDeviceManagerTest extends TelecomTestCase { 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 Loading
tests/src/com/android/server/telecom/tests/ComponentContextFixture.java +6 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.content.res.Resources; 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; Loading Loading @@ -489,6 +490,11 @@ public class ComponentContextFixture implements TestFixture<Context> { 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"; Loading