summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--OWNERS4
-rw-r--r--android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp10
-rw-r--r--android/app/src/com/android/bluetooth/bass_client/BassClientService.java87
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java9
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterProperties.java1
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterService.java3
-rw-r--r--android/app/src/com/android/bluetooth/btservice/RemoteDevices.java4
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattService.java23
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java297
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java1148
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapActivityTest.java7
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceTest.java7
-rw-r--r--android/pandora/mmi2grpc/pyrightconfig.json14
-rw-r--r--android/pandora/server/src/Hap.kt15
-rw-r--r--android/pandora/test/hap_test.py5
-rw-r--r--android/pandora/test/pyrightconfig.json19
-rw-r--r--flags/framework.aconfig8
-rw-r--r--framework/api/system-current.txt2
-rw-r--r--framework/java/android/bluetooth/BluetoothDevice.java1
-rw-r--r--pyrightconfig.json34
-rw-r--r--service/src/com/android/server/bluetooth/BluetoothManagerService.java8
-rw-r--r--sysprop/Android.bp1
-rw-r--r--sysprop/BUILD.gn1
-rw-r--r--sysprop/exported_include/android_bluetooth_sysprop.h1
-rw-r--r--sysprop/gap.sysprop12
-rw-r--r--system/bta/dm/bta_dm_disc.cc13
-rw-r--r--system/bta/gatt/bta_gattc_act.cc7
-rw-r--r--system/bta/gatt/bta_gattc_utils.cc5
-rw-r--r--system/bta/has/has_client.cc23
-rw-r--r--system/bta/ras/ras_client.cc7
-rw-r--r--system/bta/ras/ras_server.cc10
-rw-r--r--system/btif/src/bluetooth.cc4
-rw-r--r--system/btif/src/btif_a2dp_source.cc8
-rw-r--r--system/conf/interop_database.conf3
-rw-r--r--system/device/test/interop_test.cc3
-rw-r--r--system/gd/hci/BUILD.gn1
-rw-r--r--system/gd/hci/controller.cc12
-rw-r--r--system/gd/hci/distance_measurement_manager.cc6
-rw-r--r--system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs69
-rw-r--r--system/gd/rust/topshim/src/btif.rs4
-rw-r--r--system/include/hardware/bluetooth.h3
-rw-r--r--system/main/Android.bp1
-rw-r--r--system/pdl/hci/hci_packets.pdl7
-rw-r--r--system/stack/btm/btm_sco_hfp_hal_linux.cc7
-rw-r--r--system/stack/btm/btm_sec.cc16
-rw-r--r--system/test/headless/headless.cc2
-rw-r--r--system/test/mock/mock_stack_btm_interface.cc5
-rw-r--r--system/test/suite/adapter/adapter_unittest.cc2
-rw-r--r--system/test/suite/adapter/bluetooth_test.cc2
49 files changed, 983 insertions, 958 deletions
diff --git a/OWNERS b/OWNERS
index f3eb92e010..4df6c9967e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -8,8 +8,8 @@ okamil@google.com #{LAST_RESORT_SUGGESTION}
# Per-file ownership
-# Build files / test_config / presubmit / preupload
-per-file PREUPLOAD.cfg,TEST_MAPPING,*.bp,*.xml=file:/OWNERS_build
+# Build files / test_config / presubmit / preupload / linter file
+per-file PREUPLOAD.cfg,TEST_MAPPING,*.bp,*.xml,pyrightconfig.json=file:/OWNERS_build
# ChromeOS team owns Linux build files
# - build.py is used for Linux build
diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
index b4cf5eb326..050fc7b1a5 100644
--- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -1020,7 +1020,7 @@ int hal_util_load_bt_library(const bt_interface_t** interface) {
}
static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest, jboolean isCommonCriteriaMode,
- int configCompareResult, jboolean isAtvDevice, jstring userDataDirectory) {
+ int configCompareResult, jboolean isAtvDevice) {
std::unique_lock<std::shared_timed_mutex> lock(jniObjMutex);
log::verbose("");
@@ -1035,14 +1035,10 @@ static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest, jboolean isCo
return JNI_FALSE;
}
- const char* user_data_directory = env->GetStringUTFChars(userDataDirectory, NULL);
-
int ret =
sBluetoothInterface->init(&sBluetoothCallbacks, isGuest == JNI_TRUE ? 1 : 0,
isCommonCriteriaMode == JNI_TRUE ? 1 : 0, configCompareResult,
- nullptr, isAtvDevice == JNI_TRUE ? 1 : 0, user_data_directory);
-
- env->ReleaseStringUTFChars(userDataDirectory, user_data_directory);
+ isAtvDevice == JNI_TRUE ? 1 : 0);
if (ret != BT_STATUS_SUCCESS) {
log::error("Error while setting the callbacks: {}", ret);
@@ -2225,7 +2221,7 @@ static jboolean restoreFilterAcceptListNative(JNIEnv* /* env */, jobject /* obj
int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
const JNINativeMethod methods[] = {
- {"initNative", "(ZZIZLjava/lang/String;)Z", reinterpret_cast<void*>(initNative)},
+ {"initNative", "(ZZIZ)Z", reinterpret_cast<void*>(initNative)},
{"cleanupNative", "()V", reinterpret_cast<void*>(cleanupNative)},
{"enableNative", "()Z", reinterpret_cast<void*>(enableNative)},
{"disableNative", "()Z", reinterpret_cast<void*>(disableNative)},
diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
index 63d6bb23cf..2f95d06703 100644
--- a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
+++ b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
@@ -27,6 +27,7 @@ import static com.android.bluetooth.flags.Flags.leaudioBroadcastAssistantPeriphe
import static com.android.bluetooth.flags.Flags.leaudioBroadcastExtractPeriodicScannerFromStateMachine;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastMonitorSourceSyncStatus;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastResyncHelper;
+import static com.android.bluetooth.flags.Flags.leaudioSortScansToSyncByFails;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
@@ -158,6 +159,7 @@ public class BassClientService extends ProfileService {
new HashMap<>();
private final PriorityQueue<SourceSyncRequest> mSourceSyncRequestsQueue =
new PriorityQueue<>(sSourceSyncRequestComparator);
+ private final Map<Integer, Integer> mSyncFailureCounter = new HashMap<>();
private final Map<Integer, Integer> mBisDiscoveryCounterMap = new HashMap<>();
private final List<AddSourceData> mPendingSourcesToAdd = new ArrayList<>();
@@ -280,12 +282,14 @@ public class BassClientService extends ProfileService {
}
private static class SourceSyncRequest {
- private ScanResult mScanResult;
- private boolean mHasPriority;
+ private final ScanResult mScanResult;
+ private final boolean mHasPriority;
+ private final int mSyncFailureCounter;
- SourceSyncRequest(ScanResult scanResult, boolean hasPriority) {
+ SourceSyncRequest(ScanResult scanResult, boolean hasPriority, int syncFailureCounter) {
this.mScanResult = scanResult;
this.mHasPriority = hasPriority;
+ this.mSyncFailureCounter = syncFailureCounter;
}
public ScanResult getScanResult() {
@@ -300,6 +304,10 @@ public class BassClientService extends ProfileService {
return mHasPriority;
}
+ public int getFailsCounter() {
+ return mSyncFailureCounter;
+ }
+
@Override
public String toString() {
return "SourceSyncRequest{"
@@ -307,6 +315,8 @@ public class BassClientService extends ProfileService {
+ mScanResult
+ ", mHasPriority="
+ mHasPriority
+ + ", mSyncFailureCounter="
+ + mSyncFailureCounter
+ '}';
}
}
@@ -319,6 +329,9 @@ public class BassClientService extends ProfileService {
return -1;
} else if (!ssr1.hasPriority() && ssr2.hasPriority()) {
return 1;
+ } else if (leaudioSortScansToSyncByFails()
+ && (ssr1.getFailsCounter() != ssr2.getFailsCounter())) {
+ return Integer.compare(ssr1.getFailsCounter(), ssr2.getFailsCounter());
} else {
return Integer.compare(ssr2.getRssi(), ssr1.getRssi());
}
@@ -1046,9 +1059,8 @@ public class BassClientService extends ProfileService {
if (isPlaying) {
stopBigMonitoring(broadcastId, false);
} else if (!mPausedBroadcastIds.containsKey(broadcastId)) {
- ScanResult scanRes = getCachedBroadcast(broadcastId);
- if (scanRes != null) {
- addSelectSourceRequest(scanRes, true);
+ if (mCachedBroadcasts.containsKey(broadcastId)) {
+ addSelectSourceRequest(broadcastId, true);
mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNKNOWN);
logPausedBroadcastsAndSinks();
mHandler.removeMessages(MESSAGE_BIG_CHECK_START);
@@ -1842,11 +1854,11 @@ public class BassClientService extends ProfileService {
"Broadcast Source Found: Broadcast ID: " + broadcastId);
if (broadcastId != BassConstants.INVALID_BROADCAST_ID
- && mCachedBroadcasts.get(broadcastId) == null) {
+ && !mCachedBroadcasts.containsKey(broadcastId)) {
log("selectBroadcastSource: broadcastId " + broadcastId);
mCachedBroadcasts.put(broadcastId, result);
if (leaudioBroadcastExtractPeriodicScannerFromStateMachine()) {
- addSelectSourceRequest(result, false);
+ addSelectSourceRequest(broadcastId, false);
} else {
synchronized (mStateMachines) {
for (BassClientStateMachine sm :
@@ -1866,15 +1878,13 @@ public class BassClientService extends ProfileService {
informConnectedDeviceAboutScanOffloadStop();
}
};
+ mSyncFailureCounter.clear();
mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
if (leaudioBroadcastResyncHelper()) {
// Sync to the broadcasts already synced with sinks
Set<Integer> syncedBroadcasts = getExternalBroadcastsActiveOnSinks();
for (int syncedBroadcast : syncedBroadcasts) {
- ScanResult scanRes = getCachedBroadcast(syncedBroadcast);
- if (scanRes != null) {
- addSelectSourceRequest(scanRes, true);
- }
+ addSelectSourceRequest(syncedBroadcast, true);
}
}
// when starting scan, clear the previously cached broadcast scan results
@@ -1972,10 +1982,7 @@ public class BassClientService extends ProfileService {
Integer broadcastId = entry.getKey();
PauseType pauseType = entry.getValue();
if (pauseType != PauseType.HOST_INTENTIONAL) {
- ScanResult scanRes = getCachedBroadcast(broadcastId);
- if (scanRes != null) {
- addSelectSourceRequest(scanRes, true);
- }
+ addSelectSourceRequest(broadcastId, true);
}
}
}
@@ -1985,6 +1992,7 @@ public class BassClientService extends ProfileService {
private void clearAllSyncData() {
log("clearAllSyncData");
mSourceSyncRequestsQueue.clear();
+ mSyncFailureCounter.clear();
mPendingSourcesToAdd.clear();
cancelActiveSync(null);
@@ -2106,6 +2114,10 @@ public class BassClientService extends ProfileService {
}
}
stopBigMonitoring(broadcastId, false);
+ synchronized (mSourceSyncRequestsQueue) {
+ int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1;
+ mSyncFailureCounter.put(broadcastId, failsCounter);
+ }
synchronized (mSearchScanCallbackLock) {
// Clear from cache to make possible sync again (only during active searching)
if (mSearchScanCallback != null) {
@@ -2180,6 +2192,10 @@ public class BassClientService extends ProfileService {
mCallbacks.notifySourceLost(broadcastId);
}
stopBigMonitoring(broadcastId, false);
+ synchronized (mSourceSyncRequestsQueue) {
+ int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1;
+ mSyncFailureCounter.put(broadcastId, failsCounter);
+ }
}
clearAllDataForSyncHandle(syncHandle);
// Clear from cache to make possible sync again (only during active searching)
@@ -2464,30 +2480,35 @@ public class BassClientService extends ProfileService {
return broadcastName;
}
- void addSelectSourceRequest(ScanResult scanRes, boolean hasPriority) {
+ void addSelectSourceRequest(int broadcastId, boolean hasPriority) {
sEventLogger.logd(
TAG,
- "Add Select Broadcast Source, result: "
- + scanRes
+ "Add Select Broadcast Source, broadcastId: "
+ + broadcastId
+ ", hasPriority: "
+ hasPriority);
- if (scanRes == null) {
- Log.e(TAG, "addSelectSourceRequest: Error bad parameters: scanRes cannot be null");
- return;
- }
+ ScanResult scanRes = getCachedBroadcast(broadcastId);
+ if (scanRes != null) {
+ ScanRecord scanRecord = scanRes.getScanRecord();
+ if (scanRecord == null) {
+ log("addSelectSourceRequest: ScanRecord empty");
+ return;
+ }
- ScanRecord scanRecord = scanRes.getScanRecord();
- if (scanRecord == null) {
- log("addSelectSourceRequest: ScanRecord empty");
- return;
- }
+ synchronized (mSourceSyncRequestsQueue) {
+ if (!mSyncFailureCounter.containsKey(broadcastId)) {
+ mSyncFailureCounter.put(broadcastId, 0);
+ }
+ mSourceSyncRequestsQueue.add(
+ new SourceSyncRequest(
+ scanRes, hasPriority, mSyncFailureCounter.get(broadcastId)));
+ }
- synchronized (mSourceSyncRequestsQueue) {
- mSourceSyncRequestsQueue.add(new SourceSyncRequest(scanRes, hasPriority));
+ handleSelectSourceRequest();
+ } else {
+ log("addSelectSourceRequest: ScanResult empty");
}
-
- handleSelectSourceRequest();
}
@SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/350563786 - Fix BASS annotation
@@ -2732,7 +2753,7 @@ public class BassClientService extends ProfileService {
mPendingSourcesToAdd.add(
new AddSourceData(sink, sourceMetadata, isGroupOp));
if (!alreadyAdded) {
- addSelectSourceRequest(getCachedBroadcast(broadcastId), true);
+ addSelectSourceRequest(broadcastId, true);
}
}
} else {
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java b/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java
index 87cd3536a4..4a5bb81267 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterNativeInterface.java
@@ -64,15 +64,13 @@ public class AdapterNativeInterface {
boolean startRestricted,
boolean isCommonCriteriaMode,
int configCompareResult,
- boolean isAtvDevice,
- String userDataDirectory) {
+ boolean isAtvDevice) {
mJniCallbacks = new JniCallbacks(service, adapterProperties);
return initNative(
startRestricted,
isCommonCriteriaMode,
configCompareResult,
- isAtvDevice,
- userDataDirectory);
+ isAtvDevice);
}
void cleanup() {
@@ -295,8 +293,7 @@ public class AdapterNativeInterface {
boolean startRestricted,
boolean isCommonCriteriaMode,
int configCompareResult,
- boolean isAtvDevice,
- String userDataDirectory);
+ boolean isAtvDevice);
private native void cleanupNative();
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java
index 448c9aa855..728bad66cf 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -977,6 +977,7 @@ class AdapterProperties {
mName = name;
if (Flags.getNameAndAddressAsCallback()) {
mService.updateAdapterName(mName);
+ break;
}
intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, mName);
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
index 19c8aee207..563950078d 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
@@ -700,8 +700,7 @@ public class AdapterService extends Service {
mUserManager.isGuestUser(),
isCommonCriteriaMode,
configCompareResult,
- isAtvDevice,
- getApplicationInfo().dataDir);
+ isAtvDevice);
mNativeAvailable = true;
// Load the name and address
mNativeInterface.getAdapterProperty(AbstractionLayer.BT_PROPERTY_BDADDR);
diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
index a2693764b8..c48e8b8e3c 100644
--- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -1381,10 +1381,6 @@ public class RemoteDevices {
Log.i(TAG, "keyMissingCallback device: " + bluetoothDevice);
if (getBondState(bluetoothDevice) == BluetoothDevice.BOND_BONDED) {
- if (!Flags.keyMissingBroadcast()) {
- Log.d(TAG, "flag not set - don't send key missing broadcast");
- return;
- }
Intent intent =
new Intent(BluetoothDevice.ACTION_KEY_MISSING)
.putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice)
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java
index 9015774554..1f7593fa2c 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattService.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattService.java
@@ -145,7 +145,7 @@ public class GattService extends ProfileService {
private static final Integer GATT_MTU_MAX = 517;
private static final Map<String, Integer> EARLY_MTU_EXCHANGE_PACKAGES =
- Map.of("com.teslamotors.tesla", GATT_MTU_MAX);
+ Map.of("com.teslamotors", GATT_MTU_MAX);
@VisibleForTesting static final int GATT_CLIENT_LIMIT_PER_APP = 32;
@@ -2161,14 +2161,19 @@ public class GattService extends ProfileService {
// Some applications expect MTU to be exchanged immediately on connections
String packageName = attributionSource.getPackageName();
- if (packageName != null && EARLY_MTU_EXCHANGE_PACKAGES.containsKey(packageName)) {
- preferredMtu = EARLY_MTU_EXCHANGE_PACKAGES.get(packageName);
- Log.i(
- TAG,
- "Early MTU exchange preference ("
- + preferredMtu
- + ") requested for "
- + packageName);
+ if (packageName != null) {
+ for (Map.Entry<String, Integer> entry : EARLY_MTU_EXCHANGE_PACKAGES.entrySet()) {
+ if (packageName.contains(entry.getKey())) {
+ preferredMtu = entry.getValue();
+ Log.i(
+ TAG,
+ "Early MTU exchange preference ("
+ + preferredMtu
+ + ") requested for "
+ + packageName);
+ break;
+ }
+ }
}
mNativeInterface.gattClientConnect(
diff --git a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java
index b48c278e57..3ba383a656 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java
@@ -2377,35 +2377,11 @@ public class BassClientServiceTest {
@Test
@EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void testSelectSource_withSameBroadcastId() {
- byte[] scanRecord = getScanRecord(TEST_BROADCAST_ID);
-
- ScanResult scanResult1 =
- new ScanResult(
- mSourceDevice,
- 0,
- 0,
- 0,
- 0,
- 0,
- TEST_RSSI,
- 0,
- ScanRecord.parseFromBytes(scanRecord),
- 0);
- ScanResult scanResult2 =
- new ScanResult(
- mSourceDevice2,
- 0,
- 0,
- 0,
- 0,
- 0,
- TEST_RSSI,
- 0,
- ScanRecord.parseFromBytes(scanRecord),
- 0);
+ prepareConnectedDeviceGroup();
+ startSearchingForSources();
// First selectSource
- mBassClientService.addSelectSourceRequest(scanResult1, false);
+ onScanResult(mSourceDevice, TEST_BROADCAST_ID);
mInOrderMethodProxy
.verify(mMethodProxy)
.periodicAdvertisingManagerRegisterSync(
@@ -2414,7 +2390,7 @@ public class BassClientServiceTest {
onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE);
// Second selectSource with the same broadcast id
- mBassClientService.addSelectSourceRequest(scanResult2, false);
+ onScanResult(mSourceDevice2, TEST_BROADCAST_ID);
mInOrderMethodProxy
.verify(mMethodProxy, never())
.periodicAdvertisingManagerRegisterSync(
@@ -2491,7 +2467,9 @@ public class BassClientServiceTest {
ScanRecord.parseFromBytes(scanRecord),
0);
- mBassClientService.addSelectSourceRequest(scanResult, false);
+ prepareConnectedDeviceGroup();
+ startSearchingForSources();
+ mCallbackCaptor.getValue().onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
verify(mMethodProxy, never())
.periodicAdvertisingManagerRegisterSync(
any(), any(), anyInt(), anyInt(), any(), any());
@@ -2591,7 +2569,9 @@ public class BassClientServiceTest {
ScanRecord.parseFromBytes(scanRecord),
0);
- mBassClientService.addSelectSourceRequest(scanResult, false);
+ prepareConnectedDeviceGroup();
+ startSearchingForSources();
+ mCallbackCaptor.getValue().onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
verify(mMethodProxy)
.periodicAdvertisingManagerRegisterSync(
any(), any(), anyInt(), anyInt(), any(), any());
@@ -2667,7 +2647,9 @@ public class BassClientServiceTest {
ScanRecord.parseFromBytes(scanRecord),
0);
- mBassClientService.addSelectSourceRequest(scanResult, false);
+ prepareConnectedDeviceGroup();
+ startSearchingForSources();
+ mCallbackCaptor.getValue().onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
verify(mMethodProxy)
.periodicAdvertisingManagerRegisterSync(
any(), any(), anyInt(), anyInt(), any(), any());
@@ -3318,7 +3300,7 @@ public class BassClientServiceTest {
@Test
@EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
- public void testSelectSource_orderOfSyncRegistering() {
+ public void testSelectSource_orderOfSyncRegisteringByPriorityAndRssi() {
final BluetoothDevice device1 =
mBluetoothAdapter.getRemoteLeDevice(
"00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM);
@@ -3441,20 +3423,42 @@ public class BassClientServiceTest {
ScanRecord.parseFromBytes(scanRecord7),
0);
+ prepareConnectedDeviceGroup();
+ startSearchingForSources();
+
// Added and executed immidiatelly as no other in queue
- mBassClientService.addSelectSourceRequest(scanResult1, false);
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
// Added to queue with worst rssi
- mBassClientService.addSelectSourceRequest(scanResult2, false);
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult2);
// Added to queue with best rssi
- mBassClientService.addSelectSourceRequest(scanResult3, false);
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult3);
// Added to queue with medium rssi
- mBassClientService.addSelectSourceRequest(scanResult4, false);
- // Added to queue with priority and worst rssi
- mBassClientService.addSelectSourceRequest(scanResult5, true);
- // Added to queue with priority and best rssi
- mBassClientService.addSelectSourceRequest(scanResult6, true);
- // Added to queue with priority and medium rssi
- mBassClientService.addSelectSourceRequest(scanResult7, true);
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult4);
+ // Added to queue with worst rssi (increase priority after all)
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult5);
+ // Added to queue with best rssi (increase priority after all)
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult6);
+ // Added to queue with medium rssi (increase priority after all)
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult7);
+
+ // Increase priority of last 3 of them
+ mBassClientService.addSelectSourceRequest(broadcastId5, true);
+ mBassClientService.addSelectSourceRequest(broadcastId6, true);
+ mBassClientService.addSelectSourceRequest(broadcastId7, true);
ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class);
mInOrderMethodProxy
@@ -3556,6 +3560,215 @@ public class BassClientServiceTest {
}
@Test
+ @EnableFlags({
+ Flags.FLAG_LEAUDIO_SORT_SCANS_TO_SYNC_BY_FAILS,
+ Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE
+ })
+ public void testSelectSource_orderOfSyncRegisteringByRssiAndFailsCounter() {
+ final BluetoothDevice device1 =
+ mBluetoothAdapter.getRemoteLeDevice(
+ "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM);
+ final BluetoothDevice device2 =
+ mBluetoothAdapter.getRemoteLeDevice(
+ "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM);
+ final BluetoothDevice device3 =
+ mBluetoothAdapter.getRemoteLeDevice(
+ "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM);
+ final int broadcastId1 = 1111;
+ final int broadcastId2 = 2222;
+ final int broadcastId3 = 3333;
+
+ byte[] scanRecord1 = getScanRecord(broadcastId1);
+ byte[] scanRecord2 = getScanRecord(broadcastId2);
+ byte[] scanRecord3 = getScanRecord(broadcastId3);
+
+ ScanResult scanResult1 =
+ new ScanResult(
+ device1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ TEST_RSSI + 10,
+ 0,
+ ScanRecord.parseFromBytes(scanRecord1),
+ 0);
+ ScanResult scanResult2 =
+ new ScanResult(
+ device2,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ TEST_RSSI + 9,
+ 0,
+ ScanRecord.parseFromBytes(scanRecord2),
+ 0);
+ ScanResult scanResult3 =
+ new ScanResult(
+ device3,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ TEST_RSSI,
+ 0,
+ ScanRecord.parseFromBytes(scanRecord3),
+ 0);
+
+ prepareConnectedDeviceGroup();
+ startSearchingForSources();
+
+ // Test using onSyncEstablishedFailed
+
+ // Added and executed immidiatelly as no other in queue, high rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
+ // Added to queue, medium rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult2);
+ // Added to queue, low rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult3);
+
+ ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
+ assertThat(
+ BassUtils.parseBroadcastId(
+ resultCaptor
+ .getValue()
+ .getScanRecord()
+ .getServiceData()
+ .get(BassConstants.BAAS_UUID)))
+ .isEqualTo(broadcastId1);
+
+ onSyncEstablishedFailed(device1, TEST_SYNC_HANDLE);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
+ assertThat(
+ BassUtils.parseBroadcastId(
+ resultCaptor
+ .getValue()
+ .getScanRecord()
+ .getServiceData()
+ .get(BassConstants.BAAS_UUID)))
+ .isEqualTo(broadcastId2);
+
+ // Added to queue again, high rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
+
+ onSyncEstablishedFailed(device2, TEST_SYNC_HANDLE + 1);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
+ assertThat(
+ BassUtils.parseBroadcastId(
+ resultCaptor
+ .getValue()
+ .getScanRecord()
+ .getServiceData()
+ .get(BassConstants.BAAS_UUID)))
+ .isEqualTo(broadcastId3);
+
+ onSyncEstablished(device3, TEST_SYNC_HANDLE + 2);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
+ assertThat(
+ BassUtils.parseBroadcastId(
+ resultCaptor
+ .getValue()
+ .getScanRecord()
+ .getServiceData()
+ .get(BassConstants.BAAS_UUID)))
+ .isEqualTo(broadcastId1);
+
+ // Restart searching clears the mSyncFailureCounter
+ mBassClientService.stopSearchingForSources();
+ mInOrderMethodProxy
+ .verify(mMethodProxy, times(2))
+ .periodicAdvertisingManagerUnregisterSync(any(), any());
+ startSearchingForSources();
+
+ // Test using onSyncLost
+
+ // Added and executed immidiatelly as no other in queue, high rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
+ // Added to queue, medium rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult2);
+ // Added to queue, low rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult3);
+
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
+ assertThat(
+ BassUtils.parseBroadcastId(
+ resultCaptor
+ .getValue()
+ .getScanRecord()
+ .getServiceData()
+ .get(BassConstants.BAAS_UUID)))
+ .isEqualTo(broadcastId1);
+
+ onSyncEstablished(device1, TEST_SYNC_HANDLE);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
+ assertThat(
+ BassUtils.parseBroadcastId(
+ resultCaptor
+ .getValue()
+ .getScanRecord()
+ .getServiceData()
+ .get(BassConstants.BAAS_UUID)))
+ .isEqualTo(broadcastId2);
+ onSyncLost();
+
+ // Added to queue again, high rssi
+ mCallbackCaptor
+ .getValue()
+ .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
+
+ onSyncEstablished(device2, TEST_SYNC_HANDLE + 1);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
+ assertThat(
+ BassUtils.parseBroadcastId(
+ resultCaptor
+ .getValue()
+ .getScanRecord()
+ .getServiceData()
+ .get(BassConstants.BAAS_UUID)))
+ .isEqualTo(broadcastId3);
+ }
+
+ @Test
@DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
public void testSelectSource_invalidActiveSource() {
final int testSyncHandle = 0;
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
index 726dc14fa5..1ca22bec3c 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java
@@ -16,9 +16,18 @@
package com.android.bluetooth.hfpclient;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+import static android.bluetooth.BluetoothProfile.EXTRA_PREVIOUS_STATE;
+import static android.bluetooth.BluetoothProfile.EXTRA_STATE;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
+import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+
import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.AT_OK;
import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.ENTER_PRIVATE_MODE;
import static com.android.bluetooth.hfpclient.HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER;
@@ -35,24 +44,22 @@ import android.bluetooth.BluetoothAssignedNumbers;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHeadsetClientCall;
-import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothSinkAudioPolicy;
import android.bluetooth.BluetoothStatusCodes;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Bundle;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.os.test.TestLooper;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.Pair;
-import androidx.test.espresso.intent.matcher.IntentMatchers;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.LargeTest;
-import androidx.test.filters.MediumTest;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -62,17 +69,16 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.RemoteDevices;
import com.android.bluetooth.hfp.HeadsetService;
+import org.hamcrest.Matcher;
import org.hamcrest.core.AllOf;
-import org.hamcrest.core.IsInstanceOf;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.hamcrest.MockitoHamcrest;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -80,14 +86,17 @@ import org.mockito.junit.MockitoRule;
import java.util.List;
import java.util.Set;
-/** Test cases for {@link HeadsetClientStateMachine}. */
-@LargeTest
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class HeadsetClientStateMachineTest {
- private BluetoothAdapter mAdapter;
- private HandlerThread mHandlerThread;
+ private final Context mTargetContext = InstrumentationRegistry.getTargetContext();
+ private final BluetoothAdapter mAdapter =
+ mTargetContext.getSystemService(BluetoothManager.class).getAdapter();
+ private final BluetoothDevice mTestDevice = TestUtils.getTestDevice(mAdapter, 42);
+
private TestHeadsetClientStateMachine mHeadsetClientStateMachine;
- private BluetoothDevice mTestDevice;
+ private InOrder mInOrder;
+ private TestLooper mTestLooper;
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@@ -102,250 +111,163 @@ public class HeadsetClientStateMachineTest {
@Mock private PackageManager mPackageManager;
@Mock private NativeInterface mNativeInterface;
- private static final int STANDARD_WAIT_MILLIS = 1000;
- private static final int QUERY_CURRENT_CALLS_WAIT_MILLIS = 2000;
- private static final int QUERY_CURRENT_CALLS_TEST_WAIT_MILLIS =
- QUERY_CURRENT_CALLS_WAIT_MILLIS * 3 / 2;
- private static final int TIMEOUT_MS = 1000;
-
@Before
public void setUp() throws Exception {
- // Setup mocks and test assets
+ mInOrder = inOrder(mHeadsetClientService);
+
// Set a valid volume
- when(mAudioManager.getStreamVolume(anyInt())).thenReturn(2);
- when(mAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10);
- when(mAudioManager.getStreamMinVolume(anyInt())).thenReturn(1);
- when(mHeadsetClientService.getAudioManager()).thenReturn(mAudioManager);
- when(mHeadsetClientService.getResources()).thenReturn(mMockHfpResources);
- when(mHeadsetClientService.getPackageManager()).thenReturn(mPackageManager);
- when(mPackageManager.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
- when(mMockHfpResources.getBoolean(R.bool.hfp_clcc_poll_during_call)).thenReturn(true);
- when(mMockHfpResources.getInteger(R.integer.hfp_clcc_poll_interval_during_call))
- .thenReturn(2000);
+ doReturn(2).when(mAudioManager).getStreamVolume(anyInt());
+ doReturn(10).when(mAudioManager).getStreamMaxVolume(anyInt());
+ doReturn(1).when(mAudioManager).getStreamMinVolume(anyInt());
+
+ doReturn(mAudioManager).when(mHeadsetClientService).getAudioManager();
+ doReturn(mMockHfpResources).when(mHeadsetClientService).getResources();
+ doReturn(mPackageManager).when(mHeadsetClientService).getPackageManager();
+ doReturn(CONNECTION_POLICY_ALLOWED).when(mHeadsetClientService).getConnectionPolicy(any());
+
+ doReturn(true).when(mMockHfpResources).getBoolean(eq(R.bool.hfp_clcc_poll_during_call));
+ doReturn(2000)
+ .when(mMockHfpResources)
+ .getInteger(eq(R.integer.hfp_clcc_poll_interval_during_call));
doReturn(mRemoteDevices).when(mAdapterService).getRemoteDevices();
doReturn(true).when(mNativeInterface).sendAndroidAt(anyObject(), anyString());
- // This line must be called to make sure relevant objects are initialized properly
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- // Get a device for testing
- mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05");
-
- // Setup thread and looper
- mHandlerThread = new HandlerThread("HeadsetClientStateMachineTestHandlerThread");
- mHandlerThread.start();
- // Manage looper execution in main test thread explicitly to guarantee timing consistency
+ mTestLooper = new TestLooper();
mHeadsetClientStateMachine =
new TestHeadsetClientStateMachine(
mAdapterService,
mHeadsetClientService,
mHeadsetService,
- mHandlerThread.getLooper(),
+ mTestLooper.getLooper(),
mNativeInterface);
mHeadsetClientStateMachine.start();
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ mTestLooper.dispatchAll();
}
@After
public void tearDown() throws Exception {
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ mTestLooper.dispatchAll();
mHeadsetClientStateMachine.allowConnect = null;
mHeadsetClientStateMachine.doQuit();
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- mHandlerThread.quit();
+ mTestLooper.dispatchAll();
verifyNoMoreInteractions(mHeadsetService);
}
/** Test that default state is disconnected */
- @SmallTest
@Test
public void testDefaultDisconnectedState() {
- Assert.assertEquals(
- mHeadsetClientStateMachine.getConnectionState(null),
- BluetoothProfile.STATE_DISCONNECTED);
+ assertThat(mHeadsetClientStateMachine.getConnectionState(null))
+ .isEqualTo(STATE_DISCONNECTED);
}
/** Test that an incoming connection with low priority is rejected */
- @MediumTest
@Test
public void testIncomingPriorityReject() {
- // Return false for priority.
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ doReturn(CONNECTION_POLICY_FORBIDDEN)
+ .when(mHeadsetClientService)
+ .getConnectionPolicy(any());
// Inject an event for when incoming connection is requested
StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
connStCh.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh);
+ sendMessage(StackEvent.STACK_EVENT, connStCh);
// Verify that only DISCONNECTED -> DISCONNECTED broadcast is fired
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS))
- .sendBroadcastMultiplePermissions(
- MockitoHamcrest.argThat(
- AllOf.allOf(
- IntentMatchers.hasAction(
- BluetoothHeadsetClient
- .ACTION_CONNECTION_STATE_CHANGED),
- IntentMatchers.hasExtra(
- BluetoothProfile.EXTRA_STATE,
- BluetoothProfile.STATE_DISCONNECTED),
- IntentMatchers.hasExtra(
- BluetoothProfile.EXTRA_PREVIOUS_STATE,
- BluetoothProfile.STATE_DISCONNECTED))),
- any(String[].class),
- any(BroadcastOptions.class));
- // Check we are in disconnected state still.
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class));
+ verifySendBroadcastMultiplePermissions(
+ hasAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED),
+ hasExtra(EXTRA_STATE, STATE_DISCONNECTED),
+ hasExtra(EXTRA_PREVIOUS_STATE, STATE_DISCONNECTED));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnected.class);
}
/** Test that an incoming connection with high priority is accepted */
- @MediumTest
@Test
public void testIncomingPriorityAccept() {
- // Return true for priority.
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-
// Inject an event for when incoming connection is requested
StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
connStCh.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh);
+ sendMessage(StackEvent.STACK_EVENT, connStCh);
// Verify that one connection state broadcast is executed
- ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS))
- .sendBroadcastMultiplePermissions(
- intentArgument1.capture(),
- any(String[].class),
- any(BroadcastOptions.class));
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTING,
- intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_CONNECTING));
- // Check we are in connecting state now.
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connecting.class);
// Send a message to trigger SLC connection
StackEvent slcEvent = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
slcEvent.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED;
slcEvent.valueInt2 = HeadsetClientHalConstants.PEER_FEAT_ECS;
slcEvent.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, slcEvent);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(StackEvent.STACK_EVENT, slcEvent);
setUpAndroidAt(false);
// Verify that one connection state broadcast is executed
- ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(2))
- .sendBroadcastMultiplePermissions(
- intentArgument2.capture(),
- any(String[].class),
- any(BroadcastOptions.class));
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTED,
- intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
- // Check we are in connecting state now.
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_CONNECTED));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
}
/** Test that an incoming connection that times out */
- @MediumTest
@Test
public void testIncomingTimeout() {
- // Return true for priority.
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-
// Inject an event for when incoming connection is requested
StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
connStCh.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh);
-
- // Verify that one connection state broadcast is executed
- ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS))
- .sendBroadcastMultiplePermissions(
- intentArgument1.capture(),
- any(String[].class),
- any(BroadcastOptions.class));
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTING,
- intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
-
- // Check we are in connecting state now.
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ sendMessage(StackEvent.STACK_EVENT, connStCh);
// Verify that one connection state broadcast is executed
- ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class);
- verify(
- mHeadsetClientService,
- timeout(HeadsetClientStateMachine.CONNECTING_TIMEOUT_MS * 2).times(2))
- .sendBroadcastMultiplePermissions(
- intentArgument2.capture(),
- any(String[].class),
- any(BroadcastOptions.class));
- Assert.assertEquals(
- BluetoothProfile.STATE_DISCONNECTED,
- intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
-
- // Check we are in connecting state now.
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class));
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_CONNECTING));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connecting.class);
+
+ // Trigger timeout
+ mTestLooper.moveTimeForward(HeadsetClientStateMachine.CONNECTING_TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_DISCONNECTED));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnected.class);
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
}
+ private boolean processAndroidSlcCommand(String command) {
+ return mHeadsetClientStateMachine.processAndroidSlcCommand(command, mTestDevice);
+ }
+
@Test
public void testProcessAndroidSlcCommand() {
initToConnectedState();
// True on correct AT command and BluetothDevice
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID: (SINKAUDIOPOLICY)", mTestDevice));
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand("+ANDROID: ()", mTestDevice));
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID: (,,,)", mTestDevice));
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID: (SINKAUDIOPOLICY),(OTHERFEATURE)", mTestDevice));
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID: (SINKAUDIOPOLICY),(OTHERFEATURE,1,2,3),(1,2,3)", mTestDevice));
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand("+ANDROID: 123", mTestDevice));
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand("+ANDROID: ", mTestDevice));
+ assertThat(processAndroidSlcCommand("+ANDROID: (SINKAUDIOPOLICY)")).isTrue();
+ assertThat(processAndroidSlcCommand("+ANDROID: ()")).isTrue();
+ assertThat(processAndroidSlcCommand("+ANDROID: (,,,)")).isTrue();
+ assertThat(processAndroidSlcCommand("+ANDROID: (SINKAUDIOPOLICY),(OTHERFEATURE)")).isTrue();
+ assertThat(
+ processAndroidSlcCommand(
+ "+ANDROID: (SINKAUDIOPOLICY),(OTHERFEATURE,1,2,3),(1,2,3)"))
+ .isTrue();
+ assertThat(processAndroidSlcCommand("+ANDROID: 123")).isTrue();
+ assertThat(processAndroidSlcCommand("+ANDROID: ")).isTrue();
// False on incorrect AT command format
- Assert.assertFalse(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID= (SINKAUDIOPOLICY)", mTestDevice));
- Assert.assertFalse(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "RANDOM ^%$# STRING", mTestDevice));
- Assert.assertFalse(mHeadsetClientStateMachine.processAndroidSlcCommand("", mTestDevice));
+ assertThat(processAndroidSlcCommand("+ANDROID= (SINKAUDIOPOLICY)")).isFalse();
+ assertThat(processAndroidSlcCommand("RANDOM ^%$# STRING")).isFalse();
+ assertThat(processAndroidSlcCommand("")).isFalse();
// False on incorrect BluetoothDevice
- Assert.assertFalse(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID: (SINKAUDIOPOLICY)",
- mAdapter.getRemoteDevice("05:04:01:02:03:00")));
+ assertThat(
+ mHeadsetClientStateMachine.processAndroidSlcCommand(
+ "+ANDROID: (SINKAUDIOPOLICY)",
+ mAdapter.getRemoteDevice("05:04:01:02:03:00")))
+ .isFalse();
}
@Test
@@ -353,82 +275,45 @@ public class HeadsetClientStateMachineTest {
initToConnectedState();
mHeadsetClientStateMachine.setAudioPolicyRemoteSupported(false);
- Assert.assertFalse(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "RANDOM ^%$# STRING", mTestDevice));
- Assert.assertEquals(
- BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
- mHeadsetClientStateMachine.getAudioPolicyRemoteSupported());
+ assertThat(processAndroidSlcCommand("RANDOM ^%$# STRING")).isFalse();
+ assertThat(mHeadsetClientStateMachine.getAudioPolicyRemoteSupported())
+ .isEqualTo(BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
mHeadsetClientStateMachine.setAudioPolicyRemoteSupported(false);
- Assert.assertFalse(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID= (SINKAUDIOPOLICY)", mTestDevice));
- Assert.assertEquals(
- BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
- mHeadsetClientStateMachine.getAudioPolicyRemoteSupported());
+ assertThat(processAndroidSlcCommand("+ANDROID= (SINKAUDIOPOLICY)")).isFalse();
+ assertThat(mHeadsetClientStateMachine.getAudioPolicyRemoteSupported())
+ .isEqualTo(BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
mHeadsetClientStateMachine.setAudioPolicyRemoteSupported(false);
- Assert.assertTrue(
- mHeadsetClientStateMachine.processAndroidSlcCommand(
- "+ANDROID: (SINKAUDIOPOLICY)", mTestDevice));
- Assert.assertEquals(
- BluetoothStatusCodes.FEATURE_SUPPORTED,
- mHeadsetClientStateMachine.getAudioPolicyRemoteSupported());
+ assertThat(processAndroidSlcCommand("+ANDROID: (SINKAUDIOPOLICY)")).isTrue();
+ assertThat(mHeadsetClientStateMachine.getAudioPolicyRemoteSupported())
+ .isEqualTo(BluetoothStatusCodes.FEATURE_SUPPORTED);
}
/** Test that In Band Ringtone information is relayed from phone. */
- @LargeTest
@Test
- @FlakyTest
public void testInBandRingtone() {
- // Return true for priority.
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-
- Assert.assertEquals(false, mHeadsetClientStateMachine.getInBandRing());
+ assertThat(mHeadsetClientStateMachine.getInBandRing()).isFalse();
// Inject an event for when incoming connection is requested
StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
connStCh.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh);
-
- int expectedBroadcastIndex = 1;
- int expectedBroadcastMultiplePermissionsIndex = 1;
+ sendMessage(StackEvent.STACK_EVENT, connStCh);
// Verify that one connection state broadcast is executed
- ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
- verify(
- mHeadsetClientService,
- timeout(STANDARD_WAIT_MILLIS)
- .times(expectedBroadcastMultiplePermissionsIndex++))
- .sendBroadcastMultiplePermissions(
- intentArgument.capture(), any(String[].class), any(BroadcastOptions.class));
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTING,
- intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_CONNECTING));
// Send a message to trigger SLC connection
StackEvent slcEvent = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
slcEvent.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED;
slcEvent.valueInt2 = HeadsetClientHalConstants.PEER_FEAT_ECS;
slcEvent.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, slcEvent);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(StackEvent.STACK_EVENT, slcEvent);
setUpAndroidAt(false);
- verify(
- mHeadsetClientService,
- timeout(STANDARD_WAIT_MILLIS)
- .times(expectedBroadcastMultiplePermissionsIndex++))
- .sendBroadcastMultiplePermissions(
- intentArgument.capture(), any(String[].class), any(BroadcastOptions.class));
-
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTED,
- intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_CONNECTED));
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
@@ -440,25 +325,15 @@ public class HeadsetClientStateMachineTest {
StackEvent eventInBandRing = new StackEvent(StackEvent.EVENT_TYPE_IN_BAND_RINGTONE);
eventInBandRing.valueInt = 1;
eventInBandRing.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, eventInBandRing);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(expectedBroadcastIndex++))
- .sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
- Assert.assertEquals(
- 1,
- intentArgument
- .getValue()
- .getIntExtra(BluetoothHeadsetClient.EXTRA_IN_BAND_RING, -1));
- Assert.assertEquals(true, mHeadsetClientStateMachine.getInBandRing());
+ sendMessage(StackEvent.STACK_EVENT, eventInBandRing);
+ verifySendBroadcast(hasExtra(BluetoothHeadsetClient.EXTRA_IN_BAND_RING, 1));
+ assertThat(mHeadsetClientStateMachine.getInBandRing()).isTrue();
// Simulate a new incoming phone call
StackEvent eventCallStatusUpdated = new StackEvent(StackEvent.EVENT_TYPE_CLIP);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, eventCallStatusUpdated);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- verify(
- mHeadsetClientService,
- timeout(STANDARD_WAIT_MILLIS).times(expectedBroadcastIndex - 1))
- .sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
+ sendMessage(StackEvent.STACK_EVENT, eventCallStatusUpdated);
+ mInOrder.verify(mHeadsetClientService, never())
+ .sendBroadcast(any(Intent.class), anyString(), any(Bundle.class));
// Provide information about the new call
StackEvent eventIncomingCall = new StackEvent(StackEvent.EVENT_TYPE_CURRENT_CALLS);
@@ -469,73 +344,58 @@ public class HeadsetClientStateMachineTest {
eventIncomingCall.valueString = "5551212"; // phone number
eventIncomingCall.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, eventIncomingCall);
- verify(
- mHeadsetClientService,
- timeout(STANDARD_WAIT_MILLIS).times(expectedBroadcastIndex - 1))
- .sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
+ sendMessage(StackEvent.STACK_EVENT, eventIncomingCall);
+ mInOrder.verify(mHeadsetClientService, never())
+ .sendBroadcast(any(Intent.class), anyString(), any(Bundle.class));
// Signal that the complete list of calls was received.
StackEvent eventCommandStatus = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
eventCommandStatus.valueInt = AT_OK;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, eventCommandStatus);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- verify(
- mHeadsetClientService,
- timeout(QUERY_CURRENT_CALLS_TEST_WAIT_MILLIS)
- .times(expectedBroadcastIndex++))
+ sendMessage(StackEvent.STACK_EVENT, eventCommandStatus);
+
+ ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
+ mInOrder.verify(mHeadsetClientService)
.sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
// Verify that the new call is being registered with the inBandRing flag set.
- Assert.assertEquals(
- true,
- ((HfpClientCall)
- intentArgument
- .getValue()
- .getParcelableExtra(BluetoothHeadsetClient.EXTRA_CALL))
- .isInBandRing());
+ HfpClientCall clientCall =
+ (HfpClientCall)
+ intentArgument
+ .getValue()
+ .getParcelableExtra(BluetoothHeadsetClient.EXTRA_CALL);
+ assertThat(clientCall.isInBandRing()).isTrue();
// Disable In Band Ring and verify state gets propagated.
eventInBandRing.valueInt = 0;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, eventInBandRing);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(expectedBroadcastIndex++))
- .sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
- Assert.assertEquals(
- 0,
- intentArgument
- .getValue()
- .getIntExtra(BluetoothHeadsetClient.EXTRA_IN_BAND_RING, -1));
- Assert.assertEquals(false, mHeadsetClientStateMachine.getInBandRing());
+ sendMessage(StackEvent.STACK_EVENT, eventInBandRing);
+ verifySendBroadcast(hasExtra(BluetoothHeadsetClient.EXTRA_IN_BAND_RING, 0));
+ assertThat(mHeadsetClientStateMachine.getInBandRing()).isFalse();
}
/** Test that wearables use {@code BluetoothHeadsetClientCall} in intent. */
@Test
public void testWearablesUseBluetoothHeadsetClientCallInIntent() {
// Specify the watch form factor when package manager is asked
- when(mPackageManager.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_WATCH);
// Skip over the Android AT commands to test this code path
doReturn(false).when(mNativeInterface).sendAndroidAt(anyObject(), anyString());
- // Return true for connection policy to allow connections
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-
// Send an incoming connection event
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
event.device = mTestDevice;
event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, event);
+ sendMessage(StackEvent.STACK_EVENT, event);
// Send a message to trigger service level connection using the required ECS feature
event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
event.device = mTestDevice;
event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED;
event.valueInt2 = HeadsetClientHalConstants.PEER_FEAT_ECS;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, event);
+ sendMessage(StackEvent.STACK_EVENT, event);
// Dial a phone call, which will fail as @{code dial} method is not specified in @{code
// mNativeInterface} mock and trigger a call state changed broadcast
- mHeadsetClientStateMachine.sendMessage(
+ sendMessage(
HeadsetClientStateMachine.DIAL_NUMBER,
new HfpClientCall(
mTestDevice,
@@ -546,73 +406,54 @@ public class HeadsetClientStateMachineTest {
false,
false));
- // Wait for processing
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
-
// Verify the broadcast
ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, times(1))
+ mInOrder.verify(mHeadsetClientService)
.sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
// Verify that the parcelable extra has a legacy {@code BluetoothHeadsetClientCall} type for
// wearables.
- Assert.assertThat(
- intentArgument.getValue().getParcelableExtra(BluetoothHeadsetClient.EXTRA_CALL),
- IsInstanceOf.instanceOf(BluetoothHeadsetClientCall.class));
+ Object clientCall =
+ (Object)
+ intentArgument
+ .getValue()
+ .getParcelableExtra(BluetoothHeadsetClient.EXTRA_CALL);
+ assertThat(clientCall).isInstanceOf(BluetoothHeadsetClientCall.class);
// To satisfy the @After verification
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
}
/* Utility function to simulate HfpClient is connected. */
- private int setUpHfpClientConnection(int startBroadcastIndex) {
+ private void setUpHfpClientConnection() {
// Trigger an incoming connection is requested
StackEvent connStCh = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
connStCh.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, connStCh);
- ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(startBroadcastIndex))
- .sendBroadcastMultiplePermissions(
- intentArgument.capture(), any(String[].class), any(BroadcastOptions.class));
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTING,
- intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
- startBroadcastIndex++;
- return startBroadcastIndex;
+ sendMessage(StackEvent.STACK_EVENT, connStCh);
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_CONNECTING));
}
/* Utility function to simulate SLC connection. */
- private int setUpServiceLevelConnection(int startBroadcastIndex) {
- return setUpServiceLevelConnection(startBroadcastIndex, false);
+ private void setUpServiceLevelConnection() {
+ setUpServiceLevelConnection(false);
}
- private int setUpServiceLevelConnection(int startBroadcastIndex, boolean androidAtSupported) {
+ private void setUpServiceLevelConnection(boolean androidAtSupported) {
// Trigger SLC connection
StackEvent slcEvent = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
slcEvent.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED;
slcEvent.valueInt2 = HeadsetClientHalConstants.PEER_FEAT_ECS;
slcEvent.valueInt2 |= HeadsetClientHalConstants.PEER_FEAT_HF_IND;
slcEvent.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, slcEvent);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(StackEvent.STACK_EVENT, slcEvent);
setUpAndroidAt(androidAtSupported);
- ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(startBroadcastIndex))
- .sendBroadcastMultiplePermissions(
- intentArgument.capture(), any(String[].class), any(BroadcastOptions.class));
- Assert.assertEquals(
- BluetoothProfile.STATE_CONNECTED,
- intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_CONNECTED));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
-
- startBroadcastIndex++;
- return startBroadcastIndex;
}
/**
@@ -626,48 +467,36 @@ public class HeadsetClientStateMachineTest {
StackEvent unknownEvt = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
unknownEvt.valueString = "+ANDROID: (SINKAUDIOPOLICY)";
unknownEvt.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, unknownEvt);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(StackEvent.STACK_EVENT, unknownEvt);
// receive CMD_RESULT OK after the Android AT command from remote
StackEvent cmdResEvt = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
cmdResEvt.valueInt = StackEvent.CMD_RESULT_TYPE_OK;
cmdResEvt.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, cmdResEvt);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(StackEvent.STACK_EVENT, cmdResEvt);
- Assert.assertEquals(
- BluetoothStatusCodes.FEATURE_SUPPORTED,
- mHeadsetClientStateMachine.getAudioPolicyRemoteSupported());
+ assertThat(mHeadsetClientStateMachine.getAudioPolicyRemoteSupported())
+ .isEqualTo(BluetoothStatusCodes.FEATURE_SUPPORTED);
} else {
// receive CMD_RESULT CME_ERROR due to remote not supporting Android AT
StackEvent cmdResEvt = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
cmdResEvt.valueInt = StackEvent.CMD_RESULT_TYPE_CME_ERROR;
cmdResEvt.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, cmdResEvt);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(StackEvent.STACK_EVENT, cmdResEvt);
- Assert.assertEquals(
- BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
- mHeadsetClientStateMachine.getAudioPolicyRemoteSupported());
+ assertThat(mHeadsetClientStateMachine.getAudioPolicyRemoteSupported())
+ .isEqualTo(BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
}
}
/* Utility function: supported AT command should lead to native call */
private void runSupportedVendorAtCommand(String atCommand, int vendorId) {
- // Return true for priority.
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
- Message msg =
- mHeadsetClientStateMachine.obtainMessage(
- HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND, vendorId, 0, atCommand);
- mHeadsetClientStateMachine.sendMessage(msg);
+ sendMessage(HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND, vendorId, 0, atCommand);
- verify(mNativeInterface, timeout(STANDARD_WAIT_MILLIS).times(1))
+ verify(mNativeInterface)
.sendATCmd(
mTestDevice,
HeadsetClientHalConstants.HANDSFREECLIENT_AT_CMD_VENDOR_SPECIFIC_CMD,
@@ -677,7 +506,6 @@ public class HeadsetClientStateMachineTest {
}
/** Test: supported vendor specific command: set operation */
- @LargeTest
@Test
public void testSupportedVendorAtCommandSet() {
int vendorId = BluetoothAssignedNumbers.APPLE;
@@ -686,7 +514,6 @@ public class HeadsetClientStateMachineTest {
}
/** Test: supported vendor specific command: read operation */
- @LargeTest
@Test
public void testSupportedVendorAtCommandRead() {
int vendorId = BluetoothAssignedNumbers.APPLE;
@@ -696,24 +523,15 @@ public class HeadsetClientStateMachineTest {
/* utility function: unsupported vendor specific command shall be filtered. */
public void runUnsupportedVendorAtCommand(String atCommand, int vendorId) {
- // Return true for priority.
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
+ sendMessage(HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND, vendorId, 0, atCommand);
- Message msg =
- mHeadsetClientStateMachine.obtainMessage(
- HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND, vendorId, 0, atCommand);
- mHeadsetClientStateMachine.sendMessage(msg);
-
- verify(mNativeInterface, timeout(STANDARD_WAIT_MILLIS).times(0))
- .sendATCmd(any(), anyInt(), anyInt(), anyInt(), any());
+ verify(mNativeInterface, never()).sendATCmd(any(), anyInt(), anyInt(), anyInt(), any());
}
/** Test: unsupported vendor specific command shall be filtered: bad command code */
- @LargeTest
@Test
public void testUnsupportedVendorAtCommandBadCode() {
String atCommand = "+XAAPL=ABCD-1234-0100,100";
@@ -722,7 +540,6 @@ public class HeadsetClientStateMachineTest {
}
/** Test: unsupported vendor specific command shall be filtered: no back to back command */
- @LargeTest
@Test
public void testUnsupportedVendorAtCommandBackToBack() {
String atCommand = "+XAPL=ABCD-1234-0100,100; +XAPL=ab";
@@ -735,44 +552,25 @@ public class HeadsetClientStateMachineTest {
*/
private void runSupportedVendorEvent(
int vendorId, String vendorEventCode, String vendorEventArgument) {
- // Setup connection state machine to be in connected state
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- int expectedBroadcastIndex = 1;
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
// Simulate a known event arrive
String vendorEvent = vendorEventCode + vendorEventArgument;
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
event.device = mTestDevice;
event.valueString = vendorEvent;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, event);
+ sendMessage(StackEvent.STACK_EVENT, event);
// Validate broadcast intent
- ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(expectedBroadcastIndex))
- .sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
- Assert.assertEquals(
- BluetoothHeadsetClient.ACTION_VENDOR_SPECIFIC_HEADSETCLIENT_EVENT,
- intentArgument.getValue().getAction());
- Assert.assertEquals(
- vendorId,
- intentArgument.getValue().getIntExtra(BluetoothHeadsetClient.EXTRA_VENDOR_ID, -1));
- Assert.assertEquals(
- vendorEventCode,
- intentArgument
- .getValue()
- .getStringExtra(BluetoothHeadsetClient.EXTRA_VENDOR_EVENT_CODE));
- Assert.assertEquals(
- vendorEvent,
- intentArgument
- .getValue()
- .getStringExtra(BluetoothHeadsetClient.EXTRA_VENDOR_EVENT_FULL_ARGS));
+ verifySendBroadcast(
+ hasAction(BluetoothHeadsetClient.ACTION_VENDOR_SPECIFIC_HEADSETCLIENT_EVENT),
+ hasExtra(BluetoothHeadsetClient.EXTRA_VENDOR_ID, vendorId),
+ hasExtra(BluetoothHeadsetClient.EXTRA_VENDOR_EVENT_CODE, vendorEventCode),
+ hasExtra(BluetoothHeadsetClient.EXTRA_VENDOR_EVENT_FULL_ARGS, vendorEvent));
}
/** Test: supported vendor specific response: response to read command */
- @LargeTest
@Test
public void testSupportedVendorEventReadResponse() {
final int vendorId = BluetoothAssignedNumbers.APPLE;
@@ -782,7 +580,6 @@ public class HeadsetClientStateMachineTest {
}
/** Test: supported vendor specific response: response to test command */
- @LargeTest
@Test
public void testSupportedVendorEventTestResponse() {
final int vendorId = BluetoothAssignedNumbers.APPLE;
@@ -794,18 +591,15 @@ public class HeadsetClientStateMachineTest {
/* Utility test function: unsupported vendor specific response shall be filtered out*/
public void runUnsupportedVendorEvent(
int vendorId, String vendorEventCode, String vendorEventArgument) {
- // Setup connection state machine to be in connected state
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
// Simulate an unknown event arrive
String vendorEvent = vendorEventCode + vendorEventArgument;
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
event.device = mTestDevice;
event.valueString = vendorEvent;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, event);
+ sendMessage(StackEvent.STACK_EVENT, event);
// Validate no broadcast intent
verify(mHeadsetClientService, atMost(2))
@@ -813,7 +607,6 @@ public class HeadsetClientStateMachineTest {
}
/** Test unsupported vendor response: bad read response */
- @LargeTest
@Test
public void testUnsupportedVendorEventBadReadResponse() {
final int vendorId = BluetoothAssignedNumbers.APPLE;
@@ -823,7 +616,6 @@ public class HeadsetClientStateMachineTest {
}
/** Test unsupported vendor response: bad test response */
- @LargeTest
@Test
public void testUnsupportedVendorEventBadTestResponse() {
final int vendorId = BluetoothAssignedNumbers.APPLE;
@@ -833,80 +625,57 @@ public class HeadsetClientStateMachineTest {
}
/** Test voice recognition state change broadcast. */
- @MediumTest
@Test
public void testVoiceRecognitionStateChange() {
- // Setup connection state machine to be in connected state
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
doReturn(true).when(mNativeInterface).startVoiceRecognition(any(BluetoothDevice.class));
doReturn(true).when(mNativeInterface).stopVoiceRecognition(any(BluetoothDevice.class));
- int expectedBroadcastIndex = 1;
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
// Simulate a voice recognition start
- mHeadsetClientStateMachine.sendMessage(VOICE_RECOGNITION_START);
+ sendMessage(VOICE_RECOGNITION_START);
// Signal that the complete list of actions was received.
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
event.device = mTestDevice;
event.valueInt = AT_OK;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, event);
+ sendMessage(StackEvent.STACK_EVENT, event);
- expectedBroadcastIndex =
- verifyVoiceRecognitionBroadcast(
- expectedBroadcastIndex, HeadsetClientHalConstants.VR_STATE_STARTED);
+ verifySendBroadcast(
+ hasAction(BluetoothHeadsetClient.ACTION_AG_EVENT),
+ hasExtra(
+ BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION,
+ HeadsetClientHalConstants.VR_STATE_STARTED));
// Simulate a voice recognition stop
- mHeadsetClientStateMachine.sendMessage(VOICE_RECOGNITION_STOP);
+ sendMessage(VOICE_RECOGNITION_STOP);
// Signal that the complete list of actions was received.
event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
event.device = mTestDevice;
event.valueInt = AT_OK;
- mHeadsetClientStateMachine.sendMessage(StackEvent.STACK_EVENT, event);
-
- verifyVoiceRecognitionBroadcast(
- expectedBroadcastIndex, HeadsetClientHalConstants.VR_STATE_STOPPED);
- }
+ sendMessage(StackEvent.STACK_EVENT, event);
- private int verifyVoiceRecognitionBroadcast(int expectedBroadcastIndex, int expectedState) {
- // Validate broadcast intent
- ArgumentCaptor<Intent> intentArgument = ArgumentCaptor.forClass(Intent.class);
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(expectedBroadcastIndex))
- .sendBroadcast(intentArgument.capture(), anyString(), any(Bundle.class));
- Assert.assertEquals(
- BluetoothHeadsetClient.ACTION_AG_EVENT, intentArgument.getValue().getAction());
- int state =
- intentArgument
- .getValue()
- .getIntExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, -1);
- Assert.assertEquals(expectedState, state);
- return expectedBroadcastIndex + 1;
+ verifySendBroadcast(
+ hasAction(BluetoothHeadsetClient.ACTION_AG_EVENT),
+ hasExtra(
+ BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION,
+ HeadsetClientHalConstants.VR_STATE_STOPPED));
}
/** Test send BIEV command */
- @MediumTest
@Test
public void testSendBIEVCommand() {
- // Setup connection state machine to be in connected state
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
int indicator_id = 2;
int indicator_value = 50;
- Message msg = mHeadsetClientStateMachine.obtainMessage(HeadsetClientStateMachine.SEND_BIEV);
- msg.arg1 = indicator_id;
- msg.arg2 = indicator_value;
-
- mHeadsetClientStateMachine.sendMessage(msg);
+ sendMessage(HeadsetClientStateMachine.SEND_BIEV, indicator_id, indicator_value);
- verify(mNativeInterface, timeout(STANDARD_WAIT_MILLIS).times(1))
+ verify(mNativeInterface)
.sendATCmd(
mTestDevice,
HeadsetClientHalConstants.HANDSFREECLIENT_AT_CMD_BIEV,
@@ -918,17 +687,12 @@ public class HeadsetClientStateMachineTest {
/**
* Test state machine shall try to send AT+BIEV command to AG to update an init battery level.
*/
- @MediumTest
@Test
public void testSendBatteryUpdateIndicatorWhenConnect() {
- // Setup connection state machine to be in connected state
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
-
- verify(mHeadsetClientService, timeout(STANDARD_WAIT_MILLIS).times(1)).updateBatteryLevel();
+ verify(mHeadsetClientService).updateBatteryLevel();
}
@Test
@@ -938,7 +702,7 @@ public class HeadsetClientStateMachineTest {
BluetoothHeadsetClient.STATE_AUDIO_CONNECTED,
BluetoothHeadsetClient.STATE_AUDIO_CONNECTING);
- verify(mHeadsetClientService).sendBroadcast(any(), any(), any());
+ mInOrder.verify(mHeadsetClientService).sendBroadcast(any(), any(), any());
}
@Test
@@ -948,8 +712,8 @@ public class HeadsetClientStateMachineTest {
mTestDevice, 0, HfpClientCall.CALL_STATE_WAITING, "1", false, false, false);
mHeadsetClientStateMachine.mCalls.put(0, call);
- Assert.assertEquals(
- mHeadsetClientStateMachine.callsInState(HfpClientCall.CALL_STATE_WAITING), 1);
+ assertThat(mHeadsetClientStateMachine.callsInState(HfpClientCall.CALL_STATE_WAITING))
+ .isEqualTo(1);
}
@Test
@@ -965,7 +729,7 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.enterPrivateMode(0);
Pair expectedPair = new Pair<Integer, Object>(ENTER_PRIVATE_MODE, call);
- Assert.assertEquals(mHeadsetClientStateMachine.mQueuedActions.peek(), expectedPair);
+ assertThat(mHeadsetClientStateMachine.mQueuedActions.peek()).isEqualTo(expectedPair);
}
@Test
@@ -985,14 +749,14 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.explicitCallTransfer();
Pair expectedPair = new Pair<Integer, Object>(EXPLICIT_CALL_TRANSFER, 0);
- Assert.assertEquals(mHeadsetClientStateMachine.mQueuedActions.peek(), expectedPair);
+ assertThat(mHeadsetClientStateMachine.mQueuedActions.peek()).isEqualTo(expectedPair);
}
@Test
public void testSetAudioRouteAllowed() {
mHeadsetClientStateMachine.setAudioRouteAllowed(true);
- Assert.assertTrue(mHeadsetClientStateMachine.getAudioRouteAllowed());
+ assertThat(mHeadsetClientStateMachine.getAudioRouteAllowed()).isTrue();
// Case 1: if remote is not supported
// Expect: Should not send +ANDROID to remote
@@ -1020,11 +784,10 @@ public class HeadsetClientStateMachineTest {
@Test
public void testGetAudioState_withCurrentDeviceNull() {
- Assert.assertNull(mHeadsetClientStateMachine.mCurrentDevice);
+ assertThat(mHeadsetClientStateMachine.mCurrentDevice).isNull();
- Assert.assertEquals(
- mHeadsetClientStateMachine.getAudioState(mTestDevice),
- BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
+ assertThat(mHeadsetClientStateMachine.getAudioState(mTestDevice))
+ .isEqualTo(BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
}
@Test
@@ -1033,7 +796,7 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.mAudioState = audioState;
mHeadsetClientStateMachine.mCurrentDevice = mTestDevice;
- Assert.assertEquals(mHeadsetClientStateMachine.getAudioState(mTestDevice), audioState);
+ assertThat(mHeadsetClientStateMachine.getAudioState(mTestDevice)).isEqualTo(audioState);
}
@Test
@@ -1045,7 +808,7 @@ public class HeadsetClientStateMachineTest {
int[] states = new int[1];
states[0] = HfpClientCall.CALL_STATE_ACTIVE;
- Assert.assertEquals(mHeadsetClientStateMachine.getCall(states), call);
+ assertThat(mHeadsetClientStateMachine.getCall(states)).isEqualTo(call);
}
@Test
@@ -1057,52 +820,48 @@ public class HeadsetClientStateMachineTest {
int[] states = new int[1];
states[0] = HfpClientCall.CALL_STATE_ACTIVE;
- Assert.assertNull(mHeadsetClientStateMachine.getCall(states));
+ assertThat(mHeadsetClientStateMachine.getCall(states)).isNull();
}
@Test
public void testGetConnectionState_withNullDevice() {
- Assert.assertEquals(
- mHeadsetClientStateMachine.getConnectionState(null),
- BluetoothProfile.STATE_DISCONNECTED);
+ assertThat(mHeadsetClientStateMachine.getConnectionState(null))
+ .isEqualTo(STATE_DISCONNECTED);
}
@Test
public void testGetConnectionState_withNonNullDevice() {
mHeadsetClientStateMachine.mCurrentDevice = mTestDevice;
- Assert.assertEquals(
- mHeadsetClientStateMachine.getConnectionState(mTestDevice),
- BluetoothProfile.STATE_DISCONNECTED);
+ assertThat(mHeadsetClientStateMachine.getConnectionState(mTestDevice))
+ .isEqualTo(STATE_DISCONNECTED);
}
@Test
public void testGetConnectionStateFromAudioState() {
- Assert.assertEquals(
- HeadsetClientStateMachine.getConnectionStateFromAudioState(
- BluetoothHeadsetClient.STATE_AUDIO_CONNECTED),
- BluetoothAdapter.STATE_CONNECTED);
- Assert.assertEquals(
- HeadsetClientStateMachine.getConnectionStateFromAudioState(
- BluetoothHeadsetClient.STATE_AUDIO_CONNECTING),
- BluetoothAdapter.STATE_CONNECTING);
- Assert.assertEquals(
- HeadsetClientStateMachine.getConnectionStateFromAudioState(
- BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED),
- BluetoothAdapter.STATE_DISCONNECTED);
+ assertThat(
+ HeadsetClientStateMachine.getConnectionStateFromAudioState(
+ BluetoothHeadsetClient.STATE_AUDIO_CONNECTED))
+ .isEqualTo(BluetoothAdapter.STATE_CONNECTED);
+ assertThat(
+ HeadsetClientStateMachine.getConnectionStateFromAudioState(
+ BluetoothHeadsetClient.STATE_AUDIO_CONNECTING))
+ .isEqualTo(BluetoothAdapter.STATE_CONNECTING);
+ assertThat(
+ HeadsetClientStateMachine.getConnectionStateFromAudioState(
+ BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED))
+ .isEqualTo(BluetoothAdapter.STATE_DISCONNECTED);
int invalidAudioState = 3;
- Assert.assertEquals(
- HeadsetClientStateMachine.getConnectionStateFromAudioState(invalidAudioState),
- BluetoothAdapter.STATE_DISCONNECTED);
+ assertThat(HeadsetClientStateMachine.getConnectionStateFromAudioState(invalidAudioState))
+ .isEqualTo(BluetoothAdapter.STATE_DISCONNECTED);
}
@Test
public void testGetCurrentAgEvents() {
Bundle bundle = mHeadsetClientStateMachine.getCurrentAgEvents();
- Assert.assertEquals(
- bundle.getString(BluetoothHeadsetClient.EXTRA_SUBSCRIBER_INFO),
- mHeadsetClientStateMachine.mSubscriberInfo);
+ assertThat(bundle.getString(BluetoothHeadsetClient.EXTRA_SUBSCRIBER_INFO))
+ .isEqualTo(mHeadsetClientStateMachine.mSubscriberInfo);
}
@Test
@@ -1110,30 +869,30 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_3WAY;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC;
Set<Integer> features = mHeadsetClientStateMachine.getCurrentAgFeatures();
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.PEER_FEAT_3WAY));
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC));
+ assertThat(features.contains(HeadsetClientHalConstants.PEER_FEAT_3WAY)).isTrue();
+ assertThat(features.contains(HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC)).isTrue();
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_VREC;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_REL;
features = mHeadsetClientStateMachine.getCurrentAgFeatures();
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.PEER_FEAT_VREC));
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.CHLD_FEAT_REL));
+ assertThat(features.contains(HeadsetClientHalConstants.PEER_FEAT_VREC)).isTrue();
+ assertThat(features.contains(HeadsetClientHalConstants.CHLD_FEAT_REL)).isTrue();
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_REJECT;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_REL_ACC;
features = mHeadsetClientStateMachine.getCurrentAgFeatures();
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.PEER_FEAT_REJECT));
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.CHLD_FEAT_REL_ACC));
+ assertThat(features.contains(HeadsetClientHalConstants.PEER_FEAT_REJECT)).isTrue();
+ assertThat(features.contains(HeadsetClientHalConstants.CHLD_FEAT_REL_ACC)).isTrue();
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_ECC;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_MERGE;
features = mHeadsetClientStateMachine.getCurrentAgFeatures();
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.PEER_FEAT_ECC));
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.CHLD_FEAT_MERGE));
+ assertThat(features.contains(HeadsetClientHalConstants.PEER_FEAT_ECC)).isTrue();
+ assertThat(features.contains(HeadsetClientHalConstants.CHLD_FEAT_MERGE)).isTrue();
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH;
features = mHeadsetClientStateMachine.getCurrentAgFeatures();
- Assert.assertTrue(features.contains(HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH));
+ assertThat(features.contains(HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH)).isTrue();
}
@Test
@@ -1141,37 +900,42 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_3WAY;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_HOLD_ACC;
Bundle bundle = mHeadsetClientStateMachine.getCurrentAgFeaturesBundle();
- Assert.assertTrue(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_3WAY_CALLING));
- Assert.assertTrue(
- bundle.getBoolean(
- BluetoothHeadsetClient.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL));
+ assertThat(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_3WAY_CALLING))
+ .isTrue();
+ assertThat(
+ bundle.getBoolean(
+ BluetoothHeadsetClient
+ .EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL))
+ .isTrue();
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_VREC;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_REL;
bundle = mHeadsetClientStateMachine.getCurrentAgFeaturesBundle();
- Assert.assertTrue(
- bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_VOICE_RECOGNITION));
- Assert.assertTrue(
- bundle.getBoolean(
- BluetoothHeadsetClient.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL));
+ assertThat(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_VOICE_RECOGNITION))
+ .isTrue();
+ assertThat(
+ bundle.getBoolean(
+ BluetoothHeadsetClient
+ .EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL))
+ .isTrue();
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_REJECT;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_REL_ACC;
bundle = mHeadsetClientStateMachine.getCurrentAgFeaturesBundle();
- Assert.assertTrue(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_REJECT_CALL));
- Assert.assertTrue(
- bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT));
+ assertThat(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_REJECT_CALL)).isTrue();
+ assertThat(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT))
+ .isTrue();
mHeadsetClientStateMachine.mPeerFeatures = HeadsetClientHalConstants.PEER_FEAT_ECC;
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_MERGE;
bundle = mHeadsetClientStateMachine.getCurrentAgFeaturesBundle();
- Assert.assertTrue(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ECC));
- Assert.assertTrue(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE));
+ assertThat(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_ECC)).isTrue();
+ assertThat(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE)).isTrue();
mHeadsetClientStateMachine.mChldFeatures = HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH;
bundle = mHeadsetClientStateMachine.getCurrentAgFeaturesBundle();
- Assert.assertTrue(
- bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE_AND_DETACH));
+ assertThat(bundle.getBoolean(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE_AND_DETACH))
+ .isTrue();
}
@Test
@@ -1183,91 +947,41 @@ public class HeadsetClientStateMachineTest {
List<HfpClientCall> currentCalls = mHeadsetClientStateMachine.getCurrentCalls();
- Assert.assertEquals(currentCalls.get(0), call);
+ assertThat(currentCalls.get(0)).isEqualTo(call);
+ }
+
+ private void assertName(int message, String message_name) {
+ assertThat(HeadsetClientStateMachine.getMessageName(message)).isEqualTo(message_name);
}
@Test
public void testGetMessageName() {
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(StackEvent.STACK_EVENT), "STACK_EVENT");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.CONNECT),
- "CONNECT");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.DISCONNECT),
- "DISCONNECT");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.CONNECT_AUDIO),
- "CONNECT_AUDIO");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(
- HeadsetClientStateMachine.DISCONNECT_AUDIO),
- "DISCONNECT_AUDIO");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(VOICE_RECOGNITION_START),
- "VOICE_RECOGNITION_START");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(VOICE_RECOGNITION_STOP),
- "VOICE_RECOGNITION_STOP");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.SET_MIC_VOLUME),
- "SET_MIC_VOLUME");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(
- HeadsetClientStateMachine.SET_SPEAKER_VOLUME),
- "SET_SPEAKER_VOLUME");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.DIAL_NUMBER),
- "DIAL_NUMBER");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.ACCEPT_CALL),
- "ACCEPT_CALL");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.REJECT_CALL),
- "REJECT_CALL");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.HOLD_CALL),
- "HOLD_CALL");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.TERMINATE_CALL),
- "TERMINATE_CALL");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(ENTER_PRIVATE_MODE), "ENTER_PRIVATE_MODE");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.SEND_DTMF),
- "SEND_DTMF");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(EXPLICIT_CALL_TRANSFER),
- "EXPLICIT_CALL_TRANSFER");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.DISABLE_NREC),
- "DISABLE_NREC");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(
- HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND),
- "SEND_VENDOR_AT_COMMAND");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.SEND_BIEV),
- "SEND_BIEV");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(
- HeadsetClientStateMachine.QUERY_CURRENT_CALLS),
- "QUERY_CURRENT_CALLS");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(
- HeadsetClientStateMachine.QUERY_OPERATOR_NAME),
- "QUERY_OPERATOR_NAME");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(HeadsetClientStateMachine.SUBSCRIBER_INFO),
- "SUBSCRIBER_INFO");
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(
- HeadsetClientStateMachine.CONNECTING_TIMEOUT),
- "CONNECTING_TIMEOUT");
+ assertName(StackEvent.STACK_EVENT, "STACK_EVENT");
+ assertName(HeadsetClientStateMachine.CONNECT, "CONNECT");
+ assertName(HeadsetClientStateMachine.DISCONNECT, "DISCONNECT");
+ assertName(HeadsetClientStateMachine.CONNECT_AUDIO, "CONNECT_AUDIO");
+ assertName(HeadsetClientStateMachine.DISCONNECT_AUDIO, "DISCONNECT_AUDIO");
+ assertName(VOICE_RECOGNITION_START, "VOICE_RECOGNITION_START");
+ assertName(VOICE_RECOGNITION_STOP, "VOICE_RECOGNITION_STOP");
+ assertName(HeadsetClientStateMachine.SET_MIC_VOLUME, "SET_MIC_VOLUME");
+ assertName(HeadsetClientStateMachine.SET_SPEAKER_VOLUME, "SET_SPEAKER_VOLUME");
+ assertName(HeadsetClientStateMachine.DIAL_NUMBER, "DIAL_NUMBER");
+ assertName(HeadsetClientStateMachine.ACCEPT_CALL, "ACCEPT_CALL");
+ assertName(HeadsetClientStateMachine.REJECT_CALL, "REJECT_CALL");
+ assertName(HeadsetClientStateMachine.HOLD_CALL, "HOLD_CALL");
+ assertName(HeadsetClientStateMachine.TERMINATE_CALL, "TERMINATE_CALL");
+ assertName(ENTER_PRIVATE_MODE, "ENTER_PRIVATE_MODE");
+ assertName(HeadsetClientStateMachine.SEND_DTMF, "SEND_DTMF");
+ assertName(EXPLICIT_CALL_TRANSFER, "EXPLICIT_CALL_TRANSFER");
+ assertName(HeadsetClientStateMachine.DISABLE_NREC, "DISABLE_NREC");
+ assertName(HeadsetClientStateMachine.SEND_VENDOR_AT_COMMAND, "SEND_VENDOR_AT_COMMAND");
+ assertName(HeadsetClientStateMachine.SEND_BIEV, "SEND_BIEV");
+ assertName(HeadsetClientStateMachine.QUERY_CURRENT_CALLS, "QUERY_CURRENT_CALLS");
+ assertName(HeadsetClientStateMachine.QUERY_OPERATOR_NAME, "QUERY_OPERATOR_NAME");
+ assertName(HeadsetClientStateMachine.SUBSCRIBER_INFO, "SUBSCRIBER_INFO");
+ assertName(HeadsetClientStateMachine.CONNECTING_TIMEOUT, "CONNECTING_TIMEOUT");
int unknownMessageInt = 54;
- Assert.assertEquals(
- HeadsetClientStateMachine.getMessageName(unknownMessageInt),
- "UNKNOWN(" + unknownMessageInt + ")");
+ assertName(unknownMessageInt, "UNKNOWN(" + unknownMessageInt + ")");
}
/**
@@ -1276,12 +990,8 @@ public class HeadsetClientStateMachineTest {
*/
@Test
public void testAndroidAtRemoteNotSupported_StateTransition_setAudioPolicy() {
- // Setup connection state machine to be in connected state
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
-
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection();
BluetoothSinkAudioPolicy dummyAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build();
mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
@@ -1289,15 +999,11 @@ public class HeadsetClientStateMachineTest {
.sendAndroidAt(mTestDevice, "+ANDROID=SINKAUDIOPOLICY,0,0,0");
}
- @SmallTest
@Test
public void testSetGetCallAudioPolicy() {
- // Return true for priority.
- when(mHeadsetClientService.getConnectionPolicy(any(BluetoothDevice.class)))
- .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);
- setUpHfpClientConnection(1);
- setUpServiceLevelConnection(2, true);
+ setUpHfpClientConnection();
+ setUpServiceLevelConnection(true);
BluetoothSinkAudioPolicy dummyAudioPolicy =
new BluetoothSinkAudioPolicy.Builder()
@@ -1312,19 +1018,19 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
verify(mNativeInterface, never())
.sendAndroidAt(mTestDevice, "+ANDROID=SINKAUDIOPOLICY,1,2,1");
- Assert.assertEquals(0, mHeadsetClientStateMachine.mQueuedActions.size());
+ assertThat(mHeadsetClientStateMachine.mQueuedActions).isEmpty();
// Test setAudioPolicy
mHeadsetClientStateMachine.setAudioPolicyRemoteSupported(true);
mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
verify(mNativeInterface).sendAndroidAt(mTestDevice, "+ANDROID=SINKAUDIOPOLICY,1,2,1");
- Assert.assertEquals(1, mHeadsetClientStateMachine.mQueuedActions.size());
+ assertThat(mHeadsetClientStateMachine.mQueuedActions.size()).isEqualTo(1);
mHeadsetClientStateMachine.mQueuedActions.clear();
// Test if fail to sendAndroidAt
doReturn(false).when(mNativeInterface).sendAndroidAt(anyObject(), anyString());
mHeadsetClientStateMachine.setAudioPolicy(dummyAudioPolicy);
- Assert.assertEquals(0, mHeadsetClientStateMachine.mQueuedActions.size());
+ assertThat(mHeadsetClientStateMachine.mQueuedActions).isEmpty();
}
@Test
@@ -1335,8 +1041,7 @@ public class HeadsetClientStateMachineTest {
// Check if set default policy when Connecting -> Connected
// The testing sys prop is 0. It is ok to check if set audio policy while leaving connecting
// state.
- verify(mNativeInterface, times(1))
- .sendAndroidAt(mTestDevice, "+ANDROID=SINKAUDIOPOLICY,0,0,0");
+ verify(mNativeInterface).sendAndroidAt(mTestDevice, "+ANDROID=SINKAUDIOPOLICY,0,0,0");
// Check if won't set default policy when AudioOn -> Connected
// Transit to AudioOn
@@ -1344,26 +1049,19 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_CONNECTED;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.AudioOn.class);
// Back to Connected
event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
-
- verify(mNativeInterface, times(1))
- .sendAndroidAt(mTestDevice, "+ANDROID=SINKAUDIOPOLICY,0,0,0");
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
+
+ verify(mNativeInterface).sendAndroidAt(mTestDevice, "+ANDROID=SINKAUDIOPOLICY,0,0,0");
}
@Test
@@ -1373,10 +1071,9 @@ public class HeadsetClientStateMachineTest {
@Test
public void testProcessDisconnectMessage_onDisconnectedState() {
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertEquals(
- STATE_DISCONNECTED, mHeadsetClientStateMachine.getConnectionState(mTestDevice));
+ sendMessage(HeadsetClientStateMachine.DISCONNECT);
+ assertThat(mHeadsetClientStateMachine.getConnectionState(mTestDevice))
+ .isEqualTo(STATE_DISCONNECTED);
}
@Test
@@ -1417,11 +1114,11 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
HeadsetClientStateMachine.CONNECT))
.isFalse();
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertTrue(
- mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
- HeadsetClientStateMachine.CONNECT));
+ sendMessage(HeadsetClientStateMachine.CONNECT);
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.CONNECT))
+ .isTrue();
}
@Test
@@ -1442,11 +1139,9 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connecting.class);
}
@Test
@@ -1455,11 +1150,9 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTING;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connecting.class);
}
@Test
@@ -1470,11 +1163,9 @@ public class HeadsetClientStateMachineTest {
event.device = mTestDevice;
assertThat(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(StackEvent.STACK_EVENT))
.isFalse();
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertTrue(
- mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(StackEvent.STACK_EVENT));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(StackEvent.STACK_EVENT))
+ .isTrue();
}
@Test
@@ -1483,11 +1174,9 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CMD_RESULT);
event.valueInt = StackEvent.CMD_RESULT_TYPE_OK;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connecting.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connecting.class);
}
@Test
@@ -1498,22 +1187,19 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
event.valueString = atCommand;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
}
@Test
public void testProcessConnectTimeoutMessage_onConnectingState() {
initToConnectingState();
- Message msg =
+ sendMessageAndVerifyTransition(
mHeadsetClientStateMachine.obtainMessage(
- HeadsetClientStateMachine.CONNECTING_TIMEOUT);
- sendMessageAndVerifyTransition(msg, HeadsetClientStateMachine.Disconnected.class);
+ HeadsetClientStateMachine.CONNECTING_TIMEOUT),
+ HeadsetClientStateMachine.Disconnected.class);
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
}
@@ -1525,9 +1211,7 @@ public class HeadsetClientStateMachineTest {
event.device = mTestDevice;
assertThat(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(StackEvent.STACK_EVENT))
.isFalse();
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(StackEvent.STACK_EVENT, event);
assertThat(mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(StackEvent.STACK_EVENT))
.isTrue();
}
@@ -1535,42 +1219,36 @@ public class HeadsetClientStateMachineTest {
@Test
public void testProcessConnectMessage_onConnectedState() {
initToConnectedState();
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ sendMessage(HeadsetClientStateMachine.CONNECT);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
}
@Test
public void testProcessDisconnectMessage_onConnectedState() {
initToConnectedState();
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
verify(mNativeInterface).disconnect(any(BluetoothDevice.class));
}
@Test
public void testProcessConnectAudioMessage_onConnectedState() {
initToConnectedState();
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO);
verify(mNativeInterface).connectAudio(any(BluetoothDevice.class));
}
@Test
public void testProcessDisconnectAudioMessage_onConnectedState() {
initToConnectedState();
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
verify(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
}
@Test
public void testProcessVoiceRecognitionStartMessage_onConnectedState() {
initToConnectedState();
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_START);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(HeadsetClientStateMachine.VOICE_RECOGNITION_START);
verify(mNativeInterface).startVoiceRecognition(any(BluetoothDevice.class));
}
@@ -1581,19 +1259,17 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
HeadsetClientStateMachine.DISCONNECT))
.isFalse();
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertTrue(
- mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
- HeadsetClientStateMachine.DISCONNECT));
+ sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.DISCONNECT))
+ .isTrue();
}
@Test
public void testProcessDisconnectAudioMessage_onAudioOnState() {
initToAudioOnState();
- mHeadsetClientStateMachine.sendMessage(
- HeadsetClientStateMachine.DISCONNECT_AUDIO, mTestDevice);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO, mTestDevice);
verify(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
}
@@ -1606,52 +1282,42 @@ public class HeadsetClientStateMachineTest {
mHeadsetClientStateMachine.mCalls.put(0, call);
int[] states = new int[1];
states[0] = HfpClientCall.CALL_STATE_ACTIVE;
- mHeadsetClientStateMachine.sendMessage(HeadsetClientStateMachine.HOLD_CALL, mTestDevice);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
+ sendMessage(HeadsetClientStateMachine.HOLD_CALL, mTestDevice);
verify(mNativeInterface).handleCallAction(any(BluetoothDevice.class), anyInt(), eq(0));
}
@Test
public void testProcessStackEvent_ConnectionStateChanged_onAudioOnState() {
initToAudioOnState();
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.AudioOn.class);
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnected.class);
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
}
@Test
public void testProcessStackEvent_AudioStateChanged_onAudioOnState() {
initToAudioOnState();
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.AudioOn.class);
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
}
@Test
public void testProcessStackEvent_CodecSelection_onConnectedState() {
initToConnectedState();
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
// Trigger a MSBC codec stack event. Expect to mAudioWbs = true.
mHeadsetClientStateMachine.mAudioWbs = false;
@@ -1659,11 +1325,9 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_CONNECTED_MSBC;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertTrue(mHeadsetClientStateMachine.mAudioWbs);
- Assert.assertFalse(mHeadsetClientStateMachine.mAudioSWB);
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.mAudioWbs).isTrue();
+ assertThat(mHeadsetClientStateMachine.mAudioSWB).isFalse();
// Trigger a LC3 codec stack event. Expect to mAudioSWB = true.
mHeadsetClientStateMachine.mAudioWbs = false;
@@ -1671,11 +1335,9 @@ public class HeadsetClientStateMachineTest {
event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_CONNECTED_LC3;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertFalse(mHeadsetClientStateMachine.mAudioWbs);
- Assert.assertTrue(mHeadsetClientStateMachine.mAudioSWB);
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.mAudioWbs).isFalse();
+ assertThat(mHeadsetClientStateMachine.mAudioSWB).isTrue();
}
/**
@@ -1701,12 +1363,9 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_UNKNOWN_EVENT);
event.valueString = atCommand;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Connected.class);
verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true));
}
@@ -1716,23 +1375,58 @@ public class HeadsetClientStateMachineTest {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
event.valueInt = HeadsetClientHalConstants.AUDIO_STATE_CONNECTED;
event.device = mTestDevice;
- mHeadsetClientStateMachine.sendMessage(
- mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event));
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(),
- IsInstanceOf.instanceOf(HeadsetClientStateMachine.AudioOn.class));
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.AudioOn.class);
}
- private <T> void sendMessageAndVerifyTransition(Message msg, Class<T> type) {
- Mockito.clearInvocations(mHeadsetClientService);
- mHeadsetClientStateMachine.sendMessage(msg);
- // Verify that one connection state broadcast is executed
- verify(mHeadsetClientService, timeout(TIMEOUT_MS))
+ private void verifySendBroadcastMultiplePermissions(Matcher<Intent>... matchers) {
+ mInOrder.verify(mHeadsetClientService)
.sendBroadcastMultiplePermissions(
- any(Intent.class), any(String[].class), any(BroadcastOptions.class));
- Assert.assertThat(
- mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(type));
+ MockitoHamcrest.argThat(AllOf.allOf(matchers)),
+ any(String[].class),
+ any(BroadcastOptions.class));
+ }
+
+ private void verifySendBroadcast(Matcher<Intent>... matchers) {
+ mInOrder.verify(mHeadsetClientService)
+ .sendBroadcast(
+ MockitoHamcrest.argThat(AllOf.allOf(matchers)),
+ anyString(),
+ any(Bundle.class));
+ }
+
+ private void sendMessage(Message msg) {
+ mHeadsetClientStateMachine.sendMessage(msg);
+ mTestLooper.dispatchAll();
+ }
+
+ private void sendMessage(int what) {
+ sendMessage(mHeadsetClientStateMachine.obtainMessage(what));
+ }
+
+ private void sendMessage(int what, Object obj) {
+ sendMessage(mHeadsetClientStateMachine.obtainMessage(what, obj));
+ }
+
+ private void sendMessage(int what, int arg1, int arg2) {
+ sendMessage(mHeadsetClientStateMachine.obtainMessage(what, arg1, arg2));
+ }
+
+ private void sendMessage(int what, int arg1, int arg2, Object obj) {
+ sendMessage(mHeadsetClientStateMachine.obtainMessage(what, arg1, arg2, obj));
+ }
+
+ private <T> void sendMessageAndVerifyTransition(Message msg, Class<T> type) {
+ int previousState = mHeadsetClientStateMachine.getConnectionState(mTestDevice);
+
+ sendMessage(msg);
+
+ int newState = mHeadsetClientStateMachine.getConnectionState(mTestDevice);
+ verifySendBroadcastMultiplePermissions(
+ hasExtra(EXTRA_PREVIOUS_STATE, previousState), hasExtra(EXTRA_STATE, newState));
+
+ assertThat(mHeadsetClientStateMachine.getCurrentState()).isInstanceOf(type);
}
public static class TestHeadsetClientStateMachine extends HeadsetClientStateMachine {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapActivityTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapActivityTest.java
index 54674b1d14..1e837f3d9a 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapActivityTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapActivityTest.java
@@ -84,7 +84,12 @@ public class BluetoothPbapActivityTest {
if (mActivityScenario != null) {
// Workaround for b/159805732. Without this, test hangs for 45 seconds.
Thread.sleep(1_000);
- mActivityScenario.close();
+ try {
+ mActivityScenario.close();
+ } catch (Exception e) {
+ // Ignore exception: Sometimes the state does not reach "DESTROYED",
+ // however this should not affect our test.
+ }
}
enableActivity(false);
BluetoothMethodProxy.setInstanceForTesting(null);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceTest.java
index dbbb53e9d8..b5d098695a 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbap/BluetoothPbapServiceTest.java
@@ -18,6 +18,8 @@ package com.android.bluetooth.pbap;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -31,6 +33,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Message;
import android.os.UserManager;
import android.os.test.TestLooper;
@@ -97,6 +100,10 @@ public class BluetoothPbapServiceTest {
mService = new BluetoothPbapService(mAdapterService, mNotificationManager);
mService.start();
mService.setAvailable(true);
+
+ PackageManager pm = mTargetContext.getPackageManager();
+ assumeNotNull(pm);
+ assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
}
@After
diff --git a/android/pandora/mmi2grpc/pyrightconfig.json b/android/pandora/mmi2grpc/pyrightconfig.json
deleted file mode 100644
index fab9f6135d..0000000000
--- a/android/pandora/mmi2grpc/pyrightconfig.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "typeCheckingMode": "strict",
- "useLibraryCodeForTypes": true,
- "verboseOutput": false,
- "reportMissingTypeStubs": false,
- "reportUnknownLambdaType": false,
- "reportImportCycles": false,
- "reportPrivateUsage": false,
- "extraPaths": [
- "../../../pandora/server",
- "../../../../../../out/soong/.intermediates/external/pandora/bt-test-interfaces/python/pandora-python-gen-src/gen/",
- "../../../../../../out/soong/.intermediates/packages/modules/Bluetooth/pandora/interfaces/python/pandora_experimental-python-gen-src/gen/"
- ]
-}
diff --git a/android/pandora/server/src/Hap.kt b/android/pandora/server/src/Hap.kt
index 92fb7bbab6..c4a6f84805 100644
--- a/android/pandora/server/src/Hap.kt
+++ b/android/pandora/server/src/Hap.kt
@@ -156,8 +156,7 @@ class Hap(val context: Context) : HAPImplBase(), Closeable {
) {
grpcUnary<GetPresetRecordResponse>(scope, responseObserver) {
val device = request.connection.toBluetoothDevice(bluetoothAdapter)
-
- Log.i(TAG, "getPresetRecord device=${device.address} index=${request.index}")
+ Log.i(TAG, "getPresetRecord($device, ${request.index})")
val presetInfo: BluetoothHapPresetInfo? =
bluetoothHapClient.getPresetInfo(device, request.index)
@@ -211,8 +210,7 @@ class Hap(val context: Context) : HAPImplBase(), Closeable {
) {
grpcUnary<Empty>(scope, responseObserver) {
val device = request.connection.toBluetoothDevice(bluetoothAdapter)
-
- Log.i(TAG, "writePresetName index=${request.index} name=${request.name}")
+ Log.i(TAG, "writePresetName($device, ${request.index}, ${request.name})")
bluetoothHapClient.setPresetName(device, request.index, request.name)
@@ -226,8 +224,7 @@ class Hap(val context: Context) : HAPImplBase(), Closeable {
) {
grpcUnary<Empty>(scope, responseObserver) {
val device = request.connection.toBluetoothDevice(bluetoothAdapter)
-
- Log.i(TAG, "SetActivePreset")
+ Log.i(TAG, "SetActivePreset($device, ${request.index})")
bluetoothHapClient.selectPreset(device, request.index)
@@ -241,8 +238,7 @@ class Hap(val context: Context) : HAPImplBase(), Closeable {
) {
grpcUnary<Empty>(scope, responseObserver) {
val device = request.connection.toBluetoothDevice(bluetoothAdapter)
-
- Log.i(TAG, "setNextPreset")
+ Log.i(TAG, "setNextPreset($device)")
bluetoothHapClient.switchToNextPreset(device)
@@ -256,8 +252,7 @@ class Hap(val context: Context) : HAPImplBase(), Closeable {
) {
grpcUnary<Empty>(scope, responseObserver) {
val device = request.connection.toBluetoothDevice(bluetoothAdapter)
-
- Log.i(TAG, "setPreviousPreset")
+ Log.i(TAG, "setPreviousPreset($device)")
bluetoothHapClient.switchToPreviousPreset(device)
diff --git a/android/pandora/test/hap_test.py b/android/pandora/test/hap_test.py
index f382cd8601..ec1fd40f89 100644
--- a/android/pandora/test/hap_test.py
+++ b/android/pandora/test/hap_test.py
@@ -18,6 +18,7 @@ from bumble.gatt import GATT_HEARING_ACCESS_SERVICE, GATT_AUDIO_STREAM_CONTROL_S
from bumble.profiles import hap
from bumble.profiles.hap import DynamicPresets, HearingAccessService, HearingAidFeatures, HearingAidType, IndependentPresets, PresetRecord, PresetSynchronizationSupport, WritablePresetsSupport
+from pandora_experimental.os_grpc_aio import Os as OsAio
from pandora_experimental.gatt_grpc_aio import GATT
from pandora_experimental.hap_grpc_aio import HAP
from pandora_experimental.hap_pb2 import PresetRecord as grpcPresetRecord # type: ignore
@@ -84,6 +85,8 @@ class HapTest(base_test.BaseTestClass):
@asynchronous
async def setup_test(self) -> None:
await asyncio.gather(self.dut.reset(), self.ref_left.reset())
+ self.logcat = OsAio(channel=self.dut.aio.channel)
+ await self.logcat.Log("setup test")
self.hap_grpc = HAP(channel=self.dut.aio.channel)
device_features = HearingAidFeatures(HearingAidType.MONAURAL_HEARING_AID,
PresetSynchronizationSupport.PRESET_SYNCHRONIZATION_IS_NOT_SUPPORTED,
@@ -162,6 +165,7 @@ class HapTest(base_test.BaseTestClass):
@asynchronous
async def test_get_features(self) -> None:
+ await self.logcat.Log("test_get_features")
dut_connection_to_ref = await self.setupHapConnection()
features = hap.HearingAidFeatures_from_bytes(
@@ -170,6 +174,7 @@ class HapTest(base_test.BaseTestClass):
@asynchronous
async def test_get_preset(self) -> None:
+ await self.logcat.Log("test_get_preset")
dut_connection_to_ref = await self.setupHapConnection()
await self.assertIdentiqPresetInDutAndRef(dut_connection_to_ref)
diff --git a/android/pandora/test/pyrightconfig.json b/android/pandora/test/pyrightconfig.json
deleted file mode 100644
index ea458b5c64..0000000000
--- a/android/pandora/test/pyrightconfig.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "typeCheckingMode": "strict",
- "useLibraryCodeForTypes": true,
- "verboseOutput": false,
- "reportMissingTypeStubs": false,
- "reportUnknownLambdaType": false,
- "reportImportCycles": false,
- "reportPrivateUsage": false,
- "extraPaths": [
- "../../../pandora/server",
- "../../../../../../external/pandora/avatar",
- "../../../../../../external/python/bumble",
- "../../../../../../external/python/mobly",
- "../../../../../../external/python/pyee",
- "../../../../../../external/python/portpicker/src",
- "../../../../../../out/soong/.intermediates/external/pandora/bt-test-interfaces/python/pandora-python-gen-src/gen/",
- "../../../../../../out/soong/.intermediates/packages/modules/Bluetooth/pandora/interfaces/python/pandora_experimental-python-gen-src/gen/"
- ]
-} \ No newline at end of file
diff --git a/flags/framework.aconfig b/flags/framework.aconfig
index c2f1f51e81..7834bfd524 100644
--- a/flags/framework.aconfig
+++ b/flags/framework.aconfig
@@ -28,14 +28,6 @@ flag {
}
flag {
- name: "key_missing_broadcast"
- is_exported: true
- namespace: "bluetooth"
- description: "Broadcast when remote device it lost bond"
- bug: "311447399"
-}
-
-flag {
name: "identity_address_null_if_not_known"
namespace: "bluetooth"
description: "Return null for identity address if identity address is not known"
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 0a65d636c1..8fb6d6940a 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -225,7 +225,7 @@ package android.bluetooth {
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_ACCESS_CANCEL = "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_ACCESS_REPLY = "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_ACCESS_REQUEST = "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
- field @FlaggedApi("com.android.bluetooth.flags.key_missing_broadcast") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_KEY_MISSING = "android.bluetooth.device.action.KEY_MISSING";
+ field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_KEY_MISSING = "android.bluetooth.device.action.KEY_MISSING";
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PAIRING_CANCEL = "android.bluetooth.device.action.PAIRING_CANCEL";
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
field @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public static final String ACTION_SWITCH_BUFFER_SIZE = "android.bluetooth.device.action.SWITCH_BUFFER_SIZE";
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index 206056a92e..23b85060dc 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -302,7 +302,6 @@ public final class BluetoothDevice implements Parcelable, Attributable {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_KEY_MISSING_BROADCAST)
@SuppressLint("ActionValue")
@RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
diff --git a/pyrightconfig.json b/pyrightconfig.json
new file mode 100644
index 0000000000..e2b62afdf1
--- /dev/null
+++ b/pyrightconfig.json
@@ -0,0 +1,34 @@
+{
+ "typeCheckingMode": "strict",
+ "useLibraryCodeForTypes": true,
+ "verboseOutput": false,
+ "reportMissingTypeStubs": false,
+ "reportUnknownLambdaType": false,
+ "reportImportCycles": false,
+ "reportPrivateUsage": false,
+ "executionEnvironments": [
+ {
+ "root": "android/pandora/test",
+ "extraPaths": ["pandora/server"]
+ },
+ {
+ "root": "android/pandora/mmi2grpc"
+ },
+ {
+ "root": "pandora/server/bumble_experimental"
+ },
+ {
+ "root": "framework/tests/bumble/src/bumble_server.py",
+ "extraPaths": ["pandora/server"]
+ }
+ ],
+ "extraPaths": [
+ "../../../external/pandora/avatar",
+ "../../../external/python/bumble",
+ "../../../external/python/mobly",
+ "../../../external/python/pyee",
+ "../../../external/python/portpicker/src",
+ "../../../out/soong/.intermediates/external/pandora/bt-test-interfaces/python/pandora-python-gen-src/gen/",
+ "../../../out/soong/.intermediates/packages/modules/Bluetooth/pandora/interfaces/python/pandora_experimental-python-gen-src/gen/"
+ ]
+}
diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
index 6c0f74c635..b59ab9de45 100644
--- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java
+++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.bluetooth;
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.bluetooth.BluetoothAdapter.STATE_BLE_ON;
import static android.bluetooth.BluetoothAdapter.STATE_BLE_TURNING_OFF;
import static android.bluetooth.BluetoothAdapter.STATE_BLE_TURNING_ON;
@@ -254,6 +255,13 @@ class BluetoothManagerService {
}
mName = name;
Log.v(TAG, "storeName(" + mName + "): Success");
+ mContext.sendBroadcastAsUser(
+ new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)
+ .putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, name)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
+ UserHandle.ALL,
+ BLUETOOTH_CONNECT,
+ getTempAllowlistBroadcastOptions());
}
private void storeAddress(String address) {
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index c2e71a97c8..1b72eb4cb7 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -11,6 +11,7 @@ sysprop_library {
"ble.sysprop",
"bta.sysprop",
"device_id.sysprop",
+ "gap.sysprop",
"hfp.sysprop",
],
property_owner: "Platform",
diff --git a/sysprop/BUILD.gn b/sysprop/BUILD.gn
index 09126c8df0..407b7a88fc 100644
--- a/sysprop/BUILD.gn
+++ b/sysprop/BUILD.gn
@@ -7,6 +7,7 @@ sysprop("libcom.android.sysprop.bluetooth") {
"ble.sysprop",
"bta.sysprop",
"device_id.sysprop",
+ "gap.sysprop",
"hfp.sysprop",
]
deps = [ "//bt/floss/android-base:android-base" ]
diff --git a/sysprop/exported_include/android_bluetooth_sysprop.h b/sysprop/exported_include/android_bluetooth_sysprop.h
index 50553ecc5b..8d5122d8e2 100644
--- a/sysprop/exported_include/android_bluetooth_sysprop.h
+++ b/sysprop/exported_include/android_bluetooth_sysprop.h
@@ -21,4 +21,5 @@
#include <ble.sysprop.h>
#include <bta.sysprop.h>
#include <device_id.sysprop.h>
+#include <gap.sysprop.h>
#include <hfp.sysprop.h>
diff --git a/sysprop/gap.sysprop b/sysprop/gap.sysprop
new file mode 100644
index 0000000000..e9f7e00a3c
--- /dev/null
+++ b/sysprop/gap.sysprop
@@ -0,0 +1,12 @@
+module: "android.sysprop.bluetooth.Gap"
+owner: Platform
+
+prop {
+ api_name: "min_key_size"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "bluetooth.gap.min_key_size"
+}
+
+
diff --git a/system/bta/dm/bta_dm_disc.cc b/system/bta/dm/bta_dm_disc.cc
index f22870f900..455309e60a 100644
--- a/system/bta/dm/bta_dm_disc.cc
+++ b/system/bta/dm/bta_dm_disc.cc
@@ -31,8 +31,10 @@
#include "bta/dm/bta_dm_disc_int.h"
#include "bta/include/bta_gatt_api.h"
+#include "btif/include/btif_storage.h"
#include "common/circular_buffer.h"
#include "common/strings.h"
+#include "device/include/interop.h"
#include "internal_include/bt_target.h"
#include "main/shim/dumpsys.h"
#include "os/logging/log_adapter.h"
@@ -276,8 +278,17 @@ static void bta_dm_disc_result(tBTA_DM_SVC_RES& disc_result) {
bta_dm_discovery_cb.service_search_cbacks.on_service_discovery_results(r.bd_addr, r.uuids,
r.result);
} else {
+ char remote_name[BD_NAME_LEN] = "";
bta_dm_discovery_cb.transports &= ~BT_TRANSPORT_LE;
- GAP_BleReadPeerPrefConnParams(bta_dm_discovery_cb.peer_bdaddr);
+ if (btif_storage_get_stored_remote_name(bta_dm_discovery_cb.peer_bdaddr, remote_name) &&
+ interop_match_name(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS, remote_name)) {
+ // Some devices provide PPCP values that are incompatible with the device-side firmware.
+ log::info("disable PPCP read: interop matched name {} address {}", remote_name,
+ bta_dm_discovery_cb.peer_bdaddr);
+ } else {
+ log::info("reading PPCP");
+ GAP_BleReadPeerPrefConnParams(bta_dm_discovery_cb.peer_bdaddr);
+ }
bta_dm_discovery_cb.service_search_cbacks.on_gatt_results(bta_dm_discovery_cb.peer_bdaddr,
disc_result.gatt_uuids,
diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc
index 636951cb8c..95eb0a7337 100644
--- a/system/bta/gatt/bta_gattc_act.cc
+++ b/system/bta/gatt/bta_gattc_act.cc
@@ -297,7 +297,7 @@ void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) {
/* close all CLCB related to this app */
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb : bta_gattc_cb.clcb_set) {
- if (p_clcb->p_rcb != p_clreg) {
+ if (!p_clcb->in_use || p_clcb->p_rcb != p_clreg) {
continue;
}
p_clreg->dereg_pending = true;
@@ -1504,7 +1504,8 @@ void bta_gattc_process_api_refresh(const RawAddress& remote_bda) {
tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb_i : bta_gattc_cb.clcb_set) {
- if (p_clcb_i->p_srcb == p_srvc_cb) {
+ if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srvc_cb) {
+ p_clcb = p_clcb_i.get();
found = true;
break;
}
@@ -1576,7 +1577,7 @@ static bool bta_gattc_process_srvc_chg_ind(tCONN_ID conn_id, tBTA_GATTC_RCB* p_c
if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) {
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb_i : bta_gattc_cb.clcb_set) {
- if (p_clcb_i->p_srcb == p_srcb && p_clcb_i->p_q_cmd == NULL) {
+ if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srcb && p_clcb_i->p_q_cmd == NULL) {
p_clcb = p_clcb_i.get();
break;
}
diff --git a/system/bta/gatt/bta_gattc_utils.cc b/system/bta/gatt/bta_gattc_utils.cc
index 606566827a..8b0870f55f 100644
--- a/system/bta/gatt/bta_gattc_utils.cc
+++ b/system/bta/gatt/bta_gattc_utils.cc
@@ -145,7 +145,7 @@ tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if, const RawAddress&
tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(tCONN_ID conn_id) {
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb : bta_gattc_cb.clcb_set) {
- if (p_clcb->bta_conn_id == conn_id) {
+ if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) {
return p_clcb.get();
}
}
@@ -960,6 +960,9 @@ void bta_gatt_client_dump(int fd) {
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
stream << " ->clcb (dynamic)\n";
for (auto& p_clcb : bta_gattc_cb.clcb_set) {
+ if (!p_clcb->in_use) {
+ continue;
+ }
entry_count++;
stream << " conn_id: " << loghex(p_clcb->bta_conn_id)
<< " address: " << ADDRESS_TO_LOGGABLE_STR(p_clcb->bda)
diff --git a/system/bta/has/has_client.cc b/system/bta/has/has_client.cc
index fddb26cd65..03f75a72e9 100644
--- a/system/bta/has/has_client.cc
+++ b/system/bta/has/has_client.cc
@@ -1394,6 +1394,12 @@ private:
break;
}
+ if (!device.has_presets.contains(nt.index)) {
+ log::error("Unknown preset. Notification is discarded: {}", nt);
+ device.has_journal_.Append(HasJournalRecord(nt));
+ device.ctp_notifications_.pop_front();
+ continue;
+ }
auto preset = device.has_presets.extract(nt.index).value();
auto new_props = preset.GetProperties();
@@ -1560,7 +1566,15 @@ private:
/* Get the active preset value */
auto* pp = value;
- STREAM_TO_UINT8(device->currently_active_preset, pp);
+ uint8_t active_preset_index;
+ STREAM_TO_UINT8(active_preset_index, pp);
+ if (active_preset_index != 0 && device->isGattServiceValid() &&
+ !device->has_presets.contains(active_preset_index)) {
+ log::error("Unknown preset {}. Active preset change is discarded", active_preset_index);
+ device->has_journal_.Append(HasJournalRecord(active_preset_index, false));
+ return;
+ }
+ device->currently_active_preset = active_preset_index;
if (device->isGattServiceValid()) {
btif_storage_set_leaudio_has_active_preset(device->addr, device->currently_active_preset);
@@ -1573,7 +1587,9 @@ private:
MarkDeviceValidIfInInitialDiscovery(*device);
if (device->isGattServiceValid()) {
- if (!pending_group_operation_timeouts_.empty()) {
+ if (pending_group_operation_timeouts_.empty()) {
+ callbacks_->OnActivePresetSelected(device->addr, device->currently_active_preset);
+ } else {
for (auto it = pending_group_operation_timeouts_.rbegin();
it != pending_group_operation_timeouts_.rend(); ++it) {
auto& group_op_coordinator = it->second;
@@ -1609,9 +1625,6 @@ private:
break;
}
}
-
- } else {
- callbacks_->OnActivePresetSelected(device->addr, device->currently_active_preset);
}
}
}
diff --git a/system/bta/ras/ras_client.cc b/system/bta/ras/ras_client.cc
index 8d5cd3b473..093dfe0265 100644
--- a/system/bta/ras/ras_client.cc
+++ b/system/bta/ras/ras_client.cc
@@ -20,6 +20,8 @@
#include "bta/include/bta_gatt_api.h"
#include "bta/include/bta_ras_api.h"
#include "bta/ras/ras_types.h"
+#include "gd/hci/controller_interface.h"
+#include "main/shim/entry.h"
#include "os/logging/log_adapter.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_ble_addr.h"
@@ -100,6 +102,11 @@ public:
};
void Initialize() override {
+ auto controller = bluetooth::shim::GetController();
+ if (controller && !controller->SupportsBleChannelSounding()) {
+ log::info("controller does not support channel sounding.");
+ return;
+ }
BTA_GATTC_AppRegister(
[](tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
if (instance && p_data) {
diff --git a/system/bta/ras/ras_server.cc b/system/bta/ras/ras_server.cc
index e6720a440c..a676deb6c4 100644
--- a/system/bta/ras/ras_server.cc
+++ b/system/bta/ras/ras_server.cc
@@ -23,8 +23,10 @@
#include "bta/include/bta_gatt_api.h"
#include "bta/include/bta_ras_api.h"
#include "bta/ras/ras_types.h"
+#include "gd/hci/controller_interface.h"
#include "gd/hci/uuid.h"
#include "gd/os/rand.h"
+#include "main/shim/entry.h"
#include "os/logging/log_adapter.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_ble_addr.h"
@@ -74,11 +76,15 @@ public:
uint16_t last_overwritten_procedure_ = 0;
};
- void Initialize() {
+ void Initialize() override {
+ auto controller = bluetooth::shim::GetController();
+ if (controller && !controller->SupportsBleChannelSounding()) {
+ log::info("controller does not support channel sounding.");
+ return;
+ }
Uuid uuid = Uuid::From128BitBE(bluetooth::os::GenerateRandom<Uuid::kNumBytes128>());
app_uuid_ = uuid;
log::info("Register server with uuid:{}", app_uuid_.ToString());
-
BTA_GATTS_AppRegister(
app_uuid_,
[](tBTA_GATTS_EVT event, tBTA_GATTS* p_data) {
diff --git a/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc
index aeeb450a21..8438dee760 100644
--- a/system/btif/src/bluetooth.cc
+++ b/system/btif/src/bluetooth.cc
@@ -435,9 +435,7 @@ int GetAdapterIndex() { return 0; } // Unsupported outside of FLOSS
#endif
static int init(bt_callbacks_t* callbacks, bool start_restricted, bool is_common_criteria_mode,
- int config_compare_result, const char** /* init_flags */, bool is_atv,
- const char* user_data_directory) {
- (void)user_data_directory;
+ int config_compare_result, bool is_atv) {
log::info(
"start restricted = {} ; common criteria mode = {}, config compare "
"result = {}",
diff --git a/system/btif/src/btif_a2dp_source.cc b/system/btif/src/btif_a2dp_source.cc
index 38c45cc78e..b9004718dc 100644
--- a/system/btif/src/btif_a2dp_source.cc
+++ b/system/btif/src/btif_a2dp_source.cc
@@ -1013,18 +1013,10 @@ static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n,
log::warn("Cannot read RSSI: status {}", status);
}
- // Intel controllers don't handle ReadFailedContactCounter very well, it
- // sends back Hardware Error event which will crash the daemon. So
- // temporarily disable this for Floss.
- // TODO(b/249876976): Intel controllers to handle this command correctly.
- // And if the need for disabling metrics-related HCI call grows, consider
- // creating a framework to avoid ifdefs.
-#ifndef TARGET_FLOSS
status = BTM_ReadFailedContactCounter(peer_bda, btm_read_failed_contact_counter_cb);
if (status != tBTM_STATUS::BTM_CMD_STARTED) {
log::warn("Cannot read Failed Contact Counter: status {}", status);
}
-#endif
status = BTM_ReadTxPower(peer_bda, BT_TRANSPORT_BR_EDR, btm_read_tx_power_cb);
if (status != tBTM_STATUS::BTM_CMD_STARTED) {
diff --git a/system/conf/interop_database.conf b/system/conf/interop_database.conf
index ba5c679b22..c7827c41af 100644
--- a/system/conf/interop_database.conf
+++ b/system/conf/interop_database.conf
@@ -194,6 +194,9 @@ Motorola Keyboard KZ500 v122 = Name_Based
[INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS]
BSMBB09DS = Name_Based
ELECOM = Name_Based
+Dexcom = Name_Based
+DXCM = Name_Based
+DX0 = Name_Based
# Disable role switch for headsets/car-kits
# Some car kits allow role switch but when DUT initiates role switch
diff --git a/system/device/test/interop_test.cc b/system/device/test/interop_test.cc
index e0c44b1cb7..c27801f208 100644
--- a/system/device/test/interop_test.cc
+++ b/system/device/test/interop_test.cc
@@ -365,6 +365,9 @@ TEST_F(InteropTest, test_name_hit) {
"Targus BT Laser Notebook Mouse"));
EXPECT_TRUE(interop_match_name(INTEROP_REMOVE_HID_DIG_DESCRIPTOR, "Motorola Keyboard KZ500"));
EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS, "BSMBB09DS"));
+ EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS, "DXCMog"));
+ EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS, "Dexcom 123"));
+ EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS, "DX01ab"));
EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AAC_CODEC, "abramtek M1"));
EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AAC_VBR_CODEC, "Audi_MMI_2781"));
EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AVDTP_RECONFIGURE, "KMM-BT51*HD"));
diff --git a/system/gd/hci/BUILD.gn b/system/gd/hci/BUILD.gn
index d7366c33b2..8f65671fd7 100644
--- a/system/gd/hci/BUILD.gn
+++ b/system/gd/hci/BUILD.gn
@@ -43,6 +43,7 @@ source_set("BluetoothHciSources") {
deps = [
"//bt/flags:bluetooth_flags_c_lib",
"//bt/system/gd:gd_default_deps",
+ "//bt/sysprop:libcom.android.sysprop.bluetooth",
]
configs += [
diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc
index 3a4ab17dfb..9a3f721110 100644
--- a/system/gd/hci/controller.cc
+++ b/system/gd/hci/controller.cc
@@ -16,6 +16,7 @@
#include "hci/controller.h"
+#include <android_bluetooth_sysprop.h>
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
@@ -39,7 +40,9 @@
namespace bluetooth {
namespace hci {
-constexpr uint8_t kMinEncryptionKeySize = 7; // #define MIN_ENCRYPTION_KEY_SIZE 7
+constexpr int kMinEncryptionKeySize = 7;
+constexpr int kMinEncryptionKeySizeDefault = kMinEncryptionKeySize;
+constexpr int kMaxEncryptionKeySize = 16;
constexpr bool kDefaultVendorCapabilitiesEnabled = true;
static const std::string kPropertyVendorCapabilitiesEnabled =
@@ -107,8 +110,13 @@ struct Controller::impl {
handler->BindOnceOn(this, &Controller::impl::read_buffer_size_complete_handler));
if (is_supported(OpCode::SET_MIN_ENCRYPTION_KEY_SIZE)) {
+ uint8_t min_key_size =
+ (uint8_t)std::min(std::max(android::sysprop::bluetooth::Gap::min_key_size().value_or(
+ kMinEncryptionKeySizeDefault),
+ kMinEncryptionKeySize),
+ kMaxEncryptionKeySize);
hci_->EnqueueCommand(
- SetMinEncryptionKeySizeBuilder::Create(kMinEncryptionKeySize),
+ SetMinEncryptionKeySizeBuilder::Create(min_key_size),
handler->BindOnceOn(this, &Controller::impl::set_min_encryption_key_size_handler));
}
diff --git a/system/gd/hci/distance_measurement_manager.cc b/system/gd/hci/distance_measurement_manager.cc
index 6949069a0b..d7928ee749 100644
--- a/system/gd/hci/distance_measurement_manager.cc
+++ b/system/gd/hci/distance_measurement_manager.cc
@@ -538,7 +538,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
kMaxMainModeSteps, kMainModeRepetition, kMode0Steps, CsRole::INITIATOR,
CsConfigRttType::RTT_WITH_128_BIT_RANDOM_SEQUENCE, CsSyncPhy::LE_1M_PHY,
channel_map, kChannelMapRepetition, CsChannelSelectionType::TYPE_3B,
- CsCh3cShape::HAT_SHAPE, kCh3cJump, Enable::DISABLED),
+ CsCh3cShape::HAT_SHAPE, kCh3cJump),
handler_->BindOnceOn(this, &impl::on_cs_setup_command_status_cb, connection_handle));
}
@@ -906,8 +906,8 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
if (procedure_data->local_status != CsProcedureDoneStatus::PARTIAL_RESULTS &&
unsent_data_size <= kMtuForRasData) {
procedure_data->segmentation_header_.last_segment_ = 1;
- } else if (procedure_data->ras_raw_data_.size() < kMtuForRasData) {
- log::verbose("waiting for more data, current size {}", procedure_data->ras_raw_data_.size());
+ } else if (unsent_data_size < kMtuForRasData) {
+ log::verbose("waiting for more data, current unsent data size {}", unsent_data_size);
return;
}
diff --git a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
index 430454d216..3cc3c91cf2 100644
--- a/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
+++ b/system/gd/rust/linux/dbus_projection/dbus_macros/src/lib.rs
@@ -125,16 +125,21 @@ pub fn generate_dbus_exporter(attr: TokenStream, item: TokenStream) -> TokenStre
for item in ast.items {
if let ImplItem::Method(method) = item {
- if method.attrs.len() != 1 {
- continue;
+ // Find the #[dbus_method] attribute
+ let mut dbus_method_attr = None;
+ for attr in &method.attrs {
+ if attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
+ dbus_method_attr = Some(attr);
+ break;
+ }
}
- let attr = &method.attrs[0];
- if !attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
+ // Skip the method is not marked with #[dbus_method].
+ if dbus_method_attr.is_none() {
continue;
}
- let meta_list = match attr.parse_meta().unwrap() {
+ let meta_list = match dbus_method_attr.unwrap().parse_meta().unwrap() {
Meta::List(meta_list) => meta_list,
_ => continue,
};
@@ -333,9 +338,17 @@ pub fn generate_dbus_interface_client(attr: TokenStream, item: TokenStream) -> T
// Iterate on every methods of a trait impl
for item in ast.items {
if let ImplItem::Method(method) = item {
- // If the method is not marked with #[dbus_method], just copy the
- // original method body.
- if method.attrs.len() != 1 {
+ // Find the #[dbus_method] attribute
+ let mut dbus_method_attr = None;
+ for attr in &method.attrs {
+ if attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
+ dbus_method_attr = Some(attr);
+ break;
+ }
+ }
+
+ // If the method is not marked with #[dbus_method], just copy the original method body.
+ if dbus_method_attr.is_none() {
methods = quote! {
#methods
@@ -344,15 +357,9 @@ pub fn generate_dbus_interface_client(attr: TokenStream, item: TokenStream) -> T
continue;
}
- let attr = &method.attrs[0];
- if !attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
- continue;
- }
-
- let sig = &method.sig;
-
// For RPC-friendly method, copy the original signature but add public, async, and wrap
// the return with Result.
+ let sig = &method.sig;
let mut rpc_sig = sig.clone();
rpc_sig.asyncness = Some(<syn::Token![async]>::default());
rpc_sig.output = match rpc_sig.output {
@@ -367,11 +374,12 @@ pub fn generate_dbus_interface_client(attr: TokenStream, item: TokenStream) -> T
pub #rpc_sig
};
- let dbus_method_name = if let Meta::List(meta_list) = attr.parse_meta().unwrap() {
- Some(meta_list.nested[0].clone())
- } else {
- None
- };
+ let dbus_method_name =
+ if let Meta::List(meta_list) = dbus_method_attr.unwrap().parse_meta().unwrap() {
+ Some(meta_list.nested[0].clone())
+ } else {
+ None
+ };
if dbus_method_name.is_none() {
continue;
@@ -769,9 +777,17 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream {
for item in ast.items {
if let ImplItem::Method(method) = item {
- // If the method is not marked with #[dbus_method], just copy the
- // original method body.
- if method.attrs.len() != 1 {
+ // Find the #[dbus_method] attribute
+ let mut dbus_method_attr = None;
+ for attr in &method.attrs {
+ if attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
+ dbus_method_attr = Some(attr);
+ break;
+ }
+ }
+
+ // If the method is not marked with #[dbus_method], just copy the original method body.
+ if dbus_method_attr.is_none() {
method_impls = quote! {
#method_impls
#method
@@ -779,12 +795,7 @@ pub fn dbus_proxy_obj(attr: TokenStream, item: TokenStream) -> TokenStream {
continue;
}
- let attr = &method.attrs[0];
- if !attr.path.get_ident().unwrap().to_string().eq("dbus_method") {
- continue;
- }
-
- let meta_list = match attr.parse_meta().unwrap() {
+ let meta_list = match dbus_method_attr.unwrap().parse_meta().unwrap() {
Meta::List(meta_list) => meta_list,
_ => continue,
};
diff --git a/system/gd/rust/topshim/src/btif.rs b/system/gd/rust/topshim/src/btif.rs
index 5a6d76b770..e3bd8480c3 100644
--- a/system/gd/rust/topshim/src/btif.rs
+++ b/system/gd/rust/topshim/src/btif.rs
@@ -1262,9 +1262,7 @@ impl BluetoothInterface {
guest_mode,
is_common_criteria_mode,
config_compare_result,
- std::ptr::null_mut(),
- is_atv,
- std::ptr::null()
+ is_atv
);
self.is_init = init == 0;
diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h
index 7e891573b9..77ff10a999 100644
--- a/system/include/hardware/bluetooth.h
+++ b/system/include/hardware/bluetooth.h
@@ -691,8 +691,7 @@ typedef struct {
* the local device is an Android TV
*/
int (*init)(bt_callbacks_t* callbacks, bool guest_mode, bool is_common_criteria_mode,
- int config_compare_result, const char** init_flags, bool is_atv,
- const char* user_data_directory);
+ int config_compare_result, bool is_atv);
/** Enable Bluetooth. */
int (*enable)();
diff --git a/system/main/Android.bp b/system/main/Android.bp
index a0d8ffe633..629735a233 100644
--- a/system/main/Android.bp
+++ b/system/main/Android.bp
@@ -65,7 +65,6 @@ cc_library {
visibility: [
"//cts/hostsidetests:__subpackages__",
"//packages/modules/Bluetooth:__subpackages__",
- "//vendor:__subpackages__",
],
defaults: ["fluoride_defaults"],
header_libs: ["libbluetooth_headers"],
diff --git a/system/pdl/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl
index 9225204045..df7c47db2a 100644
--- a/system/pdl/hci/hci_packets.pdl
+++ b/system/pdl/hci/hci_packets.pdl
@@ -5012,6 +5012,7 @@ packet LeCsReadLocalSupportedCapabilitiesComplete : CommandComplete (command_op_
optional_t_fcs_times_supported : CsOptionalTFcsTimesSupported,
optional_t_pm_times_supported : CsOptionalTPmTimesSupported,
t_sw_time_supported : 8,
+ optional_tx_snr_capability : 8,
}
packet LeCsReadRemoteSupportedCapabilities : DistanceMeasurementCommand (op_code = LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES) {
@@ -5044,6 +5045,7 @@ packet LeCsWriteCachedRemoteSupportedCapabilities : DistanceMeasurementCommand (
optional_t_fcs_times_supported : CsOptionalTFcsTimesSupported,
optional_t_pm_times_supported : CsOptionalTPmTimesSupported,
t_sw_time_supported : 8,
+ optional_tx_snr_capability: 8,
}
packet LeCsWriteCachedRemoteSupportedCapabilitiesComplete : CommandComplete (command_op_code = LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES) {
@@ -5173,7 +5175,7 @@ packet LeCsCreateConfig : DistanceMeasurementCommand (op_code = LE_CS_CREATE_CON
channel_selection_type : CsChannelSelectionType,
ch3c_shape : CsCh3cShape,
ch3c_jump : 8,
- companion_signal_enable : Enable,
+ _reserved_ : 8,
}
packet LeCsCreateConfigStatus : CommandStatus (command_op_code = LE_CS_CREATE_CONFIG) {
@@ -6801,6 +6803,7 @@ packet LeCsReadRemoteSupportedCapabilitiesComplete : LeMetaEvent (subevent_code
optional_t_fcs_times_supported : CsOptionalTFcsTimesSupported,
optional_t_pm_times_supported : CsOptionalTPmTimesSupported,
t_sw_time_supported : 8,
+ optional_tx_snr_capability : 8,
}
packet LeCsReadRemoteFaeTableComplete : LeMetaEvent (subevent_code = LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE) {
@@ -6854,7 +6857,7 @@ packet LeCsConfigComplete : LeMetaEvent (subevent_code = LE_CS_CONFIG_COMPLETE)
channel_selection_type : CsChannelSelectionType,
ch3c_shape : CsCh3cShape,
ch3c_jump : 8,
- companion_signal_enable : Enable,
+ _reserved_ : 8,
t_ip1_time : 8,
t_ip2_time : 8,
t_fcs_time : 8,
diff --git a/system/stack/btm/btm_sco_hfp_hal_linux.cc b/system/stack/btm/btm_sco_hfp_hal_linux.cc
index 1488b6899e..018ba1fd65 100644
--- a/system/stack/btm/btm_sco_hfp_hal_linux.cc
+++ b/system/stack/btm/btm_sco_hfp_hal_linux.cc
@@ -294,6 +294,13 @@ void init() {
bluetooth::log::info("Successfully queried SCO codec capabilities.");
}
+#ifndef TARGET_FLOSS
+ // If hfp software path is not enabled, fallback to offload path.
+ if (!osi_property_get_bool("bluetooth.hfp.software_datapath.enabled", false)) {
+ enable_offload(true);
+ }
+#endif
+
close(fd);
}
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index d458bf79a8..e647715e40 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -26,6 +26,7 @@
#include "stack/btm/btm_sec.h"
+#include <android_bluetooth_sysprop.h>
#include <base/functional/bind.h>
#include <base/strings/stringprintf.h>
#include <bluetooth/log.h>
@@ -3365,7 +3366,16 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, uint8_t encr_en
}
}
-constexpr uint8_t MIN_KEY_SIZE = 7;
+constexpr int MIN_KEY_SIZE = 7;
+constexpr int MIN_KEY_SIZE_DEFAULT = MIN_KEY_SIZE;
+constexpr int MAX_KEY_SIZE = 16;
+static uint8_t get_min_enc_key_size() {
+ static uint8_t min_key_size = (uint8_t)std::min(
+ std::max(android::sysprop::bluetooth::Gap::min_key_size().value_or(MIN_KEY_SIZE_DEFAULT),
+ MIN_KEY_SIZE),
+ MAX_KEY_SIZE);
+ return min_key_size;
+}
static void read_encryption_key_size_complete_after_encryption_change(uint8_t status,
uint16_t handle,
@@ -3386,7 +3396,7 @@ static void read_encryption_key_size_complete_after_encryption_change(uint8_t st
return;
}
- if (key_size < MIN_KEY_SIZE) {
+ if (key_size < get_min_enc_key_size()) {
log::error("encryption key too short, disconnecting. handle:0x{:x},key_size:{}", handle,
key_size);
@@ -3961,7 +3971,7 @@ static void read_encryption_key_size_complete_after_key_refresh(uint8_t status,
return;
}
- if (key_size < MIN_KEY_SIZE) {
+ if (key_size < get_min_enc_key_size()) {
log::error("encryption key too short, disconnecting. handle: 0x{:x} key_size {}", handle,
key_size);
diff --git a/system/test/headless/headless.cc b/system/test/headless/headless.cc
index dd15c2a557..ebfcb041ec 100644
--- a/system/test/headless/headless.cc
+++ b/system/test/headless/headless.cc
@@ -258,7 +258,7 @@ void HeadlessStack::SetUp() {
const bool is_atv = false;
int status = bluetoothInterface.init(&bt_callbacks, start_restricted, is_common_criteria_mode,
- config_compare_result, nullptr, is_atv, nullptr);
+ config_compare_result, is_atv);
if (status == BT_STATUS_SUCCESS) {
log::info("Initialized bluetooth callbacks");
diff --git a/system/test/mock/mock_stack_btm_interface.cc b/system/test/mock/mock_stack_btm_interface.cc
index 7016d4b662..116d2008af 100644
--- a/system/test/mock/mock_stack_btm_interface.cc
+++ b/system/test/mock/mock_stack_btm_interface.cc
@@ -142,6 +142,10 @@ struct btm_client_interface_t default_btm_client_interface = {
},
.BTM_IsLinkKeyKnown = [](const RawAddress& /* bd_addr */,
tBT_TRANSPORT /* transport */) -> bool { return false; },
+ .BTM_SetSecurityLevel = [](bool /* is_originator */, const char* /*p_name */,
+ uint8_t /* service_id */, uint16_t /* sec_level */,
+ uint16_t /* psm */, uint32_t /* mx_proto_id */,
+ uint32_t /* mx_chan_id */) -> bool { return false; },
.BTM_SecClrService = [](uint8_t /* service_id */) -> uint8_t { return 0; },
.BTM_SecClrServiceByPsm = [](uint16_t /* psm */) -> uint8_t { return 0; },
.BTM_SecBond = [](const RawAddress& /* bd_addr */, tBLE_ADDR_TYPE /* addr_type */,
@@ -150,7 +154,6 @@ struct btm_client_interface_t default_btm_client_interface = {
.BTM_SecBondCancel = [](const RawAddress& /* bd_addr */) -> tBTM_STATUS {
return tBTM_STATUS::BTM_SUCCESS;
},
-
.BTM_RemoteOobDataReply = [](tBTM_STATUS /* res */, const RawAddress& /* bd_addr */,
const Octet16& /* c */, const Octet16& /* r */) {},
.BTM_PINCodeReply = [](const RawAddress& /* bd_addr */, tBTM_STATUS /* res */,
diff --git a/system/test/suite/adapter/adapter_unittest.cc b/system/test/suite/adapter/adapter_unittest.cc
index 65de637a7c..8e2769ea10 100644
--- a/system/test/suite/adapter/adapter_unittest.cc
+++ b/system/test/suite/adapter/adapter_unittest.cc
@@ -160,7 +160,7 @@ TEST_F(BluetoothTest, AdapterCleanupDuringDiscovery) {
ASSERT_TRUE(callbacks != nullptr);
for (int i = 0; i < kTestRepeatCount; ++i) {
- bt_interface()->init(callbacks, false, false, 0, nullptr, false, nullptr);
+ bt_interface()->init(callbacks, false, false, 0, false);
EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
semaphore_wait(adapter_state_changed_callback_sem_);
EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
diff --git a/system/test/suite/adapter/bluetooth_test.cc b/system/test/suite/adapter/bluetooth_test.cc
index e28a2259fa..4855b7a72d 100644
--- a/system/test/suite/adapter/bluetooth_test.cc
+++ b/system/test/suite/adapter/bluetooth_test.cc
@@ -86,7 +86,7 @@ void BluetoothTest::SetUp() {
remove("/data/misc/bluedroid/bt_config.conf.encrypted-checksum");
instance = this;
- int status = bluetoothInterface.init(&callbacks, false, false, 0, nullptr, false, nullptr);
+ int status = bluetoothInterface.init(&callbacks, false, false, 0, false);
ASSERT_EQ(status, BT_STATUS_SUCCESS);
}