Merge "Add bluetooth as a supported route when we actually eneted a bluetooth route." into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 28c85e1..c6f5e9c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -318,18 +318,6 @@
android:exported="false"
android:process=":ui"/>
- <service android:name=".components.BluetoothPhoneService"
- android:singleUser="true"
- android:process="system"
- android:exported="true">
- <intent-filter>
- <action android:name="android.bluetooth.IBluetoothHeadsetPhone"/>
- </intent-filter>
- <intent-filter>
- <action android:name="android.bluetooth.IBluetoothLeCallControlCallback" />
- </intent-filter>
- </service>
-
<service android:name=".components.TelecomService"
android:singleUser="true"
android:process="system"
diff --git a/flags/Android.bp b/flags/Android.bp
index 4f43a52..af8b683 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -34,6 +34,7 @@
"telecom_callaudiomodestatemachine_flags.aconfig",
"telecom_calllog_flags.aconfig",
"telecom_resolve_hidden_dependencies.aconfig",
+ "telecom_bluetoothroutemanager_flags.aconfig",
],
}
diff --git a/flags/telecom_bluetoothroutemanager_flags.aconfig b/flags/telecom_bluetoothroutemanager_flags.aconfig
new file mode 100644
index 0000000..ddd8571
--- /dev/null
+++ b/flags/telecom_bluetoothroutemanager_flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.telecom.flags"
+
+flag {
+ name: "use_actual_address_to_enter_connecting_state"
+ namespace: "telecom"
+ description: "Fix bugs that may add bluetooth device with null address."
+ bug: "306113816"
+}
+
diff --git a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
index 4af60f0..5fc2414 100644
--- a/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
+++ b/src/com/android/server/telecom/CallAudioCommunicationDeviceTracker.java
@@ -159,6 +159,11 @@
if (audioDeviceType == AudioDeviceInfo.TYPE_BLE_HEADSET) {
mBluetoothRouteManager.onAudioOn(mBtAudioDevice);
}
+ } else if (Flags.communicationDeviceProtectedByLock()) {
+ // Clear BT device if it's still stored. Handles race condition for when a non-BT
+ // device is set for communication shortly after a BT (LE) device is set for
+ // communication but the selection hasn't been cleared yet.
+ mBtAudioDevice = null;
}
}
if (Flags.communicationDeviceProtectedByLock()) {
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index c11ee6e..07b048d 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -525,8 +525,6 @@
.validateAccountIconUserBoundary(icon, callingUserHandle));
}
- if (ConnectionServiceWrapper.this.mIsRemoteConnectionService) return;
-
if (parcelableConference.getConnectElapsedTimeMillis() != 0
&& mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
@@ -941,9 +939,6 @@
public void addExistingConnection(String callId, ParcelableConnection connection,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, "CSW.aEC", mPackageAbbreviation);
-
- if (ConnectionServiceWrapper.this.mIsRemoteConnectionService) return;
-
UserHandle userHandle = Binder.getCallingUserHandle();
// Check that the Calling Package matches PhoneAccountHandle's Component Package
PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount();
@@ -1358,7 +1353,6 @@
private final CallsManager mCallsManager;
private final AppOpsManager mAppOpsManager;
private final Context mContext;
- public boolean mIsRemoteConnectionService = false;
private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener;
@@ -2548,13 +2542,13 @@
private void logIncoming(String msg, Object... params) {
// Keep these as debug; the incoming logging is traced on a package level through the
// session logging.
- Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]:"
- + " isRCS = " + this.mIsRemoteConnectionService + ": " + msg, params);
+ Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: "
+ + msg, params);
}
private void logOutgoing(String msg, Object... params) {
- Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]:"
- + " isRCS = " + this.mIsRemoteConnectionService + ": " + msg, params);
+ Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: "
+ + msg, params);
}
private void queryRemoteConnectionServices(final UserHandle userHandle,
@@ -2581,7 +2575,6 @@
ConnectionServiceWrapper service = mConnectionServiceRepository.getService(
handle.getComponentName(), handle.getUserHandle());
if (service != null && service != this) {
- service.mIsRemoteConnectionService = true;
simServices.add(service);
} else {
// This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 6cf6ae4..8124f60 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -45,6 +45,7 @@
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -134,7 +135,8 @@
@Override
public void enter() {
BluetoothDevice erroneouslyConnectedDevice = getBluetoothAudioConnectedDevice();
- if (erroneouslyConnectedDevice != null) {
+ if (erroneouslyConnectedDevice != null &&
+ !erroneouslyConnectedDevice.equals(mHearingAidActiveDeviceCache)) {
Log.w(LOG_TAG, "Entering AudioOff state but device %s appears to be connected. " +
"Switching to audio-on state for that device.", erroneouslyConnectedDevice);
// change this to just transition to the new audio on state
@@ -252,6 +254,27 @@
SomeArgs args = (SomeArgs) msg.obj;
String address = (String) args.arg2;
boolean switchingBtDevices = !Objects.equals(mDeviceAddress, address);
+
+ if (switchingBtDevices == true) { // check if it is an hearing aid pair
+ BluetoothAdapter bluetoothAdapter = mDeviceManager.getBluetoothAdapter();
+ if (bluetoothAdapter != null) {
+ List<BluetoothDevice> activeHearingAids =
+ bluetoothAdapter.getActiveDevices(BluetoothProfile.HEARING_AID);
+ for (BluetoothDevice hearingAid : activeHearingAids) {
+ if (hearingAid != null) {
+ String hearingAidAddress = hearingAid.getAddress();
+ if (hearingAidAddress != null) {
+ if (hearingAidAddress.equals(address) ||
+ hearingAidAddress.equals(mDeviceAddress)) {
+ switchingBtDevices = false;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ }
try {
switch (msg.what) {
case NEW_DEVICE_CONNECTED:
@@ -393,8 +416,13 @@
String actualAddress = connectBtAudio(address,
true /* switchingBtDevices*/);
if (actualAddress != null) {
- transitionTo(getConnectingStateForAddress(address,
- "AudioConnected/CONNECT_BT"));
+ if (mFeatureFlags.useActualAddressToEnterConnectingState()) {
+ transitionTo(getConnectingStateForAddress(actualAddress,
+ "AudioConnected/CONNECT_BT"));
+ } else {
+ transitionTo(getConnectingStateForAddress(address,
+ "AudioConnected/CONNECT_BT"));
+ }
} else {
Log.w(LOG_TAG, "Tried to connect to %s but failed" +
" to connect to any BT device.", (String) args.arg2);
@@ -863,12 +891,18 @@
: mDeviceManager.isHearingAidSetAsCommunicationDevice();
if (bluetoothHearingAid != null) {
if (isHearingAidSetForCommunication) {
- for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
- BluetoothProfile.HEARING_AID)) {
- if (device != null) {
- hearingAidActiveDevice = device;
- activeDevices++;
- break;
+ List<BluetoothDevice> hearingAidsActiveDevices = bluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEARING_AID);
+ if (hearingAidsActiveDevices.contains(mHearingAidActiveDeviceCache)) {
+ hearingAidActiveDevice = mHearingAidActiveDeviceCache;
+ activeDevices++;
+ } else {
+ for (BluetoothDevice device : hearingAidsActiveDevices) {
+ if (device != null) {
+ hearingAidActiveDevice = device;
+ activeDevices++;
+ break;
+ }
}
}
}
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
index 3ed96a0..e1ef08a 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -37,6 +38,8 @@
import android.telecom.Log;
import android.test.suitebuilder.annotation.SmallTest;
+import android.media.AudioDeviceInfo;
+
import com.android.internal.os.SomeArgs;
import com.android.server.telecom.CallAudioCommunicationDeviceTracker;
import com.android.server.telecom.TelecomSystem;
@@ -62,7 +65,14 @@
static final BluetoothDevice DEVICE1 = makeBluetoothDevice("00:00:00:00:00:01");
static final BluetoothDevice DEVICE2 = makeBluetoothDevice("00:00:00:00:00:02");
static final BluetoothDevice DEVICE3 = makeBluetoothDevice("00:00:00:00:00:03");
- static final BluetoothDevice HEARING_AID_DEVICE = makeBluetoothDevice("00:00:00:00:00:04");
+ static final BluetoothDevice HEARING_AID_DEVICE_LEFT = makeBluetoothDevice("CA:FE:DE:CA:00:01");
+ static final BluetoothDevice HEARING_AID_DEVICE_RIGHT =
+ makeBluetoothDevice("CA:FE:DE:CA:00:02");
+ // See HearingAidService#getActiveDevices
+ // Note: It is really important that the left HA is the first one. The left HA is always
+ // in the first index (0) and the right one in the second index (1).
+ static final BluetoothDevice[] HEARING_AIDS =
+ new BluetoothDevice[]{HEARING_AID_DEVICE_LEFT, HEARING_AID_DEVICE_RIGHT};
@Mock private BluetoothAdapter mBluetoothAdapter;
@Mock private BluetoothDeviceManager mDeviceManager;
@@ -87,6 +97,59 @@
@SmallTest
@Test
+ public void testConnectLeftHearingAidWhenLeftIsActive() {
+ BluetoothRouteManager sm = setupStateMachine(
+ BluetoothRouteManager.AUDIO_OFF_STATE_NAME, HEARING_AID_DEVICE_LEFT);
+ sm.onActiveDeviceChanged(HEARING_AID_DEVICE_LEFT,
+ BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
+ when(mDeviceManager.connectAudio(anyString(), anyBoolean())).thenReturn(true);
+ when(mDeviceManager.isHearingAidSetAsCommunicationDevice()).thenReturn(true);
+
+ setupConnectedDevices(null, HEARING_AIDS, null, null, HEARING_AIDS, null);
+ when(mBluetoothHeadset.getAudioState(nullable(BluetoothDevice.class)))
+ .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+
+ executeRoutingAction(sm,
+ BluetoothRouteManager.NEW_DEVICE_CONNECTED, HEARING_AID_DEVICE_LEFT.getAddress());
+
+ executeRoutingAction(sm,
+ BluetoothRouteManager.CONNECT_BT, HEARING_AID_DEVICE_LEFT.getAddress());
+
+ assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
+ + ":" + HEARING_AID_DEVICE_LEFT.getAddress(), sm.getCurrentState().getName());
+
+ sm.quitNow();
+ }
+
+ @SmallTest
+ @Test
+ public void testConnectRightHearingAidWhenLeftIsActive() {
+ BluetoothRouteManager sm = setupStateMachine(
+ BluetoothRouteManager.AUDIO_OFF_STATE_NAME, HEARING_AID_DEVICE_RIGHT);
+ sm.onActiveDeviceChanged(HEARING_AID_DEVICE_LEFT,
+ BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
+ when(mDeviceManager.connectAudio(anyString(), anyBoolean())).thenReturn(true);
+ when(mDeviceManager.isHearingAidSetAsCommunicationDevice()).thenReturn(true);
+
+
+ setupConnectedDevices(null, HEARING_AIDS, null, null, HEARING_AIDS, null);
+ when(mBluetoothHeadset.getAudioState(nullable(BluetoothDevice.class)))
+ .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+
+ executeRoutingAction(sm,
+ BluetoothRouteManager.NEW_DEVICE_CONNECTED, HEARING_AID_DEVICE_LEFT.getAddress());
+
+ executeRoutingAction(sm,
+ BluetoothRouteManager.CONNECT_BT, HEARING_AID_DEVICE_LEFT.getAddress());
+
+ assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
+ + ":" + HEARING_AID_DEVICE_LEFT.getAddress(), sm.getCurrentState().getName());
+
+ sm.quitNow();
+ }
+
+ @SmallTest
+ @Test
public void testConnectBtRetryWhileNotConnected() {
BluetoothRouteManager sm = setupStateMachine(
BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null);
@@ -113,15 +176,15 @@
BluetoothRouteManager sm = setupStateMachine(
BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
setupConnectedDevices(new BluetoothDevice[]{DEVICE1},
- new BluetoothDevice[]{HEARING_AID_DEVICE}, new BluetoothDevice[]{DEVICE2},
- DEVICE1, HEARING_AID_DEVICE, DEVICE2);
+ HEARING_AIDS, new BluetoothDevice[]{DEVICE2},
+ DEVICE1, HEARING_AIDS, DEVICE2);
sm.onActiveDeviceChanged(DEVICE1, BluetoothDeviceManager.DEVICE_TYPE_HEADSET);
sm.onActiveDeviceChanged(DEVICE2, BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO);
- sm.onActiveDeviceChanged(HEARING_AID_DEVICE,
+ sm.onActiveDeviceChanged(HEARING_AID_DEVICE_LEFT,
BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress());
- verifyConnectionAttempt(HEARING_AID_DEVICE, 0);
+ verifyConnectionAttempt(HEARING_AID_DEVICE_LEFT, 0);
verifyConnectionAttempt(DEVICE1, 0);
verifyConnectionAttempt(DEVICE2, 0);
assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
@@ -176,15 +239,42 @@
@Test
public void testSkipInactiveBtDeviceWhenEvaluateActualState() {
BluetoothRouteManager sm = setupStateMachine(
- BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, HEARING_AID_DEVICE);
- setupConnectedDevices(null, new BluetoothDevice[]{HEARING_AID_DEVICE},
- null, null, HEARING_AID_DEVICE, null);
+ BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, HEARING_AID_DEVICE_LEFT);
+ setupConnectedDevices(null, HEARING_AIDS,
+ null, null, HEARING_AIDS, null);
executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST,
- HEARING_AID_DEVICE.getAddress());
+ HEARING_AID_DEVICE_LEFT.getAddress());
assertEquals(BluetoothRouteManager.AUDIO_OFF_STATE_NAME, sm.getCurrentState().getName());
sm.quitNow();
}
+ @SmallTest
+ @Test
+ public void testConnectBtWithoutAddress() {
+ when(mFeatureFlags.useActualAddressToEnterConnectingState()).thenReturn(true);
+ BluetoothRouteManager sm = setupStateMachine(
+ BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
+ setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null, null,
+ null);
+ when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
+ nullable(ContentResolver.class))).thenReturn(0L);
+ when(mBluetoothHeadset.connectAudio()).thenReturn(BluetoothStatusCodes.ERROR_UNKNOWN);
+ executeRoutingAction(sm, BluetoothRouteManager.CONNECT_BT, null);
+ // Wait 3 times: the first connection attempt is accounted for in executeRoutingAction,
+ // so wait twice for the retry attempt, again to make sure there are only three attempts,
+ // and once more for good luck.
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+ verifyConnectionAttempt(DEVICE1, 1);
+ assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
+ + ":" + DEVICE1.getAddress(),
+ sm.getCurrentState().getName());
+ sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT);
+ sm.quitNow();
+ }
+
private BluetoothRouteManager setupStateMachine(String initialState,
BluetoothDevice initialDevice) {
resetMocks();
@@ -200,10 +290,11 @@
private void setupConnectedDevices(BluetoothDevice[] hfpDevices,
BluetoothDevice[] hearingAidDevices, BluetoothDevice[] leAudioDevices,
- BluetoothDevice hfpActiveDevice, BluetoothDevice hearingAidActiveDevice,
+ BluetoothDevice hfpActiveDevice, BluetoothDevice[] hearingAidActiveDevices,
BluetoothDevice leAudioDevice) {
if (hfpDevices == null) hfpDevices = new BluetoothDevice[]{};
if (hearingAidDevices == null) hearingAidDevices = new BluetoothDevice[]{};
+ if (hearingAidActiveDevices == null) hearingAidActiveDevices = new BluetoothDevice[]{};
if (leAudioDevice == null) leAudioDevices = new BluetoothDevice[]{};
when(mDeviceManager.getNumConnectedDevices()).thenReturn(
@@ -222,7 +313,7 @@
when(mBluetoothHearingAid.getConnectedDevices())
.thenReturn(Arrays.asList(hearingAidDevices));
when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
- .thenReturn(Arrays.asList(hearingAidActiveDevice, null));
+ .thenReturn(Arrays.asList(hearingAidActiveDevices));
when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
.thenReturn(Arrays.asList(leAudioDevice, null));
}