Merge "Add flag a2dp_lhdc_api" into main
diff --git a/Android.bp b/Android.bp
index fde5137..9142bd5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -189,10 +189,9 @@
java_defaults {
name: "bluetooth_framework_errorprone_rules",
defaults: ["bluetooth_errorprone_rules"],
- plugins: [
- "error_prone_android_framework",
- ],
errorprone: {
+ extra_check_modules: ["error_prone_android_framework"],
+
javacflags: [
"-Xep:AndroidFrameworkBinderIdentity:ERROR",
"-Xep:AndroidFrameworkBluetoothPermission:ERROR",
diff --git a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java
index 9d39dcb..1dc7533 100644
--- a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java
+++ b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/DistanceMeasurementInitiator.java
@@ -38,6 +38,34 @@
class DistanceMeasurementInitiator {
+ enum Freq {
+ HIGH(DistanceMeasurementParams.REPORT_FREQUENCY_HIGH),
+ MEDIUM(DistanceMeasurementParams.REPORT_FREQUENCY_MEDIUM),
+ LOW(DistanceMeasurementParams.REPORT_FREQUENCY_LOW);
+ private final int freq;
+
+ Freq(int freq) {
+ this.freq = freq;
+ }
+
+ int getFreq() {
+ return freq;
+ }
+
+ @Override
+ public String toString() {
+ return name();
+ }
+
+ public static Freq fromName(String name) {
+ try {
+ return Freq.valueOf(name);
+ } catch (IllegalArgumentException e) {
+ return MEDIUM;
+ }
+ }
+ }
+
private static final int DISTANCE_MEASUREMENT_DURATION_SEC = 3600;
private static final List<Pair<Integer, String>> mDistanceMeasurementMethodMapping =
List.of(
@@ -119,8 +147,12 @@
return methods;
}
+ List<String> getMeasurementFreqs() {
+ return List.of(Freq.MEDIUM.toString(), Freq.HIGH.toString(), Freq.LOW.toString());
+ }
+
@SuppressLint("MissingPermission") // permissions are checked upfront
- void startDistanceMeasurement(String distanceMeasurementMethodName) {
+ void startDistanceMeasurement(String distanceMeasurementMethodName, String selectedFreq) {
if (mTargetDevice == null) {
printLog("do Gatt connect first");
@@ -132,7 +164,7 @@
DistanceMeasurementParams params =
new DistanceMeasurementParams.Builder(mTargetDevice)
.setDurationSeconds(DISTANCE_MEASUREMENT_DURATION_SEC)
- .setFrequency(DistanceMeasurementParams.REPORT_FREQUENCY_LOW)
+ .setFrequency(Freq.fromName(selectedFreq).getFreq())
.setMethodId(getDistanceMeasurementMethodId(distanceMeasurementMethodName))
.build();
DistanceMeasurementManager distanceMeasurementManager =
diff --git a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java
index fe3a211..b1b96d7 100644
--- a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java
+++ b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorFragment.java
@@ -43,9 +43,11 @@
private static final DecimalFormat DISTANCE_DECIMAL_FMT = new DecimalFormat("0.00");
private ArrayAdapter<String> mDmMethodArrayAdapter;
+ private ArrayAdapter<String> mFreqArrayAdapter;
private TextView mDistanceText;
private CanvasView mDistanceCanvasView;
private Spinner mSpinnerDmMethod;
+ private Spinner mSpinnerFreq;
private Button mButtonCs;
private LinearLayout mDistanceViewLayout;
private TextView mLogText;
@@ -63,6 +65,7 @@
mButtonCs = (Button) root.findViewById(R.id.btn_cs);
mSpinnerDmMethod = (Spinner) root.findViewById(R.id.spinner_dm_method);
+ mSpinnerFreq = (Spinner) root.findViewById(R.id.spinner_freq);
mDistanceViewLayout = (LinearLayout) root.findViewById(R.id.layout_distance_view);
mDistanceText = new TextView(getContext());
mDistanceViewLayout.addView(mDistanceText);
@@ -85,6 +88,11 @@
mDmMethodArrayAdapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);
mSpinnerDmMethod.setAdapter(mDmMethodArrayAdapter);
+ mFreqArrayAdapter =
+ new ArrayAdapter<String>(
+ getContext(), android.R.layout.simple_spinner_item, new ArrayList<>());
+ mFreqArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mSpinnerFreq.setAdapter(mFreqArrayAdapter);
mInitiatorViewModel = new ViewModelProvider(this).get(InitiatorViewModel.class);
mBleConnectionViewModel = new ViewModelProvider(this).get(BleConnectionViewModel.class);
@@ -134,14 +142,15 @@
});
mDmMethodArrayAdapter.addAll(mInitiatorViewModel.getSupportedDmMethods());
-
+ mFreqArrayAdapter.addAll(mInitiatorViewModel.getMeasurementFreqs());
mButtonCs.setOnClickListener(
v -> {
String methodName = mSpinnerDmMethod.getSelectedItem().toString();
+ String freq = mSpinnerFreq.getSelectedItem().toString();
if (TextUtils.isEmpty(methodName)) {
printLog("the device doesn't support any distance measurement methods.");
}
- mInitiatorViewModel.toggleCsStartStop(methodName);
+ mInitiatorViewModel.toggleCsStartStop(methodName, freq);
});
}
diff --git a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java
index f54ec7b..e07e7a1 100644
--- a/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java
+++ b/android/ChannelSoundingTestApp/app/src/main/java/com/android/bluetooth/channelsoundingtestapp/InitiatorViewModel.java
@@ -71,9 +71,14 @@
return mDistanceMeasurementInitiator.getDistanceMeasurementMethods();
}
- void toggleCsStartStop(String distanceMeasurementMethodName) {
+ List<String> getMeasurementFreqs() {
+ return mDistanceMeasurementInitiator.getMeasurementFreqs();
+ }
+
+ void toggleCsStartStop(String distanceMeasurementMethodName, String freq) {
if (!mCsStarted.getValue()) {
- mDistanceMeasurementInitiator.startDistanceMeasurement(distanceMeasurementMethodName);
+ mDistanceMeasurementInitiator.startDistanceMeasurement(
+ distanceMeasurementMethodName, freq);
} else {
mDistanceMeasurementInitiator.stopDistanceMeasurement();
}
diff --git a/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml b/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml
index f5f57f2..39b0246 100644
--- a/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml
+++ b/android/ChannelSoundingTestApp/app/src/main/res/layout/fragment_initiator.xml
@@ -21,15 +21,43 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
-
+ <TextView
+ android:id="@+id/dm_method_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text= "Method"
+ app:layout_constraintBottom_toTopOf="@id/btn_cs"
+ app:layout_constraintEnd_toStartOf="@id/spinner_dm_method"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container"
+ />
<Spinner
android:id="@+id/spinner_dm_method"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:padding="10dp"
- app:layout_constraintEnd_toStartOf="@id/btn_cs"
- app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/freq_label"
+ app:layout_constraintStart_toEndOf="@id/dm_method_label"
+ app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container" />
+ <TextView
+ android:id="@+id/freq_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text= "Freq"
+ app:layout_constraintBottom_toTopOf="@id/btn_cs"
+ app:layout_constraintEnd_toStartOf="@id/spinner_freq"
+ app:layout_constraintStart_toEndOf="@id/spinner_dm_method"
+ app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container"
+ />
+ <Spinner
+ android:id="@+id/spinner_freq"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:padding="10dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/freq_label"
app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container" />
<Button
android:id="@+id/btn_cs"
@@ -40,8 +68,8 @@
android:padding="10dp"
android:text="Start Distance Measurement"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@id/spinner_dm_method"
- app:layout_constraintTop_toBottomOf="@id/init_ble_connection_container" />
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/spinner_dm_method" />
<TextView
android:id="@+id/text_log"
android:layout_width="match_parent"
diff --git a/android/app/Android.bp b/android/app/Android.bp
index e8ca967..84de551 100644
--- a/android/app/Android.bp
+++ b/android/app/Android.bp
@@ -259,6 +259,7 @@
"BluetoothApiShims",
"android.hardware.radio-V1.0-java",
"android.hardware.radio.sap-V1-java",
+ "android.media.audio-aconfig-exported-java",
"androidx.annotation_annotation",
"androidx.core_core",
"androidx.lifecycle_lifecycle-livedata",
@@ -283,7 +284,6 @@
plugins: [
"androidx.room_room-compiler-plugin",
- "error_prone_android_framework",
],
// Export schemas to the test directory so that we have an history
diff --git a/android/app/AndroidManifest.xml b/android/app/AndroidManifest.xml
index 3416c8f..3b27e4b 100644
--- a/android/app/AndroidManifest.xml
+++ b/android/app/AndroidManifest.xml
@@ -295,7 +295,7 @@
</activity>
<service android:process="@string/process"
- android:name="com.android.bluetooth.pbapclient.AuthenticationService"
+ android:name="com.android.bluetooth.pbapclient.PbapClientAccountAuthenticatorService"
android:enabled="false"
android:exported="true">
<intent-filter>
diff --git a/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl b/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl
index e09f6e9..f9436a7 100644
--- a/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl
+++ b/android/app/aidl/android/bluetooth/IBluetoothGatt.aidl
@@ -192,4 +192,6 @@
int getChannelSoundingMaxSupportedSecurityLevel(in BluetoothDevice remoteDevice, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
int getLocalChannelSoundingMaxSupportedSecurityLevel(in AttributionSource attributionSource);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ int[] getChannelSoundingSupportedSecurityLevels(in AttributionSource attributionSource);
}
diff --git a/android/app/aidl/android/bluetooth/IBluetoothLeAudio.aidl b/android/app/aidl/android/bluetooth/IBluetoothLeAudio.aidl
index f026d2c..795650b 100644
--- a/android/app/aidl/android/bluetooth/IBluetoothLeAudio.aidl
+++ b/android/app/aidl/android/bluetooth/IBluetoothLeAudio.aidl
@@ -60,6 +60,10 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
void setCodecConfigPreference(in int groupId, in BluetoothLeAudioCodecConfig inputCodecConfig, in BluetoothLeAudioCodecConfig outputCodecConfig, in AttributionSource source);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ void setBroadcastToUnicastFallbackGroup(in int groupId, in AttributionSource attributionSource);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ int getBroadcastToUnicastFallbackGroup(in AttributionSource attributionSource);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
oneway void registerCallback(in IBluetoothLeAudioCallback callback, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
oneway void unregisterCallback(in IBluetoothLeAudioCallback callback, in AttributionSource attributionSource);
diff --git a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
index a0b80f7..5150a01 100644
--- a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
+++ b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
@@ -779,7 +779,7 @@
return JNI_FALSE;
}
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
log::info("key_code: {}, key_state: {}", key_code, key_state);
@@ -808,7 +808,7 @@
return JNI_FALSE;
}
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
log::info("key_code: {}, key_state: {}", key_code, key_state);
@@ -833,7 +833,7 @@
static void setPlayerApplicationSettingValuesNative(JNIEnv* env, jobject /* object */,
jbyteArray address, jbyte num_attrib,
jbyteArray attrib_ids, jbyteArray attrib_val) {
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
if (!sBluetoothAvrcpInterface) {
return;
}
@@ -893,7 +893,7 @@
return;
}
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -916,7 +916,7 @@
jniThrowIOException(env, EINVAL);
return;
}
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -939,7 +939,7 @@
jniThrowIOException(env, EINVAL);
return;
}
- log::verbose("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -961,7 +961,7 @@
jniThrowIOException(env, EINVAL);
return;
}
- log::verbose("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -982,7 +982,7 @@
jniThrowIOException(env, EINVAL);
return;
}
- log::verbose("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -1004,7 +1004,7 @@
jniThrowIOException(env, EINVAL);
return;
}
- log::verbose("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -1025,7 +1025,7 @@
jniThrowIOException(env, EINVAL);
return;
}
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -1053,7 +1053,7 @@
// return;
//}
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
@@ -1077,7 +1077,7 @@
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_cmd(rawAddress, (uint16_t)id);
if (status != BT_STATUS_SUCCESS) {
log::error("Failed sending setBrowsedPlayerNative command, status: {}", bt_status_text(status));
@@ -1098,7 +1098,7 @@
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_cmd(rawAddress, (uint16_t)id);
if (status != BT_STATUS_SUCCESS) {
log::error("Failed sending setAddressedPlayerNative command, status: {}",
@@ -1126,7 +1126,7 @@
RawAddress rawAddress;
rawAddress.FromOctets((uint8_t*)addr);
- log::info("sBluetoothAvrcpInterface: {}", fmt::ptr(sBluetoothAvrcpInterface));
+ log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
bt_status_t status = sBluetoothAvrcpInterface->play_item_cmd(
rawAddress, (uint8_t)scope, (uint8_t*)&uid, (uint16_t)uidCounter);
if (status != BT_STATUS_SUCCESS) {
diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
index da4b61e..0d31f17 100644
--- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -49,12 +49,12 @@
using bluetooth::Uuid;
extern bt_interface_t bluetoothInterface;
-namespace fmt {
+namespace std {
template <>
struct formatter<bt_state_t> : enum_formatter<bt_state_t> {};
template <>
struct formatter<bt_discovery_state_t> : enum_formatter<bt_discovery_state_t> {};
-} // namespace fmt
+} // namespace std
static Uuid from_java_uuid(jlong uuid_msb, jlong uuid_lsb) {
std::array<uint8_t, Uuid::kNumBytes128> uu;
@@ -825,7 +825,7 @@
vm->AttachCurrentThread(&callbackEnv, &args);
sHaveCallbackThread = true;
sCallbackThread = pthread_self();
- log::verbose("Callback thread attached: {}", fmt::ptr(callbackEnv));
+ log::verbose("Callback thread attached: {}", std::format_ptr(callbackEnv));
} else if (event == DISASSOCIATE_JVM) {
if (!isCallbackThread()) {
log::error("Callback: '' is not called on the correct thread");
diff --git a/android/app/lint-baseline.xml b/android/app/lint-baseline.xml
index c972c11..5bd3f2f 100644
--- a/android/app/lint-baseline.xml
+++ b/android/app/lint-baseline.xml
@@ -359,7 +359,7 @@
errorLine1=" SimpleDateFormat parser = new SimpleDateFormat(TIMESTAMP_FORMAT);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/modules/Bluetooth/android/app/src/com/android/bluetooth/pbapclient/CallLogPullRequest.java"
+ file="packages/modules/Bluetooth/android/app/src/com/android/bluetooth/pbapclient/obex/CallLogPullRequest.java"
line="105"
column="43"/>
</issue>
diff --git a/android/app/res/values-af/strings_pbap_client.xml b/android/app/res/values-af/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-af/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-am/strings_pbap_client.xml b/android/app/res/values-am/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-am/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ar/strings_pbap_client.xml b/android/app/res/values-ar/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ar/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-as/strings_pbap_client.xml b/android/app/res/values-as/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-as/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-az/strings_pbap_client.xml b/android/app/res/values-az/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-az/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-b+sr+Latn/strings_pbap_client.xml b/android/app/res/values-b+sr+Latn/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-b+sr+Latn/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-be/strings_pbap_client.xml b/android/app/res/values-be/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-be/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-bg/strings_pbap_client.xml b/android/app/res/values-bg/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-bg/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-bn/strings_pbap_client.xml b/android/app/res/values-bn/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-bn/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-bs/strings_pbap_client.xml b/android/app/res/values-bs/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-bs/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ca/strings_pbap_client.xml b/android/app/res/values-ca/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ca/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-cs/strings_pbap_client.xml b/android/app/res/values-cs/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-cs/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-da/strings_pbap_client.xml b/android/app/res/values-da/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-da/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-de/strings_pbap_client.xml b/android/app/res/values-de/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-de/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-el/strings_pbap_client.xml b/android/app/res/values-el/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-el/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-en-rAU/strings_pbap_client.xml b/android/app/res/values-en-rAU/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-en-rAU/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-en-rCA/strings_pbap_client.xml b/android/app/res/values-en-rCA/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-en-rCA/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-en-rGB/strings_pbap_client.xml b/android/app/res/values-en-rGB/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-en-rGB/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-en-rIN/strings_pbap_client.xml b/android/app/res/values-en-rIN/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-en-rIN/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-en-rXC/strings_pbap_client.xml b/android/app/res/values-en-rXC/strings_pbap_client.xml
deleted file mode 100644
index b27d984..0000000
--- a/android/app/res/values-en-rXC/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-es-rUS/strings_pbap_client.xml b/android/app/res/values-es-rUS/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-es-rUS/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-es/strings_pbap_client.xml b/android/app/res/values-es/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-es/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-et/strings_pbap_client.xml b/android/app/res/values-et/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-et/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-eu/strings_pbap_client.xml b/android/app/res/values-eu/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-eu/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-fa/strings_pbap_client.xml b/android/app/res/values-fa/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-fa/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-fi/strings_pbap_client.xml b/android/app/res/values-fi/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-fi/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-fr-rCA/strings_pbap_client.xml b/android/app/res/values-fr-rCA/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-fr-rCA/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-fr/strings_pbap_client.xml b/android/app/res/values-fr/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-fr/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-gl/strings_pbap_client.xml b/android/app/res/values-gl/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-gl/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-gu/strings_pbap_client.xml b/android/app/res/values-gu/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-gu/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-hi/strings_pbap_client.xml b/android/app/res/values-hi/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-hi/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-hr/strings_pbap_client.xml b/android/app/res/values-hr/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-hr/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-hu/strings_pbap_client.xml b/android/app/res/values-hu/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-hu/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-hy/strings_pbap_client.xml b/android/app/res/values-hy/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-hy/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-in/strings_pbap_client.xml b/android/app/res/values-in/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-in/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-is/strings_pbap_client.xml b/android/app/res/values-is/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-is/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-it/strings_pbap_client.xml b/android/app/res/values-it/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-it/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-iw/strings_pbap_client.xml b/android/app/res/values-iw/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-iw/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ja/strings_pbap_client.xml b/android/app/res/values-ja/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ja/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ka/strings_pbap_client.xml b/android/app/res/values-ka/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ka/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-kk/strings_pbap_client.xml b/android/app/res/values-kk/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-kk/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-km/strings_pbap_client.xml b/android/app/res/values-km/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-km/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-kn/strings_pbap_client.xml b/android/app/res/values-kn/strings_pbap_client.xml
deleted file mode 100644
index 8aceb64..0000000
--- a/android/app/res/values-kn/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.ಬ್ಲೂಟೂತ್.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ko/strings_pbap_client.xml b/android/app/res/values-ko/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ko/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ky/strings_pbap_client.xml b/android/app/res/values-ky/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ky/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-lo/strings_pbap_client.xml b/android/app/res/values-lo/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-lo/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-lt/strings_pbap_client.xml b/android/app/res/values-lt/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-lt/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-lv/strings_pbap_client.xml b/android/app/res/values-lv/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-lv/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-mk/strings_pbap_client.xml b/android/app/res/values-mk/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-mk/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ml/strings_pbap_client.xml b/android/app/res/values-ml/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ml/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-mn/strings_pbap_client.xml b/android/app/res/values-mn/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-mn/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-mr/strings_pbap_client.xml b/android/app/res/values-mr/strings_pbap_client.xml
deleted file mode 100644
index 0ad7629..0000000
--- a/android/app/res/values-mr/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.ब्लूटूथ.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ms/strings_pbap_client.xml b/android/app/res/values-ms/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ms/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-my/strings_pbap_client.xml b/android/app/res/values-my/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-my/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-nb/strings_pbap_client.xml b/android/app/res/values-nb/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-nb/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ne/strings_pbap_client.xml b/android/app/res/values-ne/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ne/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-nl/strings_pbap_client.xml b/android/app/res/values-nl/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-nl/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-or/strings_pbap_client.xml b/android/app/res/values-or/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-or/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-pa/strings_pbap_client.xml b/android/app/res/values-pa/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-pa/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-pl/strings_pbap_client.xml b/android/app/res/values-pl/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-pl/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-pt-rPT/strings_pbap_client.xml b/android/app/res/values-pt-rPT/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-pt-rPT/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-pt/strings_pbap_client.xml b/android/app/res/values-pt/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-pt/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ro/strings_pbap_client.xml b/android/app/res/values-ro/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ro/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ru/strings_pbap_client.xml b/android/app/res/values-ru/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ru/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-si/strings_pbap_client.xml b/android/app/res/values-si/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-si/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-sk/strings_pbap_client.xml b/android/app/res/values-sk/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-sk/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-sl/strings_pbap_client.xml b/android/app/res/values-sl/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-sl/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-sq/strings_pbap_client.xml b/android/app/res/values-sq/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-sq/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-sr/strings_pbap_client.xml b/android/app/res/values-sr/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-sr/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-sv/strings_pbap_client.xml b/android/app/res/values-sv/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-sv/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-sw/strings_pbap_client.xml b/android/app/res/values-sw/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-sw/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ta/strings_pbap_client.xml b/android/app/res/values-ta/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ta/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-te/strings_pbap_client.xml b/android/app/res/values-te/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-te/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-th/strings_pbap_client.xml b/android/app/res/values-th/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-th/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-tl/strings_pbap_client.xml b/android/app/res/values-tl/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-tl/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-tr/strings_pbap_client.xml b/android/app/res/values-tr/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-tr/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-uk/strings_pbap_client.xml b/android/app/res/values-uk/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-uk/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-ur/strings_pbap_client.xml b/android/app/res/values-ur/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-ur/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-uz/strings_pbap_client.xml b/android/app/res/values-uz/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-uz/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-vi/strings_pbap_client.xml b/android/app/res/values-vi/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-vi/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-zh-rCN/strings_pbap_client.xml b/android/app/res/values-zh-rCN/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-zh-rCN/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-zh-rHK/strings_pbap_client.xml b/android/app/res/values-zh-rHK/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-zh-rHK/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-zh-rTW/strings_pbap_client.xml b/android/app/res/values-zh-rTW/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-zh-rTW/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values-zu/strings_pbap_client.xml b/android/app/res/values-zu/strings_pbap_client.xml
deleted file mode 100644
index 57ca2ef..0000000
--- a/android/app/res/values-zu/strings_pbap_client.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type" msgid="7595186298710257905">"com.android.bluetooth.pbapsink"</string>
-</resources>
diff --git a/android/app/res/values/strings_pbap_client.xml b/android/app/res/values/strings_pbap_client.xml
index 465d4ee..e528702 100644
--- a/android/app/res/values/strings_pbap_client.xml
+++ b/android/app/res/values/strings_pbap_client.xml
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_account_type">com.android.bluetooth.pbapsink</string>
+ <string name="pbap_client_account_type" translatable="false">com.android.bluetooth.pbapclient</string>
</resources>
diff --git a/android/app/res/xml/authenticator.xml b/android/app/res/xml/authenticator.xml
index ab08a61..e7a1d62 100644
--- a/android/app/res/xml/authenticator.xml
+++ b/android/app/res/xml/authenticator.xml
@@ -17,4 +17,4 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:icon="@mipmap/bt_share"
android:smallIcon="@mipmap/bt_share"
- android:accountType="@string/pbap_account_type" />
+ android:accountType="@string/pbap_client_account_type" />
diff --git a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
index 82af2ac..9d744db 100644
--- a/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
+++ b/android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java
@@ -22,6 +22,7 @@
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSinkAudioPolicy;
import android.media.AudioDeviceCallback;
@@ -569,8 +570,8 @@
boolean hasFallbackDevice = false;
if (Objects.equals(mLeAudioActiveDevice, device)) {
hasFallbackDevice = setFallbackDeviceActiveLocked(device);
- if (!hasFallbackDevice) {
- setLeAudioActiveDevice(null, false);
+ if (!hasFallbackDevice && !Flags.admFixDisconnectOfSetMember()) {
+ leAudioService.removeActiveDevice(false);
}
}
leAudioService.deviceDisconnected(device, hasFallbackDevice);
@@ -1095,13 +1096,25 @@
return false;
}
+ if (firstDevice == null || secondDevice == null) {
+ return false;
+ }
+
final LeAudioService leAudioService = mFactory.getLeAudioService();
if (leAudioService == null) {
Log.e(TAG, "LeAudioService not available");
return false;
}
- return leAudioService.getGroupId(firstDevice) == leAudioService.getGroupId(secondDevice);
+ int groupIdFirst = leAudioService.getGroupId(firstDevice);
+ int groupIdSecond = leAudioService.getGroupId(secondDevice);
+
+ if (groupIdFirst == BluetoothLeAudio.GROUP_ID_INVALID
+ || groupIdSecond == BluetoothLeAudio.GROUP_ID_INVALID) {
+ return false;
+ }
+
+ return groupIdFirst == groupIdSecond;
}
/**
@@ -1113,7 +1126,7 @@
*/
@GuardedBy("mLock")
private boolean setFallbackDeviceActiveLocked(BluetoothDevice recentlyRemovedDevice) {
- Log.d(TAG, "setFallbackDeviceActive");
+ Log.d(TAG, "setFallbackDeviceActive, recently removed: " + recentlyRemovedDevice);
mDbManager = mAdapterService.getDatabase();
List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>();
if (!mHearingAidConnectedDevices.isEmpty()) {
@@ -1368,7 +1381,18 @@
*/
private boolean isBroadcastingAudio() {
final LeAudioService leAudioService = mFactory.getLeAudioService();
- return leAudioService != null && !leAudioService.getAllBroadcastMetadata().isEmpty();
+ if (leAudioService == null) {
+ Log.d(TAG, "isBroadcastingAudio: false - there is no LeAudioService");
+ return false;
+ }
+
+ if (leAudioService.getAllBroadcastMetadata().isEmpty()) {
+ Log.d(TAG, "isBroadcastingAudio: false - getAllBroadcastMetadata is empty");
+ return false;
+ }
+
+ Log.d(TAG, "isBroadcastingAudio: true");
+ return true;
}
/**
diff --git a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
index 6a20a7f..63bb766 100644
--- a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -1020,6 +1020,7 @@
BatteryService batteryService = mFactory.getBatteryService();
HidHostService hidHostService = mFactory.getHidHostService();
BassClientService bcService = mFactory.getBassClientService();
+ HapClientService hapClientService = mFactory.getHapClientService();
if (hsService != null) {
if (!mHeadsetRetrySet.contains(device)
@@ -1120,6 +1121,19 @@
bcService.connect(device);
}
}
+ if (Flags.connectHapOnOtherProfileConnect()) {
+ if (hapClientService != null) {
+ List<BluetoothDevice> connectedDevices = hapClientService.getConnectedDevices();
+ if (!connectedDevices.contains(device)
+ && (hapClientService.getConnectionPolicy(device)
+ == BluetoothProfile.CONNECTION_POLICY_ALLOWED)
+ && (hapClientService.getConnectionState(device)
+ == BluetoothProfile.STATE_DISCONNECTED)) {
+ debugLog("Retrying connection to HAS with device " + device);
+ hapClientService.connect(device);
+ }
+ }
+ }
}
/**
diff --git a/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java b/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java
index 850fb72..a23af3a 100644
--- a/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java
+++ b/android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java
@@ -32,6 +32,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -202,6 +203,11 @@
return ChannelSoundingParams.CS_SECURITY_LEVEL_ONE;
}
+ Set<Integer> getChannelSoundingSupportedSecurityLevels() {
+ // TODO(b/378685103): get it from the HAL when level 4 is supported and HAL v2 is available.
+ return Set.of(ChannelSoundingParams.CS_SECURITY_LEVEL_ONE);
+ }
+
private synchronized int stopRssiTracker(UUID uuid, String identityAddress, boolean timeout) {
CopyOnWriteArraySet<DistanceMeasurementTracker> set = mRssiTrackers.get(identityAddress);
if (set == null) {
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java
index 9c0daa0..2be39b6 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattService.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattService.java
@@ -241,9 +241,7 @@
}
mAdvertiseManager.clear();
mClientMap.clear();
- if (Flags.gattCleanupRestrictedHandles()) {
- mRestrictedHandles.clear();
- }
+ mRestrictedHandles.clear();
mServerMap.clear();
mHandleMap.clear();
mReliableQueue.clear();
@@ -1266,6 +1264,26 @@
service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
return service.getLocalChannelSoundingMaxSupportedSecurityLevel();
}
+
+ @Override
+ public int[] getChannelSoundingSupportedSecurityLevels(
+ AttributionSource attributionSource) {
+ GattService service = getService();
+
+ if (service == null
+ || !callerIsSystemOrActiveOrManagedUser(
+ service, TAG, "GattService getChannelSoundingSupportedSecurityLevels")
+ || !Utils.checkConnectPermissionForDataDelivery(
+ service,
+ attributionSource,
+ "GattService getChannelSoundingSupportedSecurityLevels")) {
+ return new int[0];
+ }
+ service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ return service.getChannelSoundingSupportedSecurityLevels().stream()
+ .mapToInt(i -> i)
+ .toArray();
+ }
}
;
@@ -1335,9 +1353,7 @@
mClientMap.removeConnection(clientIf, connId);
ContextMap<IBluetoothGattCallback>.App app = mClientMap.getById(clientIf);
- if (Flags.gattCleanupRestrictedHandles()) {
- mRestrictedHandles.remove(connId);
- }
+ mRestrictedHandles.remove(connId);
// Remove AtomicBoolean representing permit if no other connections rely on this remote
// device.
@@ -2097,6 +2113,10 @@
return mDistanceMeasurementManager.getLocalChannelSoundingMaxSupportedSecurityLevel();
}
+ Set<Integer> getChannelSoundingSupportedSecurityLevels() {
+ return mDistanceMeasurementManager.getChannelSoundingSupportedSecurityLevels();
+ }
+
/**************************************************************************
* GATT Service functions - CLIENT
*************************************************************************/
diff --git a/android/app/src/com/android/bluetooth/hap/HapClientService.java b/android/app/src/com/android/bluetooth/hap/HapClientService.java
index facb63f..09f2b63 100644
--- a/android/app/src/com/android/bluetooth/hap/HapClientService.java
+++ b/android/app/src/com/android/bluetooth/hap/HapClientService.java
@@ -280,7 +280,10 @@
}
}
- List<BluetoothDevice> getConnectedDevices() {
+ /**
+ * @return A list of connected {@link BluetoothDevice}.
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
synchronized (mStateMachines) {
List<BluetoothDevice> devices = new ArrayList<>();
for (HapClientStateMachine sm : mStateMachines.values()) {
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index 9897e69..32dbf73 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -217,7 +217,6 @@
return amVol;
}
- @VisibleForTesting
int amToHfVol(int amVol) {
int amRange = (mMaxAmVcVol > mMinAmVcVol) ? (mMaxAmVcVol - mMinAmVcVol) : 1;
int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME;
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index ee53a4d..fa01088 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -14,11 +14,21 @@
* limitations under the License.
*/
-/**
- * Bluetooth Headset Client StateMachine (Disconnected) | ^ ^ CONNECT | | | DISCONNECTED V | |
- * (Connecting) | | | CONNECTED | | DISCONNECT V | (Connected) | ^ CONNECT_AUDIO | |
- * DISCONNECT_AUDIO V | (AudioOn)
- */
+// Bluetooth Headset Client State Machine
+// (Disconnected)
+// | ^
+// CONNECT | | DISCONNECTED
+// V |
+// (Connecting) (Disconnecting)
+// | ^
+// CONNECTED | | DISCONNECT
+// V |
+// (Connected)
+// | |
+// CONNECT_AUDIO | | DISCONNECT_AUDIO
+// | |
+// (Audio_On)
+
package com.android.bluetooth.hfpclient;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
@@ -56,6 +66,7 @@
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IState;
@@ -109,12 +120,14 @@
@VisibleForTesting static final int QUERY_OPERATOR_NAME = 51;
@VisibleForTesting static final int SUBSCRIBER_INFO = 52;
@VisibleForTesting static final int CONNECTING_TIMEOUT = 53;
+ @VisibleForTesting static final int DISCONNECTING_TIMEOUT = 54;
// special action to handle terminating specific call from multiparty call
static final int TERMINATE_SPECIFIC_CALL = 53;
// Timeouts.
@VisibleForTesting static final int CONNECTING_TIMEOUT_MS = 10000; // 10s
+ @VisibleForTesting static final int DISCONNECTING_TIMEOUT_MS = 10000; // 10s
private static final int ROUTING_DELAY_MS = 250;
static final int HF_ORIGINATED_CALL_ID = -1;
@@ -127,6 +140,7 @@
private final Disconnected mDisconnected;
private final Connecting mConnecting;
private final Connected mConnected;
+ private final Disconnecting mDisconnecting;
private final AudioOn mAudioOn;
private State mPrevState;
@@ -314,6 +328,8 @@
return "SUBSCRIBER_INFO";
case CONNECTING_TIMEOUT:
return "CONNECTING_TIMEOUT";
+ case DISCONNECTING_TIMEOUT:
+ return "DISCONNECTING_TIMEOUT";
default:
return "UNKNOWN(" + what + ")";
}
@@ -932,11 +948,15 @@
mConnecting = new Connecting();
mConnected = new Connected();
mAudioOn = new AudioOn();
+ mDisconnecting = new Disconnecting();
addState(mDisconnected);
addState(mConnecting);
addState(mConnected);
addState(mAudioOn, mConnected);
+ if (Flags.hfpClientDisconnectingState()) {
+ addState(mDisconnecting);
+ }
setInitialState(mDisconnected);
}
@@ -1003,7 +1023,11 @@
class Disconnected extends State {
@Override
public void enter() {
- debug("Enter Disconnected: " + getCurrentMessage().what);
+ debug(
+ "Enter Disconnected: from state="
+ + mPrevState
+ + ", message="
+ + getMessageName(getCurrentMessage().what));
// cleanup
mIndicatorNetworkState = HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE;
@@ -1040,7 +1064,15 @@
mCurrentDevice,
BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTED);
- } else if (mPrevState != null) { // null is the default state before Disconnected
+ } else if (Flags.hfpClientDisconnectingState()) {
+ if (mPrevState == mDisconnecting) {
+ broadcastConnectionState(
+ mCurrentDevice,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_DISCONNECTING);
+ }
+ } else if (mPrevState != null) {
+ // null is the default state before Disconnected
error(
"Disconnected: Illegal state transition from "
+ mPrevState.getName()
@@ -1139,7 +1171,7 @@
@Override
public void exit() {
- debug("Exit Disconnected: " + getCurrentMessage().what);
+ debug("Exit Disconnected: " + getMessageName(getCurrentMessage().what));
mPrevState = this;
}
}
@@ -1147,7 +1179,7 @@
class Connecting extends State {
@Override
public void enter() {
- debug("Enter Connecting: " + getCurrentMessage().what);
+ debug("Enter Connecting: " + getMessageName(getCurrentMessage().what));
// This message is either consumed in processMessage or
// removed in exit. It is safe to send a CONNECTING_TIMEOUT here since
// the only transition is when connection attempt is initiated.
@@ -1351,7 +1383,7 @@
@Override
public void exit() {
- debug("Exit Connecting: " + getCurrentMessage().what);
+ debug("Exit Connecting: " + getMessageName(getCurrentMessage().what));
removeMessages(CONNECTING_TIMEOUT);
mPrevState = this;
}
@@ -1362,7 +1394,7 @@
@Override
public void enter() {
- debug("Enter Connected: " + getCurrentMessage().what);
+ debug("Enter Connected: " + getMessageName(getCurrentMessage().what));
mAudioWbs = false;
mAudioSWB = false;
mCommandedSpeakerVolume = -1;
@@ -1409,7 +1441,12 @@
if (!mCurrentDevice.equals(dev)) {
break;
}
- if (!mNativeInterface.disconnect(dev)) {
+ if (Flags.hfpClientDisconnectingState()) {
+ if (!mNativeInterface.disconnect(mCurrentDevice)) {
+ warn("disconnectNative failed for " + mCurrentDevice);
+ }
+ transitionTo(mDisconnecting);
+ } else if (!mNativeInterface.disconnect(dev)) {
error("disconnectNative failed for " + dev);
}
break;
@@ -1569,7 +1606,7 @@
+ event.device
+ ": "
+ event.valueInt);
- processConnectionEvent(event.valueInt, event.device);
+ processConnectionEvent(message, event.valueInt, event.device);
break;
case StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED:
debug(
@@ -1810,13 +1847,19 @@
}
// in Connected state
- private void processConnectionEvent(int state, BluetoothDevice device) {
+ private void processConnectionEvent(Message message, int state, BluetoothDevice device) {
switch (state) {
case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED:
debug("Connected disconnects.");
// AG disconnects
if (mCurrentDevice.equals(device)) {
- transitionTo(mDisconnected);
+ if (Flags.hfpClientDisconnectingState()) {
+ transitionTo(mDisconnecting);
+ // message is deferred to be processed in the disconnecting state
+ deferMessage(message);
+ } else {
+ transitionTo(mDisconnected);
+ }
} else {
error("Disconnected from unknown device: " + device);
}
@@ -1915,7 +1958,101 @@
@Override
public void exit() {
- debug("Exit Connected: " + getCurrentMessage().what);
+ debug("Exit Connected: " + getMessageName(getCurrentMessage().what));
+ mPrevState = this;
+ }
+ }
+
+ class Disconnecting extends State {
+ @Override
+ public void enter() {
+ debug(
+ "Disconnecting: enter disconnecting from state="
+ + mPrevState
+ + ", message="
+ + getMessageName(getCurrentMessage().what));
+ if (mPrevState == mConnected || mPrevState == mAudioOn) {
+ broadcastConnectionState(
+ mCurrentDevice,
+ BluetoothProfile.STATE_DISCONNECTING,
+ BluetoothProfile.STATE_CONNECTED);
+ } else {
+ String prevStateName = mPrevState == null ? "null" : mPrevState.getName();
+ error(
+ "Disconnecting: Illegal state transition from "
+ + prevStateName
+ + " to Disconnecting");
+ }
+ sendMessageDelayed(DISCONNECTING_TIMEOUT, DISCONNECTING_TIMEOUT_MS);
+ }
+
+ @Override
+ public synchronized boolean processMessage(Message message) {
+ debug("Disconnecting: Process message: " + message.what);
+
+ switch (message.what) {
+ // Defering messages as state machine objects are meant to be reused and after
+ // disconnect is complete we want honor other message requests
+ case CONNECT:
+ case CONNECT_AUDIO:
+ case DISCONNECT:
+ case DISCONNECT_AUDIO:
+ deferMessage(message);
+ break;
+
+ case DISCONNECTING_TIMEOUT:
+ // We timed out trying to disconnect, force transition to disconnected.
+ warn("Disconnecting: Disconnection timeout for " + mCurrentDevice);
+ transitionTo(mDisconnected);
+ break;
+
+ case StackEvent.STACK_EVENT:
+ StackEvent event = (StackEvent) message.obj;
+
+ switch (event.type) {
+ case StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED:
+ debug(
+ "Disconnecting: Connection state changed: "
+ + event.device
+ + ": "
+ + event.valueInt);
+ processConnectionEvent(event.valueInt, event.device);
+ break;
+ default:
+ error("Disconnecting: Unknown stack event: " + event.type);
+ break;
+ }
+ break;
+ default:
+ warn("Disconnecting: Message not handled " + message);
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+
+ private void processConnectionEvent(int state, BluetoothDevice device) {
+ switch (state) {
+ case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED:
+ if (mCurrentDevice.equals(device)) {
+ transitionTo(mDisconnected);
+ } else {
+ error("Disconnecting: Disconnected from unknown device: " + device);
+ }
+ break;
+ default:
+ error(
+ "Disconnecting: Connection State Device: "
+ + device
+ + " bad state: "
+ + state);
+ break;
+ }
+ }
+
+ @Override
+ public void exit() {
+ debug("Disconnecting: Exit Disconnecting: " + getMessageName(getCurrentMessage().what));
+ removeMessages(DISCONNECTING_TIMEOUT);
mPrevState = this;
}
}
@@ -1923,7 +2060,7 @@
class AudioOn extends State {
@Override
public void enter() {
- debug("Enter AudioOn: " + getCurrentMessage().what);
+ debug("Enter AudioOn: " + getMessageName(getCurrentMessage().what));
broadcastAudioState(
mCurrentDevice,
BluetoothHeadsetClient.STATE_AUDIO_CONNECTED,
@@ -1975,7 +2112,7 @@
+ event.device
+ ": "
+ event.valueInt);
- processConnectionEvent(event.valueInt, event.device);
+ processConnectionEvent(message, event.valueInt, event.device);
break;
case StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED:
debug(
@@ -1996,13 +2133,20 @@
}
// in AudioOn state. Can AG disconnect RFCOMM prior to SCO? Handle this
- private void processConnectionEvent(int state, BluetoothDevice device) {
+ private void processConnectionEvent(Message message, int state, BluetoothDevice device) {
switch (state) {
case HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED:
if (mCurrentDevice.equals(device)) {
processAudioEvent(
HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED, device);
- transitionTo(mDisconnected);
+ if (Flags.hfpClientDisconnectingState()) {
+ transitionTo(mDisconnecting);
+ // message is deferred to be processed in the disconnecting state
+ deferMessage(message);
+ } else {
+ transitionTo(mDisconnected);
+ }
+
} else {
error("Disconnected from unknown device: " + device);
}
@@ -2041,7 +2185,7 @@
@Override
public void exit() {
- debug("Exit AudioOn: " + getCurrentMessage().what);
+ debug("Exit AudioOn: " + getMessageName(getCurrentMessage().what));
mPrevState = this;
broadcastAudioState(
mCurrentDevice,
@@ -2064,7 +2208,11 @@
return BluetoothProfile.STATE_CONNECTED;
}
- error("Bad currentState: " + currentState);
+ if (Flags.hfpClientDisconnectingState()) {
+ if (currentState == mDisconnecting) {
+ return BluetoothProfile.STATE_DISCONNECTING;
+ }
+ }
return BluetoothProfile.STATE_DISCONNECTED;
}
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
index 2e0a80c..8bf6e41 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -24,8 +24,8 @@
import static com.android.bluetooth.bass_client.BassConstants.INVALID_BROADCAST_ID;
import static com.android.bluetooth.flags.Flags.leaudioAllowedContextMask;
import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState;
-import static com.android.bluetooth.flags.Flags.leaudioBroadcastAssistantPeripheralEntrustment;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastApiManagePrimaryGroup;
+import static com.android.bluetooth.flags.Flags.leaudioBroadcastAssistantPeripheralEntrustment;
import static com.android.bluetooth.flags.Flags.leaudioUseAudioModeListener;
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
@@ -843,6 +843,35 @@
mNativeInterface.setEnableState(device, enabled);
}
+ private void setDefaultBroadcastToUnicastFallbackGroup() {
+ DatabaseManager dbManager = mAdapterService.getDatabase();
+ if (dbManager == null) {
+ Log.i(
+ TAG,
+ "Can't get db manager to pick default Broadcast to Unicast fallback group"
+ + ", leaving: "
+ + mUnicastGroupIdDeactivatedForBroadcastTransition);
+ return;
+ }
+
+ List<BluetoothDevice> devices = dbManager.getMostRecentlyConnectedDevices();
+
+ int targetDeviceIdx = -1;
+ int targetGroupId = LE_AUDIO_GROUP_ID_INVALID;
+ for (BluetoothDevice device : getConnectedDevices()) {
+ LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
+ if (devices.contains(device)) {
+ int idx = devices.indexOf(device);
+ if (idx > targetDeviceIdx) {
+ targetDeviceIdx = idx;
+ targetGroupId = descriptor.mGroupId;
+ }
+ }
+ }
+
+ updateFallbackUnicastGroupIdForBroadcast(targetGroupId);
+ }
+
public boolean connect(BluetoothDevice device) {
Log.d(TAG, "connect(): " + device);
@@ -2417,7 +2446,8 @@
+ ", mExposedActiveDevice: "
+ mExposedActiveDevice);
- if (isBroadcastActive()
+ if (!Flags.leaudioBroadcastPrimaryGroupSelection()
+ && isBroadcastActive()
&& currentlyActiveGroupId == LE_AUDIO_GROUP_ID_INVALID
&& mUnicastGroupIdDeactivatedForBroadcastTransition != LE_AUDIO_GROUP_ID_INVALID) {
@@ -3205,7 +3235,9 @@
TAG,
"transitionFromBroadcastToUnicast: No valid unicast device for group ID: "
+ mUnicastGroupIdDeactivatedForBroadcastTransition);
- updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
+ if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
+ updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
+ }
updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false);
return;
}
@@ -3217,7 +3249,9 @@
+ ", with device: "
+ unicastDevice);
- updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
+ if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
+ updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
+ }
setActiveDevice(unicastDevice);
}
@@ -3705,7 +3739,9 @@
if (isBroadcastAllowedToBeActivateInCurrentAudioMode()) {
/* Check if broadcast was deactivated due to unicast */
if (mBroadcastIdDeactivatedForUnicastTransition.isPresent()) {
- updateFallbackUnicastGroupIdForBroadcast(groupId);
+ if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
+ updateFallbackUnicastGroupIdForBroadcast(groupId);
+ }
if (!leaudioUseAudioModeListener()) {
mQueuedInCallValue = Optional.empty();
}
@@ -3722,7 +3758,9 @@
}
} else {
if (!mCreateBroadcastQueue.isEmpty()) {
- updateFallbackUnicastGroupIdForBroadcast(groupId);
+ if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
+ updateFallbackUnicastGroupIdForBroadcast(groupId);
+ }
BluetoothLeBroadcastSettings settings =
mCreateBroadcastQueue.remove();
createBroadcast(settings);
@@ -4181,6 +4219,12 @@
if (!isScannerNeeded()) {
stopAudioServersBackgroundScan();
}
+
+ /* Set by default earliest connected device */
+ if (Flags.leaudioBroadcastPrimaryGroupSelection()
+ && mUnicastGroupIdDeactivatedForBroadcastTransition == LE_AUDIO_GROUP_ID_INVALID) {
+ setDefaultBroadcastToUnicastFallbackGroup();
+ }
}
/** Process a change for disconnection of a device. */
@@ -4246,6 +4290,12 @@
false);
return;
}
+
+ /* Set by default earliest connected device */
+ if (Flags.leaudioBroadcastPrimaryGroupSelection()
+ && mUnicastGroupIdDeactivatedForBroadcastTransition == groupId) {
+ setDefaultBroadcastToUnicastFallbackGroup();
+ }
}
if (descriptor.isActive()
@@ -4840,6 +4890,12 @@
mGroupWriteLock.unlock();
}
+ /* Set by default earliest connected device */
+ if (Flags.leaudioBroadcastPrimaryGroupSelection()
+ && mUnicastGroupIdDeactivatedForBroadcastTransition == LE_AUDIO_GROUP_ID_INVALID) {
+ setDefaultBroadcastToUnicastFallbackGroup();
+ }
+
if (mBluetoothEnabled) {
setAuthorizationForRelatedProfiles(device, true);
startAudioServersBackgroundScan(/* retry= */ false);
@@ -4905,7 +4961,11 @@
}
if (mUnicastGroupIdDeactivatedForBroadcastTransition == groupId) {
- updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
+ if (Flags.leaudioBroadcastPrimaryGroupSelection()) {
+ setDefaultBroadcastToUnicastFallbackGroup();
+ } else {
+ updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
+ }
}
}
mHandler.post(() -> notifyGroupNodeRemoved(device, groupId));
@@ -5231,6 +5291,93 @@
mNativeInterface.setCodecConfigPreference(groupId, inputCodecConfig, outputCodecConfig);
}
+ void setBroadcastToUnicastFallbackGroup(int groupId) {
+ if (!leaudioBroadcastApiManagePrimaryGroup()) {
+ return;
+ }
+
+ Log.d(TAG, "setBroadcastToUnicastFallbackGroup(" + groupId + ")");
+
+ if (mUnicastGroupIdDeactivatedForBroadcastTransition == groupId) {
+ Log.d(TAG, "Requested Broadcast to Unicast fallback group is already set");
+ return;
+ }
+
+ mGroupReadLock.lock();
+ try {
+ LeAudioGroupDescriptor oldFallbackGroupDescriptor =
+ getGroupDescriptor(mUnicastGroupIdDeactivatedForBroadcastTransition);
+ LeAudioGroupDescriptor newFallbackGroupDescriptor = getGroupDescriptor(groupId);
+ if (oldFallbackGroupDescriptor == null && newFallbackGroupDescriptor == null) {
+ Log.w(
+ TAG,
+ "Failed to set Broadcast to Unicast Fallback group "
+ + "(lack of new and old group descriptors): "
+ + mUnicastGroupIdDeactivatedForBroadcastTransition
+ + " -> "
+ + groupId);
+ return;
+ }
+
+ /* Fallback group should be not updated if new group is not connected or requested
+ * group ID is different than INVALID but there is no such descriptor.
+ */
+ if (groupId != LE_AUDIO_GROUP_ID_INVALID
+ && (newFallbackGroupDescriptor == null
+ || !newFallbackGroupDescriptor.mIsConnected)) {
+ Log.w(
+ TAG,
+ "Failed to set Broadcast to Unicast Fallback group (invalid new group): "
+ + mUnicastGroupIdDeactivatedForBroadcastTransition
+ + " -> "
+ + groupId);
+ return;
+ }
+
+ /* Update exposed monitoring input device while being in Broadcast mode */
+ if (isBroadcastActive()
+ && getActiveGroupId() == LE_AUDIO_GROUP_ID_INVALID
+ && mUnicastGroupIdDeactivatedForBroadcastTransition
+ != LE_AUDIO_GROUP_ID_INVALID) {
+ /* In case of removing fallback unicast group, monitoring input
+ * device should be removed from active devices.
+ */
+ int newDirection = AUDIO_DIRECTION_NONE;
+ int oldDirection = oldFallbackGroupDescriptor != null
+ ? oldFallbackGroupDescriptor.mDirection : AUDIO_DIRECTION_NONE;
+ boolean notifyAndUpdateInactiveOutDeviceOnly = false;
+ boolean hasFallbackDeviceWhenGettingInactive = oldFallbackGroupDescriptor != null
+ ? oldFallbackGroupDescriptor.mHasFallbackDeviceWhenGettingInactive
+ : false;
+ if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
+ newDirection = AUDIO_DIRECTION_INPUT_BIT;
+ notifyAndUpdateInactiveOutDeviceOnly = true;
+ }
+ updateActiveDevices(
+ groupId,
+ oldDirection,
+ newDirection,
+ false, // isActive
+ hasFallbackDeviceWhenGettingInactive,
+ notifyAndUpdateInactiveOutDeviceOnly);
+ }
+ } finally {
+ mGroupReadLock.unlock();
+ }
+
+ updateFallbackUnicastGroupIdForBroadcast(groupId);
+ }
+
+ int getBroadcastToUnicastFallbackGroup() {
+ if (!leaudioBroadcastApiManagePrimaryGroup()) {
+ return LE_AUDIO_GROUP_ID_INVALID;
+ }
+
+ Log.v(TAG, "getBroadcastToUnicastFallbackGroup()");
+
+ return mUnicastGroupIdDeactivatedForBroadcastTransition;
+ }
+
/**
* Checks if the remote device supports LE Audio duplex (output and input).
*
@@ -5908,6 +6055,28 @@
}
@Override
+ public void setBroadcastToUnicastFallbackGroup(int groupId, AttributionSource source) {
+ LeAudioService service = getServiceAndEnforceConnect(source);
+ if (service == null) {
+ return;
+ }
+
+ service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ service.setBroadcastToUnicastFallbackGroup(groupId);
+ }
+
+ @Override
+ public int getBroadcastToUnicastFallbackGroup(AttributionSource source) {
+ LeAudioService service = getServiceAndEnforceConnect(source);
+ if (service == null) {
+ return LE_AUDIO_GROUP_ID_INVALID;
+ }
+
+ service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ return service.getBroadcastToUnicastFallbackGroup();
+ }
+
+ @Override
public boolean isBroadcastActive(AttributionSource source) {
LeAudioService service = getServiceAndEnforceConnect(source);
if (service == null) {
diff --git a/android/app/src/com/android/bluetooth/pbapclient/Authenticator.java b/android/app/src/com/android/bluetooth/pbapclient/Authenticator.java
deleted file mode 100644
index 899e2e6..0000000
--- a/android/app/src/com/android/bluetooth/pbapclient/Authenticator.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.bluetooth.pbapclient;
-
-import android.accounts.AbstractAccountAuthenticator;
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorResponse;
-import android.accounts.AccountManager;
-import android.accounts.NetworkErrorException;
-import android.content.Context;
-import android.os.Bundle;
-import android.util.Log;
-
-public class Authenticator extends AbstractAccountAuthenticator {
- private static final String TAG = "PbapClientAuthenticator";
-
- public Authenticator(Context context) {
- super(context);
- }
-
- // Editing properties is not supported
- @Override
- public Bundle editProperties(AccountAuthenticatorResponse r, String s) {
- Log.d(TAG, "got call", new Exception());
- throw new UnsupportedOperationException();
- }
-
- // Don't add additional accounts
- @Override
- public Bundle addAccount(
- AccountAuthenticatorResponse r, String s, String s2, String[] strings, Bundle bundle)
- throws NetworkErrorException {
- Log.d(TAG, "got call", new Exception());
- // Don't allow accounts to be added.
- throw new UnsupportedOperationException();
- }
-
- // Ignore attempts to confirm credentials
- @Override
- public Bundle confirmCredentials(AccountAuthenticatorResponse r, Account account, Bundle bundle)
- throws NetworkErrorException {
- Log.d(TAG, "got call", new Exception());
- return null;
- }
-
- // Getting an authentication token is not supported
- @Override
- public Bundle getAuthToken(
- AccountAuthenticatorResponse r, Account account, String s, Bundle bundle)
- throws NetworkErrorException {
- Log.d(TAG, "got call", new Exception());
- throw new UnsupportedOperationException();
- }
-
- // Getting a label for the auth token is not supported
- @Override
- public String getAuthTokenLabel(String s) {
- Log.d(TAG, "got call", new Exception());
- return null;
- }
-
- // Updating user credentials is not supported
- @Override
- public Bundle updateCredentials(
- AccountAuthenticatorResponse r, Account account, String s, Bundle bundle)
- throws NetworkErrorException {
- Log.d(TAG, "got call", new Exception());
- return null;
- }
-
- // Checking features for the account is not supported
- @Override
- public Bundle hasFeatures(AccountAuthenticatorResponse r, Account account, String[] strings)
- throws NetworkErrorException {
- Log.d(TAG, "got call", new Exception());
-
- final Bundle result = new Bundle();
- result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
- return result;
- }
-}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequest.java b/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequest.java
deleted file mode 100644
index 77e266e..0000000
--- a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import android.util.Log;
-
-import com.android.obex.ClientOperation;
-import com.android.obex.ClientSession;
-import com.android.obex.HeaderSet;
-import com.android.obex.ResponseCodes;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-abstract class BluetoothPbapRequest {
- static final String TAG = "PbapClient.BaseRequest";
-
- protected static final byte OAP_TAGID_ORDER = 0x01;
- protected static final byte OAP_TAGID_SEARCH_VALUE = 0x02;
- protected static final byte OAP_TAGID_SEARCH_ATTRIBUTE = 0x03;
- protected static final byte OAP_TAGID_MAX_LIST_COUNT = 0x04;
- protected static final byte OAP_TAGID_LIST_START_OFFSET = 0x05;
- protected static final byte OAP_TAGID_FILTER = 0x06;
- protected static final byte OAP_TAGID_FORMAT = 0x07;
- protected static final byte OAP_TAGID_PHONEBOOK_SIZE = 0x08;
- protected static final byte OAP_TAGID_NEW_MISSED_CALLS = 0x09;
- protected static final byte OAP_TAGID_PBAP_SUPPORTED_FEATURES = 0x10;
-
- protected HeaderSet mHeaderSet;
-
- protected int mResponseCode;
-
- private boolean mAborted = false;
-
- private ClientOperation mOp = null;
-
- BluetoothPbapRequest() {
- mHeaderSet = new HeaderSet();
- }
-
- public final boolean isSuccess() {
- return (mResponseCode == ResponseCodes.OBEX_HTTP_OK);
- }
-
- public void execute(ClientSession session) throws IOException {
- Log.v(TAG, "execute");
-
- /* in case request is aborted before can be executed */
- if (mAborted) {
- mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
- return;
- }
-
- try {
- mOp = (ClientOperation) session.get(mHeaderSet);
-
- /* make sure final flag for GET is used (PBAP spec 6.2.2) */
- mOp.setGetFinalFlag(true);
-
- /*
- * this will trigger ClientOperation to use non-buffered stream so
- * we can abort operation
- */
- mOp.continueOperation(true, false);
-
- readResponseHeaders(mOp.getReceivedHeader());
-
- InputStream is = mOp.openInputStream();
- readResponse(is);
- is.close();
-
- mOp.close();
-
- mResponseCode = mOp.getResponseCode();
-
- Log.d(TAG, "mResponseCode=" + mResponseCode);
-
- checkResponseCode(mResponseCode);
- } catch (IOException e) {
- Log.e(TAG, "IOException occurred when processing request", e);
- mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
-
- throw e;
- }
- }
-
- public void abort() {
- mAborted = true;
-
- if (mOp != null) {
- try {
- mOp.abort();
- } catch (IOException e) {
- Log.e(TAG, "Exception occurred when trying to abort", e);
- }
- }
- }
-
- protected void readResponse(InputStream stream) throws IOException {
- Log.v(TAG, "readResponse");
-
- /* nothing here by default */
- }
-
- protected void readResponseHeaders(HeaderSet headerset) {
- Log.v(TAG, "readResponseHeaders");
-
- /* nothing here by default */
- }
-
- protected void checkResponseCode(int responseCode) throws IOException {
- Log.v(TAG, "checkResponseCode");
-
- /* nothing here by default */
- }
-}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java b/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java
deleted file mode 100644
index becb7e6..0000000
--- a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBook.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import android.accounts.Account;
-import android.util.Log;
-
-import com.android.bluetooth.ObexAppParameters;
-import com.android.obex.HeaderSet;
-import com.android.vcard.VCardEntry;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-
-final class BluetoothPbapRequestPullPhoneBook extends BluetoothPbapRequest {
- private static final String TAG = "PbapClient.PullPb";
-
- private static final String TYPE = "x-bt/phonebook";
-
- private BluetoothPbapVcardList mResponse;
-
- private Account mAccount;
-
- private int mNewMissedCalls = -1;
-
- private final byte mFormat;
-
- BluetoothPbapRequestPullPhoneBook(
- String pbName,
- Account account,
- long filter,
- byte format,
- int maxListCount,
- int listStartOffset) {
- mAccount = account;
- if (maxListCount < 0 || maxListCount > 65535) {
- throw new IllegalArgumentException("maxListCount should be [0..65535]");
- }
-
- if (listStartOffset < 0 || listStartOffset > 65535) {
- throw new IllegalArgumentException("listStartOffset should be [0..65535]");
- }
-
- mHeaderSet.setHeader(HeaderSet.NAME, pbName);
-
- mHeaderSet.setHeader(HeaderSet.TYPE, TYPE);
-
- ObexAppParameters oap = new ObexAppParameters();
-
- /* make sure format is one of allowed values */
- if (format != PbapClientConnectionHandler.VCARD_TYPE_21
- && format != PbapClientConnectionHandler.VCARD_TYPE_30) {
- format = PbapClientConnectionHandler.VCARD_TYPE_21;
- }
-
- if (filter != 0) {
- oap.add(OAP_TAGID_FILTER, filter);
- }
-
- oap.add(OAP_TAGID_FORMAT, format);
-
- /*
- * maxListCount == 0 is a special case which is handled in
- * BluetoothPbapRequestPullPhoneBookSize
- */
- if (maxListCount > 0) {
- oap.add(OAP_TAGID_MAX_LIST_COUNT, (short) maxListCount);
- } else {
- oap.add(OAP_TAGID_MAX_LIST_COUNT, (short) 65535);
- }
-
- if (listStartOffset > 0) {
- oap.add(OAP_TAGID_LIST_START_OFFSET, (short) listStartOffset);
- }
-
- oap.addToHeaderSet(mHeaderSet);
-
- mFormat = format;
- }
-
- @Override
- protected void readResponse(InputStream stream) throws IOException {
- Log.v(TAG, "readResponse");
-
- mResponse = new BluetoothPbapVcardList(mAccount, stream, mFormat);
- Log.d(TAG, "Read " + mResponse.getCount() + " entries");
- }
-
- @Override
- protected void readResponseHeaders(HeaderSet headerset) {
- Log.v(TAG, "readResponseHeaders");
-
- ObexAppParameters oap = ObexAppParameters.fromHeaderSet(headerset);
-
- if (oap.exists(OAP_TAGID_NEW_MISSED_CALLS)) {
- mNewMissedCalls = oap.getByte(OAP_TAGID_NEW_MISSED_CALLS);
- }
- }
-
- public List<VCardEntry> getList() {
- return mResponse.getList();
- }
-
- public int getNewMissedCalls() {
- return mNewMissedCalls;
- }
-}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSize.java b/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSize.java
deleted file mode 100644
index 9432881..0000000
--- a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSize.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import android.util.Log;
-
-import com.android.bluetooth.ObexAppParameters;
-import com.android.obex.HeaderSet;
-
-final class BluetoothPbapRequestPullPhoneBookSize extends BluetoothPbapRequest {
- private static final String TAG = "PbapClient.PullPbSize";
-
- private static final String TYPE = "x-bt/phonebook";
-
- private int mSize;
-
- BluetoothPbapRequestPullPhoneBookSize(String pbName, long filter) {
- mHeaderSet.setHeader(HeaderSet.NAME, pbName);
-
- mHeaderSet.setHeader(HeaderSet.TYPE, TYPE);
-
- ObexAppParameters oap = new ObexAppParameters();
- // Set MaxListCount in the request to 0 to get PhonebookSize in the response.
- // If a vCardSelector is present in the request, then the result shall
- // contain the number of items that satisfy the selector’s criteria.
- // See PBAP v1.2.3, Sec. 5.1.4.5.
- oap.add(OAP_TAGID_MAX_LIST_COUNT, (short) 0);
- if (filter != 0) {
- oap.add(OAP_TAGID_FILTER, filter);
- }
- oap.addToHeaderSet(mHeaderSet);
- }
-
- @Override
- protected void readResponseHeaders(HeaderSet headerset) {
- Log.v(TAG, "readResponseHeaders");
-
- ObexAppParameters oap = ObexAppParameters.fromHeaderSet(headerset);
-
- if (oap.exists(OAP_TAGID_PHONEBOOK_SIZE)) {
- mSize = oap.getShort(OAP_TAGID_PHONEBOOK_SIZE);
- }
- }
-
- public int getSize() {
- return mSize;
- }
-}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapVcardList.java b/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapVcardList.java
deleted file mode 100644
index e2b703a..0000000
--- a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapVcardList.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import android.accounts.Account;
-import android.util.Log;
-
-import com.android.vcard.VCardConfig;
-import com.android.vcard.VCardEntry;
-import com.android.vcard.VCardEntryConstructor;
-import com.android.vcard.VCardEntryHandler;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardParser_V21;
-import com.android.vcard.VCardParser_V30;
-import com.android.vcard.exception.VCardException;
-import com.android.vcard.exception.VCardVersionException;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-class BluetoothPbapVcardList {
- private static final String TAG = BluetoothPbapVcardList.class.getSimpleName();
- // {@link BufferedInputStream#DEFAULT_BUFFER_SIZE} is not public
- private static final int BIS_DEFAULT_BUFFER_SIZE = 8192;
-
- private final List<VCardEntry> mCards = new ArrayList<VCardEntry>();
- private final Account mAccount;
-
- class CardEntryHandler implements VCardEntryHandler {
- @Override
- public void onStart() {}
-
- @Override
- public void onEntryCreated(VCardEntry entry) {
- mCards.add(entry);
- }
-
- @Override
- public void onEnd() {}
- }
-
- BluetoothPbapVcardList(Account account, InputStream in, byte format) throws IOException {
- if (format != PbapClientConnectionHandler.VCARD_TYPE_21
- && format != PbapClientConnectionHandler.VCARD_TYPE_30) {
- throw new IllegalArgumentException("Unsupported vCard version.");
- }
- mAccount = account;
- parse(in, format);
- }
-
- private void parse(InputStream in, byte format) throws IOException {
- VCardParser parser;
-
- if (format == PbapClientConnectionHandler.VCARD_TYPE_30) {
- parser = new VCardParser_V30();
- } else {
- parser = new VCardParser_V21();
- }
-
- VCardEntryConstructor constructor =
- new VCardEntryConstructor(VCardConfig.VCARD_TYPE_V21_GENERIC, mAccount);
-
- CardEntryHandler handler = new CardEntryHandler();
- constructor.addEntryHandler(handler);
-
- parser.addInterpreter(constructor);
-
- // {@link BufferedInputStream} supports the {@link InputStream#mark} and
- // {@link InputStream#reset} methods.
- BufferedInputStream bufferedInput = new BufferedInputStream(in);
- bufferedInput.mark(BIS_DEFAULT_BUFFER_SIZE /* readlimit */);
-
- // If there is a {@link VCardVersionException}, try parsing again with a different
- // version. Otherwise, parsing either succeeds (i.e., no {@link VCardException}) or it
- // fails with a different {@link VCardException}.
- if (parsedWithVcardVersionException(parser, bufferedInput)) {
- // PBAP v1.2.3 only supports vCard versions 2.1 and 3.0; it's one or the other
- if (format == PbapClientConnectionHandler.VCARD_TYPE_21) {
- parser = new VCardParser_V30();
- Log.w(TAG, "vCard version and Parser mismatch; expected v2.1, switching to v3.0");
- } else {
- parser = new VCardParser_V21();
- Log.w(TAG, "vCard version and Parser mismatch; expected v3.0, switching to v2.1");
- }
- // reset and try again
- bufferedInput.reset();
- mCards.clear();
- constructor.clear();
- parser.addInterpreter(constructor);
- if (parsedWithVcardVersionException(parser, bufferedInput)) {
- Log.e(TAG, "unsupported vCard version, neither v2.1 nor v3.0");
- }
- }
- }
-
- /**
- * Attempts to parse, with an eye on whether the correct version of Parser is used.
- *
- * @param parser -- the {@link VCardParser} to use.
- * @param in -- the {@link InputStream} to parse.
- * @return {@code true} if there was a {@link VCardVersionException}; {@code false} if there is
- * any other {@link VCardException} or succeeds (i.e., no {@link VCardException}).
- * @throws IOException if there's an issue reading the {@link InputStream}.
- */
- private boolean parsedWithVcardVersionException(VCardParser parser, InputStream in)
- throws IOException {
- try {
- parser.parse(in);
- } catch (VCardVersionException e1) {
- Log.w(TAG, "vCard version and Parser mismatch", e1);
- return true;
- } catch (VCardException e2) {
- Log.e(TAG, "vCard exception", e2);
- }
- return false;
- }
-
- public int getCount() {
- return mCards.size();
- }
-
- public List<VCardEntry> getList() {
- return mCards;
- }
-
- public VCardEntry getFirst() {
- return mCards.get(0);
- }
-}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticator.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticator.java
new file mode 100644
index 0000000..45b181e
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticator.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.bluetooth.pbapclient;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * An AccountAuthenticator class that allows us to register with the AccountManagerService framework
+ *
+ * <p>In order to store contacts on device, we need to associate them with an AccountManager
+ * Account. This allows for easy management, including deletion.
+ *
+ * <p>This class is hosted by a service object, which AccountManagerService can use to interact with
+ * us. In practice though, most/all of this class goes unused and is only an necessary evil so that
+ * AccountManagerService will allow us to explicitly make accounts of the type we specify.
+ */
+public class PbapClientAccountAuthenticator extends AbstractAccountAuthenticator {
+ private static final String TAG = PbapClientAccountAuthenticator.class.getSimpleName();
+
+ public PbapClientAccountAuthenticator(Context context) {
+ super(context);
+ }
+
+ // Editing properties is not supported
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse r, String accountType) {
+ Log.d(TAG, "editProperties(accountType=" + accountType + ")");
+ throw new UnsupportedOperationException();
+ }
+
+ // Don't add additional accounts
+ @Override
+ public Bundle addAccount(
+ AccountAuthenticatorResponse r,
+ String accountType,
+ String authTokenType,
+ String[] requiredFeatures,
+ Bundle options)
+ throws NetworkErrorException {
+ Log.d(
+ TAG,
+ "addAccount(accountType="
+ + accountType
+ + ", authTokenType="
+ + authTokenType
+ + ", requiredFeatures="
+ + Arrays.toString(requiredFeatures)
+ + ")");
+ // Don't allow accounts to be added.
+ throw new UnsupportedOperationException();
+ }
+
+ // Ignore attempts to confirm credentials
+ @Override
+ public Bundle confirmCredentials(
+ AccountAuthenticatorResponse r, Account account, Bundle options)
+ throws NetworkErrorException {
+ Log.d(TAG, "confirmCredentials(account=" + account + ", options=" + options + ")");
+ return null;
+ }
+
+ // Getting an authentication token is not supported
+ @Override
+ public Bundle getAuthToken(
+ AccountAuthenticatorResponse r, Account account, String authTokenType, Bundle options)
+ throws NetworkErrorException {
+ Log.d(
+ TAG,
+ "getAuthToken(account="
+ + account
+ + ", authTokenType="
+ + authTokenType
+ + ", options="
+ + options
+ + ")");
+ throw new UnsupportedOperationException();
+ }
+
+ // Getting a label for the auth token is not supported
+ @Override
+ public String getAuthTokenLabel(String authTokenType) {
+ Log.d(TAG, "getAuthTokenLabel(authTokenType=" + authTokenType + ")");
+ return null;
+ }
+
+ // Updating user credentials is not supported
+ @Override
+ public Bundle updateCredentials(
+ AccountAuthenticatorResponse r, Account account, String authTokenType, Bundle options)
+ throws NetworkErrorException {
+ Log.d(
+ TAG,
+ "updateCredentials(account="
+ + account
+ + ", authTokenType="
+ + authTokenType
+ + ", options="
+ + options
+ + ")");
+ return null;
+ }
+
+ // Checking features for the account is not supported
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse r, Account account, String[] features)
+ throws NetworkErrorException {
+ Log.d(
+ TAG,
+ "hasFeatures(Account=" + account + ", features=" + Arrays.toString(features) + ")");
+
+ final Bundle result = new Bundle();
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+ return result;
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/AuthenticationService.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorService.java
similarity index 73%
rename from android/app/src/com/android/bluetooth/pbapclient/AuthenticationService.java
rename to android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorService.java
index c876457..216dc2c 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/AuthenticationService.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorService.java
@@ -19,12 +19,17 @@
import android.content.Intent;
import android.os.IBinder;
-public class AuthenticationService extends Service {
- private Authenticator mAuthenticator;
+/**
+ * A service to host out AccountManagerService compliant Authenticator
+ *
+ * <p>See PbapClientAccountAuthenticator for details.
+ */
+public class PbapClientAccountAuthenticatorService extends Service {
+ private PbapClientAccountAuthenticator mAuthenticator;
@Override
public void onCreate() {
- mAuthenticator = new Authenticator(this);
+ mAuthenticator = new PbapClientAccountAuthenticator(this);
}
@Override
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountManager.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountManager.java
new file mode 100644
index 0000000..da0c2a1
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientAccountManager.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.bluetooth.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This class abstracts away interactions and management of the AccountManager Account objects that
+ * we need to store contacts and call logs on Android. This object provides functions to get/create
+ * an account, as well as remove or cleanup accounts.
+ *
+ * <p>Most AccountManager functions we want to use require the caller (us) to have a signature match
+ * with the authenticator that owns the specified account. AccountManager knowing this is contingent
+ * on our AuthenticationService being started (Our PbapClientAccountAuthenticatorService, which owns
+ * our PbapClientAccountAuthenticator) and AccountManagerService being notified of it so it can
+ * update its cache. This happens asynchronously and can sometimes take as long as 30 seconds after
+ * stack startup to be available. This object also abstracts this issue away, handling the timing
+ * and notifying clients when accounts are ready.
+ *
+ * <p>Once the account list has been intitialized, clients can begin making calls to add, remove and
+ * list accounts.
+ */
+class PbapClientAccountManager {
+ private static final String TAG = PbapClientAccountManager.class.getSimpleName();
+
+ private final Context mContext;
+ private final AccountManager mAccountManager;
+ private final UserManager mUserManager;
+ private final String mAccountType;
+ private final AccountManagerReceiver mAccountManagerReceiver = new AccountManagerReceiver();
+
+ private HandlerThread mHandlerThread = null;
+ private AccountHandler mAccountHandler = null;
+
+ private final Object mAccountLock = new Object();
+
+ @GuardedBy("mAccountLock")
+ private final Set<Account> mAccounts = new HashSet<Account>();
+
+ private boolean mIsUserReady = false;
+ private volatile boolean mAccountsInitialized = false;
+
+ // For sending events back to the object owner
+ private final Callback mCallback;
+
+ /** A Callback interface so clients can receive structured events from this account manager */
+ interface Callback {
+ /**
+ * Receive account visibility updates
+ *
+ * @param oldAccounts The list of previously available accounts, or null if this is the
+ * first account update after initialization
+ * @param newAccounts The list of newly available accounts
+ */
+ void onAccountsChanged(List<Account> oldAccounts, List<Account> newAccounts);
+ }
+
+ PbapClientAccountManager(Context context, Callback callback) {
+ this(context, null, callback);
+ }
+
+ @VisibleForTesting
+ PbapClientAccountManager(Context context, HandlerThread handlerThread, Callback callback) {
+ mContext = Objects.requireNonNull(context);
+ mAccountManager = mContext.getSystemService(AccountManager.class);
+ mUserManager = mContext.getSystemService(UserManager.class);
+ mAccountType = mContext.getResources().getString(R.string.pbap_client_account_type);
+ mHandlerThread = handlerThread;
+ mCallback = callback;
+ }
+
+ public void start() {
+ Log.d(TAG, "start()");
+
+ mAccountsInitialized = false;
+ synchronized (mAccountLock) {
+ mAccounts.clear();
+ }
+
+ // Allow injecting a TestLooper
+ if (mHandlerThread == null) {
+ mHandlerThread = new HandlerThread(TAG);
+ }
+
+ mHandlerThread.start();
+ mAccountHandler = new AccountHandler(mHandlerThread.getLooper());
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(mAccountManagerReceiver, filter);
+
+ if (isUserUnlocked()) {
+ mAccountHandler.obtainMessage(AccountHandler.MSG_USER_UNLOCKED).sendToTarget();
+ }
+ }
+
+ public void stop() {
+ Log.d(TAG, "stop()");
+
+ mContext.unregisterReceiver(mAccountManagerReceiver);
+ if (mAccountHandler != null) {
+ mAccountHandler.removeCallbacksAndMessages(null);
+ mAccountHandler = null;
+ }
+
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ mHandlerThread = null;
+ }
+
+ mAccountsInitialized = false;
+ }
+
+ /**
+ * Determine if this object has completed initialization of the accounts list.
+ *
+ * <p>Initialization happens once the user is unlock and our account type is recognized by the
+ * AccountManager framework.
+ *
+ * @return True if the accounts list has been initialized, false otherwise.
+ */
+ public boolean isAccountTypeInitialized() {
+ return mAccountsInitialized;
+ }
+
+ /**
+ * Get a well-formed Pbap Client based Account object to add for a given remote device.
+ *
+ * <p>This account should be used when making storage calls. Be sure the account is added and
+ * exists before using it for storage calls.
+ *
+ * @param device The remote device you would like a PBAP Client account for
+ * @return an Account object corresponding to the given remote device
+ */
+ public Account getAccountForDevice(BluetoothDevice device) {
+ if (device == null) {
+ throw new IllegalArgumentException("Null device");
+ }
+ return new Account(device.getAddress(), mAccountType);
+ }
+
+ /**
+ * Get the list of available PBAP Client accounts
+ *
+ * @return A list of all available PBAP Client based accounts on this device
+ */
+ public List<Account> getAccounts() {
+ if (!mAccountsInitialized) {
+ Log.w(TAG, "getAccounts(): Not initialized");
+ return Collections.emptyList();
+ }
+ synchronized (mAccountLock) {
+ return Collections.unmodifiableList(new ArrayList<>(mAccounts));
+ }
+ }
+
+ /**
+ * Request for an account to be added
+ *
+ * <p>Storage must be initialized before calls to this function will be successful
+ *
+ * @param account The account to add
+ * @return True if the account is successfully added, False otherwise
+ */
+ public boolean addAccount(Account account) {
+ if (!mAccountsInitialized) {
+ Log.w(TAG, "addAccount(account=" + account + "): Cannot add account, not initialized");
+ return false;
+ }
+ synchronized (mAccountLock) {
+ List<Account> oldAccounts = new ArrayList<>(mAccounts);
+ if (addAccountInternal(account)) {
+ notifyAccountsChanged(oldAccounts, new ArrayList<>(mAccounts));
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Request for an account to be removed
+ *
+ * <p>Storage must be initialized before calls to this function will be successful
+ *
+ * @param account The account to remove
+ * @return True if the account is successfully removed, False otherwise
+ */
+ public boolean removeAccount(Account account) {
+ if (!mAccountsInitialized) {
+ Log.w(
+ TAG,
+ "removeAccount(account="
+ + account
+ + "): Cannot remove account, not initialized");
+ return false;
+ }
+ synchronized (mAccountLock) {
+ List<Account> oldAccounts = new ArrayList<>(mAccounts);
+ if (removeAccountInternal(account)) {
+ notifyAccountsChanged(oldAccounts, new ArrayList<>(mAccounts));
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /** Receive user lifecycle events and forward them to the handler for processing */
+ private class AccountManagerReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.v(TAG, "onReceive action=" + action);
+ if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
+ mAccountHandler.obtainMessage(AccountHandler.MSG_USER_UNLOCKED).sendToTarget();
+ }
+ }
+ }
+
+ /**
+ * A handler to serialize account events. This allows us to wait for our authentication service
+ * to be available until we interact with accounts, and then safely create and remove accounts
+ * as needed.
+ */
+ private class AccountHandler extends Handler {
+ // There's an ~1-2 second latency between when our Authentication service is set as
+ // available to the system and when the Authentication/Account framework code will recognize
+ // it and allow us to alter accounts. In lieu of the Accounts team dealing with this race
+ // condition, we're going to periodically poll over 3 seconds until our accounts are
+ // visible, remove old accounts, and then notify device state machines that they can create
+ // accounts and download contacts.
+ //
+ // TODO(233361365): Remove this pattern when the framework solves their race condition
+ private static final int ACCOUNT_ADD_RETRY_MS = 1000;
+
+ public static final int MSG_USER_UNLOCKED = 0;
+ public static final int MSG_ACCOUNT_CHECK = 1;
+
+ AccountHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ Log.v(TAG, "Process message=" + messageToString(msg.what));
+ switch (msg.what) {
+ case MSG_USER_UNLOCKED:
+ handleUserUnlocked();
+ break;
+ case MSG_ACCOUNT_CHECK:
+ handleAccountCheck();
+ break;
+ default:
+ Log.e(TAG, "received an unknown message : " + msg.what);
+ }
+ }
+
+ private void handleUserUnlocked() {
+ if (mIsUserReady) {
+ Log.i(TAG, "Notified user unlocked, but we've already processed this event. Skip");
+ return;
+ }
+
+ Log.i(TAG, "User is unlocked. Begin account check process");
+ mIsUserReady = true;
+ this.obtainMessage(MSG_ACCOUNT_CHECK).sendToTarget();
+ }
+
+ private void handleAccountCheck() {
+ if (mAccountsInitialized) {
+ Log.w(TAG, "Accounts already initialized. Skipping");
+ return;
+ }
+
+ if (isAccountAuthenticationServiceReady()) {
+ Log.d(TAG, "Account type ready to be interacted with. Initialize account list");
+
+ Account[] availableAccounts = mAccountManager.getAccountsByType(mAccountType);
+ synchronized (mAccountLock) {
+ for (Account account : availableAccounts) {
+ Log.i(TAG, "Loaded saved account, account=" + account);
+ mAccounts.add(account);
+ }
+
+ mAccountsInitialized = true;
+
+ Log.d(TAG, "Accounts list initialized");
+ notifyAccountsChanged(null, new ArrayList<>(mAccounts));
+ }
+ } else {
+ Log.d(TAG, "Accounts not ready. Check again in " + ACCOUNT_ADD_RETRY_MS + "ms");
+ sendMessageDelayed(obtainMessage(MSG_ACCOUNT_CHECK), ACCOUNT_ADD_RETRY_MS);
+ }
+ }
+
+ private static String messageToString(int msg) {
+ switch (msg) {
+ case MSG_USER_UNLOCKED:
+ return "MSG_USER_UNLOCKED";
+ case MSG_ACCOUNT_CHECK:
+ return "MSG_ACCOUNT_CHECK";
+ default:
+ return "MSG_RESERVED_" + msg;
+ }
+ }
+ }
+
+ /**
+ * Determine if the user is unlocked
+ *
+ * <p>AccountManager functionality doesn't work until the user is unlocked. We need to hold our
+ * calls until we know the user is unlocked.
+ *
+ * @return True if the use it unlocked, False otherwise
+ */
+ private boolean isUserUnlocked() {
+ return mUserManager.isUserUnlocked();
+ }
+
+ /**
+ * Determine if we're able to interact with our own account type
+ *
+ * <p>We're able to interact with our account when our account service is up and the
+ * AccountManagerService has finished updating itself such that it also knows our service is
+ * ready. The AccountManager framework doesn't have a good way for us to know _exactly_ when
+ * this is, so the best we can do is try to interact with our account type and see if it works.
+ *
+ * <p>We use a fake device address and our accoun ttype here to see if our account is visible
+ * yet.
+ *
+ * <p>This function is used in conjunction with the handler and a polling scheme to see
+ * determine when we're finally ready.
+ *
+ * <p>Note: that this function uses the same restrictions as the other add and remove functions,
+ * but is *also* available to all system apps instead of throwing a runtime SecurityException.
+ * AccountManagerService makes an !isSystemUid check before throwing.
+ *
+ * @return True if our PBAP Client Account type is ready to use, False otherwise.
+ */
+ private boolean isAccountAuthenticationServiceReady() {
+ Account account = new Account("00:00:00:00:00:00", mAccountType);
+ int visibility = mAccountManager.getAccountVisibility(account, mContext.getPackageName());
+ Log.d(TAG, "Checking visibility, visibility=" + visibility);
+ return visibility == AccountManager.VISIBILITY_VISIBLE
+ || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
+ }
+
+ /**
+ * Explicitly add an account. Returns true is successful, false otherwise.
+ *
+ * <p>Any exceptions generated cause this function to fail silently. In particular,
+ * SecurityExceptions due to the fact that our authentication service isn't recognized by the
+ * AccountManager framework yet are dropped. Our handler is setup to make it so we shouldn't
+ * make these calls unless we know AccountManager knows of us though.
+ *
+ * @param account The account to add
+ * @return True on success, false otherwise
+ */
+ private boolean addAccountInternal(Account account) {
+ try {
+ synchronized (mAccountLock) {
+ if (mAccountManager.addAccountExplicitly(account, null, null)) {
+ mAccounts.add(account);
+ Log.i(TAG, "Added account=" + account);
+ return true;
+ }
+ Log.w(TAG, "Failed to add account=" + account);
+ return false;
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Exception while trying to add account=" + account, e);
+ return false;
+ }
+ }
+
+ /**
+ * Explicitly remove an account. Returns true is successful, false otherwise.
+ *
+ * <p>Any exceptions generated cause this function to fail silently. In particular,
+ * SecurityExceptions due to the fact that our authentication service isn't recognized by the
+ * AccountManager framework yet are dropped. Our handler is setup to make it so we shouldn't
+ * make these calls unless we know AccountManager knows of us though.
+ *
+ * @param account the account to explicitly remove
+ * @return True on success, false otherwise
+ */
+ private boolean removeAccountInternal(Account account) {
+ try {
+ synchronized (mAccountLock) {
+ if (mAccountManager.removeAccountExplicitly(account)) {
+ mAccounts.remove(account);
+ Log.i(TAG, "Removed account=" + account);
+ return true;
+ }
+ Log.w(TAG, "Failed to remove account=" + account);
+ return false;
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Exception while trying to remove account=" + account, e);
+ return false;
+ }
+ }
+
+ /**
+ * Notify all client callbacks that the set of accounts has changed
+ *
+ * @param oldAccounts The previous list of accounts available, or null if this is the first
+ * update
+ * @param newAccounts The new list of accounts available
+ */
+ private void notifyAccountsChanged(List<Account> oldAccounts, List<Account> newAccounts) {
+ Log.v(TAG, "notifyAccountsChanged, old=" + oldAccounts + ", new=" + newAccounts);
+ if (mCallback != null) {
+ mCallback.onAccountsChanged(oldAccounts, newAccounts);
+ }
+ }
+
+ /** Get a debug dump of this class, containing the accounts on the device */
+ public String dump() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(TAG).append(":\n");
+ sb.append(" Account Type: ").append(mAccountType).append("\n");
+ sb.append(" User Unlocked: ").append(isUserUnlocked()).append("\n");
+ sb.append(" Account Type Ready: ")
+ .append(isAccountAuthenticationServiceReady())
+ .append("\n");
+ sb.append(" Accounts Initialized: ").append(mAccountsInitialized).append("\n");
+ sb.append(" Accounts:\n");
+ for (Account account : getAccounts()) {
+ sb.append(" ").append(account).append("\n");
+ }
+ return sb.toString();
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientBinder.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientBinder.java
new file mode 100644
index 0000000..df09be4
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientBinder.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+
+import android.annotation.RequiresPermission;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.IBluetoothPbapClient;
+import android.content.AttributionSource;
+import android.util.Log;
+
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/** Handler for incoming service calls destined for PBAP Client */
+public class PbapClientBinder extends IBluetoothPbapClient.Stub implements IProfileServiceBinder {
+ private static final String TAG = PbapClientBinder.class.getSimpleName();
+
+ private PbapClientService mService;
+
+ PbapClientBinder(PbapClientService service) {
+ mService = service;
+ }
+
+ @Override
+ public void cleanup() {
+ mService = null;
+ }
+
+ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
+ private PbapClientService getService(AttributionSource source) {
+ // Cache mService because it can change while getService is called
+ PbapClientService service = mService;
+
+ if (Utils.isInstrumentationTestMode()) {
+ return service;
+ }
+
+ if (!Utils.checkServiceAvailable(service, TAG)) {
+ Log.w(TAG, "getService() failed, service not available");
+ return null;
+ }
+
+ if (!Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)
+ || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
+ Log.w(TAG, "getService() failed, rejected due to permissions");
+ return null;
+ }
+
+ service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+
+ return service;
+ }
+
+ @Override
+ public boolean connect(BluetoothDevice device, AttributionSource source) {
+ Log.d(TAG, "connect(device=" + device + ")");
+ PbapClientService service = getService(source);
+ if (service == null) {
+ return false;
+ }
+ return service.connect(device);
+ }
+
+ @Override
+ public boolean disconnect(BluetoothDevice device, AttributionSource source) {
+ Log.d(TAG, "disconnect(device=" + device + ")");
+ PbapClientService service = getService(source);
+ if (service == null) {
+ return false;
+ }
+ return service.disconnect(device);
+ }
+
+ @Override
+ public List<BluetoothDevice> getConnectedDevices(AttributionSource source) {
+ Log.d(TAG, "getConnectedDevices()");
+ PbapClientService service = getService(source);
+ if (service == null) {
+ return Collections.emptyList();
+ }
+ return service.getConnectedDevices();
+ }
+
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ int[] states, AttributionSource source) {
+ Log.d(TAG, "getDevicesMatchingConnectionStates(states=" + Arrays.toString(states) + ")");
+ PbapClientService service = getService(source);
+ if (service == null) {
+ return Collections.emptyList();
+ }
+ return service.getDevicesMatchingConnectionStates(states);
+ }
+
+ @Override
+ public int getConnectionState(BluetoothDevice device, AttributionSource source) {
+ Log.d(TAG, "getConnectionState(device=" + device + ")");
+ PbapClientService service = getService(source);
+ if (service == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return service.getConnectionState(device);
+ }
+
+ @Override
+ public boolean setConnectionPolicy(
+ BluetoothDevice device, int connectionPolicy, AttributionSource source) {
+ Log.d(TAG, "setConnectionPolicy(device=" + device + ", policy=" + connectionPolicy + ")");
+
+ PbapClientService service = getService(source);
+ if (service == null) {
+ return false;
+ }
+ return service.setConnectionPolicy(device, connectionPolicy);
+ }
+
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) {
+ Log.d(TAG, "getConnectionPolicy(device=" + device + ")");
+ PbapClientService service = getService(source);
+ if (service == null) {
+ return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
+ }
+ return service.getConnectionPolicy(device);
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
index 961337c..b343c07 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientService.java
@@ -16,22 +16,13 @@
package com.android.bluetooth.pbapclient;
-import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
-
import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
-import android.bluetooth.IBluetoothPbapClient;
-import android.content.AttributionSource;
-import android.content.BroadcastReceiver;
+import android.bluetooth.SdpPseRecord;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
@@ -40,9 +31,6 @@
import android.sysprop.BluetoothProperties;
import android.util.Log;
-import com.android.bluetooth.BluetoothMethodProxy;
-import com.android.bluetooth.R;
-import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
@@ -51,7 +39,6 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -65,7 +52,7 @@
/** The component names for the owned authenticator service */
private static final String AUTHENTICATOR_SERVICE =
- AuthenticationService.class.getCanonicalName();
+ PbapClientAccountAuthenticatorService.class.getCanonicalName();
// MAXIMUM_DEVICES set to 10 to prevent an excessive number of simultaneous devices.
private static final int MAXIMUM_DEVICES = 10;
@@ -75,61 +62,34 @@
new ConcurrentHashMap<>();
private static PbapClientService sPbapClientService;
- @VisibleForTesting PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver();
+ private final PbapClientAccountManager mPbapClientAccountManager;
private int mSdpHandle = -1;
-
private DatabaseManager mDatabaseManager;
-
- /**
- * There's an ~1-2 second latency between when our Authentication service is set as available to
- * the system and when the Authentication/Account framework code will recognize it and allow us
- * to alter accounts. In lieu of the Accounts team dealing with this race condition, we're going
- * to periodically poll over 3 seconds until our accounts are visible, remove old accounts, and
- * then notify device state machines that they can create accounts and download contacts.
- */
- // TODO(233361365): Remove this pattern when the framework solves their race condition
- private static final int ACCOUNT_VISIBILITY_CHECK_MS = 500;
-
- private static final int ACCOUNT_VISIBILITY_CHECK_TRIES_MAX = 6;
- private int mAccountVisibilityCheckTries = 0;
- private final Handler mAuthServiceHandler = new Handler();
private Handler mHandler;
- private final Runnable mCheckAuthService =
- new Runnable() {
- @Override
- public void run() {
- // If our accounts are finally visible to use, clean up old ones and tell
- // devices they can issue downloads if they're ready. Otherwise, wait and try
- // again.
- if (isAuthenticationServiceReady()) {
- Log.i(
- TAG,
- "Service ready! Clean up old accounts and try contacts downloads");
- removeUncleanAccounts();
- for (PbapClientStateMachine stateMachine :
- mPbapClientStateMachineMap.values()) {
- stateMachine.tryDownloadIfConnected();
- }
- } else if (mAccountVisibilityCheckTries < ACCOUNT_VISIBILITY_CHECK_TRIES_MAX) {
- mAccountVisibilityCheckTries += 1;
- Log.w(
- TAG,
- "AccountManager hasn't registered our service yet. Retry "
- + mAccountVisibilityCheckTries
- + "/"
- + ACCOUNT_VISIBILITY_CHECK_TRIES_MAX);
- mAuthServiceHandler.postDelayed(this, ACCOUNT_VISIBILITY_CHECK_MS);
- } else {
- Log.e(
- TAG,
- "Failed to register Authentication Service and get account"
- + " visibility");
- }
- }
- };
- public PbapClientService(Context ctx) {
- super(ctx);
+ class PbapClientAccountManagerCallback implements PbapClientAccountManager.Callback {
+ @Override
+ public void onAccountsChanged(List<Account> oldAccounts, List<Account> newAccounts) {
+ Log.i(TAG, "onAccountsChanged: old=" + oldAccounts + ", new=" + newAccounts);
+ if (oldAccounts == null) {
+ removeUncleanAccounts();
+ for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
+ stateMachine.tryDownloadIfConnected();
+ }
+ }
+ }
+ }
+
+ public PbapClientService(Context context) {
+ super(context);
+ mPbapClientAccountManager =
+ new PbapClientAccountManager(context, new PbapClientAccountManagerCallback());
+ }
+
+ @VisibleForTesting
+ PbapClientService(Context context, PbapClientAccountManager accountManager) {
+ super(context);
+ mPbapClientAccountManager = accountManager;
}
public static boolean isEnabled() {
@@ -138,7 +98,7 @@
@Override
public IProfileServiceBinder initBinder() {
- return new BluetoothPbapClientBinder(this);
+ return new PbapClientBinder(this);
}
@Override
@@ -153,17 +113,9 @@
setComponentAvailable(AUTHENTICATOR_SERVICE, true);
mHandler = new Handler(Looper.getMainLooper());
- IntentFilter filter = new IntentFilter();
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- // delay initial download until after the user is unlocked to add an account.
- filter.addAction(Intent.ACTION_USER_UNLOCKED);
- try {
- registerReceiver(mPbapBroadcastReceiver, filter);
- } catch (Exception e) {
- Log.w(TAG, "Unable to register pbapclient receiver", e);
- }
- initializeAuthenticationService();
+ mPbapClientAccountManager.start();
+
registerSdpRecord();
setPbapClientService(this);
}
@@ -172,11 +124,7 @@
public void stop() {
setPbapClientService(null);
cleanUpSdpRecord();
- try {
- unregisterReceiver(mPbapBroadcastReceiver);
- } catch (Exception e) {
- Log.w(TAG, "Unable to unregister pbapclient receiver", e);
- }
+
for (PbapClientStateMachine pbapClientStateMachine : mPbapClientStateMachineMap.values()) {
pbapClientStateMachine.doQuit();
}
@@ -188,113 +136,32 @@
mHandler = null;
}
- cleanupAuthenticationService();
+ removeUncleanAccounts();
+ mPbapClientAccountManager.stop();
+
setComponentAvailable(AUTHENTICATOR_SERVICE, false);
}
- void cleanupDevice(BluetoothDevice device) {
- Log.d(TAG, "Cleanup device: " + device);
- synchronized (mPbapClientStateMachineMap) {
- PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device);
- if (pbapClientStateMachine != null) {
- mPbapClientStateMachineMap.remove(device);
- pbapClientStateMachine.doQuit();
- }
- }
- }
-
/**
- * Periodically check if the account framework has recognized our service and will allow us to
- * interact with our accounts. Notify state machines once our service is ready so we can trigger
- * account downloads.
- */
- private void initializeAuthenticationService() {
- mAuthServiceHandler.postDelayed(mCheckAuthService, ACCOUNT_VISIBILITY_CHECK_MS);
- }
-
- private void cleanupAuthenticationService() {
- mAuthServiceHandler.removeCallbacks(mCheckAuthService);
- removeUncleanAccounts();
- }
-
- /**
- * Determine if our account type is visible to us yet. If it is, then our service is ready and
- * our account type is ready to use.
+ * Add our PBAP Client SDP record to the device SDP database
*
- * <p>Make a placeholder device account and determine our visibility relative to it. Note that
- * this function uses the same restrictions as the other add and remove functions, but is *also*
- * available to all system apps instead of throwing a runtime SecurityException.
+ * <p>This allows our client to be recognized by the remove device. The record must be cleaned
+ * up when we shutdown.
*/
- protected boolean isAuthenticationServiceReady() {
- Account account = new Account("00:00:00:00:00:00", getString(R.string.pbap_account_type));
- AccountManager accountManager = AccountManager.get(this);
- int visibility = accountManager.getAccountVisibility(account, getPackageName());
- Log.d(TAG, "Checking visibility, visibility=" + visibility);
- return visibility == AccountManager.VISIBILITY_VISIBLE
- || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
- }
-
- private void removeUncleanAccounts() {
- if (!isAuthenticationServiceReady()) {
- Log.w(TAG, "Can't remove accounts. AccountManager hasn't registered our service yet.");
- return;
- }
-
- // Find all accounts that match the type "pbap" and delete them.
- AccountManager accountManager = AccountManager.get(this);
- Account[] accounts =
- accountManager.getAccountsByType(getString(R.string.pbap_account_type));
- Log.v(TAG, "Found " + accounts.length + " unclean accounts");
- for (Account acc : accounts) {
- Log.w(TAG, "Deleting " + acc);
- try {
- getContentResolver()
- .delete(
- CallLog.Calls.CONTENT_URI,
- CallLog.Calls.PHONE_ACCOUNT_ID + "=?",
- new String[] {acc.name});
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Call Logs could not be deleted, they may not exist yet.");
- }
- // The device ID is the name of the account.
- accountManager.removeAccountExplicitly(acc);
- }
- }
-
- private void removeHfpCallLog(String accountName, Context context) {
- Log.d(TAG, "Removing call logs from " + accountName);
- // Delete call logs belonging to accountName==BD_ADDR that also match
- // component name "hfpclient".
- ComponentName componentName = new ComponentName(context, HfpClientConnectionService.class);
- String selectionFilter =
- CallLog.Calls.PHONE_ACCOUNT_ID
- + "=? AND "
- + CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME
- + "=?";
- String[] selectionArgs = new String[] {accountName, componentName.flattenToString()};
- try {
- BluetoothMethodProxy.getInstance()
- .contentResolverDelete(
- getContentResolver(),
- CallLog.Calls.CONTENT_URI,
- selectionFilter,
- selectionArgs);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Call Logs could not be deleted, they may not exist yet.");
- }
- }
-
private void registerSdpRecord() {
SdpManagerNativeInterface nativeInterface = SdpManagerNativeInterface.getInstance();
if (!nativeInterface.isAvailable()) {
Log.e(TAG, "SdpManagerNativeInterface is not available");
return;
}
- mSdpHandle =
- nativeInterface.createPbapPceRecord(
- SERVICE_NAME, PbapClientConnectionHandler.PBAP_V1_2);
+ mSdpHandle = nativeInterface.createPbapPceRecord(SERVICE_NAME, PbapSdpRecord.VERSION_1_2);
}
+ /**
+ * Remove our PBAP Client SDP record from the device SDP database
+ *
+ * <p>Gracefully removes PBAP Client support from our SDP records. Called when shutting down.
+ */
private void cleanUpSdpRecord() {
if (mSdpHandle < 0) {
Log.e(TAG, "cleanUpSdpRecord, SDP record never created");
@@ -317,20 +184,137 @@
}
}
- @VisibleForTesting
- class PbapBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- Log.v(TAG, "onReceive" + action);
- if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
- for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
- stateMachine.tryDownloadIfConnected();
- }
+ void cleanupDevice(BluetoothDevice device) {
+ Log.d(TAG, "Cleanup device: " + device);
+ synchronized (mPbapClientStateMachineMap) {
+ PbapClientStateMachine pbapClientStateMachine = mPbapClientStateMachineMap.get(device);
+ if (pbapClientStateMachine != null) {
+ mPbapClientStateMachineMap.remove(device);
+ pbapClientStateMachine.doQuit();
}
}
}
+ /**
+ * Clean up any existing accounts.
+ *
+ * <p>This function gets the list of available Pbap Client accounts and deletes them. Deletion
+ * of the account causes Contacts Provider to also delete the associated contacts data. We
+ * separately clean up the call log data associated with a given account too.
+ */
+ private void removeUncleanAccounts() {
+ List<Account> accounts = mPbapClientAccountManager.getAccounts();
+ Log.i(TAG, "removeUncleanAccounts: Found " + accounts.size() + " accounts");
+
+ for (Account account : accounts) {
+ Log.d(TAG, "removeUncleanAccounts: removing call logs for account=" + account);
+ try {
+ // The device ID for call logs is the name of the account
+ getContentResolver()
+ .delete(
+ CallLog.Calls.CONTENT_URI,
+ CallLog.Calls.PHONE_ACCOUNT_ID + "=?",
+ new String[] {account.name});
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Call Logs could not be deleted, they may not exist yet.", e);
+ }
+
+ Log.i(TAG, "removeUncleanAccounts: removing account=" + account);
+ mPbapClientAccountManager.removeAccount(account);
+ }
+ }
+
+ private void removeHfpCallLog(String accountName) {
+ Log.d(TAG, "Removing call logs from " + accountName);
+ // Delete call logs belonging to accountName==BD_ADDR that also match component "hfpclient"
+ ComponentName componentName = new ComponentName(this, HfpClientConnectionService.class);
+ String selectionFilter =
+ CallLog.Calls.PHONE_ACCOUNT_ID
+ + "=? AND "
+ + CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME
+ + "=?";
+ String[] selectionArgs = new String[] {accountName, componentName.flattenToString()};
+ try {
+ getContentResolver().delete(CallLog.Calls.CONTENT_URI, selectionFilter, selectionArgs);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Call Logs could not be deleted, they may not exist yet.");
+ }
+ }
+
+ /**
+ * Ensure that after HFP disconnects, we remove call logs. This addresses the situation when
+ * PBAP was never connected while calls were made. Ideally {@link PbapClientConnectionHandler}
+ * has code to remove calllogs when PBAP disconnects.
+ */
+ public void handleHeadsetClientConnectionStateChanged(
+ BluetoothDevice device, int oldState, int newState) {
+ if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+ Log.d(TAG, "Received intent to disconnect HFP with " + device);
+ // HFP client stores entries in calllog.db by BD_ADDR and component name
+ // Using the current Service as the context.
+ removeHfpCallLog(device.getAddress());
+ }
+ }
+
+ /**
+ * Determine if our account type is available and ready to be interacted with
+ *
+ * @return True is account type is ready, false otherwise
+ */
+ public boolean isAccountTypeReady() {
+ return mPbapClientAccountManager.isAccountTypeInitialized();
+ }
+
+ /**
+ * Add an account
+ *
+ * @param account The account you wish to add
+ * @return True if the account addition was successful, False otherwise
+ */
+ public boolean addAccount(Account account) {
+ return mPbapClientAccountManager.addAccount(account);
+ }
+
+ /**
+ * Remove an account
+ *
+ * @param account The account you wish to remove
+ * @return True if the account removal was successful, False otherwise
+ */
+ public boolean removeAccount(Account account) {
+ return mPbapClientAccountManager.removeAccount(account);
+ }
+
+ /**
+ * Get debug information about this PbapClientService instance
+ *
+ * @param sb The StringBuilder instance to add our debug dump info to
+ */
+ @Override
+ public void dump(StringBuilder sb) {
+ super.dump(sb);
+ for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
+ stateMachine.dump(sb);
+ }
+ ProfileService.println(sb, mPbapClientAccountManager.dump());
+ }
+
+ // *********************************************************************************************
+ // * Events from AdapterService
+ // *********************************************************************************************
+
+ /**
+ * Get notified of incoming ACL disconnections
+ *
+ * <p>OBEX client's are supposed to be in control of the connection lifecycle, and servers are
+ * not supposed to disconnect OBEX sessions. Despite this, its normal/possible the remote device
+ * to tear down connections at lower levels than OBEX, mainly the L2CAP/RFCOMM links or the ACL.
+ * The OBEX framework isn't setup to be notified of these disconnections, so we must listen for
+ * them separately and clean up the device connection and, if necessary, data when this happens.
+ *
+ * @param device The device that had the ACL disconnect
+ * @param transport The transport the device disconnected on
+ */
public void aclDisconnected(BluetoothDevice device, int transport) {
mHandler.post(() -> handleAclDisconnected(device, transport));
}
@@ -353,132 +337,45 @@
}
/**
- * Ensure that after HFP disconnects, we remove call logs. This addresses the situation when
- * PBAP was never connected while calls were made. Ideally {@link PbapClientConnectionHandler}
- * has code to remove calllogs when PBAP disconnects.
+ * Get notified of incoming SDP records
+ *
+ * <p>This function looks for PBAP Server records coming from remote devices, and forwards them
+ * to the appropriate device's state machine instance for processing. SDP records are used to
+ * determine which L2CAP/RFCOMM psm/channel to connect on, as well as which phonebooks to expect
*/
- public void handleHeadsetClientConnectionStateChanged(
- BluetoothDevice device, int oldState, int newState) {
- if (newState == BluetoothProfile.STATE_DISCONNECTED) {
- Log.d(TAG, "Received intent to disconnect HFP with " + device);
- // HFP client stores entries in calllog.db by BD_ADDR and component name
- // Using the current Service as the context.
- removeHfpCallLog(device.getAddress(), this);
+ public void receiveSdpSearchRecord(
+ BluetoothDevice device, int status, Parcelable record, ParcelUuid uuid) {
+ Log.v(
+ TAG,
+ "Received SDP record for UUID="
+ + uuid.toString()
+ + " (expected UUID="
+ + BluetoothUuid.PBAP_PSE.toString()
+ + ")");
+ if (uuid.equals(BluetoothUuid.PBAP_PSE)) {
+ PbapClientStateMachine stateMachine = mPbapClientStateMachineMap.get(device);
+ if (stateMachine == null) {
+ Log.e(TAG, "No Statemachine found for the device=" + device.toString());
+ return;
+ }
+ SdpPseRecord pseRecord = (SdpPseRecord) record;
+ if (pseRecord != null) {
+ stateMachine
+ .obtainMessage(
+ PbapClientStateMachine.MSG_SDP_COMPLETE,
+ new PbapSdpRecord(device, pseRecord))
+ .sendToTarget();
+ } else {
+ Log.w(TAG, "Received null PSE record for device=" + device);
+ }
}
}
- /** Handler for incoming service calls */
- @VisibleForTesting
- static class BluetoothPbapClientBinder extends IBluetoothPbapClient.Stub
- implements IProfileServiceBinder {
- private PbapClientService mService;
+ // *********************************************************************************************
+ // * API methods
+ // *********************************************************************************************
- BluetoothPbapClientBinder(PbapClientService svc) {
- mService = svc;
- }
-
- @Override
- public void cleanup() {
- mService = null;
- }
-
- @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
- private PbapClientService getService(AttributionSource source) {
- // Cache mService because it can change while getService is called
- PbapClientService service = mService;
-
- if (Utils.isInstrumentationTestMode()) {
- return service;
- }
-
- if (!Utils.checkServiceAvailable(service, TAG)
- || !Utils.checkCallerIsSystemOrActiveOrManagedUser(service, TAG)
- || !Utils.checkConnectPermissionForDataDelivery(service, source, TAG)) {
- return null;
- }
-
- service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
-
- return service;
- }
-
- @Override
- public boolean connect(BluetoothDevice device, AttributionSource source) {
- Log.d(TAG, "PbapClient Binder connect");
-
- PbapClientService service = getService(source);
- if (service == null) {
- Log.e(TAG, "PbapClient Binder connect no service");
- return false;
- }
-
- return service.connect(device);
- }
-
- @Override
- public boolean disconnect(BluetoothDevice device, AttributionSource source) {
- PbapClientService service = getService(source);
- if (service == null) {
- return false;
- }
-
- return service.disconnect(device);
- }
-
- @Override
- public List<BluetoothDevice> getConnectedDevices(AttributionSource source) {
- PbapClientService service = getService(source);
- if (service == null) {
- return Collections.emptyList();
- }
-
- return service.getConnectedDevices();
- }
-
- @Override
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(
- int[] states, AttributionSource source) {
- PbapClientService service = getService(source);
- if (service == null) {
- return Collections.emptyList();
- }
-
- return service.getDevicesMatchingConnectionStates(states);
- }
-
- @Override
- public int getConnectionState(BluetoothDevice device, AttributionSource source) {
- PbapClientService service = getService(source);
- if (service == null) {
- return BluetoothProfile.STATE_DISCONNECTED;
- }
-
- return service.getConnectionState(device);
- }
-
- @Override
- public boolean setConnectionPolicy(
- BluetoothDevice device, int connectionPolicy, AttributionSource source) {
- PbapClientService service = getService(source);
- if (service == null) {
- return false;
- }
-
- return service.setConnectionPolicy(device, connectionPolicy);
- }
-
- @Override
- public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) {
- PbapClientService service = getService(source);
- if (service == null) {
- return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
- }
-
- return service.getConnectionPolicy(device);
- }
- }
-
- // API methods
+ /** Get the singleton instance of PbapClientService, if one exists */
public static synchronized PbapClientService getPbapClientService() {
if (sPbapClientService == null) {
Log.w(TAG, "getPbapClientService(): service is null");
@@ -491,12 +388,23 @@
return sPbapClientService;
}
+ /**
+ * Set the singleton instance of PbapClientService
+ *
+ * <p>This function is meant to be used by tests only.
+ */
@VisibleForTesting
static synchronized void setPbapClientService(PbapClientService instance) {
Log.v(TAG, "setPbapClientService(): set to: " + instance);
sPbapClientService = instance;
}
+ /**
+ * Requests a connection to the given device's PBAP Server
+ *
+ * @param device is the device with which we will connect to
+ * @return true if we successfully begin the connection process, false otherwise
+ */
public boolean connect(BluetoothDevice device) {
if (device == null) {
throw new IllegalArgumentException("Null device");
@@ -540,13 +448,24 @@
}
}
+ /**
+ * Get the list of PBAP Server devices this PBAP Client device is connected to
+ *
+ * @return The list of connected PBAP Server devices
+ */
public List<BluetoothDevice> getConnectedDevices() {
int[] desiredStates = {BluetoothProfile.STATE_CONNECTED};
return getDevicesMatchingConnectionStates(desiredStates);
}
- @VisibleForTesting
- List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ /**
+ * Get the list of PBAP Server devices this PBAP Client device know about, who are in a given
+ * state.
+ *
+ * @param states The array of BluutoothProfile states you want to match on
+ * @return The list of connected PBAP Server devices
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(0);
for (Map.Entry<BluetoothDevice, PbapClientStateMachine> stateMachineEntry :
mPbapClientStateMachineMap.entrySet()) {
@@ -561,27 +480,6 @@
return deviceList;
}
- public void receiveSdpSearchRecord(
- BluetoothDevice device, int status, Parcelable record, ParcelUuid uuid) {
- PbapClientStateMachine stateMachine = mPbapClientStateMachineMap.get(device);
- if (stateMachine == null) {
- Log.e(TAG, "No Statemachine found for the device=" + device.toString());
- return;
- }
- Log.v(
- TAG,
- "Received SDP record for UUID="
- + uuid.toString()
- + " (expected UUID="
- + BluetoothUuid.PBAP_PSE.toString()
- + ")");
- if (uuid.equals(BluetoothUuid.PBAP_PSE)) {
- stateMachine
- .obtainMessage(PbapClientStateMachine.MSG_SDP_COMPLETE, record)
- .sendToTarget();
- }
- }
-
/**
* Get the current connection state of the profile
*
@@ -651,13 +549,4 @@
}
return mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.PBAP_CLIENT);
}
-
- @Override
- public void dump(StringBuilder sb) {
- super.dump(sb);
- ProfileService.println(sb, "isAuthServiceReady: " + isAuthenticationServiceReady());
- for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
- stateMachine.dump(sb);
- }
- }
}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java b/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java
index 2c8a441..0a555c0 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapClientStateMachine.java
@@ -90,6 +90,9 @@
static final int CONNECT_TIMEOUT = 10000;
static final int DISCONNECT_TIMEOUT = 3000;
+ private static final int LOCAL_SUPPORTED_FEATURES =
+ PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT | PbapSdpRecord.FEATURE_DOWNLOADING;
+
private final Object mLock;
private State mDisconnected;
private State mConnecting;
@@ -168,7 +171,8 @@
mConnectionHandler =
new PbapClientConnectionHandler.Builder()
.setLooper(looper)
- .setContext(mService)
+ .setLocalSupportedFeatures(LOCAL_SUPPORTED_FEATURES)
+ .setService(mService)
.setClientSM(PbapClientStateMachine.this)
.setRemoteDevice(mCurrentDevice)
.build();
@@ -311,14 +315,14 @@
/** Trigger a contacts download if the user is unlocked and our accounts are available to us */
private void downloadIfReady() {
boolean userReady = mUserManager.isUserUnlocked();
- boolean accountServiceReady = mService.isAuthenticationServiceReady();
- if (!userReady || !accountServiceReady) {
+ boolean accountTypeReady = mService.isAccountTypeReady();
+ if (!userReady || !accountTypeReady) {
Log.w(
TAG,
"Cannot download contacts yet, userReady="
+ userReady
- + ", accountServiceReady="
- + accountServiceReady);
+ + ", accountTypeReady="
+ + accountTypeReady);
return;
}
PbapClientConnectionHandler connectionHandler = mConnectionHandler;
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapSdpRecord.java b/android/app/src/com/android/bluetooth/pbapclient/PbapSdpRecord.java
new file mode 100644
index 0000000..c475bfc
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/PbapSdpRecord.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.SdpPseRecord;
+
+import java.util.Objects;
+
+/**
+ * This object represents an SDP Record for the PBAP profile. It extends the framework class by
+ * housing all the supported feature masks.
+ */
+public class PbapSdpRecord {
+ public static final int VERSION_1_0 = 0x0100;
+ public static final int VERSION_1_1 = 0x0101;
+ public static final int VERSION_1_2 = 0x0102;
+
+ public static final int FEATURES_EXCLUDED = -1;
+ public static final int FEATURE_DOWNLOADING = 1 << 0;
+ public static final int FEATURE_BROWSING = 1 << 1;
+ public static final int FEATURE_DATABASE_IDENTIFIER = 1 << 2;
+ public static final int FEATURE_FOLDER_VERSION_COUNTERS = 1 << 3;
+ public static final int FEATURE_VCARD_SELECTING = 1 << 4;
+ public static final int FEATURE_ENHANCED_MISSED_CALLS = 1 << 5;
+ public static final int FEATURE_XBT_UCI_VCARD_PROPERTY = 1 << 6;
+ public static final int FEATURE_XBT_UID_VCARD_PROPERTY = 1 << 7;
+ public static final int FEATURE_CONTACT_REFERENCING = 1 << 8;
+ public static final int FEATURE_DEFAULT_IMAGE_FORMAT = 1 << 9;
+
+ // PBAP v1.2.3 Sec. 7.1.2
+ public static final int REPOSITORY_LOCAL_PHONEBOOK = 1 << 0;
+ public static final int REPOSITORY_SIM_CARD = 1 << 1;
+ public static final int REPOSITORY_SPEED_DIAL = 1 << 2;
+ public static final int REPOSITORY_FAVORITES = 1 << 3;
+
+ public static final int FIELD_MISSING = -1;
+
+ private final BluetoothDevice mDevice;
+ private final SdpPseRecord mSdpRecord;
+
+ PbapSdpRecord(BluetoothDevice device, SdpPseRecord record) {
+ mDevice = Objects.requireNonNull(device);
+ mSdpRecord = Objects.requireNonNull(record);
+ }
+
+ /** Get the device associated with this SDP record */
+ public BluetoothDevice getDevice() {
+ return mDevice;
+ }
+
+ /** Get the profile version associated with this SDP record */
+ public int getProfileVersion() {
+ return mSdpRecord.getProfileVersion();
+ }
+
+ /** Get the service name associated with this SDP record */
+ public String getServiceName() {
+ return mSdpRecord.getServiceName();
+ }
+
+ /** Get the L2CAP PSM associated with this SDP record */
+ public int getL2capPsm() {
+ return mSdpRecord.getL2capPsm();
+ }
+
+ /** Get the RFCOMM channel number associated with this SDP record */
+ public int getRfcommChannelNumber() {
+ return mSdpRecord.getRfcommChannelNumber();
+ }
+
+ /** Get the supported features associated with this SDP record */
+ public int getSupportedFeatures() {
+ return mSdpRecord.getSupportedFeatures();
+ }
+
+ /** Returns true if this SDP record supports a given feature */
+ public boolean isFeatureSupported(int feature) {
+ int remoteFeatures = mSdpRecord.getSupportedFeatures();
+ if (remoteFeatures != FIELD_MISSING) {
+ return (feature & remoteFeatures) != 0;
+ }
+ return false;
+ }
+
+ /** Git the supported repositories bitmask associated with this SDP record */
+ public int getSupportedRepositories() {
+ return mSdpRecord.getSupportedRepositories();
+ }
+
+ /** Returns true if this SDP record supports a given repository */
+ public boolean isRepositorySupported(int repository) {
+ int remoteRepositories = mSdpRecord.getSupportedRepositories();
+ if (remoteRepositories != FIELD_MISSING) {
+ return (repository & remoteRepositories) != 0;
+ }
+ return false;
+ }
+
+ /** Get a string representation of this SDP record */
+ @Override
+ public String toString() {
+ return mSdpRecord.toString();
+ }
+
+ /**
+ * Get a string representation of any of the SDP PBAP version constants
+ *
+ * <p>Version is represented as a series of specification defined constants, in the form:
+ * 0x[Major 2 bytes][Minor 2 bytes] -> [Major].[Minor]
+ *
+ * <p>For example, 0x0102 is 1.2.
+ */
+ public static String versionToString(int version) {
+ switch (version) {
+ case FIELD_MISSING:
+ return "VERSION_UNKNOWN";
+ case VERSION_1_0:
+ return "VERSION_1_0";
+ case VERSION_1_1:
+ return "VERSION_1_1";
+ case VERSION_1_2:
+ return "VERSION_1_2";
+ default:
+ return "VERSION_UNRECOGNIZED_" + String.format("%04X", version);
+ }
+ }
+
+ /** Get a string representation of any of the SDP feature constants */
+ public static String featureToString(int feature) {
+ switch (feature) {
+ case FEATURE_DOWNLOADING:
+ return "FEATURE_DOWNLOADING";
+ case FEATURE_BROWSING:
+ return "FEATURE_BROWSING";
+ case FEATURE_DATABASE_IDENTIFIER:
+ return "FEATURE_DATABASE_IDENTIFIER";
+ case FEATURE_FOLDER_VERSION_COUNTERS:
+ return "FEATURE_FOLDER_VERSION_COUNTERS";
+ case FEATURE_VCARD_SELECTING:
+ return "FEATURE_VCARD_SELECTING";
+ case FEATURE_ENHANCED_MISSED_CALLS:
+ return "FEATURE_ENHANCED_MISSED_CALLS";
+ case FEATURE_XBT_UCI_VCARD_PROPERTY:
+ return "FEATURE_XBT_UCI_VCARD_PROPERTY";
+ case FEATURE_XBT_UID_VCARD_PROPERTY:
+ return "FEATURE_XBT_UID_VCARD_PROPERTY";
+ case FEATURE_CONTACT_REFERENCING:
+ return "FEATURE_CONTACT_REFERENCING";
+ case FEATURE_DEFAULT_IMAGE_FORMAT:
+ return "FEATURE_DEFAULT_IMAGE_FORMAT";
+ default:
+ return "FEATURE_RESERVED_BIT_" + feature;
+ }
+ }
+
+ /** Get a string representation of any of the SDP repository constants */
+ public static String repositoryToString(int repository) {
+ switch (repository) {
+ case REPOSITORY_LOCAL_PHONEBOOK:
+ return "REPOSITORY_LOCAL_PHONEBOOK";
+ case REPOSITORY_SIM_CARD:
+ return "REPOSITORY_SIM_CARD";
+ case REPOSITORY_SPEED_DIAL:
+ return "REPOSITORY_SPEED_DIAL";
+ case REPOSITORY_FAVORITES:
+ return "REPOSITORY_FAVORITES";
+ default:
+ return "REPOSITORY_RESERVED_BIT_" + repository;
+ }
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/CallLogPullRequest.java b/android/app/src/com/android/bluetooth/pbapclient/obex/CallLogPullRequest.java
similarity index 95%
rename from android/app/src/com/android/bluetooth/pbapclient/CallLogPullRequest.java
rename to android/app/src/com/android/bluetooth/pbapclient/obex/CallLogPullRequest.java
index 4780d1d..5becf2a 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/CallLogPullRequest.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/CallLogPullRequest.java
@@ -41,7 +41,7 @@
import java.util.Map;
public class CallLogPullRequest extends PullRequest {
- private static final String TAG = "CallLogPullRequest";
+ private static final String TAG = CallLogPullRequest.class.getSimpleName();
@VisibleForTesting static final String TIMESTAMP_PROPERTY = "X-IRMC-CALL-DATETIME";
private static final String TIMESTAMP_FORMAT = "yyyyMMdd'T'HHmmss";
@@ -69,11 +69,11 @@
Log.d(TAG, "onPullComplete with " + mEntries.size() + " entries");
int type;
try {
- if (path.equals(PbapClientConnectionHandler.ICH_PATH)) {
+ if (path.equals(PbapPhonebook.ICH_PATH)) {
type = CallLog.Calls.INCOMING_TYPE;
- } else if (path.equals(PbapClientConnectionHandler.OCH_PATH)) {
+ } else if (path.equals(PbapPhonebook.OCH_PATH)) {
type = CallLog.Calls.OUTGOING_TYPE;
- } else if (path.equals(PbapClientConnectionHandler.MCH_PATH)) {
+ } else if (path.equals(PbapPhonebook.MCH_PATH)) {
type = CallLog.Calls.MISSED_TYPE;
} else {
Log.w(TAG, "Unknown path type:" + path);
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapApplicationParameters.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapApplicationParameters.java
new file mode 100644
index 0000000..da4fa0e
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapApplicationParameters.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+public class PbapApplicationParameters {
+ private static final String TAG = PbapApplicationParameters.class.getSimpleName();
+
+ // Max size for a phonebook, which determines the max size of a batch and an offset. This comes
+ // from the fact that each field is 2 bytes -> 16 bits -> [0, 65535] (i.e, inclusive)
+ public static final int MAX_PHONEBOOK_SIZE = 65535;
+
+ // Application Parameter Header keys (PBAP 1.2.3, Section 6.2.1)
+ public static final byte OAP_ORDER = 0x01;
+ public static final byte OAP_SEARCH_VALUE = 0x02;
+ public static final byte OAP_SEARCH_PROPERTY = 0x03;
+ public static final byte OAP_MAX_LIST_COUNT = 0x04;
+ public static final byte OAP_LIST_START_OFFSET = 0x05;
+ public static final byte OAP_PROPERTY_SELECTOR = 0x06;
+ public static final byte OAP_FORMAT = 0x07;
+ public static final byte OAP_PHONEBOOK_SIZE = 0x08;
+ public static final byte OAP_NEW_MISSED_CALLS = 0x09;
+ public static final byte OAP_PRIMARY_FOLDER_VERSION = 0x0A;
+ public static final byte OAP_SECONDARY_FOLDER_VERSION = 0x0B;
+ public static final byte OAP_VCARD_SELECTOR = 0x0C;
+ public static final byte OAP_DATABASE_IDENTIFIER = 0x0D;
+ public static final byte OAP_VCARD_SELECTOR_OPERATOR = 0x0E;
+ public static final byte OAP_RESET_NEW_MISSED_CALLS = 0x0F;
+ public static final byte OAP_PBAP_SUPPORTED_FEATURES = 0x10;
+
+ // Property Selector "filter" constants, PBAP 1.2.3, section 5.1.4.1
+ public static final long PROPERTIES_ALL = 0;
+ public static final long PROPERTY_VERSION = 1 << 0;
+ public static final long PROPERTY_FN = 1 << 1;
+ public static final long PROPERTY_N = 1 << 2;
+ public static final long PROPERTY_PHOTO = 1 << 3;
+ public static final long PROPERTY_ADR = 1 << 5;
+ public static final long PROPERTY_TEL = 1 << 7;
+ public static final long PROPERTY_EMAIL = 1 << 8;
+ public static final long PROPERTY_NICKNAME = 1 << 23;
+
+ // MaxListCount field, PBAP 1.2.3, Section 5.3.4.4: "0" signifies to the PSE that the PCE is
+ // requesting the number of indexes in the phonebook of interest that are actually used
+ // (i.e. indexes that correspond to non-NULL entries). Using this causes other parameters to be
+ // ignored. Only metadata will be returned, like the size.
+ public static final int RETURN_SIZE_ONLY = 0;
+
+ private final long mProperties; // 64-bit property selector bit field, 8 bytes
+ private final byte mFormat; // Vcard format, 0 or 1, 1 byte, From PbapVcardList object
+ private final int mMaxListCount; // The total number of items to fetch, for batching, 2 bytes
+ private final int mListStartOffset; // The item index to start at, for batching, 2 bytes
+
+ PbapApplicationParameters(long properties, byte format, int maxListCount, int listStartOffset) {
+ if (maxListCount < 0 || maxListCount > MAX_PHONEBOOK_SIZE) {
+ throw new IllegalArgumentException("maxListCount should be [0, 65535]");
+ }
+ if (listStartOffset < 0 || listStartOffset > MAX_PHONEBOOK_SIZE) {
+ throw new IllegalArgumentException("listStartOffset should be [0, 65535]");
+ }
+ if (format != PbapPhonebook.FORMAT_VCARD_21 && format != PbapPhonebook.FORMAT_VCARD_30) {
+ throw new IllegalArgumentException("VCard format must be 2.1 or 3.0");
+ }
+
+ mProperties = properties;
+ mFormat = format;
+ mMaxListCount = maxListCount;
+ mListStartOffset = listStartOffset;
+ }
+
+ public long getPropertySelectorMask() {
+ return mProperties;
+ }
+
+ public byte getVcardFormat() {
+ return mFormat;
+ }
+
+ public int getMaxListCount() {
+ return mMaxListCount;
+ }
+
+ public int getListStartOffset() {
+ return mListStartOffset;
+ }
+
+ public static String propertiesToString(long properties) {
+ if (properties == PROPERTIES_ALL) {
+ return "PROPERTIES_ALL";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ if ((properties & PROPERTY_VERSION) != 0) {
+ sb.append("PROPERTY_VERSION ");
+ }
+ if ((properties & PROPERTY_FN) != 0) {
+ sb.append("PROPERTY_FN ");
+ }
+ if ((properties & PROPERTY_N) != 0) {
+ sb.append("PROPERTY_N ");
+ }
+ if ((properties & PROPERTY_PHOTO) != 0) {
+ sb.append("PROPERTY_PHOTO ");
+ }
+ if ((properties & PROPERTY_ADR) != 0) {
+ sb.append("PROPERTY_ADR ");
+ }
+ if ((properties & PROPERTY_TEL) != 0) {
+ sb.append("PROPERTY_TEL ");
+ }
+ if ((properties & PROPERTY_EMAIL) != 0) {
+ sb.append("PROPERTY_EMAIL ");
+ }
+ if ((properties & PROPERTY_NICKNAME) != 0) {
+ sb.append("PROPERTY_NICKNAME ");
+ }
+ sb.deleteCharAt(sb.length() - 1);
+ sb.append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return "<"
+ + TAG
+ + (" properties=" + propertiesToString(getPropertySelectorMask()))
+ + (" format=" + getVcardFormat())
+ + (" maxListCount=" + getMaxListCount())
+ + (" listStartOffset=" + getListStartOffset())
+ + ">";
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientConnectionHandler.java
similarity index 72%
rename from android/app/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java
rename to android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientConnectionHandler.java
index 470d906..45440c6 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandler.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientConnectionHandler.java
@@ -16,13 +16,10 @@
package com.android.bluetooth.pbapclient;
import android.accounts.Account;
-import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.BluetoothUuid;
-import android.bluetooth.SdpPseRecord;
-import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -57,14 +54,13 @@
// progress when Bluetooth stack is torn down.
private static final int DEFAULT_BATCH_SIZE = 250;
- // Upper limit on the indices of the vcf cards/entries, inclusive,
- // i.e., valid indices are [0, 1, ... , UPPER_LIMIT]
- private static final int UPPER_LIMIT = 65535;
-
static final int MSG_CONNECT = 1;
static final int MSG_DISCONNECT = 2;
static final int MSG_DOWNLOAD = 3;
+ static final int L2CAP_INVALID_PSM = -1;
+ static final int RFCOMM_INVALID_CHANNEL_ID = -1;
+
// The following constants are pulled from the Bluetooth Phone Book Access Profile specification
// 1.1
private static final byte[] PBAP_TARGET =
@@ -87,84 +83,42 @@
0x66
};
- private static final int PBAP_FEATURE_DEFAULT_IMAGE_FORMAT = 0x00000200;
- private static final int PBAP_FEATURE_DOWNLOADING = 0x00000001;
-
- private static final long PBAP_FILTER_VERSION = 1 << 0;
- private static final long PBAP_FILTER_FN = 1 << 1;
- private static final long PBAP_FILTER_N = 1 << 2;
- private static final long PBAP_FILTER_PHOTO = 1 << 3;
- private static final long PBAP_FILTER_ADR = 1 << 5;
- private static final long PBAP_FILTER_TEL = 1 << 7;
- private static final long PBAP_FILTER_EMAIL = 1 << 8;
- private static final long PBAP_FILTER_NICKNAME = 1 << 23;
-
- private static final int PBAP_SUPPORTED_FEATURE =
- PBAP_FEATURE_DEFAULT_IMAGE_FORMAT | PBAP_FEATURE_DOWNLOADING;
- private static final long PBAP_REQUESTED_FIELDS =
- PBAP_FILTER_VERSION
- | PBAP_FILTER_FN
- | PBAP_FILTER_N
- | PBAP_FILTER_PHOTO
- | PBAP_FILTER_ADR
- | PBAP_FILTER_EMAIL
- | PBAP_FILTER_TEL
- | PBAP_FILTER_NICKNAME;
-
- @VisibleForTesting static final int L2CAP_INVALID_PSM = -1;
-
- public static final String PB_PATH = "telecom/pb.vcf";
- public static final String FAV_PATH = "telecom/fav.vcf";
- public static final String MCH_PATH = "telecom/mch.vcf";
- public static final String ICH_PATH = "telecom/ich.vcf";
- public static final String OCH_PATH = "telecom/och.vcf";
- public static final String SIM_PB_PATH = "SIM1/telecom/pb.vcf";
- public static final String SIM_MCH_PATH = "SIM1/telecom/mch.vcf";
- public static final String SIM_ICH_PATH = "SIM1/telecom/ich.vcf";
- public static final String SIM_OCH_PATH = "SIM1/telecom/och.vcf";
-
- // PBAP v1.2.3 Sec. 7.1.2
- private static final int SUPPORTED_REPOSITORIES_LOCALPHONEBOOK = 1 << 0;
- private static final int SUPPORTED_REPOSITORIES_SIMCARD = 1 << 1;
- private static final int SUPPORTED_REPOSITORIES_FAVORITES = 1 << 3;
-
- public static final int PBAP_V1_2 = 0x0102;
- public static final byte VCARD_TYPE_21 = 0;
- public static final byte VCARD_TYPE_30 = 1;
-
private Account mAccount;
- private AccountManager mAccountManager;
private BluetoothSocket mSocket;
private final BluetoothDevice mDevice;
+ private final int mLocalSupportedFeatures;
// PSE SDP Record for current device.
- private SdpPseRecord mPseRec = null;
+ private PbapSdpRecord mPseRec = null;
private ClientSession mObexSession;
- private Context mContext;
- private BluetoothPbapObexAuthenticator mAuth = null;
+ private PbapClientService mService;
+ private PbapClientObexAuthenticator mAuth = null;
private final PbapClientStateMachine mPbapClientStateMachine;
private boolean mAccountCreated;
/**
* Constructs PCEConnectionHandler object
*
- * @param pceHandlerbuild To build BluetoothPbapClientHandler Instance.
+ * @param pceHandlerbuild To build PbapClientConnectionHandler Instance.
*/
PbapClientConnectionHandler(Builder pceHandlerbuild) {
super(pceHandlerbuild.mLooper);
mDevice = pceHandlerbuild.mDevice;
- mContext = pceHandlerbuild.mContext;
+ mLocalSupportedFeatures = pceHandlerbuild.mLocalSupportedFeatures;
+ mService = pceHandlerbuild.mService;
mPbapClientStateMachine = pceHandlerbuild.mClientStateMachine;
- mAuth = new BluetoothPbapObexAuthenticator();
- mAccountManager = AccountManager.get(mPbapClientStateMachine.getContext());
+ mAuth = new PbapClientObexAuthenticator();
mAccount =
- new Account(mDevice.getAddress(), mContext.getString(R.string.pbap_account_type));
+ new Account(
+ mDevice.getAddress(),
+ mService.getString(R.string.pbap_client_account_type));
}
public static class Builder {
private Looper mLooper;
- private Context mContext;
+ private PbapClientService mService;
private BluetoothDevice mDevice;
+ private int mLocalSupportedFeatures;
private PbapClientStateMachine mClientStateMachine;
public Builder setLooper(Looper loop) {
@@ -172,6 +126,11 @@
return this;
}
+ public Builder setLocalSupportedFeatures(int features) {
+ this.mLocalSupportedFeatures = features;
+ return this;
+ }
+
public Builder setClientSM(PbapClientStateMachine clientStateMachine) {
this.mClientStateMachine = clientStateMachine;
return this;
@@ -182,8 +141,8 @@
return this;
}
- public Builder setContext(Context context) {
- this.mContext = context;
+ public Builder setService(PbapClientService service) {
+ this.mService = service;
return this;
}
@@ -198,7 +157,8 @@
Log.d(TAG, "Handling Message = " + msg.what);
switch (msg.what) {
case MSG_CONNECT:
- mPseRec = (SdpPseRecord) msg.obj;
+ mPseRec = (PbapSdpRecord) msg.obj;
+
/* To establish a connection, first open a socket and then create an OBEX session */
if (connectSocket()) {
Log.d(TAG, "Socket connected");
@@ -247,20 +207,20 @@
Log.e(TAG, "Account creation failed.");
return;
}
- if (isRepositorySupported(SUPPORTED_REPOSITORIES_FAVORITES)) {
- downloadContacts(FAV_PATH);
+ if (mPseRec.isRepositorySupported(PbapSdpRecord.REPOSITORY_FAVORITES)) {
+ downloadContacts(PbapPhonebook.FAVORITES_PATH);
}
- if (isRepositorySupported(SUPPORTED_REPOSITORIES_LOCALPHONEBOOK)) {
- downloadContacts(PB_PATH);
+ if (mPseRec.isRepositorySupported(PbapSdpRecord.REPOSITORY_LOCAL_PHONEBOOK)) {
+ downloadContacts(PbapPhonebook.LOCAL_PHONEBOOK_PATH);
}
- if (isRepositorySupported(SUPPORTED_REPOSITORIES_SIMCARD)) {
- downloadContacts(SIM_PB_PATH);
+ if (mPseRec.isRepositorySupported(PbapSdpRecord.REPOSITORY_SIM_CARD)) {
+ downloadContacts(PbapPhonebook.SIM_PHONEBOOK_PATH);
}
Map<String, Integer> callCounter = new HashMap<>();
- downloadCallLog(MCH_PATH, callCounter);
- downloadCallLog(ICH_PATH, callCounter);
- downloadCallLog(OCH_PATH, callCounter);
+ downloadCallLog(PbapPhonebook.MCH_PATH, callCounter);
+ downloadCallLog(PbapPhonebook.ICH_PATH, callCounter);
+ downloadCallLog(PbapPhonebook.OCH_PATH, callCounter);
break;
default:
@@ -269,7 +229,7 @@
}
@VisibleForTesting
- synchronized void setPseRecord(SdpPseRecord record) {
+ synchronized void setPseRecord(PbapSdpRecord record) {
mPseRec = record;
}
@@ -293,9 +253,12 @@
} else if (mPseRec.getL2capPsm() != L2CAP_INVALID_PSM) {
Log.v(TAG, "connectSocket: PSM: " + mPseRec.getL2capPsm());
mSocket = mDevice.createL2capSocket(mPseRec.getL2capPsm());
- } else {
+ } else if (mPseRec.getRfcommChannelNumber() != RFCOMM_INVALID_CHANNEL_ID) {
Log.v(TAG, "connectSocket: channel: " + mPseRec.getRfcommChannelNumber());
mSocket = mDevice.createRfcommSocket(mPseRec.getRfcommChannelNumber());
+ } else {
+ Log.w(TAG, "connectSocket: transport PSM or channel ID not specified");
+ return false;
}
if (mSocket != null) {
@@ -330,10 +293,10 @@
ObexAppParameters oap = new ObexAppParameters();
- if (mPseRec.getProfileVersion() >= PBAP_V1_2) {
+ if (mPseRec.getProfileVersion() >= PbapSdpRecord.VERSION_1_2) {
oap.add(
- BluetoothPbapRequest.OAP_TAGID_PBAP_SUPPORTED_FEATURES,
- PBAP_SUPPORTED_FEATURE);
+ PbapApplicationParameters.OAP_PBAP_SUPPORTED_FEATURES,
+ mLocalSupportedFeatures);
}
oap.addToHeaderSet(connectionRequest);
@@ -379,14 +342,21 @@
PhonebookPullRequest processor =
new PhonebookPullRequest(mPbapClientStateMachine.getContext());
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ /* format, unused */ (byte) 0,
+ PbapApplicationParameters.RETURN_SIZE_ONLY,
+ /* list start offeset, start from beginning */ 0);
+
// Download contacts in batches of size DEFAULT_BATCH_SIZE
- BluetoothPbapRequestPullPhoneBookSize requestPbSize =
- new BluetoothPbapRequestPullPhoneBookSize(path, PBAP_REQUESTED_FIELDS);
+ RequestPullPhonebookMetadata requestPbSize =
+ new RequestPullPhonebookMetadata(path, params);
requestPbSize.execute(mObexSession);
- int numberOfContactsRemaining = requestPbSize.getSize();
+ int numberOfContactsRemaining = requestPbSize.getMetadata().getSize();
int startOffset = 0;
- if (PB_PATH.equals(path)) {
+ if (PbapPhonebook.LOCAL_PHONEBOOK_PATH.equals(path)) {
// PBAP v1.2.3, Sec 3.1.5. The first contact in pb is owner card 0.vcf, which we
// do not want to download. The other phonebook objects (e.g., fav) don't have an
// owner card, so they don't need an offset.
@@ -395,22 +365,24 @@
numberOfContactsRemaining -= 1;
}
- while ((numberOfContactsRemaining > 0) && (startOffset <= UPPER_LIMIT)) {
+ while ((numberOfContactsRemaining > 0)
+ && (startOffset <= PbapApplicationParameters.MAX_PHONEBOOK_SIZE)) {
int numberOfContactsToDownload =
Math.min(
Math.min(DEFAULT_BATCH_SIZE, numberOfContactsRemaining),
- UPPER_LIMIT - startOffset + 1);
- BluetoothPbapRequestPullPhoneBook request =
- new BluetoothPbapRequestPullPhoneBook(
- path,
- mAccount,
- PBAP_REQUESTED_FIELDS,
- VCARD_TYPE_30,
+ PbapApplicationParameters.MAX_PHONEBOOK_SIZE - startOffset + 1);
+
+ params =
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
numberOfContactsToDownload,
startOffset);
+
+ RequestPullPhonebook request = new RequestPullPhonebook(path, params, mAccount);
request.execute(mObexSession);
List<VCardEntry> vcards = request.getList();
- if (FAV_PATH.equals(path)) {
+ if (PbapPhonebook.FAVORITES_PATH.equals(path)) {
// mark each vcard as a favorite
for (VCardEntry v : vcards) {
v.setStarred(true);
@@ -422,7 +394,8 @@
startOffset += numberOfContactsToDownload;
numberOfContactsRemaining -= numberOfContactsToDownload;
}
- if ((startOffset > UPPER_LIMIT) && (numberOfContactsRemaining > 0)) {
+ if ((startOffset > PbapApplicationParameters.MAX_PHONEBOOK_SIZE)
+ && (numberOfContactsRemaining > 0)) {
Log.w(TAG, "Download contacts incomplete, index exceeded upper limit.");
}
} catch (IOException e) {
@@ -435,8 +408,14 @@
@VisibleForTesting
void downloadCallLog(String path, Map<String, Integer> callCounter) {
try {
- BluetoothPbapRequestPullPhoneBook request =
- new BluetoothPbapRequestPullPhoneBook(path, mAccount, 0, VCARD_TYPE_30, 0, 0);
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ /* properties, unused for call logs */ 0,
+ PbapPhonebook.FORMAT_VCARD_30,
+ 0,
+ 0);
+
+ RequestPullPhonebook request = new RequestPullPhonebook(path, params, mAccount);
request.execute(mObexSession);
CallLogPullRequest processor =
new CallLogPullRequest(
@@ -452,16 +431,18 @@
@VisibleForTesting
boolean addAccount() {
- if (mAccountManager.addAccountExplicitly(mAccount, null, null)) {
+ if (mService.addAccount(mAccount)) {
Log.d(TAG, "Added account " + mAccount);
return true;
+ } else {
+ Log.e(TAG, "Failed to add account " + mAccount);
}
return false;
}
@VisibleForTesting
void removeAccount() {
- if (mAccountManager.removeAccountExplicitly(mAccount)) {
+ if (mService.removeAccount(mAccount)) {
Log.d(TAG, "Removed account " + mAccount);
} else {
Log.e(TAG, "Failed to remove account " + mAccount);
@@ -472,11 +453,11 @@
void removeCallLog() {
try {
// need to check call table is exist ?
- if (mContext.getContentResolver() == null) {
+ if (mService.getContentResolver() == null) {
Log.d(TAG, "CallLog ContentResolver is not found");
return;
}
- mContext.getContentResolver()
+ mService.getContentResolver()
.delete(
CallLog.Calls.CONTENT_URI,
Calls.PHONE_ACCOUNT_ID + "=?",
@@ -485,13 +466,4 @@
Log.d(TAG, "Call Logs could not be deleted, they may not exist yet.");
}
}
-
- @VisibleForTesting
- boolean isRepositorySupported(int mask) {
- if (mPseRec == null) {
- Log.v(TAG, "No PBAP Server SDP Record");
- return false;
- }
- return (mask & mPseRec.getSupportedRepositories()) != 0;
- }
}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapObexAuthenticator.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexAuthenticator.java
similarity index 92%
rename from android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapObexAuthenticator.java
rename to android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexAuthenticator.java
index a062efb..733dc23 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/BluetoothPbapObexAuthenticator.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientObexAuthenticator.java
@@ -28,8 +28,8 @@
* with PSE devices prior to PBAP 1.2. With profiles prior to 1.2 the actual initiation of
* authentication is implementation defined.
*/
-class BluetoothPbapObexAuthenticator implements Authenticator {
- private static final String TAG = "PbapClientObexAuth";
+class PbapClientObexAuthenticator implements Authenticator {
+ private static final String TAG = PbapClientObexAuthenticator.class.getSimpleName();
// Default session key for legacy devices is 0000
@VisibleForTesting String mSessionKey = "0000";
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientRequest.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientRequest.java
new file mode 100644
index 0000000..fd9d0f6
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapClientRequest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import android.util.Log;
+
+import com.android.obex.ClientOperation;
+import com.android.obex.ClientSession;
+import com.android.obex.HeaderSet;
+import com.android.obex.ResponseCodes;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+abstract class PbapClientRequest {
+ static final String TAG = PbapClientRequest.class.getSimpleName();
+
+ // Request Types
+ public static final int TYPE_PULL_PHONEBOOK_METADATA = 0;
+ public static final int TYPE_PULL_PHONEBOOK = 1;
+
+ protected HeaderSet mHeaderSet = new HeaderSet();
+ private int mResponseCode = -1;
+
+ PbapClientRequest() {
+ mResponseCode = -1;
+ }
+
+ /**
+ * A function that returns the type of the request.
+ *
+ * <p>Used to determine type instead of using 'instanceof'
+ */
+ public abstract int getType();
+
+ /**
+ * Get the actual response code associated with the request
+ *
+ * @return The response code as in integer
+ */
+ public final int getResponseCode() {
+ return mResponseCode;
+ }
+
+ /**
+ * A generica operation, providing overridable hooks to read response headers and content.
+ *
+ * <p>All PBAP Client operations are GET OBEX operations, so that is what this is.
+ */
+ public void execute(ClientSession session) throws IOException {
+ Log.v(TAG, "execute");
+ ClientOperation operation = null;
+ try {
+ operation = (ClientOperation) session.get(mHeaderSet);
+
+ /* make sure final flag for GET is used (PBAP spec 6.2.2) */
+ operation.setGetFinalFlag(true);
+
+ /*
+ * this will trigger ClientOperation to use non-buffered stream so
+ * we can abort operation
+ */
+ operation.continueOperation(true, false);
+
+ readResponseHeaders(operation.getReceivedHeader());
+ InputStream inputStream = operation.openInputStream();
+ readResponse(inputStream);
+ inputStream.close();
+ mResponseCode = operation.getResponseCode();
+ } catch (IOException e) {
+ mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ Log.e(TAG, "IOException occurred when processing request", e);
+ throw e;
+ } finally {
+ // Always close the operation so the next operation can successfully complete
+ if (operation != null) {
+ operation.close();
+ }
+ }
+ }
+
+ protected void readResponse(InputStream stream) throws IOException {
+ Log.v(TAG, "readResponse");
+ /* nothing here by default */
+ }
+
+ protected void readResponseHeaders(HeaderSet headerset) {
+ Log.v(TAG, "readResponseHeaders");
+ /* nothing here by default */
+ }
+
+ public static String typeToString(int type) {
+ switch (type) {
+ case TYPE_PULL_PHONEBOOK_METADATA:
+ return "TYPE_PULL_PHONEBOOK_METADATA";
+ case TYPE_PULL_PHONEBOOK:
+ return "TYPE_PULL_PHONEBOOK";
+ default:
+ return "TYPE_RESERVED (" + type + ")";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "<"
+ + TAG
+ + (" type=" + typeToString(getType()))
+ + (", responseCode=" + getResponseCode())
+ + ">";
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapPhonebook.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapPhonebook.java
new file mode 100644
index 0000000..a7bc5b6
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapPhonebook.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import android.accounts.Account;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import com.android.vcard.VCardConfig;
+import com.android.vcard.VCardEntry;
+import com.android.vcard.VCardEntryConstructor;
+import com.android.vcard.VCardEntryHandler;
+import com.android.vcard.VCardParser;
+import com.android.vcard.VCardParser_V21;
+import com.android.vcard.VCardParser_V30;
+import com.android.vcard.exception.VCardException;
+import com.android.vcard.exception.VCardVersionException;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PbapPhonebook {
+ private static final String TAG = PbapPhonebook.class.getSimpleName();
+
+ // {@link BufferedInputStream#DEFAULT_BUFFER_SIZE} is not public
+ private static final int BIS_DEFAULT_BUFFER_SIZE = 8192;
+
+ // Phonebooks, including call history. See PBAP 1.2.3, Section 3.1.2
+ public static final String LOCAL_PHONEBOOK_PATH = "telecom/pb.vcf"; // Device phonebook
+ public static final String FAVORITES_PATH = "telecom/fav.vcf"; // Contacts marked as favorite
+ public static final String MCH_PATH = "telecom/mch.vcf"; // Missed Calls
+ public static final String ICH_PATH = "telecom/ich.vcf"; // Incoming Calls
+ public static final String OCH_PATH = "telecom/och.vcf"; // Outgoing Calls
+ public static final String SIM_PHONEBOOK_PATH = "SIM1/telecom/pb.vcf"; // SIM stored phonebook
+ public static final String SIM_MCH_PATH = "SIM1/telecom/mch.vcf"; // SIM stored Missed Calls
+ public static final String SIM_ICH_PATH = "SIM1/telecom/ich.vcf"; // SIM stored Incoming Calls
+ public static final String SIM_OCH_PATH = "SIM1/telecom/och.vcf"; // SIM stored Outgoing Calls
+
+ // VCard Formats, both are required to be supported by the Server, PBAP 1.2.3, Section 5.1.4.2
+ public static byte FORMAT_VCARD_21 = 0;
+ public static byte FORMAT_VCARD_30 = 1;
+
+ private final String mPhonebook;
+ private final int mListStartOffset;
+ private final List<VCardEntry> mCards = new ArrayList<VCardEntry>();
+
+ // Needed for VCard parsing, since the account on older platform versions cannot be associated
+ // with the VCard (to construct a query) after parse time. Newer platform versions support this
+ // though, which means we can eventually remove this in favor of assigning an account post parse
+ // time.
+ @Nullable private final Account mAccount;
+
+ class CardEntryHandler implements VCardEntryHandler {
+ @Override
+ public void onStart() {}
+
+ @Override
+ public void onEntryCreated(VCardEntry entry) {
+ mCards.add(entry);
+ }
+
+ @Override
+ public void onEnd() {}
+ }
+
+ PbapPhonebook(String phonebook) {
+ mPhonebook = phonebook;
+ mAccount = null;
+ mListStartOffset = 0;
+ }
+
+ PbapPhonebook(
+ String phonebook,
+ byte format,
+ int listStartOffset,
+ @Nullable Account account,
+ InputStream inputStream)
+ throws IOException {
+ if (format != FORMAT_VCARD_21 && format != FORMAT_VCARD_30) {
+ throw new IllegalArgumentException("Unsupported vCard version.");
+ }
+ mPhonebook = phonebook;
+ mListStartOffset = listStartOffset;
+ mAccount = account;
+ parse(inputStream, format);
+ }
+
+ private void parse(InputStream in, byte format) throws IOException {
+ VCardParser parser;
+
+ if (format == FORMAT_VCARD_30) {
+ parser = new VCardParser_V30();
+ } else {
+ parser = new VCardParser_V21();
+ }
+
+ VCardEntryConstructor constructor =
+ new VCardEntryConstructor(VCardConfig.VCARD_TYPE_V21_GENERIC, mAccount);
+
+ CardEntryHandler handler = new CardEntryHandler();
+ constructor.addEntryHandler(handler);
+
+ parser.addInterpreter(constructor);
+
+ // {@link BufferedInputStream} supports the {@link InputStream#mark} and
+ // {@link InputStream#reset} methods.
+ BufferedInputStream bufferedInput = new BufferedInputStream(in);
+ bufferedInput.mark(BIS_DEFAULT_BUFFER_SIZE /* readlimit */);
+
+ // If there is a {@link VCardVersionException}, try parsing again with a different
+ // version. Otherwise, parsing either succeeds (i.e., no {@link VCardException}) or it
+ // fails with a different {@link VCardException}.
+ if (parsedWithVcardVersionException(parser, bufferedInput)) {
+ // PBAP v1.2.3 only supports vCard versions 2.1 and 3.0; it's one or the other
+ if (format == FORMAT_VCARD_21) {
+ parser = new VCardParser_V30();
+ Log.w(TAG, "vCard version and Parser mismatch; expected v2.1, switching to v3.0");
+ } else {
+ parser = new VCardParser_V21();
+ Log.w(TAG, "vCard version and Parser mismatch; expected v3.0, switching to v2.1");
+ }
+ // reset and try again
+ bufferedInput.reset();
+ mCards.clear();
+ constructor.clear();
+ parser.addInterpreter(constructor);
+ if (parsedWithVcardVersionException(parser, bufferedInput)) {
+ Log.e(TAG, "unsupported vCard version, neither v2.1 nor v3.0");
+ }
+ }
+ }
+
+ /**
+ * Attempts to parse, with an eye on whether the correct version of Parser is used.
+ *
+ * @param parser -- the {@link VCardParser} to use.
+ * @param in -- the {@link InputStream} to parse.
+ * @return {@code true} if there was a {@link VCardVersionException}; {@code false} if there is
+ * any other {@link VCardException} or succeeds (i.e., no {@link VCardException}).
+ * @throws IOException if there's an issue reading the {@link InputStream}.
+ */
+ private boolean parsedWithVcardVersionException(VCardParser parser, InputStream in)
+ throws IOException {
+ try {
+ parser.parse(in);
+ } catch (VCardVersionException e1) {
+ Log.w(TAG, "vCard version and Parser mismatch", e1);
+ return true;
+ } catch (VCardException e2) {
+ Log.e(TAG, "vCard exception", e2);
+ }
+ return false;
+ }
+
+ /**
+ * Get the phonebook path associated with this PbapPhonebook object
+ *
+ * @return a string representing the path these VCard objects were requested from
+ */
+ public String getPhonebook() {
+ return mPhonebook;
+ }
+
+ /**
+ * Get the offset associated with this PbapPhonebook object
+ *
+ * <p>The offset respresents the start index of the remote contacts pull
+ *
+ * @return an int representing the offset index where this pull started from
+ */
+ public int getOffset() {
+ return mListStartOffset;
+ }
+
+ /**
+ * Get the total number of contacts contained in this phonebook
+ *
+ * @return an int containing the total number of contacts contained in this phonebook
+ */
+ public int getCount() {
+ return mCards.size();
+ }
+
+ /**
+ * Get the list of VCard objects contained in this phonebook
+ *
+ * @return a list of VCard objects in this phonebook
+ */
+ public List<VCardEntry> getList() {
+ return mCards;
+ }
+
+ @Override
+ public String toString() {
+ return "<" + TAG + "phonebook=" + mPhonebook + " entries=" + getCount() + ">";
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/PbapPhonebookMetadata.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapPhonebookMetadata.java
new file mode 100644
index 0000000..3badee4
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PbapPhonebookMetadata.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+public class PbapPhonebookMetadata {
+ private static final String TAG = PbapPhonebookMetadata.class.getSimpleName();
+
+ public static final int INVALID_SIZE = -1;
+ public static final String INVALID_DATABASE_IDENTIFIER = null;
+ public static final String DEFAULT_DATABASE_IDENTIFIER = "0";
+ public static final String INVALID_VERSION_COUNTER = null;
+
+ private final String mPhonebook;
+ private int mSize = INVALID_SIZE; // 2 byte number
+ private String mDatabaseIdentifier = INVALID_DATABASE_IDENTIFIER; // 16 byte number as string
+ private String mPrimaryVersionCounter = INVALID_VERSION_COUNTER; // 16 byte number as string
+ private String mSecondaryVersionCounter = INVALID_VERSION_COUNTER; // 16 byte number as string
+
+ PbapPhonebookMetadata(
+ String phonebook,
+ int size,
+ String databaseIdentifier,
+ String primaryVersionCounter,
+ String secondaryVersionCounter) {
+ mPhonebook = phonebook;
+ mSize = size;
+ mDatabaseIdentifier = databaseIdentifier;
+ mPrimaryVersionCounter = primaryVersionCounter;
+ mSecondaryVersionCounter = secondaryVersionCounter;
+ }
+
+ public String getPhonebook() {
+ return mPhonebook;
+ }
+
+ public int getSize() {
+ return mSize;
+ }
+
+ public String getDatabaseIdentifier() {
+ return mDatabaseIdentifier;
+ }
+
+ public String getPrimaryVersionCounter() {
+ return mPrimaryVersionCounter;
+ }
+
+ public String getSecondaryVersionCounter() {
+ return mSecondaryVersionCounter;
+ }
+
+ @Override
+ public String toString() {
+ return "<"
+ + TAG
+ + (" phonebook=" + mPhonebook)
+ + (" size=" + mSize)
+ + (" databaseIdentifier=" + mDatabaseIdentifier)
+ + (" primaryVersionCounter=" + mPrimaryVersionCounter)
+ + (" secondaryVersionCounter=" + mSecondaryVersionCounter)
+ + ">";
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PhonebookPullRequest.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PhonebookPullRequest.java
similarity index 98%
rename from android/app/src/com/android/bluetooth/pbapclient/PhonebookPullRequest.java
rename to android/app/src/com/android/bluetooth/pbapclient/obex/PhonebookPullRequest.java
index a0780af..dc1fd92 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PhonebookPullRequest.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PhonebookPullRequest.java
@@ -38,7 +38,7 @@
public PhonebookPullRequest(Context context) {
mContext = context;
- path = PbapClientConnectionHandler.PB_PATH;
+ path = PbapPhonebook.LOCAL_PHONEBOOK_PATH;
}
@Override
diff --git a/android/app/src/com/android/bluetooth/pbapclient/PullRequest.java b/android/app/src/com/android/bluetooth/pbapclient/obex/PullRequest.java
similarity index 82%
rename from android/app/src/com/android/bluetooth/pbapclient/PullRequest.java
rename to android/app/src/com/android/bluetooth/pbapclient/obex/PullRequest.java
index f938107..210518e 100644
--- a/android/app/src/com/android/bluetooth/pbapclient/PullRequest.java
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/PullRequest.java
@@ -23,6 +23,12 @@
public String path;
protected List<VCardEntry> mEntries;
+ /**
+ * How this request should be handled and the data should be stored once its complete.
+ *
+ * <p>Override to provide an implementation specific to the type of results your implementation
+ * expects.
+ */
public abstract void onPullComplete();
@Override
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/RequestPullPhonebook.java b/android/app/src/com/android/bluetooth/pbapclient/obex/RequestPullPhonebook.java
new file mode 100644
index 0000000..e889b27
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/RequestPullPhonebook.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import android.accounts.Account;
+
+import com.android.bluetooth.ObexAppParameters;
+import com.android.obex.HeaderSet;
+import com.android.vcard.VCardEntry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+final class RequestPullPhonebook extends PbapClientRequest {
+ private static final String TAG = RequestPullPhonebook.class.getSimpleName();
+
+ private static final String TYPE = "x-bt/phonebook";
+
+ private final String mPhonebook;
+ private final byte mFormat;
+ private final int mMaxListCount;
+ private final int mListStartOffset;
+ private Account mAccount;
+
+ private PbapPhonebook mResponse;
+
+ @Override
+ public int getType() {
+ return TYPE_PULL_PHONEBOOK;
+ }
+
+ RequestPullPhonebook(String phonebook, PbapApplicationParameters params, Account account) {
+ mPhonebook = phonebook;
+ mFormat = params.getVcardFormat();
+ mMaxListCount = params.getMaxListCount();
+ mListStartOffset = params.getListStartOffset();
+ mAccount = account;
+
+ long properties = params.getPropertySelectorMask();
+
+ mHeaderSet.setHeader(HeaderSet.NAME, phonebook);
+ mHeaderSet.setHeader(HeaderSet.TYPE, TYPE);
+
+ ObexAppParameters oap = new ObexAppParameters();
+
+ oap.add(PbapApplicationParameters.OAP_FORMAT, mFormat);
+
+ if (properties != 0) {
+ oap.add(PbapApplicationParameters.OAP_PROPERTY_SELECTOR, properties);
+ }
+
+ if (mListStartOffset > 0) {
+ oap.add(PbapApplicationParameters.OAP_LIST_START_OFFSET, (short) mListStartOffset);
+ }
+
+ // maxListCount == 0 indicates to fetch all, in which case we set it to the upper bound
+ // Note that Java has no unsigned types. To capture an unsigned value in the range [0, 2^16)
+ // we need to use an int and cast to a short (2 bytes). This packs the bits we want.
+ if (mMaxListCount > 0) {
+ oap.add(PbapApplicationParameters.OAP_MAX_LIST_COUNT, (short) mMaxListCount);
+ } else {
+ oap.add(
+ PbapApplicationParameters.OAP_MAX_LIST_COUNT,
+ (short) PbapApplicationParameters.MAX_PHONEBOOK_SIZE);
+ }
+
+ oap.addToHeaderSet(mHeaderSet);
+ }
+
+ @Override
+ protected void readResponse(InputStream stream) throws IOException {
+ mResponse = new PbapPhonebook(mPhonebook, mFormat, mListStartOffset, mAccount, stream);
+ }
+
+ public String getPhonebook() {
+ return mPhonebook;
+ }
+
+ public List<VCardEntry> getList() {
+ return mResponse.getList();
+ }
+
+ public PbapPhonebook getContacts() {
+ return mResponse;
+ }
+}
diff --git a/android/app/src/com/android/bluetooth/pbapclient/obex/RequestPullPhonebookMetadata.java b/android/app/src/com/android/bluetooth/pbapclient/obex/RequestPullPhonebookMetadata.java
new file mode 100644
index 0000000..f6ce3fe
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/pbapclient/obex/RequestPullPhonebookMetadata.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import com.android.bluetooth.ObexAppParameters;
+import com.android.obex.HeaderSet;
+
+/**
+ * This implements a PullPhonebook request, with the goal of only fetching metadata for the given
+ * phonebook, but not the actual phonebook contents itself.
+ *
+ * <p>This is done by requesting the phonebook, but omitting the MaxListCount parameter, signaling
+ * that we're not interested in the contents (PBAP 1.2.3, Section 5.1, C7 of the Response Format
+ * table)
+ */
+final class RequestPullPhonebookMetadata extends PbapClientRequest {
+ private static final String TAG = RequestPullPhonebookMetadata.class.getSimpleName();
+
+ private static final String TYPE = "x-bt/phonebook";
+
+ private final String mPhonebook;
+ private PbapPhonebookMetadata mResponse;
+
+ @Override
+ public int getType() {
+ return TYPE_PULL_PHONEBOOK_METADATA;
+ }
+
+ RequestPullPhonebookMetadata(String phonebook, PbapApplicationParameters params) {
+ mPhonebook = phonebook;
+ mHeaderSet.setHeader(HeaderSet.NAME, phonebook);
+ mHeaderSet.setHeader(HeaderSet.TYPE, TYPE);
+
+ // Set MaxListCount in the request to 0 to get PhonebookSize in the response.
+ // If a vCardSelector is present in the request, then the result shall
+ // contain the number of items that satisfy the selector’s criteria.
+ // See PBAP v1.2.3, Sec. 5.1.4.5.
+ ObexAppParameters oap = new ObexAppParameters();
+ oap.add(PbapApplicationParameters.OAP_MAX_LIST_COUNT, (short) 0);
+
+ // Otherwise, listen to the property selector criteria passed in and ignore the rest
+ long properties = params.getPropertySelectorMask();
+ if (properties != PbapApplicationParameters.PROPERTIES_ALL) {
+ oap.add(PbapApplicationParameters.OAP_PROPERTY_SELECTOR, properties);
+ }
+ oap.addToHeaderSet(mHeaderSet);
+ }
+
+ @Override
+ protected void readResponseHeaders(HeaderSet headerset) {
+ int size = PbapPhonebookMetadata.INVALID_SIZE;
+ String databaseIdentifier = PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER;
+ String primaryVersionCounter = PbapPhonebookMetadata.INVALID_VERSION_COUNTER;
+ String secondaryVersionCounter = PbapPhonebookMetadata.INVALID_VERSION_COUNTER;
+
+ ObexAppParameters oap = ObexAppParameters.fromHeaderSet(headerset);
+ if (oap.exists(PbapApplicationParameters.OAP_PHONEBOOK_SIZE)) {
+ size = oap.getShort(PbapApplicationParameters.OAP_PHONEBOOK_SIZE);
+ }
+
+ mResponse =
+ new PbapPhonebookMetadata(
+ mPhonebook,
+ size,
+ databaseIdentifier,
+ primaryVersionCounter,
+ secondaryVersionCounter);
+ }
+
+ public String getPhonebook() {
+ return mPhonebook;
+ }
+
+ public PbapPhonebookMetadata getMetadata() {
+ return mResponse;
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
index 6bd8682..0299cc8 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java
@@ -43,6 +43,7 @@
import android.media.AudioDevicePort;
import android.media.AudioManager;
import android.os.test.TestLooper;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
@@ -385,10 +386,13 @@
@Test
public void headsetRemoveActive_fallbackToLeAudio() {
when(mHeadsetService.getFallbackDevice()).thenReturn(mHeadsetDevice);
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
+
+ InOrder order = inOrder(mLeAudioService);
leAudioConnected(mLeAudioDevice);
mTestLooper.dispatchAll();
- verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice);
+ order.verify(mLeAudioService, times(1)).setActiveDevice(mLeAudioDevice);
headsetConnected(mHeadsetDevice, false);
mTestLooper.dispatchAll();
@@ -827,7 +831,28 @@
/** One LE Audio is connected and disconnected later. Should then set active device to null. */
@Test
+ @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
public void lastLeAudioDisconnected_clearLeAudioActive() {
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice)).thenReturn(mLeAudioDevice);
+
+ leAudioConnected(mLeAudioDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
+
+ leAudioDisconnected(mLeAudioDevice);
+ mTestLooper.dispatchAll();
+ verify(mLeAudioService, never()).removeActiveDevice(anyBoolean());
+ verify(mLeAudioService).deviceDisconnected(mLeAudioDevice, false);
+ }
+
+ /** One LE Audio is connected and disconnected later. Should then set active device to null. */
+ @Test
+ @DisableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
+ public void lastLeAudioDisconnected_clearLeAudioActive_NoFixDisconnectFlag() {
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice)).thenReturn(mLeAudioDevice);
+
leAudioConnected(mLeAudioDevice);
mTestLooper.dispatchAll();
verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
@@ -857,11 +882,16 @@
}
/**
- * Two LE Audio are connected and the current active is then disconnected. Should then set
- * active device to fallback device.
+ * Two LE Audio Sets are connected and the current active Set is disconnected. The other
+ * connected LeAudio Set shall become an active device.
*/
@Test
public void leAudioSecondDeviceDisconnected_fallbackDeviceActive() {
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
+ when(mLeAudioService.getGroupId(mLeAudioDevice2)).thenReturn(2);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice)).thenReturn(mLeAudioDevice);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice2);
+
leAudioConnected(mLeAudioDevice);
mTestLooper.dispatchAll();
verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
@@ -1101,6 +1131,7 @@
@Test
public void leAudioAndA2dpConnectedThenA2dpDisconnected_fallbackToLeAudio() {
when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
leAudioConnected(mLeAudioDevice);
mTestLooper.dispatchAll();
@@ -1143,13 +1174,13 @@
}
/**
- * An LE Audio set connected. The active bud disconnected. Set active device returns false
- * indicating an issue (the other bud is also disconnected). Then the active device should be
- * removed and hasFallback should be set to false.
+ * An LE Audio set connected. The active bud disconnected. Active device manager should not
+ * choose other set member as active device.
*/
@Test
public void leAudioSetConnectedThenActiveOneDisconnected_noFallback() {
when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
+ when(mLeAudioService.getLeadDevice(any())).thenReturn(mLeAudioDevice);
leAudioConnected(mLeAudioDevice);
mTestLooper.dispatchAll();
@@ -1157,71 +1188,76 @@
leAudioConnected(mLeAudioDevice2);
mTestLooper.dispatchAll();
- verify(mLeAudioService).setActiveDevice(mLeAudioDevice2);
-
- Mockito.clearInvocations(mLeAudioService);
-
- // Return false to indicate an issue when setting new active device
- // (e.g. the other device disconnected as well).
- when(mLeAudioService.setActiveDevice(any())).thenReturn(false);
+ verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice2);
leAudioDisconnected(mLeAudioDevice2);
mTestLooper.dispatchAll();
- verify(mLeAudioService).removeActiveDevice(false);
+ verify(mLeAudioService, never()).removeActiveDevice(anyBoolean());
verify(mLeAudioService).deviceDisconnected(mLeAudioDevice2, false);
}
- /**
- * An LE Audio set connected. The active bud disconnected. Set active device returns true
- * indicating the other bud is going to be the active device. Then the active device should
- * change and hasFallback should be set to true.
- */
@Test
- public void leAudioSetConnectedThenActiveOneDisconnected_hasFallback() {
- when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
-
- leAudioConnected(mLeAudioDevice);
- mTestLooper.dispatchAll();
- verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
-
- leAudioConnected(mLeAudioDevice2);
- mTestLooper.dispatchAll();
- verify(mLeAudioService).setActiveDevice(mLeAudioDevice2);
-
- Mockito.clearInvocations(mLeAudioService);
-
- leAudioDisconnected(mLeAudioDevice2);
- mTestLooper.dispatchAll();
- verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
- verify(mLeAudioService).deviceDisconnected(mLeAudioDevice2, true);
- }
-
- @Test
+ @EnableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
public void leAudioSetConnectedGroupThenDisconnected_noFallback() {
when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
+ when(mLeAudioService.getGroupId(mLeAudioDevice2)).thenReturn(1);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice)).thenReturn(mLeAudioDevice);
+
+ InOrder order = inOrder(mLeAudioService);
+
leAudioConnected(mLeAudioDevice);
mTestLooper.dispatchAll();
- verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
+ order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
- Mockito.clearInvocations(mLeAudioService);
-
- when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice);
leAudioConnected(mLeAudioDevice2);
mTestLooper.dispatchAll();
- verify(mLeAudioService, never()).setActiveDevice(any());
-
- Mockito.clearInvocations(mLeAudioService);
+ order.verify(mLeAudioService, never()).setActiveDevice(any());
leAudioDisconnected(mLeAudioDevice2);
mTestLooper.dispatchAll();
- verify(mLeAudioService, never()).setActiveDevice(any());
- verify(mLeAudioService, never()).removeActiveDevice(anyBoolean());
+ order.verify(mLeAudioService, never()).setActiveDevice(any());
+ order.verify(mLeAudioService, never()).removeActiveDevice(anyBoolean());
+ order.verify(mLeAudioService).deviceDisconnected(mLeAudioDevice2, false);
leAudioDisconnected(mLeAudioDevice);
mTestLooper.dispatchAll();
- verify(mLeAudioService).removeActiveDevice(false);
- verify(mLeAudioService).deviceDisconnected(mLeAudioDevice2, false);
+ order.verify(mLeAudioService, never()).removeActiveDevice(anyBoolean());
+ order.verify(mLeAudioService).deviceDisconnected(mLeAudioDevice, false);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ADM_FIX_DISCONNECT_OF_SET_MEMBER)
+ public void leAudioSetConnectedGroupThenDisconnected_noFallback_NoFixDisconnectFlag() {
+ when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
+
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(1);
+ when(mLeAudioService.getGroupId(mLeAudioDevice2)).thenReturn(1);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice2)).thenReturn(mLeAudioDevice);
+ when(mLeAudioService.getLeadDevice(mLeAudioDevice)).thenReturn(mLeAudioDevice);
+
+ InOrder order = inOrder(mLeAudioService);
+
+ leAudioConnected(mLeAudioDevice);
+ mTestLooper.dispatchAll();
+ order.verify(mLeAudioService).setActiveDevice(mLeAudioDevice);
+
+ leAudioConnected(mLeAudioDevice2);
+ mTestLooper.dispatchAll();
+ order.verify(mLeAudioService, never()).setActiveDevice(any());
+
+ leAudioDisconnected(mLeAudioDevice2);
+ mTestLooper.dispatchAll();
+ order.verify(mLeAudioService, never()).setActiveDevice(any());
+ order.verify(mLeAudioService, never()).removeActiveDevice(anyBoolean());
+ order.verify(mLeAudioService).deviceDisconnected(mLeAudioDevice2, false);
+
+ leAudioDisconnected(mLeAudioDevice);
+ mTestLooper.dispatchAll();
+ order.verify(mLeAudioService).removeActiveDevice(false);
+ order.verify(mLeAudioService).deviceDisconnected(mLeAudioDevice, false);
}
/**
@@ -1255,6 +1291,11 @@
@Test
@EnableFlags(Flags.FLAG_ADM_VERIFY_ACTIVE_FALLBACK_DEVICE)
public void sameDeviceAsAshaAndLeAudio_noFallbackOnSwitch() {
+ /* Dual mode ASHA/LeAudio device from group 1 */
+ when(mLeAudioService.getGroupId(mHearingAidDevice)).thenReturn(1);
+ /* Different LeAudio only device from group 2 */
+ when(mLeAudioService.getGroupId(mLeAudioDevice)).thenReturn(2);
+
when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
/* Connect first device as ASHA */
@@ -1262,11 +1303,12 @@
mTestLooper.dispatchAll();
verify(mHearingAidService).setActiveDevice(mHearingAidDevice);
- /* Connect first device as LE Audio */
- leAudioConnected(mHearingAidDevice);
+ /* Disconnect ASHA and connect first device as LE Audio */
hearingAidDisconnected(mHearingAidDevice);
mTestLooper.dispatchAll();
- verify(mHearingAidService).removeActiveDevice(false);
+ verify(mHearingAidService).removeActiveDevice(true /* stop audio */);
+ leAudioConnected(mHearingAidDevice);
+ mTestLooper.dispatchAll();
verify(mLeAudioService).setActiveDevice(mHearingAidDevice);
/* Connect second device as LE Audio. First device is disconnected with fallback to
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java
index d216f66..8738085 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java
@@ -708,7 +708,6 @@
@Test
public void restrictedHandles() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_GATT_CLEANUP_RESTRICTED_HANDLES);
int clientIf = 1;
int connId = 1;
ArrayList<GattDbElement> db = new ArrayList<>();
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 1ca22be..2ee7fa0 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
@@ -56,6 +56,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.test.TestLooper;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.Pair;
@@ -67,6 +68,7 @@
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.RemoteDevices;
+import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.hfp.HeadsetService;
import org.hamcrest.Matcher;
@@ -133,6 +135,8 @@
doReturn(mRemoteDevices).when(mAdapterService).getRemoteDevices();
doReturn(true).when(mNativeInterface).sendAndroidAt(anyObject(), anyString());
+ doReturn(true).when(mNativeInterface).disconnect(any(BluetoothDevice.class));
+
mTestLooper = new TestLooper();
mHeadsetClientStateMachine =
new TestHeadsetClientStateMachine(
@@ -980,7 +984,8 @@
assertName(HeadsetClientStateMachine.QUERY_OPERATOR_NAME, "QUERY_OPERATOR_NAME");
assertName(HeadsetClientStateMachine.SUBSCRIBER_INFO, "SUBSCRIBER_INFO");
assertName(HeadsetClientStateMachine.CONNECTING_TIMEOUT, "CONNECTING_TIMEOUT");
- int unknownMessageInt = 54;
+ assertName(HeadsetClientStateMachine.DISCONNECTING_TIMEOUT, "DISCONNECTING_TIMEOUT");
+ int unknownMessageInt = 55;
assertName(unknownMessageInt, "UNKNOWN(" + unknownMessageInt + ")");
}
@@ -1232,6 +1237,27 @@
}
@Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testConnectedState_ProcessDisconnectMessage_TransitionToDisconnecting() {
+ initToDisconnectingState();
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnecting.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testProcessStackEvent_ConnectionStateChanged_Disconnected_onConnectedState() {
+ initToConnectedState();
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED;
+ event.device = mTestDevice;
+ sendMessage(StackEvent.STACK_EVENT, event);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnected.class);
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+ }
+
+ @Test
public void testProcessConnectAudioMessage_onConnectedState() {
initToConnectedState();
sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO);
@@ -1269,7 +1295,7 @@
@Test
public void testProcessDisconnectAudioMessage_onAudioOnState() {
initToAudioOnState();
- sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO, mTestDevice);
+ sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
verify(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
}
@@ -1282,7 +1308,7 @@
mHeadsetClientStateMachine.mCalls.put(0, call);
int[] states = new int[1];
states[0] = HfpClientCall.CALL_STATE_ACTIVE;
- sendMessage(HeadsetClientStateMachine.HOLD_CALL, mTestDevice);
+ sendMessage(HeadsetClientStateMachine.HOLD_CALL);
verify(mNativeInterface).handleCallAction(any(BluetoothDevice.class), anyInt(), eq(0));
}
@@ -1340,6 +1366,132 @@
assertThat(mHeadsetClientStateMachine.mAudioSWB).isTrue();
}
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testDisconnectingState_TransitionToDisconnected() {
+ initToDisconnectingState();
+
+ StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
+ event.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_DISCONNECTED;
+ event.device = mTestDevice;
+
+ sendMessage(StackEvent.STACK_EVENT, event);
+ mTestLooper.dispatchAll();
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_DISCONNECTED));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnected.class);
+
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testDisconnectingState_ReceiveConnectMsg_DeferMessage() {
+ // case CONNECT:
+ initToDisconnectingState();
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.CONNECT))
+ .isFalse();
+ sendMessage(HeadsetClientStateMachine.CONNECT);
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.CONNECT))
+ .isTrue();
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnecting.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testDisconnectingState_ReceiveConnectAudioMsg_DeferMessage() {
+ // case CONNECT_AUDIO:
+ initToDisconnectingState();
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.CONNECT_AUDIO))
+ .isFalse();
+ sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO);
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.CONNECT_AUDIO))
+ .isTrue();
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnecting.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testDisconnectingState_ReceiveDisconnectMsg_DeferMessage() {
+ // case DISCONNECT:
+ initToDisconnectingState();
+ sendMessage(HeadsetClientStateMachine.DISCONNECT);
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.DISCONNECT))
+ .isTrue();
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnecting.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testDisconnectingState_ReceiveDisconnectAudioMsg_DeferMessage() {
+ // case DISCONNECT_AUDIO:
+ initToDisconnectingState();
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.DISCONNECT_AUDIO))
+ .isFalse();
+ sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.DISCONNECT_AUDIO))
+ .isTrue();
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnecting.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testDisconnectingState_ReceiveUnknownMsg_NotHandled() {
+ initToDisconnectingState();
+ sendMessage(HeadsetClientStateMachine.NO_ACTION);
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnecting.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testAudioOnState_ReceiveDisconnectMsg_DeferMessage() {
+ initToAudioOnState();
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.DISCONNECT))
+ .isFalse();
+ sendMessage(HeadsetClientStateMachine.DISCONNECT, mTestDevice);
+ assertThat(
+ mHeadsetClientStateMachine.doesSuperHaveDeferredMessages(
+ HeadsetClientStateMachine.DISCONNECT))
+ .isTrue();
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.AudioOn.class);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_HFP_CLIENT_DISCONNECTING_STATE)
+ public void testDisconnectingState_DisconnectingTimeout_TransitionToDisconnected() {
+ initToDisconnectingState();
+ // Trigger timeout
+ mTestLooper.moveTimeForward(HeadsetClientStateMachine.DISCONNECTING_TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ verifySendBroadcastMultiplePermissions(hasExtra(EXTRA_STATE, STATE_DISCONNECTED));
+ assertThat(mHeadsetClientStateMachine.getCurrentState())
+ .isInstanceOf(HeadsetClientStateMachine.Disconnected.class);
+
+ verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false));
+ }
+
/**
* Allow/disallow connection to any device
*
@@ -1380,6 +1532,14 @@
.isInstanceOf(HeadsetClientStateMachine.AudioOn.class);
}
+ private void initToDisconnectingState() {
+ initToConnectedState();
+ sendMessageAndVerifyTransition(
+ mHeadsetClientStateMachine.obtainMessage(
+ HeadsetClientStateMachine.DISCONNECT, mTestDevice),
+ HeadsetClientStateMachine.Disconnecting.class);
+ }
+
private void verifySendBroadcastMultiplePermissions(Matcher<Intent>... matchers) {
mInOrder.verify(mHeadsetClientService)
.sendBroadcastMultiplePermissions(
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
index 1543cd6..ac6fccb 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
@@ -35,6 +35,7 @@
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -66,6 +67,7 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeoutException;
@@ -1564,6 +1566,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION)
public void testUpdateFallbackInputDevice() {
mSetFlagsRule.disableFlags(Flags.FLAG_LEAUDIO_USE_AUDIO_MODE_LISTENER);
int groupId = 1;
@@ -1658,6 +1661,49 @@
}
}
+ @Test
+ @EnableFlags({
+ Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION,
+ Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP,
+ Flags.FLAG_LEAUDIO_USE_AUDIO_MODE_LISTENER
+ })
+ public void testManageBroadcastToUnicastFallbackGroup() {
+ int groupId = 1;
+ int groupId2 = 2;
+ int broadcastId = 243;
+ byte[] code = {0x00, 0x01, 0x00, 0x02};
+ List<BluetoothDevice> devices = new ArrayList<>();
+
+ when(mDatabaseManager.getMostRecentlyConnectedDevices()).thenReturn(devices);
+
+ initializeNative();
+ devices.add(mDevice);
+ prepareHandoverStreamingBroadcast(groupId, broadcastId, code);
+ mService.deviceConnected(mDevice);
+ devices.add(mDevice2);
+ prepareConnectedUnicastDevice(groupId2, mDevice2);
+ mService.deviceConnected(mDevice2);
+
+ Assert.assertEquals(mService.mUnicastGroupIdDeactivatedForBroadcastTransition, groupId);
+
+ reset(mAudioManager);
+
+ /* Update fallback active device (only input is active) */
+ ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor =
+ ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class);
+
+ mService.setBroadcastToUnicastFallbackGroup(groupId2);
+
+ verify(mAudioManager)
+ .handleBluetoothActiveDeviceChanged(
+ eq(mDevice2), eq(mDevice), connectionInfoArgumentCaptor.capture());
+ List<BluetoothProfileConnectionInfo> connInfos =
+ connectionInfoArgumentCaptor.getAllValues();
+ Assert.assertEquals(connInfos.size(), 1);
+ Assert.assertFalse(connInfos.get(0).isLeOutput());
+ Assert.assertEquals(mService.getBroadcastToUnicastFallbackGroup(), groupId2);
+ }
+
private BluetoothLeBroadcastSettings buildBroadcastSettingsFromMetadata(
BluetoothLeAudioContentMetadata contentMetadata,
@Nullable byte[] broadcastCode,
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
index 2cd1f1a..076e4dc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
@@ -56,6 +56,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.sysprop.BluetoothProperties;
@@ -1826,6 +1827,7 @@
/** Test update unicast fallback active group when broadcast is ongoing */
@Test
+ @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION)
public void testUpdateUnicastFallbackActiveDeviceGroupDuringBroadcast() {
int groupId = 1;
int preGroupId = 2;
@@ -3639,4 +3641,82 @@
.setGroupAllowedContextMask(
groupId, BluetoothLeAudio.CONTEXTS_ALL, BluetoothLeAudio.CONTEXTS_ALL);
}
+
+ /** Test managing broadcast to unicast fallback group */
+ @Test
+ @EnableFlags({
+ Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION,
+ Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP
+ })
+ public void testManageBroadcastToUnicastFallbackGroup() {
+ int firstGroupId = 1;
+ int secondGroupId = 2;
+ /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
+ int direction = 1;
+ int snkAudioLocation = 3;
+ int srcAudioLocation = 4;
+ int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE;
+ List<BluetoothDevice> devices = new ArrayList<>();
+
+ when(mDatabaseManager.getMostRecentlyConnectedDevices()).thenReturn(devices);
+
+ // Not connected device
+ assertThat(mService.setActiveDevice(mSingleDevice)).isFalse();
+ assertThat(mService.getBroadcastToUnicastFallbackGroup())
+ .isEqualTo(BluetoothLeAudio.GROUP_ID_INVALID);
+
+ // Connected device
+ doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
+ devices.add(mSingleDevice);
+ connectTestDevice(mSingleDevice, testGroupId);
+
+ // Group should be updated to default (earliest connected)
+ assertThat(mService.getBroadcastToUnicastFallbackGroup()).isEqualTo(firstGroupId);
+
+ // Add location support
+ LeAudioStackEvent audioConfChangedEvent =
+ new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
+ audioConfChangedEvent.device = mSingleDevice;
+ audioConfChangedEvent.valueInt1 = direction;
+ audioConfChangedEvent.valueInt2 = firstGroupId;
+ audioConfChangedEvent.valueInt3 = snkAudioLocation;
+ audioConfChangedEvent.valueInt4 = srcAudioLocation;
+ audioConfChangedEvent.valueInt5 = availableContexts;
+ mService.messageFromNative(audioConfChangedEvent);
+
+ assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
+ verify(mNativeInterface).groupSetActive(firstGroupId);
+
+ // Set group and device as active
+ LeAudioStackEvent groupStatusChangedEvent =
+ new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED);
+ groupStatusChangedEvent.valueInt1 = firstGroupId;
+ groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE;
+ mService.messageFromNative(groupStatusChangedEvent);
+
+ // Set fallback group to not valid (not connected)
+ mService.setBroadcastToUnicastFallbackGroup(secondGroupId);
+
+ // Connect second device
+ devices.add(mLeftDevice);
+ connectTestDevice(mLeftDevice, secondGroupId);
+ mService.deviceConnected(mLeftDevice);
+
+ // Fallback device should remain earliest connected
+ assertThat(mService.getBroadcastToUnicastFallbackGroup()).isEqualTo(firstGroupId);
+
+ // Set fallback group to valid second
+ mService.setBroadcastToUnicastFallbackGroup(secondGroupId);
+
+ // Fallback device should be changed to second
+ assertThat(mService.getBroadcastToUnicastFallbackGroup()).isEqualTo(secondGroupId);
+
+ // no active device
+ assertThat(mService.removeActiveDevice(false)).isTrue();
+ verify(mNativeInterface).groupSetActive(BluetoothLeAudio.GROUP_ID_INVALID);
+
+ // Set group and device as inactive active
+ groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_INACTIVE;
+ mService.messageFromNative(groupStatusChangedEvent);
+ }
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/mapclient/RequestTest.java b/android/app/tests/unit/src/com/android/bluetooth/mapclient/RequestTest.java
index 1563d21..16cc355 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/mapclient/RequestTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/mapclient/RequestTest.java
@@ -76,7 +76,7 @@
@Before
public void setUp() throws IOException {
mFakeMapObexServer = new FakeMapObexServer();
- mFakeClientSession = new ClientSession(mFakeMapObexServer.mClientObexTransport);
+ mFakeClientSession = mFakeMapObexServer.getClientSession();
mFakeClientSession.connect(new HeaderSet());
}
@@ -182,7 +182,7 @@
@Override
@SuppressWarnings("JavaUtilDate")
- public int onGetValidator(final Operation op) {
+ public int onGet(final Operation op) {
OutputStream outputStream;
HeaderSet replyHeaders = new HeaderSet();
BluetoothMapAppParams outAppParams = new BluetoothMapAppParams();
@@ -223,7 +223,7 @@
}
@Override
- public int onPutValidator(final Operation op) {
+ public int onPut(final Operation op) {
try {
HeaderSet request = op.getReceivedHeader();
String type = (String) request.getHeader(HeaderSet.TYPE);
@@ -263,7 +263,7 @@
}
@Override
- public int onSetPathValidator(
+ public int onSetPath(
final HeaderSet request,
HeaderSet reply,
final boolean backup,
diff --git a/android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexServer.java b/android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexServer.java
index 85beb8e..7b7183b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexServer.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexServer.java
@@ -16,6 +16,7 @@
package com.android.bluetooth;
+import com.android.obex.ClientSession;
import com.android.obex.HeaderSet;
import com.android.obex.ObexTransport;
import com.android.obex.Operation;
@@ -23,61 +24,266 @@
import com.android.obex.ServerRequestHandler;
import com.android.obex.ServerSession;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
-/**
- * A fake obex server for testing obex clients. Test cases should implement *Validator functions to
- * validate input and return appropriate responses for individual tests.
- *
- * <p>Note: it is important to not perform any testing Assert operations within the validators as
- * that would crash the testing framework.
- */
-public abstract class FakeObexServer {
+/** A Fake OBEX Server base class for use when testing OBEX clients and client requests. */
+public class FakeObexServer {
+ private static final String TAG = FakeObexServer.class.getSimpleName();
- public ObexTransport mClientObexTransport;
+ // Server streams to talk with client under test
+ private final PipedInputStream mReceiveFromClient;
+ private final PipedOutputStream mSendToClient;
- private ObexTransport mServerObexTransport;
- private Server mFakeServer;
- private FakeObexTransport mFakeObexTransport;
+ // Client streams to talk to server
+ private final PipedInputStream mReceiveFromServer;
+ private final PipedOutputStream mSendToServer;
+
+ // Transports for either side
+ private final TestObexTransport mServerTransport;
+ private final TestObexTransport mClientTransport;
+
+ private final TestServiceRequestHandler mRequestHandler;
+ private final ServerSession mServerSession;
public FakeObexServer() throws IOException {
- mFakeServer = new Server();
- mFakeObexTransport = new FakeObexTransport();
- mServerObexTransport = mFakeObexTransport.mServerTransport;
- mClientObexTransport = mFakeObexTransport.mClientTransport;
- new ServerSession(mServerObexTransport, mFakeServer, null);
+
+ mSendToServer = new PipedOutputStream();
+ mReceiveFromServer = new PipedInputStream();
+ mReceiveFromClient = new PipedInputStream(mSendToServer);
+ mSendToClient = new PipedOutputStream(mReceiveFromServer);
+
+ // Transports
+ mServerTransport = new TestObexTransport(mReceiveFromClient, mSendToClient, true);
+ mClientTransport = new TestObexTransport(mReceiveFromServer, mSendToServer, true);
+
+ mRequestHandler = new TestServiceRequestHandler(this);
+ mServerSession = new ServerSession(mServerTransport, mRequestHandler, null);
}
- public abstract int onGetValidator(Operation op);
+ /**
+ * Get a transport for use with a client.
+ *
+ * <p>You can use the openInputStream() and openOutputStream() to get the underlying stream
+ * objects and inject them into your objects under test.
+ */
+ public ObexTransport getClientTransport() {
+ return mClientTransport;
+ }
- public abstract int onPutValidator(Operation op);
+ /**
+ * Directly create a session with this server.
+ *
+ * <p>This can be used to quickly test request objects that need a ClientSession
+ */
+ public ClientSession getClientSession() throws IOException {
+ return new ClientSession(mClientTransport);
+ }
- public abstract int onSetPathValidator(
- HeaderSet request, HeaderSet reply, boolean backup, boolean create);
+ /**
+ * This will close the underlying transport, which will close the streams given to us.
+ *
+ * <p>By specification, servers themselves cannot issue an OBEX session level disconnect.
+ */
+ public void close() {
+ mServerSession.close();
+ }
- class Server extends ServerRequestHandler {
+ // *********************************************************************************************
+ // * Server Operations
+ // *********************************************************************************************
- @Override
- public int onConnect(final HeaderSet request, HeaderSet reply) {
- return ResponseCodes.OBEX_HTTP_OK;
+ public int onConnect(final HeaderSet request, HeaderSet reply) {
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ public void onDisconnect(final HeaderSet request, HeaderSet reply) {}
+
+ public int onGet(final Operation op) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ public int onPut(final Operation op) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ public int onAbort(final HeaderSet request, HeaderSet reply) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ public int onSetPath(
+ final HeaderSet request, HeaderSet reply, final boolean backup, final boolean create) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ public void onClose() {}
+
+ /**
+ * Send a response to a client with the given headers and payload
+ *
+ * @param op The Operation object representing the ongoing operation with the client
+ * @param replyHeaders The HeaderSet to return to the client
+ * @param bytes The payload to send in the response, if any
+ */
+ public final int sendResponse(Operation op, HeaderSet replyHeaders, byte[] bytes) {
+ int responseCode = ResponseCodes.OBEX_HTTP_OK;
+ OutputStream outStream = null;
+ int maxChunkSize = 0;
+ int bytesToWrite = 0;
+ int bytesWritten = 0;
+
+ try {
+ op.sendHeaders(replyHeaders); // Do this before getting chunk size
+ outStream = op.openOutputStream();
+ if (bytes == null) {
+ op.noBodyHeader();
+ outStream.flush();
+ } else {
+ maxChunkSize = op.getMaxPacketSize();
+ while (bytesWritten < bytes.length) {
+ bytesToWrite = Math.min(maxChunkSize, bytes.length - bytesWritten);
+ outStream.write(bytes, bytesWritten, bytesToWrite);
+ bytesWritten += bytesToWrite;
+ }
+ }
+ } catch (IOException e) {
+ responseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ } finally {
+ // Make sure we close
+ if (outStream != null) {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ // drop, as we're closing anyways
+ }
+ }
+ }
+ // If we didn't write everything then send the error code
+ if (bytes != null && bytesWritten != bytes.length) {
+ responseCode = ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+ // Otherwise, success!
+ return responseCode;
+ }
+
+ // *********************************************************************************************
+ // * Transport
+ // *********************************************************************************************
+
+ public static class TestObexTransport implements ObexTransport {
+
+ private final InputStream mInput;
+ private final OutputStream mOutput;
+ private boolean mIsSrmSupported;
+
+ public TestObexTransport(InputStream input, OutputStream output, boolean isSrmSupported) {
+ mInput = input;
+ mOutput = output;
+ setSrmSupported(isSrmSupported);
}
@Override
- public void onDisconnect(final HeaderSet request, HeaderSet reply) {}
+ public DataInputStream openDataInputStream() throws IOException {
+ return new DataInputStream(openInputStream());
+ }
+
+ @Override
+ public DataOutputStream openDataOutputStream() throws IOException {
+ return new DataOutputStream(openOutputStream());
+ }
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return mInput;
+ }
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return mOutput;
+ }
+
+ @Override
+ public int getMaxReceivePacketSize() {
+ return -1;
+ }
+
+ @Override
+ public int getMaxTransmitPacketSize() {
+ return -1;
+ }
+
+ @Override
+ public void connect() throws IOException {}
+
+ @Override
+ public void create() throws IOException {}
+
+ @Override
+ public void disconnect() throws IOException {}
+
+ @Override
+ public void listen() throws IOException {}
+
+ @Override
+ public void close() throws IOException {
+ mInput.close();
+ mOutput.close();
+ }
+
+ public boolean isSrmSupported() {
+ return mIsSrmSupported;
+ }
+
+ public void setSrmSupported(boolean isSrmSupported) {
+ mIsSrmSupported = isSrmSupported;
+ }
+ }
+
+ // *********************************************************************************************
+ // * Request Handler
+ // *********************************************************************************************
+
+ /**
+ * Internal ServerRequestHandler that delegates calls to the FakeObexServer implementation
+ *
+ * <p>This is setup this way for easier test syntax, so one can extend the fake without needing
+ * to care about the framework specifics
+ */
+ private static class TestServiceRequestHandler extends ServerRequestHandler {
+ private final FakeObexServer mServer;
+
+ public TestServiceRequestHandler(FakeObexServer server) {
+ mServer = server;
+ }
+
+ @Override
+ public int onConnect(final HeaderSet request, HeaderSet reply) {
+ return mServer.onConnect(request, reply);
+ }
+
+ @Override
+ public void onDisconnect(final HeaderSet request, HeaderSet reply) {
+ mServer.onDisconnect(request, reply);
+ }
@Override
public int onGet(final Operation op) {
- return onGetValidator(op);
+ return mServer.onGet(op);
}
@Override
public int onPut(final Operation op) {
- return onPutValidator(op);
+ return mServer.onPut(op);
}
@Override
public int onAbort(final HeaderSet request, HeaderSet reply) {
- return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ return mServer.onAbort(request, reply);
}
@Override
@@ -86,10 +292,12 @@
HeaderSet reply,
final boolean backup,
final boolean create) {
- return onSetPathValidator(request, reply, backup, create);
+ return mServer.onSetPath(request, reply, backup, create);
}
@Override
- public void onClose() {}
+ public void onClose() {
+ mServer.onClose();
+ }
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexTransport.java b/android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexTransport.java
deleted file mode 100644
index 27e0a29..0000000
--- a/android/app/tests/unit/src/com/android/bluetooth/obex/FakeObexTransport.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth;
-
-import com.android.obex.ObexTransport;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-
-/**
- * A fake obex transport used for testing Client/Server connections. The transport uses two pairs of
- * pipes to route input from the client to the server, and back. The obex transport is of the
- * simplest form, returning default values for everything.
- */
-public class FakeObexTransport {
- ObexTransport mClientTransport;
- ObexTransport mServerTransport;
-
- PipedInputStream mClientInputStream;
- PipedInputStream mServerInputStream;
- PipedOutputStream mClientOutputStream;
- PipedOutputStream mServerOutputStream;
-
- public FakeObexTransport() throws IOException {
- mClientInputStream = new PipedInputStream();
- mServerOutputStream = new PipedOutputStream(mClientInputStream);
- mServerInputStream = new PipedInputStream();
- mClientOutputStream = new PipedOutputStream(mServerInputStream);
-
- mClientTransport = new BiDirectionalTransport(mClientInputStream, mClientOutputStream);
- mServerTransport = new BiDirectionalTransport(mServerInputStream, mServerOutputStream);
- }
-
- static class BiDirectionalTransport implements ObexTransport {
-
- InputStream mInputStream;
- OutputStream mOutputStream;
-
- BiDirectionalTransport(InputStream inputStream, OutputStream outputStream) {
- mInputStream = inputStream;
- mOutputStream = outputStream;
- }
-
- @Override
- public DataInputStream openDataInputStream() throws IOException {
- return new DataInputStream(openInputStream());
- }
-
- @Override
- public DataOutputStream openDataOutputStream() throws IOException {
- return new DataOutputStream(openOutputStream());
- }
-
- @Override
- public InputStream openInputStream() throws IOException {
- return mInputStream;
- }
-
- @Override
- public OutputStream openOutputStream() throws IOException {
- return mOutputStream;
- }
-
- @Override
- public void connect() throws IOException {}
-
- @Override
- public void create() throws IOException {}
-
- @Override
- public void disconnect() throws IOException {}
-
- @Override
- public void listen() throws IOException {}
-
- @Override
- public void close() throws IOException {}
-
- public boolean isConnected() throws IOException {
- return true;
- }
-
- @Override
- public int getMaxTransmitPacketSize() {
- return -1;
- }
-
- @Override
- public int getMaxReceivePacketSize() {
- return -1;
- }
-
- @Override
- public boolean isSrmSupported() {
- return true;
- }
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSizeTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSizeTest.java
deleted file mode 100644
index 35209b8..0000000
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookSizeTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.obex.HeaderSet;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BluetoothPbapRequestPullPhoneBookSizeTest {
-
- BluetoothPbapRequestPullPhoneBookSize mRequest;
-
- @Before
- public void setUp() {
- mRequest =
- new BluetoothPbapRequestPullPhoneBookSize(
- /* pbName= */ "phonebook", /* filter= */ 1);
- }
-
- @Test
- public void readResponseHeaders() {
- try {
- HeaderSet headerSet = new HeaderSet();
- mRequest.readResponseHeaders(headerSet);
- assertThat(mRequest.getSize()).isEqualTo(0);
- } catch (Exception e) {
- assertWithMessage("Exception should not happen.").fail();
- }
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookTest.java
deleted file mode 100644
index c2ef8ce..0000000
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestPullPhoneBookTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.mock;
-
-import android.accounts.Account;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.obex.HeaderSet;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BluetoothPbapRequestPullPhoneBookTest {
-
- private static final String PB_NAME = "phonebook";
- private static final Account ACCOUNT = mock(Account.class);
-
- @Test
- public void constructor_wrongMaxListCount_throwsIAE() {
- final long filter = 0;
- final byte format = PbapClientConnectionHandler.VCARD_TYPE_30;
- final int listStartOffset = 10;
-
- final int wrongMaxListCount = -1;
-
- assertThrows(
- IllegalArgumentException.class,
- () ->
- new BluetoothPbapRequestPullPhoneBook(
- PB_NAME,
- ACCOUNT,
- filter,
- format,
- wrongMaxListCount,
- listStartOffset));
- }
-
- @Test
- public void constructor_wrongListStartOffset_throwsIAE() {
- final long filter = 0;
- final byte format = PbapClientConnectionHandler.VCARD_TYPE_30;
- final int maxListCount = 100;
-
- final int wrongListStartOffset = -1;
-
- assertThrows(
- IllegalArgumentException.class,
- () ->
- new BluetoothPbapRequestPullPhoneBook(
- PB_NAME,
- ACCOUNT,
- filter,
- format,
- maxListCount,
- wrongListStartOffset));
- }
-
- @Test
- public void readResponse_failWithInputStreamThatThrowsIOEWhenRead() {
- final long filter = 1;
- final byte format = 0; // Will be properly handled as VCARD_TYPE_21.
- final int maxListCount = 0; // Will be specially handled as 65535.
- final int listStartOffset = 10;
- BluetoothPbapRequestPullPhoneBook request =
- new BluetoothPbapRequestPullPhoneBook(
- PB_NAME, ACCOUNT, filter, format, maxListCount, listStartOffset);
-
- final InputStream is =
- new InputStream() {
- @Override
- public int read() throws IOException {
- throw new IOException();
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- throw new IOException();
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- throw new IOException();
- }
- };
-
- assertThrows(IOException.class, () -> request.readResponse(is));
- }
-
- @Test
- public void readResponseHeaders() {
- final long filter = 1;
- final byte format = 0; // Will be properly handled as VCARD_TYPE_21.
- final int maxListCount = 0; // Will be specially handled as 65535.
- final int listStartOffset = 10;
- BluetoothPbapRequestPullPhoneBook request =
- new BluetoothPbapRequestPullPhoneBook(
- PB_NAME, ACCOUNT, filter, format, maxListCount, listStartOffset);
-
- try {
- HeaderSet headerSet = new HeaderSet();
- request.readResponseHeaders(headerSet);
- assertThat(request.getNewMissedCalls()).isEqualTo(-1);
- } catch (Exception e) {
- assertWithMessage("Exception should not happen.").fail();
- }
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestTest.java
deleted file mode 100644
index 8a5a5d5..0000000
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapRequestTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.mockito.Mockito.mock;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.obex.ClientSession;
-import com.android.obex.HeaderSet;
-import com.android.obex.ObexTransport;
-import com.android.obex.ResponseCodes;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.io.InputStream;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BluetoothPbapRequestTest {
-
- private BluetoothPbapRequest mRequest = new BluetoothPbapRequest() {};
-
- @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
-
- @Mock private ObexTransport mObexTransport;
-
- @Before
- public void setUp() throws Exception {
- mRequest = new BluetoothPbapRequest() {};
- }
-
- @Test
- public void isSuccess_true() {
- mRequest.mResponseCode = ResponseCodes.OBEX_HTTP_OK;
-
- assertThat(mRequest.isSuccess()).isTrue();
- }
-
- @Test
- public void isSuccess_false() {
- mRequest.mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
-
- assertThat(mRequest.isSuccess()).isFalse();
- }
-
- @Test
- public void execute_afterAbort() throws Exception {
- mRequest.abort();
- ClientSession session = new ClientSession(mObexTransport);
- mRequest.execute(session);
-
- assertThat(mRequest.mResponseCode).isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR);
- }
-
- // TODO: Add execute_success test case.
-
- @Test
- public void emptyMethods() {
- try {
- mRequest.readResponse(mock(InputStream.class));
- mRequest.readResponseHeaders(new HeaderSet());
- mRequest.checkResponseCode(ResponseCodes.OBEX_HTTP_OK);
-
- } catch (Exception e) {
- assertWithMessage("Exception should not happen.").fail();
- }
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapVcardListTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapVcardListTest.java
deleted file mode 100644
index 3882560..0000000
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapVcardListTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.mock;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.res.Resources;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.bluetooth.TestUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BluetoothPbapVcardListTest {
-
- private static final Account ACCOUNT = mock(Account.class);
- private Context mTargetContext = InstrumentationRegistry.getTargetContext();
- private Resources mTestResources = TestUtils.getTestApplicationResources(mTargetContext);
-
- @Test
- public void constructor_withInputStreamThatThrowsIoeWhenRead_throwsIOException() {
-
- final InputStream is =
- new InputStream() {
- @Override
- public int read() throws IOException {
- throw new IOException();
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- throw new IOException();
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- throw new IOException();
- }
- };
-
- assertThrows(
- IOException.class,
- () ->
- new BluetoothPbapVcardList(
- ACCOUNT, is, PbapClientConnectionHandler.VCARD_TYPE_30));
- assertThrows(
- IOException.class,
- () ->
- new BluetoothPbapVcardList(
- ACCOUNT, is, PbapClientConnectionHandler.VCARD_TYPE_21));
- }
-
- @Test
- public void constructor_withInvalidVcardType_throwsIllegalArgumentException() {
- assertThrows(
- IllegalArgumentException.class,
- () ->
- new BluetoothPbapVcardList(
- ACCOUNT,
- new ByteArrayInputStream("Hello world".getBytes()),
- (byte) -1));
- }
-
- @Test
- public void test30ParserWith21Vcard_parsingSucceeds() throws IOException {
- InputStream fileStream =
- mTestResources.openRawResource(com.android.bluetooth.tests.R.raw.v21_simple);
- BluetoothPbapVcardList result =
- new BluetoothPbapVcardList(
- ACCOUNT, fileStream, PbapClientConnectionHandler.VCARD_TYPE_30);
- assertThat(result.getCount()).isEqualTo(1);
- }
-
- @Test
- public void test21ParserWith30Vcard_parsingSucceeds() throws IOException {
- InputStream fileStream =
- mTestResources.openRawResource(com.android.bluetooth.tests.R.raw.v30_simple);
- BluetoothPbapVcardList result =
- new BluetoothPbapVcardList(
- ACCOUNT, fileStream, PbapClientConnectionHandler.VCARD_TYPE_21);
- assertThat(result.getCount()).isEqualTo(1);
- }
-
- @Test
- public void test30ParserWithUnsupportedVcardVersion_parsingFails() throws IOException {
- InputStream fileStream =
- mTestResources.openRawResource(
- com.android.bluetooth.tests.R.raw.unsupported_version);
- BluetoothPbapVcardList result =
- new BluetoothPbapVcardList(
- ACCOUNT, fileStream, PbapClientConnectionHandler.VCARD_TYPE_30);
- assertThat(result.getCount()).isEqualTo(0);
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/CallLogPullRequestTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/CallLogPullRequestTest.java
index a733160..e6cf835 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/CallLogPullRequestTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/CallLogPullRequestTest.java
@@ -75,7 +75,7 @@
@Test
public void testToString() {
- final String path = PbapClientConnectionHandler.ICH_PATH;
+ final String path = PbapPhonebook.ICH_PATH;
final CallLogPullRequest request =
new CallLogPullRequest(mTargetContext, path, mCallCounter, mAccount);
@@ -84,7 +84,7 @@
@Test
public void onPullComplete_whenResultsAreNull() {
- final String path = PbapClientConnectionHandler.ICH_PATH;
+ final String path = PbapPhonebook.ICH_PATH;
final CallLogPullRequest request =
new CallLogPullRequest(mTargetContext, path, mCallCounter, mAccount);
request.setResults(null);
@@ -111,7 +111,7 @@
@Test
public void onPullComplete_whenResultsAreEmpty() {
- final String path = PbapClientConnectionHandler.ICH_PATH;
+ final String path = PbapPhonebook.ICH_PATH;
final CallLogPullRequest request =
new CallLogPullRequest(mTargetContext, path, mCallCounter, mAccount);
List<VCardEntry> results = new ArrayList<>();
@@ -125,7 +125,7 @@
@Test
public void onPullComplete_whenThereIsNoPhoneProperty() {
- final String path = PbapClientConnectionHandler.MCH_PATH;
+ final String path = PbapPhonebook.MCH_PATH;
final CallLogPullRequest request =
new CallLogPullRequest(mTargetContext, path, mCallCounter, mAccount);
@@ -149,7 +149,7 @@
@Test
public void onPullComplete_success() {
- final String path = PbapClientConnectionHandler.OCH_PATH;
+ final String path = PbapPhonebook.OCH_PATH;
final CallLogPullRequest request =
new CallLogPullRequest(mTargetContext, path, mCallCounter, mAccount);
List<VCardEntry> results = new ArrayList<>();
@@ -178,7 +178,7 @@
@Test
public void updateTimesContacted_cursorIsClosed() {
- final String path = PbapClientConnectionHandler.OCH_PATH;
+ final String path = PbapPhonebook.OCH_PATH;
final CallLogPullRequest request =
new CallLogPullRequest(mTargetContext, path, mCallCounter, mAccount);
mCallCounter.put("key", 1);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapApplicationParametersTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapApplicationParametersTest.java
new file mode 100644
index 0000000..81c90a9
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapApplicationParametersTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PbapApplicationParametersTest {
+
+ public static final int TEST_LIST_SIZE = 250;
+ public static final int TEST_LIST_SIZE_TOO_SMALL = -1;
+ public static final int TEST_LIST_SIZE_TOO_LARGE = 65536;
+
+ public static final int TEST_LIST_OFFSET = 0;
+ public static final int TEST_LIST_OFFSET_TOO_SMALL = -1;
+ public static final int TEST_LIST_OFFSET_TOO_LARGE = 65536;
+
+ public static final String ALL_PROPERTIES_TO_STRING =
+ "<PbapApplicationParameters properties=PROPERTIES_ALL format=1 maxListCount=250"
+ + " listStartOffset=0>";
+ public static final String FILTER_PROPERTIES_TO_STRING =
+ "<PbapApplicationParameters properties=[PROPERTY_VERSION PROPERTY_FN PROPERTY_N]"
+ + " format=1 maxListCount=250 listStartOffset=0>";
+ public static final String FILTER_INDIVIDUAL_PROPERTIES_TO_STRING =
+ "<PbapApplicationParameters properties=[PROPERTY_VERSION PROPERTY_FN PROPERTY_N"
+ + " PROPERTY_PHOTO PROPERTY_ADR PROPERTY_TEL PROPERTY_EMAIL PROPERTY_NICKNAME]"
+ + " format=1 maxListCount=250 listStartOffset=0>";
+ public static final String FORMAT_21_TO_STRING =
+ "<PbapApplicationParameters properties=PROPERTIES_ALL format=0 maxListCount=250"
+ + " listStartOffset=0>";
+
+ @Test
+ public void testCreateParams_paramsWellFormed() {
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
+ TEST_LIST_SIZE,
+ TEST_LIST_OFFSET);
+
+ assertThat(params.getPropertySelectorMask())
+ .isEqualTo(PbapApplicationParameters.PROPERTIES_ALL);
+ assertThat(params.getVcardFormat()).isEqualTo(PbapPhonebook.FORMAT_VCARD_30);
+ assertThat(params.getMaxListCount()).isEqualTo(TEST_LIST_SIZE);
+ assertThat(params.getListStartOffset()).isEqualTo(TEST_LIST_OFFSET);
+ assertThat(params.toString()).isEqualTo(ALL_PROPERTIES_TO_STRING);
+ }
+
+ @Test
+ public void testCreateParams_withPropertyFilter_paramsWellFormed() {
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ (PbapApplicationParameters.PROPERTY_VERSION
+ | PbapApplicationParameters.PROPERTY_FN
+ | PbapApplicationParameters.PROPERTY_N),
+ PbapPhonebook.FORMAT_VCARD_30,
+ TEST_LIST_SIZE,
+ TEST_LIST_OFFSET);
+
+ assertThat(params.getPropertySelectorMask())
+ .isEqualTo(
+ (PbapApplicationParameters.PROPERTY_VERSION
+ | PbapApplicationParameters.PROPERTY_FN
+ | PbapApplicationParameters.PROPERTY_N));
+ assertThat(params.getVcardFormat()).isEqualTo(PbapPhonebook.FORMAT_VCARD_30);
+ assertThat(params.getMaxListCount()).isEqualTo(TEST_LIST_SIZE);
+ assertThat(params.getListStartOffset()).isEqualTo(TEST_LIST_OFFSET);
+ assertThat(params.toString()).isEqualTo(FILTER_PROPERTIES_TO_STRING);
+ }
+
+ @Test
+ public void testCreateParams_withAllPropertiesIndividually_paramsWellFormed() {
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ (PbapApplicationParameters.PROPERTY_VERSION
+ | PbapApplicationParameters.PROPERTY_FN
+ | PbapApplicationParameters.PROPERTY_N
+ | PbapApplicationParameters.PROPERTY_PHOTO
+ | PbapApplicationParameters.PROPERTY_ADR
+ | PbapApplicationParameters.PROPERTY_TEL
+ | PbapApplicationParameters.PROPERTY_EMAIL
+ | PbapApplicationParameters.PROPERTY_NICKNAME),
+ PbapPhonebook.FORMAT_VCARD_30,
+ TEST_LIST_SIZE,
+ TEST_LIST_OFFSET);
+
+ assertThat(params.getPropertySelectorMask())
+ .isEqualTo(
+ (PbapApplicationParameters.PROPERTY_VERSION
+ | PbapApplicationParameters.PROPERTY_FN
+ | PbapApplicationParameters.PROPERTY_N
+ | PbapApplicationParameters.PROPERTY_PHOTO
+ | PbapApplicationParameters.PROPERTY_ADR
+ | PbapApplicationParameters.PROPERTY_TEL
+ | PbapApplicationParameters.PROPERTY_EMAIL
+ | PbapApplicationParameters.PROPERTY_NICKNAME));
+ assertThat(params.getVcardFormat()).isEqualTo(PbapPhonebook.FORMAT_VCARD_30);
+ assertThat(params.getMaxListCount()).isEqualTo(TEST_LIST_SIZE);
+ assertThat(params.getListStartOffset()).isEqualTo(TEST_LIST_OFFSET);
+ assertThat(params.toString()).isEqualTo(FILTER_INDIVIDUAL_PROPERTIES_TO_STRING);
+ }
+
+ @Test
+ public void testCreateParams_withFormat21_paramsWellFormed() {
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_21,
+ TEST_LIST_SIZE,
+ TEST_LIST_OFFSET);
+
+ assertThat(params.getPropertySelectorMask())
+ .isEqualTo(PbapApplicationParameters.PROPERTIES_ALL);
+ assertThat(params.getVcardFormat()).isEqualTo(PbapPhonebook.FORMAT_VCARD_21);
+ assertThat(params.getMaxListCount()).isEqualTo(TEST_LIST_SIZE);
+ assertThat(params.getListStartOffset()).isEqualTo(TEST_LIST_OFFSET);
+ assertThat(params.toString()).isEqualTo(FORMAT_21_TO_STRING);
+ }
+
+ @Test
+ public void testCreateParams_maxListCountTooLarge_exceptionThrown() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
+ TEST_LIST_SIZE_TOO_LARGE,
+ TEST_LIST_OFFSET));
+ }
+
+ @Test
+ public void testCreateParams_maxListCountTooSmall_exceptionThrown() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
+ TEST_LIST_SIZE_TOO_SMALL,
+ TEST_LIST_OFFSET));
+ }
+
+ @Test
+ public void testCreateParams_OffsetTooLarge_exceptionThrown() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
+ TEST_LIST_SIZE,
+ TEST_LIST_OFFSET_TOO_LARGE));
+ }
+
+ @Test
+ public void testCreateParams_OffsetTooSmall_exceptionThrown() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
+ TEST_LIST_SIZE,
+ TEST_LIST_OFFSET_TOO_LARGE));
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/AuthenticationServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorServiceTest.java
similarity index 88%
rename from android/app/tests/unit/src/com/android/bluetooth/pbapclient/AuthenticationServiceTest.java
rename to android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorServiceTest.java
index 5464531..e25c542 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/AuthenticationServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorServiceTest.java
@@ -38,7 +38,7 @@
@MediumTest
@RunWith(AndroidJUnit4.class)
-public class AuthenticationServiceTest {
+public class PbapClientAccountAuthenticatorServiceTest {
Context mTargetContext;
@@ -58,7 +58,7 @@
@Test
public void bind() throws Exception {
Intent intent = new Intent("android.accounts.AccountAuthenticator");
- intent.setClass(mTargetContext, AuthenticationService.class);
+ intent.setClass(mTargetContext, PbapClientAccountAuthenticatorService.class);
assertThat(mServiceRule.bindService(intent)).isNotNull();
}
@@ -66,7 +66,8 @@
private void enableService(boolean enable) {
int enabledState =
enable ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DEFAULT;
- ComponentName serviceName = new ComponentName(mTargetContext, AuthenticationService.class);
+ ComponentName serviceName =
+ new ComponentName(mTargetContext, PbapClientAccountAuthenticatorService.class);
mTargetContext
.getPackageManager()
.setComponentEnabledSetting(serviceName, enabledState, DONT_KILL_APP);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/AuthenticatorTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorTest.java
similarity index 93%
rename from android/app/tests/unit/src/com/android/bluetooth/pbapclient/AuthenticatorTest.java
rename to android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorTest.java
index 8ebce0a..6b63604 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/AuthenticatorTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountAuthenticatorTest.java
@@ -37,10 +37,10 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class AuthenticatorTest {
+public class PbapClientAccountAuthenticatorTest {
private Context mTargetContext;
- private Authenticator mAuthenticator;
+ private PbapClientAccountAuthenticator mAuthenticator;
@Mock AccountAuthenticatorResponse mResponse;
@@ -49,7 +49,7 @@
@Before
public void setUp() throws Exception {
mTargetContext = InstrumentationRegistry.getTargetContext();
- mAuthenticator = new Authenticator(mTargetContext);
+ mAuthenticator = new PbapClientAccountAuthenticator(mTargetContext);
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountManagerTest.java
new file mode 100644
index 0000000..1611399
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientAccountManagerTest.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.nullable;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.HandlerThread;
+import android.os.UserManager;
+import android.os.test.TestLooper;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class PbapClientAccountManagerTest {
+ private static final String ACCOUNT_TYPE = "com.android.bluetooth.pbapclient.account";
+
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ private BluetoothAdapter mAdapter;
+
+ @Mock private Context mMockContext;
+ @Mock private HandlerThread mMockHandlerThread;
+ private TestLooper mTestLooper;
+ @Mock private Resources mMockResources;
+ @Mock private AccountManager mMockAccountManager;
+ @Mock private UserManager mMockUserManager;
+ ArgumentCaptor<BroadcastReceiver> mReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ private BroadcastReceiver mBroadcastReceiver;
+ @Mock private PbapClientAccountManager.Callback mMockCallback;
+ ArgumentCaptor<List<Account>> mFromAccountsCaptor = ArgumentCaptor.forClass(List.class);
+ ArgumentCaptor<List<Account>> mToAccountsCaptor = ArgumentCaptor.forClass(List.class);
+
+ private PbapClientAccountManager mAccountManager;
+
+ @Before
+ public void setUp() throws Exception {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ assertThat(mAdapter).isNotNull();
+
+ TestUtils.mockGetSystemService(
+ mMockContext, Context.ACCOUNT_SERVICE, AccountManager.class, mMockAccountManager);
+ setAvailableAccounts(new Account[] {});
+ setAccountVisibility(AccountManager.VISIBILITY_NOT_VISIBLE);
+ doReturn(true)
+ .when(mMockAccountManager)
+ .addAccountExplicitly(
+ any(Account.class), nullable(String.class), nullable(Bundle.class));
+ doReturn(true).when(mMockAccountManager).removeAccountExplicitly(any(Account.class));
+
+ TestUtils.mockGetSystemService(
+ mMockContext, Context.USER_SERVICE, UserManager.class, mMockUserManager);
+ doReturn("").when(mMockContext).getPackageName();
+ doReturn(false).when(mMockUserManager).isUserUnlocked();
+
+ doReturn(mMockResources).when(mMockContext).getResources();
+ doReturn(ACCOUNT_TYPE).when(mMockResources).getString(anyInt());
+
+ mTestLooper = new TestLooper();
+ doReturn(mTestLooper.getLooper()).when(mMockHandlerThread).getLooper();
+
+ mAccountManager =
+ new PbapClientAccountManager(mMockContext, mMockHandlerThread, mMockCallback);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mAccountManager != null) {
+ mAccountManager.stop();
+ mAccountManager = null;
+ }
+ }
+
+ // *********************************************************************************************
+ // * Public API Methods
+ // *********************************************************************************************
+
+ // getAccountForDevice
+
+ @Test
+ public void testGetAccountForDevice_deviceAccountNameAndTypeAreValid() {
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(account.name).isEqualTo(device.getAddress());
+ assertThat(account.type).isEqualTo(ACCOUNT_TYPE);
+ }
+
+ @Test
+ public void testGetAccountForDevice_withNullDevice_throwsIllegalArgumentException() {
+ assertThrows(
+ IllegalArgumentException.class, () -> mAccountManager.getAccountForDevice(null));
+ }
+
+ // Start/Initialization Proceedures
+
+ @Test
+ public void testStartAccountManager_userUnlockedAccountVisibleNoAccounts_accountsInitialized() {
+ doReturn(true).when(mMockUserManager).isUserUnlocked();
+ setAccountVisibility(AccountManager.VISIBILITY_VISIBLE);
+ startAccountManager();
+ mTestLooper.dispatchAll();
+
+ verify(mMockCallback, times(1))
+ .onAccountsChanged(mFromAccountsCaptor.capture(), mToAccountsCaptor.capture());
+ assertThat(mFromAccountsCaptor.getValue()).isNull();
+ assertThat(mToAccountsCaptor.getValue()).isNotNull();
+ assertThat(mToAccountsCaptor.getValue()).isEmpty();
+ }
+
+ @Test
+ public void testStartAccountManager_userUnlockedAccountVisibleHasAccount_accountsInitialized() {
+ BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ BluetoothDevice device2 = TestUtils.getTestDevice(mAdapter, /* id= */ 2);
+ Account[] accounts =
+ new Account[] {getAccountForDevice(device1), getAccountForDevice(device2)};
+
+ doReturn(true).when(mMockUserManager).isUserUnlocked();
+ setAccountVisibility(AccountManager.VISIBILITY_VISIBLE);
+ setAvailableAccounts(accounts);
+ startAccountManager();
+ mTestLooper.dispatchAll();
+
+ verify(mMockCallback, times(1))
+ .onAccountsChanged(mFromAccountsCaptor.capture(), mToAccountsCaptor.capture());
+ List<Account> fromAccounts = mFromAccountsCaptor.getValue();
+ List<Account> toAccounts = mToAccountsCaptor.getValue();
+
+ assertThat(fromAccounts).isNull();
+ assertThat(toAccounts).isNotNull();
+ assertThat(toAccounts.size()).isEqualTo(2);
+ assertThat(toAccounts).contains(accounts[0]);
+ assertThat(toAccounts).contains(accounts[1]);
+ }
+
+ @Test
+ public void testStartAccountManager_userUnlockedAndAccountNotVisible_accountChecksBegin() {
+ doReturn(true).when(mMockUserManager).isUserUnlocked();
+ startAccountManager();
+ mTestLooper.dispatchAll();
+
+ verify(mMockAccountManager, times(1)).getAccountVisibility(any(Account.class), anyString());
+ }
+
+ @Test
+ public void testStartAccountManager_userNotUnlocked_noAccountsOrChecks() {
+ doReturn(false).when(mMockUserManager).isUserUnlocked();
+ startAccountManager();
+ mTestLooper.dispatchAll();
+
+ verify(mMockAccountManager, never()).getAccountVisibility(any(Account.class), anyString());
+ verify(mMockCallback, never()).onAccountsChanged(any(List.class), any(List.class));
+ }
+
+ @Test
+ public void testReceiveUserLocked_accountNotVisible_accountChecksBegin() {
+ testStartAccountManager_userNotUnlocked_noAccountsOrChecks();
+ sendUserUnlocked();
+ mTestLooper.dispatchAll();
+
+ verify(mMockAccountManager, times(1)).getAccountVisibility(any(Account.class), anyString());
+ }
+
+ @Test
+ public void testReceiveUserLocked_accountVisible_accountsInitialized() {
+ testStartAccountManager_userNotUnlocked_noAccountsOrChecks();
+ setAccountVisibility(AccountManager.VISIBILITY_VISIBLE);
+ sendUserUnlocked();
+ mTestLooper.dispatchAll();
+
+ verify(mMockCallback, times(1))
+ .onAccountsChanged(mFromAccountsCaptor.capture(), mToAccountsCaptor.capture());
+ List<Account> fromAccounts = mFromAccountsCaptor.getValue();
+ List<Account> toAccounts = mToAccountsCaptor.getValue();
+
+ assertThat(fromAccounts).isNull();
+ assertThat(toAccounts).isNotNull();
+ assertThat(toAccounts).isEmpty();
+ }
+
+ @Test
+ public void testAccountVisibilityCheck_notReady_retryQueued() {
+ testStartAccountManager_userUnlockedAndAccountNotVisible_accountChecksBegin();
+
+ mTestLooper.moveTimeForward(2000);
+ mTestLooper.dispatchAll();
+ verify(mMockAccountManager, times(2)).getAccountVisibility(any(Account.class), anyString());
+ }
+
+ // getAccounts
+
+ @Test
+ public void testGetAccounts_storageInitializedWithAccounts_returnsAccountList() {
+ BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ BluetoothDevice device2 = TestUtils.getTestDevice(mAdapter, /* id= */ 2);
+ Account[] accounts =
+ new Account[] {getAccountForDevice(device1), getAccountForDevice(device2)};
+
+ doReturn(true).when(mMockUserManager).isUserUnlocked();
+ setAccountVisibility(AccountManager.VISIBILITY_VISIBLE);
+ setAvailableAccounts(accounts);
+ startAccountManager();
+ mTestLooper.dispatchAll();
+
+ assertThat(mAccountManager.getAccounts()).isNotNull();
+ assertThat(mAccountManager.getAccounts().size()).isEqualTo(2);
+ assertThat(mAccountManager.getAccounts()).contains(accounts[0]);
+ assertThat(mAccountManager.getAccounts()).contains(accounts[1]);
+ }
+
+ @Test
+ public void testGetAccounts_storageNotInitialized_returnsEmptyList() {
+ assertThat(mAccountManager.getAccounts()).isEmpty();
+ }
+
+ // addAccount/addAccountInternal
+
+ @Test
+ public void testAddAccount_accountDoesNotExist_accountInAccountsListAndReturnsTrue() {
+ testStartAccountManager_userUnlockedAccountVisibleNoAccounts_accountsInitialized();
+
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.addAccount(account)).isTrue();
+
+ verify(mMockCallback, times(2))
+ .onAccountsChanged(mFromAccountsCaptor.capture(), mToAccountsCaptor.capture());
+ List<Account> toAccounts = mToAccountsCaptor.getValue();
+ assertThat(toAccounts).contains(account);
+
+ assertThat(mAccountManager.getAccounts()).contains(account);
+ }
+
+ @Test
+ public void testAddAccount_accountAlreadyExists_accountInAccountsListAndReturnsTrue() {
+ testStartAccountManager_userUnlockedAccountVisibleNoAccounts_accountsInitialized();
+
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.addAccount(account)).isTrue();
+ assertThat(mAccountManager.getAccounts()).contains(account);
+
+ // Add again once its already in there
+ assertThat(mAccountManager.addAccount(account)).isTrue();
+ assertThat(mAccountManager.getAccounts().size()).isEqualTo(1);
+ assertThat(mAccountManager.getAccounts()).contains(account);
+ }
+
+ @Test
+ public void testAddAccounts_accountManagerOperationFails_returnsFalse() {
+ doReturn(false)
+ .when(mMockAccountManager)
+ .addAccountExplicitly(
+ any(Account.class), nullable(String.class), nullable(Bundle.class));
+
+ testStartAccountManager_userUnlockedAccountVisibleNoAccounts_accountsInitialized();
+
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.addAccount(account)).isFalse();
+ assertThat(mAccountManager.getAccounts()).isEmpty();
+ }
+
+ @Test
+ public void testAddAccounts_storageNotInitialized_returnsFalse() {
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.addAccount(account)).isFalse();
+ }
+
+ // removeAccount/removeAccountInternal
+
+ @Test
+ public void testRemoveAccount_accountExists_accountNotInAccountsListAndReturnsTrue() {
+ testStartAccountManager_userUnlockedAccountVisibleNoAccounts_accountsInitialized();
+
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.addAccount(account)).isTrue();
+ assertThat(mAccountManager.getAccounts()).contains(account);
+
+ // Remove Account
+ assertThat(mAccountManager.removeAccount(account)).isTrue();
+ assertThat(mAccountManager.getAccounts()).isEmpty();
+ }
+
+ @Test
+ public void testRemoveAccount_accountDoesNotExist_accountNotInAccountsListAndReturnsTrue() {
+ testStartAccountManager_userUnlockedAccountVisibleNoAccounts_accountsInitialized();
+
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.addAccount(account)).isTrue();
+ assertThat(mAccountManager.getAccounts()).contains(account);
+
+ BluetoothDevice device2 = TestUtils.getTestDevice(mAdapter, /* id= */ 2);
+ Account account2 = mAccountManager.getAccountForDevice(device2);
+ assertThat(mAccountManager.getAccounts()).doesNotContain(account2);
+ assertThat(mAccountManager.removeAccount(account2)).isTrue();
+ assertThat(mAccountManager.getAccounts()).contains(account);
+ }
+
+ @Test
+ public void testRemoveAccounts_accountManagerOperationFails_returnsFalse() {
+ testStartAccountManager_userUnlockedAccountVisibleNoAccounts_accountsInitialized();
+
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.addAccount(account)).isTrue();
+ assertThat(mAccountManager.getAccounts()).contains(account);
+
+ doReturn(false).when(mMockAccountManager).removeAccountExplicitly(any(Account.class));
+ assertThat(mAccountManager.removeAccount(account)).isFalse();
+ assertThat(mAccountManager.getAccounts()).contains(account);
+ }
+
+ @Test
+ public void testRemoveAccounts_storageNotInitialized_returnsFalse() {
+ BluetoothDevice device = TestUtils.getTestDevice(mAdapter, /* id= */ 1);
+ Account account = mAccountManager.getAccountForDevice(device);
+ assertThat(mAccountManager.removeAccount(account)).isFalse();
+ }
+
+ // *********************************************************************************************
+ // * Debug/Dump/toString()
+ // *********************************************************************************************
+
+ @Test
+ public void testDump() {
+ String dumpContents = mAccountManager.dump();
+ assertThat(dumpContents).isNotNull();
+ assertThat(dumpContents.length()).isNotEqualTo(0);
+ }
+
+ // *********************************************************************************************
+ // * Test Utilities
+ // *********************************************************************************************
+
+ private void startAccountManager() {
+ mAccountManager.start();
+ verify(mMockContext).registerReceiver(mReceiverCaptor.capture(), any(IntentFilter.class));
+ mBroadcastReceiver = mReceiverCaptor.getValue();
+ }
+
+ private void sendUserUnlocked() {
+ doReturn(true).when(mMockUserManager).isUserUnlocked();
+ Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
+ mBroadcastReceiver.onReceive(mMockContext, intent);
+ }
+
+ private Account getAccountForDevice(BluetoothDevice device) {
+ return new Account(device.getAddress(), "com.android.bluetooth.pbabclient.account");
+ }
+
+ private void setAccountVisibility(int visibility) {
+ doReturn(visibility)
+ .when(mMockAccountManager)
+ .getAccountVisibility(any(Account.class), anyString());
+ }
+
+ private void setAvailableAccounts(Account[] accounts) {
+ doReturn(accounts).when(mMockAccountManager).getAccountsByType(anyString());
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientBinderTest.java
new file mode 100644
index 0000000..5bde803
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientBinderTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.AttributionSource;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PbapClientBinderTest {
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ @Mock private PbapClientService mMockService;
+ private BluetoothDevice mTestDevice;
+ private AttributionSource mAttributionSource;
+
+ private PbapClientBinder mPbapClientBinder;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestDevice = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 1);
+ mAttributionSource = new AttributionSource.Builder(1).build();
+ mPbapClientBinder = new PbapClientBinder(mMockService);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mPbapClientBinder != null) {
+ mPbapClientBinder.cleanup();
+ mPbapClientBinder = null;
+ }
+ }
+
+ // *********************************************************************************************
+ // * API Methods
+ // *********************************************************************************************
+
+ @Test
+ public void testConnect() {
+ mPbapClientBinder.connect(mTestDevice, mAttributionSource);
+ verify(mMockService).connect(eq(mTestDevice));
+ }
+
+ @Test
+ public void testDisconnect() {
+ mPbapClientBinder.disconnect(mTestDevice, mAttributionSource);
+ verify(mMockService).disconnect(eq(mTestDevice));
+ }
+
+ @Test
+ public void testGetConnectedDevices() {
+ mPbapClientBinder.getConnectedDevices(mAttributionSource);
+ verify(mMockService).getConnectedDevices();
+ }
+
+ @Test
+ public void testGetDevicesMatchingConnectionStates() {
+ int[] states = new int[] {BluetoothProfile.STATE_CONNECTED};
+ mPbapClientBinder.getDevicesMatchingConnectionStates(states, mAttributionSource);
+ verify(mMockService).getDevicesMatchingConnectionStates(eq(states));
+ }
+
+ @Test
+ public void testGetConnectionState() {
+ mPbapClientBinder.getConnectionState(mTestDevice, mAttributionSource);
+ verify(mMockService).getConnectionState(eq(mTestDevice));
+ }
+
+ @Test
+ public void testSetConnectionPolicy() {
+ int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+ mPbapClientBinder.setConnectionPolicy(mTestDevice, connectionPolicy, mAttributionSource);
+ verify(mMockService).setConnectionPolicy(eq(mTestDevice), eq(connectionPolicy));
+ }
+
+ @Test
+ public void testGetConnectionPolicy() {
+ mPbapClientBinder.getConnectionPolicy(mTestDevice, mAttributionSource);
+ verify(mMockService).getConnectionPolicy(eq(mTestDevice));
+ }
+
+ // *********************************************************************************************
+ // * API Methods (Without service set, i.e. profile not up)
+ // *********************************************************************************************
+
+ @Test
+ public void testConnect_afterCleanup_returnsFalse() {
+ mPbapClientBinder.cleanup();
+ boolean result = mPbapClientBinder.connect(mTestDevice, mAttributionSource);
+ verify(mMockService, times(0)).connect(any(BluetoothDevice.class));
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void testDisconnect_afterCleanup_returnsFalse() {
+ mPbapClientBinder.cleanup();
+ boolean result = mPbapClientBinder.disconnect(mTestDevice, mAttributionSource);
+ verify(mMockService, times(0)).disconnect(any(BluetoothDevice.class));
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void testGetConnectedDevices_afterCleanup_returnsEmptyList() {
+ mPbapClientBinder.cleanup();
+ List<BluetoothDevice> devices = mPbapClientBinder.getConnectedDevices(mAttributionSource);
+ verify(mMockService, times(0)).getConnectedDevices();
+ assertThat(devices).isEmpty();
+ }
+
+ @Test
+ public void testGetDevicesMatchingConnectionStates_afterCleanup_returnsEmptyList() {
+ mPbapClientBinder.cleanup();
+ int[] states = new int[] {BluetoothProfile.STATE_CONNECTED};
+ List<BluetoothDevice> devices =
+ mPbapClientBinder.getDevicesMatchingConnectionStates(states, mAttributionSource);
+ verify(mMockService, times(0)).getDevicesMatchingConnectionStates(any(int[].class));
+ assertThat(devices).isEmpty();
+ }
+
+ @Test
+ public void testGetConnectionState_afterCleanup_returnsDisconnected() {
+ mPbapClientBinder.cleanup();
+ int state = mPbapClientBinder.getConnectionState(mTestDevice, mAttributionSource);
+ verify(mMockService, times(0)).getConnectionState(any(BluetoothDevice.class));
+ assertThat(state).isEqualTo(BluetoothProfile.STATE_DISCONNECTED);
+ }
+
+ @Test
+ public void testSetConnectionPolicy_afterCleanup_returnsFalse() {
+ mPbapClientBinder.cleanup();
+ int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+ boolean result =
+ mPbapClientBinder.setConnectionPolicy(
+ mTestDevice, connectionPolicy, mAttributionSource);
+ verify(mMockService, times(0)).setConnectionPolicy(any(BluetoothDevice.class), anyInt());
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void testGetConnectionPolicy_afterCleanup_returnsUnknown() {
+ mPbapClientBinder.cleanup();
+ int result = mPbapClientBinder.getConnectionPolicy(mTestDevice, mAttributionSource);
+ verify(mMockService, times(0)).getConnectionPolicy(any(BluetoothDevice.class));
+ assertThat(result).isEqualTo(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandlerTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandlerTest.java
index aea3758..5d5220b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandlerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientConnectionHandlerTest.java
@@ -18,28 +18,23 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.SdpPseRecord;
import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
+import android.content.res.Resources;
import android.os.HandlerThread;
import android.os.Looper;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
-import com.android.bluetooth.btservice.AdapterService;
-import com.android.bluetooth.btservice.storage.DatabaseManager;
import org.junit.After;
import org.junit.Before;
@@ -57,20 +52,23 @@
private static final String TAG = "ConnHandlerTest";
private static final String REMOTE_DEVICE_ADDRESS = "00:00:00:00:00:00";
+ // Normal supported features for our client
+ private static final int SUPPORTED_FEATURES =
+ PbapSdpRecord.FEATURE_DOWNLOADING | PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT;
+
private HandlerThread mThread;
private Looper mLooper;
- private Context mTargetContext;
private BluetoothDevice mRemoteDevice;
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
- @Mock private AdapterService mAdapterService;
-
- @Mock private DatabaseManager mDatabaseManager;
-
private BluetoothAdapter mAdapter;
- private PbapClientService mService;
+ @Mock private PbapClientService mService;
+
+ @Mock private Resources mMockResources;
+
+ @Mock private ContentResolver mMockContentResolver;
@Mock private PbapClientStateMachine mStateMachine;
@@ -78,20 +76,10 @@
@Before
public void setUp() throws Exception {
- mTargetContext =
- spy(
- new ContextWrapper(
- InstrumentationRegistry.getInstrumentation().getTargetContext()));
-
if (Looper.myLooper() == null) {
Looper.prepare();
}
- TestUtils.setAdapterService(mAdapterService);
- doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
- mService = new PbapClientService(mTargetContext);
- mService.start();
-
mAdapter = BluetoothAdapter.getDefaultAdapter();
mThread = new HandlerThread("test_handler_thread");
@@ -99,23 +87,23 @@
mLooper = mThread.getLooper();
mRemoteDevice = mAdapter.getRemoteDevice(REMOTE_DEVICE_ADDRESS);
- when(mStateMachine.getContext()).thenReturn(mTargetContext);
+ doReturn(mService).when(mStateMachine).getContext();
+ doReturn(mMockContentResolver).when(mService).getContentResolver();
+ doReturn(mMockResources).when(mService).getResources();
+ doReturn("com.android.bluetooth.pbapclient").when(mMockResources).getString(anyInt());
mHandler =
new PbapClientConnectionHandler.Builder()
.setLooper(mLooper)
+ .setLocalSupportedFeatures(SUPPORTED_FEATURES)
.setClientSM(mStateMachine)
- .setContext(mTargetContext)
+ .setService(mService)
.setRemoteDevice(mRemoteDevice)
.build();
}
@After
public void tearDown() throws Exception {
- mService.stop();
- mService = PbapClientService.getPbapClientService();
- assertThat(mService).isNull();
- TestUtils.clearAdapterService(mAdapterService);
mLooper.quit();
}
@@ -126,7 +114,7 @@
@Test
public void connectSocket_whenBluetoothIsNotEnabled_returnsFalse_withInvalidL2capPsm() {
- SdpPseRecord record = mock(SdpPseRecord.class);
+ PbapSdpRecord record = mock(PbapSdpRecord.class);
mHandler.setPseRecord(record);
when(record.getL2capPsm()).thenReturn(PbapClientConnectionHandler.L2CAP_INVALID_PSM);
@@ -135,7 +123,7 @@
@Test
public void connectSocket_whenBluetoothIsNotEnabled_returnsFalse_withValidL2capPsm() {
- SdpPseRecord record = mock(SdpPseRecord.class);
+ PbapSdpRecord record = mock(PbapSdpRecord.class);
mHandler.setPseRecord(record);
when(record.getL2capPsm()).thenReturn(1); // Valid PSM ranges 1 to 30;
@@ -151,7 +139,7 @@
@Test
public void abort() {
- SdpPseRecord record = mock(SdpPseRecord.class);
+ PbapSdpRecord record = mock(PbapSdpRecord.class);
when(record.getL2capPsm()).thenReturn(1); // Valid PSM ranges 1 to 30;
mHandler.setPseRecord(record);
mHandler.connectSocket(); // Workaround for setting mSocket as non-null value
@@ -165,34 +153,14 @@
@Test
public void removeCallLog_doesNotCrash() {
- ContentResolver res = mock(ContentResolver.class);
- when(mTargetContext.getContentResolver()).thenReturn(res);
mHandler.removeCallLog();
// Also test when content resolver is null.
- when(mTargetContext.getContentResolver()).thenReturn(null);
+ when(mService.getContentResolver()).thenReturn(null);
mHandler.removeCallLog();
}
@Test
- public void isRepositorySupported_withoutSettingPseRecord_returnsFalse() {
- mHandler.setPseRecord(null);
- final int mask = 0x11;
-
- assertThat(mHandler.isRepositorySupported(mask)).isFalse();
- }
-
- @Test
- public void isRepositorySupported_withSettingPseRecord() {
- SdpPseRecord record = mock(SdpPseRecord.class);
- when(record.getSupportedRepositories()).thenReturn(1);
- mHandler.setPseRecord(record);
- final int mask = 0x11;
-
- assertThat(mHandler.isRepositorySupported(mask)).isTrue();
- }
-
- @Test
public void createAndDisconnectWithoutAddingAccount_doesNotCrash() {
mHandler.obtainMessage(PbapClientConnectionHandler.MSG_DISCONNECT).sendToTarget();
TestUtils.waitForLooperToFinishScheduledTask(mHandler.getLooper());
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapObexAuthenticatorTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientObexAuthenticatorTest.java
similarity index 91%
rename from android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapObexAuthenticatorTest.java
rename to android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientObexAuthenticatorTest.java
index 64711da..74265a3 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/BluetoothPbapObexAuthenticatorTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientObexAuthenticatorTest.java
@@ -29,13 +29,13 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class BluetoothPbapObexAuthenticatorTest {
+public class PbapClientObexAuthenticatorTest {
- private BluetoothPbapObexAuthenticator mAuthenticator;
+ private PbapClientObexAuthenticator mAuthenticator;
@Before
public void setUp() throws Exception {
- mAuthenticator = new BluetoothPbapObexAuthenticator();
+ mAuthenticator = new PbapClientObexAuthenticator();
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
index fec23eb..e6a99ac 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapClientServiceTest.java
@@ -19,6 +19,8 @@
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -27,19 +29,27 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
+import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.content.Intent;
+import android.net.Uri;
import android.os.Looper;
+import android.os.UserManager;
import android.provider.CallLog;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
@@ -55,6 +65,9 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+import java.util.Arrays;
+
@MediumTest
@RunWith(AndroidJUnit4.class)
public class PbapClientServiceTest {
@@ -62,47 +75,80 @@
private PbapClientService mService = null;
private BluetoothAdapter mAdapter = null;
- private Context mTargetContext;
private BluetoothDevice mRemoteDevice;
- boolean mIsAdapterServiceSet;
- boolean mIsPbapClientServiceStarted;
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
-
- @Mock private AdapterService mAdapterService;
-
+ @Mock private Context mMockContext;
+ @Mock private AdapterService mMockAdapterService;
@Mock private DatabaseManager mDatabaseManager;
+ @Mock private PackageManager mMockPackageManager;
+ private MockContentResolver mMockContentResolver;
+ private MockCallLogProvider mMockCallLogProvider;
+ @Mock private Resources mMockResources;
+ @Mock private UserManager mMockUserManager;
+ @Mock private AccountManager mMockAccountManager;
@Before
public void setUp() throws Exception {
- mTargetContext = InstrumentationRegistry.getTargetContext();
- TestUtils.setAdapterService(mAdapterService);
- mIsAdapterServiceSet = true;
- doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
- mService = new PbapClientService(mTargetContext);
- mService.start();
- mService.setAvailable(true);
- mIsPbapClientServiceStarted = true;
- // Try getting the Bluetooth adapter
+ TestUtils.setAdapterService(mMockAdapterService);
+ doReturn(mDatabaseManager).when(mMockAdapterService).getDatabase();
+
+ doReturn("").when(mMockContext).getPackageName();
+ doReturn(mMockPackageManager).when(mMockContext).getPackageManager();
+
+ doReturn(mMockResources).when(mMockContext).getResources();
+ doReturn(Utils.ACCOUNT_TYPE).when(mMockResources).getString(anyInt());
+
+ mMockContentResolver = new MockContentResolver();
+ mMockCallLogProvider = new MockCallLogProvider();
+ mMockContentResolver.addProvider(CallLog.AUTHORITY, mMockCallLogProvider);
+ doReturn(mMockContentResolver).when(mMockContext).getContentResolver();
+
+ doReturn(AccountManager.VISIBILITY_VISIBLE)
+ .when(mMockAccountManager)
+ .getAccountVisibility(any(Account.class), anyString());
+ doReturn(new Account[]{})
+ .when(mMockAccountManager)
+ .getAccountsByType(eq(Utils.ACCOUNT_TYPE));
+ TestUtils.mockGetSystemService(
+ mMockContext,
+ Context.ACCOUNT_SERVICE,
+ AccountManager.class,
+ mMockAccountManager);
+
+ doReturn(false).when(mMockUserManager).isUserUnlocked();
+ TestUtils.mockGetSystemService(
+ mMockContext,
+ Context.USER_SERVICE,
+ UserManager.class,
+ mMockUserManager);
+
mAdapter = BluetoothAdapter.getDefaultAdapter();
Assert.assertNotNull(mAdapter);
mRemoteDevice = mAdapter.getRemoteDevice(REMOTE_DEVICE_ADDRESS);
+
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mService = new PbapClientService(mMockContext);
+ mService.start();
+ mService.setAvailable(true);
}
@After
public void tearDown() throws Exception {
- if (!mIsAdapterServiceSet) {
- return;
- }
- if (mIsPbapClientServiceStarted) {
+ if (mService != null) {
mService.stop();
- mService = PbapClientService.getPbapClientService();
- Assert.assertNull(mService);
+ mService = null;
}
- TestUtils.clearAdapterService(mAdapterService);
- BluetoothMethodProxy.setInstanceForTesting(null);
+ TestUtils.clearAdapterService(mMockAdapterService);
}
+ // *********************************************************************************************
+ // * Initialize Service
+ // *********************************************************************************************
+
@Test
public void testInitialize() {
Assert.assertNotNull(PbapClientService.getPbapClientService());
@@ -115,18 +161,95 @@
assertThat(PbapClientService.getPbapClientService()).isNull();
}
+ // *********************************************************************************************
+ // * Incoming Events
+ // *********************************************************************************************
+
+ // Account state changes from PbapClientAccountManager
+
@Test
- public void dump_callsStateMachineDump() {
+ public void onAccountsChanged_fromNulltoEmpty_tryDownloadIfConnectedCalled() {
PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
- StringBuilder builder = new StringBuilder();
- mService.dump(builder);
+ PbapClientService.PbapClientAccountManagerCallback callback =
+ mService.new PbapClientAccountManagerCallback();
+ callback.onAccountsChanged(null, new ArrayList<Account>());
- verify(sm).dump(builder);
+ verify(sm).tryDownloadIfConnected();
}
@Test
+ public void onAccountsChanged_fromEmptyToOne_tryDownloadIfConnectedNotCalled() {
+ PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
+ mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
+
+ PbapClientService.PbapClientAccountManagerCallback callback =
+ mService.new PbapClientAccountManagerCallback();
+ Account acc = mock(Account.class);
+ callback.onAccountsChanged(new ArrayList<Account>(), new ArrayList<>(Arrays.asList(acc)));
+
+ verify(sm, never()).tryDownloadIfConnected();
+ }
+
+ // ACL state changes from AdapterService
+
+ @Test
+ public void aclDisconnected_withLeTransport_doesNotCallDisconnect() {
+ int connectionState = BluetoothProfile.STATE_CONNECTED;
+ PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
+ mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
+ when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
+
+ mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_LE);
+ TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());
+
+ verify(sm, never()).disconnect(mRemoteDevice);
+ }
+
+ @Test
+ public void aclDisconnected_withBrEdrTransport_callsDisconnect() {
+ int connectionState = BluetoothProfile.STATE_CONNECTED;
+ PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
+ mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
+ when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
+
+ mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_BREDR);
+ TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());
+
+ verify(sm).disconnect(mRemoteDevice);
+ }
+
+ // HFP HF State changes
+
+ @Test
+ public void headsetClientConnectionStateChanged_hfpCallLogIsRemoved() {
+ mService.handleHeadsetClientConnectionStateChanged(
+ mRemoteDevice,
+ BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
+
+ assertThat(mMockCallLogProvider.getMostRecentlyDeletedDevice())
+ .isEqualTo(mRemoteDevice.getAddress());
+ }
+
+ // Device state machines cleans up
+
+ @Test
+ public void cleanUpDevice() {
+ PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
+ mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
+
+ mService.cleanupDevice(mRemoteDevice);
+
+ assertThat(mService.mPbapClientStateMachineMap).doesNotContainKey(mRemoteDevice);
+ }
+
+ // *********************************************************************************************
+ // * API Methods
+ // *********************************************************************************************
+
+ @Test
public void testSetConnectionPolicy_withNullDevice_throwsIAE() {
assertThrows(
IllegalArgumentException.class,
@@ -211,171 +334,38 @@
.isEqualTo(BluetoothProfile.STATE_DISCONNECTED);
}
+ // *********************************************************************************************
+ // * Debug/Dump/toString()
+ // *********************************************************************************************
+
@Test
- public void cleanUpDevice() {
+ public void dump_callsStateMachineDump() {
PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
+ StringBuilder builder = new StringBuilder();
- mService.cleanupDevice(mRemoteDevice);
+ mService.dump(builder);
- assertThat(mService.mPbapClientStateMachineMap).doesNotContainKey(mRemoteDevice);
+ verify(sm).dump(builder);
}
- @Test
- public void getConnectedDevices() {
- int connectionState = BluetoothProfile.STATE_CONNECTED;
- PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
- mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
- when(sm.getConnectionState()).thenReturn(connectionState);
+ // *********************************************************************************************
+ // * Fake Call Log Provider
+ // *********************************************************************************************
- assertThat(mService.getConnectedDevices()).contains(mRemoteDevice);
- }
+ private static class MockCallLogProvider extends MockContentProvider {
+ private String mMostRecentlyDeletedDevice = null;
- @Test
- public void binder_connect_callsServiceMethod() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ if (selectionArgs != null && selectionArgs.length > 0) {
+ mMostRecentlyDeletedDevice = selectionArgs[0];
+ }
+ return 0;
+ }
- binder.connect(mRemoteDevice, null);
-
- verify(mockService).connect(mRemoteDevice);
- }
-
- @Test
- public void binder_disconnect_callsServiceMethod() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
-
- binder.disconnect(mRemoteDevice, null);
-
- verify(mockService).disconnect(mRemoteDevice);
- }
-
- @Test
- public void binder_getConnectedDevices_callsServiceMethod() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
-
- binder.getConnectedDevices(null);
-
- verify(mockService).getConnectedDevices();
- }
-
- @Test
- public void binder_getDevicesMatchingConnectionStates_callsServiceMethod() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
-
- int[] states = new int[] {BluetoothProfile.STATE_CONNECTED};
- binder.getDevicesMatchingConnectionStates(states, null);
-
- verify(mockService).getDevicesMatchingConnectionStates(states);
- }
-
- @Test
- public void binder_getConnectionState_callsServiceMethod() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
-
- binder.getConnectionState(mRemoteDevice, null);
-
- verify(mockService).getConnectionState(mRemoteDevice);
- }
-
- @Test
- public void binder_setConnectionPolicy_callsServiceMethod() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
-
- int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
- binder.setConnectionPolicy(mRemoteDevice, connectionPolicy, null);
-
- verify(mockService).setConnectionPolicy(mRemoteDevice, connectionPolicy);
- }
-
- @Test
- public void binder_getConnectionPolicy_callsServiceMethod() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
-
- binder.getConnectionPolicy(mRemoteDevice, null);
-
- verify(mockService).getConnectionPolicy(mRemoteDevice);
- }
-
- @Test
- public void binder_cleanUp_doesNotCrash() {
- PbapClientService mockService = mock(PbapClientService.class);
- PbapClientService.BluetoothPbapClientBinder binder =
- new PbapClientService.BluetoothPbapClientBinder(mockService);
-
- binder.cleanup();
- }
-
- @Test
- public void broadcastReceiver_withActionAclDisconnectedLeTransport_doesNotCallDisconnect() {
- int connectionState = BluetoothProfile.STATE_CONNECTED;
- PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
- mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
- when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
-
- mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_LE);
- TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());
-
- verify(sm, never()).disconnect(mRemoteDevice);
- }
-
- @Test
- public void broadcastReceiver_withActionAclDisconnectedBrEdrTransport_callsDisconnect() {
- int connectionState = BluetoothProfile.STATE_CONNECTED;
- PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
- mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
- when(sm.getConnectionState(mRemoteDevice)).thenReturn(connectionState);
-
- mService.aclDisconnected(mRemoteDevice, BluetoothDevice.TRANSPORT_BREDR);
- TestUtils.waitForLooperToFinishScheduledTask(Looper.getMainLooper());
-
- verify(sm).disconnect(mRemoteDevice);
- }
-
- @Test
- public void broadcastReceiver_withActionUserUnlocked_callsTryDownloadIfConnected() {
- PbapClientStateMachine sm = mock(PbapClientStateMachine.class);
- mService.mPbapClientStateMachineMap.put(mRemoteDevice, sm);
-
- Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
- mService.mPbapBroadcastReceiver.onReceive(mService, intent);
-
- verify(sm).tryDownloadIfConnected();
- }
-
- @Test
- public void headsetClientConnectionStateChanged_hfpCallLogIsRemoved() {
- BluetoothMethodProxy methodProxy = spy(BluetoothMethodProxy.getInstance());
- BluetoothMethodProxy.setInstanceForTesting(methodProxy);
-
- mService.handleHeadsetClientConnectionStateChanged(
- mRemoteDevice,
- BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_DISCONNECTED);
-
- ArgumentCaptor<Object> selectionArgsCaptor = ArgumentCaptor.forClass(Object.class);
- verify(methodProxy)
- .contentResolverDelete(
- any(),
- eq(CallLog.Calls.CONTENT_URI),
- any(),
- (String[]) selectionArgsCaptor.capture());
-
- assertThat(((String[]) selectionArgsCaptor.getValue())[0])
- .isEqualTo(mRemoteDevice.getAddress());
+ public String getMostRecentlyDeletedDevice() {
+ return mMostRecentlyDeletedDevice;
+ }
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapParserTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapParserTest.java
deleted file mode 100644
index 09a4084..0000000
--- a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapParserTest.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bluetooth.pbapclient;
-
-import android.accounts.Account;
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.CallLog.Calls;
-import android.provider.ContactsContract;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.bluetooth.TestUtils;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.TimeZone;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class PbapParserTest {
- private Account mAccount;
- private Resources mTestResources;
- private Context mTargetContext;
- private static final String TEST_ACCOUNT_NAME = "PBAPTESTACCOUNT";
-
- @Before
- public void setUp() {
- mTargetContext = InstrumentationRegistry.getTargetContext();
- mAccount =
- new Account(
- TEST_ACCOUNT_NAME,
- mTargetContext.getString(com.android.bluetooth.R.string.pbap_account_type));
- mTestResources = TestUtils.getTestApplicationResources(mTargetContext);
- cleanupCallLog();
- cleanupPhonebook();
- }
-
- // testNoTimestamp should parse 1 poorly formed vcard and not crash.
- @Test
- public void testNoTimestamp() throws IOException {
- InputStream fileStream;
- fileStream =
- mTestResources.openRawResource(
- com.android.bluetooth.tests.R.raw.no_timestamp_call_log);
- BluetoothPbapVcardList pbapVCardList =
- new BluetoothPbapVcardList(
- mAccount, fileStream, PbapClientConnectionHandler.VCARD_TYPE_30);
- Assert.assertEquals(1, pbapVCardList.getCount());
- CallLogPullRequest processor =
- new CallLogPullRequest(
- mTargetContext,
- PbapClientConnectionHandler.MCH_PATH,
- new HashMap<>(),
- mAccount);
- processor.setResults(pbapVCardList.getList());
-
- // Verify that these entries aren't in the call log to start.
- Assert.assertFalse(verifyCallLog("555-0001", null, "3"));
-
- // Finish processing the data and verify entries were added to the call log.
- processor.onPullComplete();
- Assert.assertTrue(verifyCallLog("555-0001", null, "3"));
- }
-
- // testMissedCall should parse one phonecall correctly.
- @Test
- public void testMissedCall() throws IOException {
- InputStream fileStream;
- fileStream =
- mTestResources.openRawResource(
- com.android.bluetooth.tests.R.raw.single_missed_call);
- BluetoothPbapVcardList pbapVCardList =
- new BluetoothPbapVcardList(
- mAccount, fileStream, PbapClientConnectionHandler.VCARD_TYPE_30);
- Assert.assertEquals(1, pbapVCardList.getCount());
- CallLogPullRequest processor =
- new CallLogPullRequest(
- mTargetContext,
- PbapClientConnectionHandler.MCH_PATH,
- new HashMap<>(),
- mAccount);
- processor.setResults(pbapVCardList.getList());
-
- // Verify that these entries aren't in the call log to start.
- Assert.assertFalse(verifyCallLog("555-0002", "1483232460000", "3"));
- // Finish processing the data and verify entries were added to the call log.
- processor.onPullComplete();
- Assert.assertTrue(verifyCallLog("555-0002", "1483232460000", "3"));
- }
-
- // testUnknownCall should parse two calls with no phone number.
- @Test
- public void testUnknownCall() throws IOException {
- InputStream fileStream;
- fileStream =
- mTestResources.openRawResource(
- com.android.bluetooth.tests.R.raw.unknown_number_call);
- BluetoothPbapVcardList pbapVCardList =
- new BluetoothPbapVcardList(
- mAccount, fileStream, PbapClientConnectionHandler.VCARD_TYPE_30);
- Assert.assertEquals(2, pbapVCardList.getCount());
- CallLogPullRequest processor =
- new CallLogPullRequest(
- mTargetContext,
- PbapClientConnectionHandler.MCH_PATH,
- new HashMap<>(),
- mAccount);
- processor.setResults(pbapVCardList.getList());
-
- // Verify that these entries aren't in the call log to start.
- Assert.assertFalse(verifyCallLog("", "1483232520000", "3"));
- Assert.assertFalse(verifyCallLog("", "1483232580000", "3"));
-
- // Finish processing the data and verify entries were added to the call log.
- processor.onPullComplete();
- Assert.assertTrue(verifyCallLog("", "1483232520000", "3"));
- Assert.assertTrue(verifyCallLog("", "1483232580000", "3"));
- }
-
- @Test
- public void testPullPhoneBook() throws IOException {
- InputStream fileStream;
- fileStream = mTestResources.openRawResource(com.android.bluetooth.tests.R.raw.v30_simple);
- BluetoothPbapVcardList pbapVCardList =
- new BluetoothPbapVcardList(
- mAccount, fileStream, PbapClientConnectionHandler.VCARD_TYPE_30);
- Assert.assertEquals(1, pbapVCardList.getCount());
- PhonebookPullRequest processor = new PhonebookPullRequest(mTargetContext);
- processor.setResults(pbapVCardList.getList());
- Assert.assertFalse(verifyPhonebook("Roid And", "0300000000"));
- processor.onPullComplete();
- Assert.assertTrue(verifyPhonebook("Roid And", "0300000000"));
- }
-
- private void cleanupCallLog() {
- mTargetContext.getContentResolver().delete(Calls.CONTENT_URI, null, null);
- }
-
- private void cleanupPhonebook() {
- mTargetContext
- .getContentResolver()
- .delete(ContactsContract.RawContacts.CONTENT_URI, null, null);
- }
-
- // Find Entries in call log with type matching number and date.
- // If number or date is null it will match any number or date respectively.
- private boolean verifyCallLog(String number, String date, String type) {
- String[] query = new String[] {Calls.NUMBER, Calls.DATE, Calls.TYPE};
- Cursor cursor =
- mTargetContext
- .getContentResolver()
- .query(
- Calls.CONTENT_URI,
- query,
- Calls.TYPE + "= " + type,
- null,
- Calls.DATE + ", " + Calls.NUMBER);
- if (date != null) {
- date = adjDate(date);
- }
- if (cursor != null) {
- while (cursor.moveToNext()) {
- String foundNumber = cursor.getString(cursor.getColumnIndex(Calls.NUMBER));
- String foundDate = cursor.getString(cursor.getColumnIndex(Calls.DATE));
- if ((number == null || number.equals(foundNumber))
- && (date == null || date.equals(foundDate))) {
- return true;
- }
- }
- cursor.close();
- }
- return false;
- }
-
- // Get time zone from device and adjust date to the device's time zone.
- private static String adjDate(String date) {
- TimeZone tz = TimeZone.getDefault();
- long dt = Long.valueOf(date) - tz.getRawOffset();
- return Long.toString(dt);
- }
-
- private boolean verifyPhonebook(String name, String number) {
- Uri uri =
- Uri.withAppendedPath(
- ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
- Cursor c = mTargetContext.getContentResolver().query(uri, null, null, null);
- if (c != null && c.getCount() > 0) {
- c.moveToNext();
- String displayName =
- c.getString(c.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
- if (displayName.equals(name)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapPhonebookMetadataTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapPhonebookMetadataTest.java
new file mode 100644
index 0000000..ce339d4
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapPhonebookMetadataTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PbapPhonebookMetadataTest {
+ private static final int SIZE = 5;
+ private static final String DATABASE_IDENTIFIER = "dbid";
+ private static final String PRIMARY_VERSION_COUNTER = "pvc";
+ private static final String SECONDARY_VERSION_COUNTER = "svc";
+
+ @Test
+ public void testCreatePhonebookMetadata_forFavorites_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.FAVORITES_PATH,
+ SIZE,
+ DATABASE_IDENTIFIER,
+ PRIMARY_VERSION_COUNTER,
+ SECONDARY_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.FAVORITES_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier()).isEqualTo(DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter()).isEqualTo(PRIMARY_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter()).isEqualTo(SECONDARY_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forLocalPhonebook_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.LOCAL_PHONEBOOK_PATH,
+ SIZE,
+ DATABASE_IDENTIFIER,
+ PRIMARY_VERSION_COUNTER,
+ SECONDARY_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.LOCAL_PHONEBOOK_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier()).isEqualTo(DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter()).isEqualTo(PRIMARY_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter()).isEqualTo(SECONDARY_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forSimLocalPhonebook_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.SIM_PHONEBOOK_PATH,
+ SIZE,
+ DATABASE_IDENTIFIER,
+ PRIMARY_VERSION_COUNTER,
+ SECONDARY_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.SIM_PHONEBOOK_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier()).isEqualTo(DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter()).isEqualTo(PRIMARY_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter()).isEqualTo(SECONDARY_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forIncomingCallHistory_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.ICH_PATH,
+ SIZE,
+ PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.ICH_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forOutgoingCallHistory_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.OCH_PATH,
+ SIZE,
+ PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.OCH_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forMissedCallHistory_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.MCH_PATH,
+ SIZE,
+ PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.MCH_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forSimIncomingCallHistory_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.SIM_ICH_PATH,
+ SIZE,
+ PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.SIM_ICH_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forSimOutgoingCallHistory_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.SIM_OCH_PATH,
+ SIZE,
+ PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.SIM_OCH_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testCreatePhonebookMetadata_forSimMissedCallHistory_metadataCreated() {
+ PbapPhonebookMetadata metadata =
+ new PbapPhonebookMetadata(
+ PbapPhonebook.SIM_MCH_PATH,
+ SIZE,
+ PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER,
+ PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ assertThat(metadata.getPhonebook()).isEqualTo(PbapPhonebook.SIM_MCH_PATH);
+ assertThat(metadata.getSize()).isEqualTo(SIZE);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+
+ String str = metadata.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapPhonebookTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapPhonebookTest.java
new file mode 100644
index 0000000..36c28fd
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapPhonebookTest.java
@@ -0,0 +1,570 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.accounts.Account;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class PbapPhonebookTest {
+
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+ @Mock private Account mMockAccount;
+
+ // *********************************************************************************************
+ // * Create Phonebook
+ // *********************************************************************************************
+
+ @Test
+ public void testCreatePhonebook_forFavorites_emptyFavoritesPhonebookeCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.FAVORITES_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.FAVORITES_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ @Test
+ public void testCreatePhonebook_forLocalPhonebook_emptyLocalPhonebookeCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.LOCAL_PHONEBOOK_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.LOCAL_PHONEBOOK_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ @Test
+ public void testCreatePhonebook_forIncomingCallHistory_emptyIncomingCallHistoryCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.ICH_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.ICH_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ @Test
+ public void testCreatePhonebook_forOutgoingCallHistory_emptyOutgoingCallHistoryCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.OCH_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.OCH_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ @Test
+ public void testCreatePhonebook_forMissedCallHistory_emptyMissedCallHistoryCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.MCH_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.MCH_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ @Test
+ public void testCreatePhonebook_forSimIncomingCallHistory_emptySimIncomingCallHistoryCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.SIM_ICH_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_ICH_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ @Test
+ public void testCreatePhonebook_forSimOutgoingCallHistory_emptySimOutgoingCallHistoryCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.SIM_OCH_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_OCH_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ @Test
+ public void testCreatePhonebook_forSimMissedCallHistory_emptyMiSimssedCallHistoryCreated()
+ throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.SIM_MCH_PATH);
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_MCH_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ // *********************************************************************************************
+ // * Parse Phonebook
+ // *********************************************************************************************
+
+ @Test
+ public void testParsePhonebook_forFavorites_favoritesParsed() throws IOException {
+ String vcard1 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Foo",
+ "Bar",
+ "+12345678901",
+ "111 Test Street;Test Town;CA;90210;USA",
+ "Foo@email.com");
+ String vcard2 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Baz",
+ "Bar",
+ "+12345678902",
+ "112 Test Street;Test Town;CA;90210;USA",
+ "Baz@email.com");
+ String phonebookString =
+ Utils.createPhonebook(Arrays.asList(new String[] {vcard1, vcard2}));
+
+ InputStream stream = toUtf8Stream(phonebookString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.FAVORITES_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.FAVORITES_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParsePhonebook_forLocalPhonebook_localPhonebookParsed() throws IOException {
+ String vcard1 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Foo",
+ "Bar",
+ "+12345678901",
+ "111 Test Street;Test Town;CA;90210;USA",
+ "Foo@email.com");
+ String vcard2 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Baz",
+ "Bar",
+ "+12345678902",
+ "112 Test Street;Test Town;CA;90210;USA",
+ "Baz@email.com");
+ String phonebookString =
+ Utils.createPhonebook(Arrays.asList(new String[] {vcard1, vcard2}));
+
+ InputStream stream = toUtf8Stream(phonebookString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.LOCAL_PHONEBOOK_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.LOCAL_PHONEBOOK_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParsePhonebook_forSimPhonebook_simPhonebookParsed() throws IOException {
+ String vcard1 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Foo",
+ "Bar",
+ "+12345678901",
+ "111 Test Street;Test Town;CA;90210;USA",
+ "Foo@email.com");
+ String vcard2 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Baz",
+ "Bar",
+ "+12345678902",
+ "112 Test Street;Test Town;CA;90210;USA",
+ "Baz@email.com");
+ String phonebookString =
+ Utils.createPhonebook(Arrays.asList(new String[] {vcard1, vcard2}));
+
+ InputStream stream = toUtf8Stream(phonebookString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.SIM_PHONEBOOK_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_PHONEBOOK_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ // *********************************************************************************************
+ // * Parse Call History
+ // *********************************************************************************************
+
+ @Test
+ public void testParsePhonebook_forIncomingCallHistory_incomingCallHistoryParsed()
+ throws IOException {
+ String call1 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.INCOMING_CALL,
+ "20240101T100000",
+ "Foo",
+ "Bar",
+ "+12345678901");
+ String call2 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.INCOMING_CALL,
+ "20240101T110000",
+ "Baz",
+ "Bar",
+ "+12345678902");
+ String historyString = Utils.createPhonebook(Arrays.asList(new String[] {call1, call2}));
+
+ InputStream stream = toUtf8Stream(historyString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.ICH_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.ICH_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParsePhonebook_forOutgoingCallHistory_outgoingCallHistoryParsed()
+ throws IOException {
+ String call1 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.OUTGOING_CALL,
+ "20240101T100000",
+ "Foo",
+ "Bar",
+ "+12345678901");
+ String call2 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.OUTGOING_CALL,
+ "20240101T110000",
+ "Baz",
+ "Bar",
+ "+12345678902");
+ String historyString = Utils.createPhonebook(Arrays.asList(new String[] {call1, call2}));
+
+ InputStream stream = toUtf8Stream(historyString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.OCH_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.OCH_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParsePhonebook_forMissedCallHistory_missedCallHistoryParsed()
+ throws IOException {
+ String call1 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.MISSED_CALL,
+ "20240101T100000",
+ "Foo",
+ "Bar",
+ "+12345678901");
+ String call2 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.MISSED_CALL,
+ "20240101T110000",
+ "Baz",
+ "Bar",
+ "+12345678902");
+ String historyString = Utils.createPhonebook(Arrays.asList(new String[] {call1, call2}));
+
+ InputStream stream = toUtf8Stream(historyString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.MCH_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.MCH_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParsePhonebook_forSimIncomingCallHistory_simIncomingCallHistoryParsed()
+ throws IOException {
+ String call1 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.INCOMING_CALL,
+ "20240101T100000",
+ "Foo",
+ "Bar",
+ "+12345678901");
+ String call2 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.INCOMING_CALL,
+ "20240101T110000",
+ "Baz",
+ "Bar",
+ "+12345678902");
+ String historyString = Utils.createPhonebook(Arrays.asList(new String[] {call1, call2}));
+
+ InputStream stream = toUtf8Stream(historyString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.SIM_ICH_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_ICH_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParsePhonebook_forSimOutgoingCallHistory_simOutgoingCallHistoryParsed()
+ throws IOException {
+ String call1 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.OUTGOING_CALL,
+ "20240101T100000",
+ "Foo",
+ "Bar",
+ "+12345678901");
+ String call2 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.OUTGOING_CALL,
+ "20240101T110000",
+ "Baz",
+ "Bar",
+ "+12345678902");
+ String historyString = Utils.createPhonebook(Arrays.asList(new String[] {call1, call2}));
+
+ InputStream stream = toUtf8Stream(historyString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.SIM_OCH_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_OCH_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParsePhonebook_forSimMissedCallHistory_simMissedCallHistoryParsed()
+ throws IOException {
+ String call1 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.MISSED_CALL,
+ "20240101T100000",
+ "Foo",
+ "Bar",
+ "+12345678901");
+ String call2 =
+ Utils.createCallHistory(
+ Utils.VERSION_21,
+ Utils.MISSED_CALL,
+ "20240101T110000",
+ "Baz",
+ "Bar",
+ "+12345678902");
+ String historyString = Utils.createPhonebook(Arrays.asList(new String[] {call1, call2}));
+
+ InputStream stream = toUtf8Stream(historyString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.SIM_MCH_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_MCH_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ // *********************************************************************************************
+ // * Parsing Edge Cases
+ // *********************************************************************************************
+
+ @Test
+ public void testParse21Phonebook_reportedAs30_parsedCorrectly() throws IOException {
+ String vcard1 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Foo",
+ "Bar",
+ "+12345678901",
+ "111 Test Street;Test Town;CA;90210;USA",
+ "Foo@email.com");
+ String vcard2 =
+ Utils.createVcard(
+ Utils.VERSION_21,
+ "Baz",
+ "Bar",
+ "+12345678902",
+ "112 Test Street;Test Town;CA;90210;USA",
+ "Baz@email.com");
+ String phonebookString =
+ Utils.createPhonebook(Arrays.asList(new String[] {vcard1, vcard2}));
+
+ InputStream stream = toUtf8Stream(phonebookString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.SIM_PHONEBOOK_PATH,
+ PbapPhonebook.FORMAT_VCARD_30,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_PHONEBOOK_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParse30Phonebook_reportedAs21_parsedCorrectly() throws IOException {
+ String vcard1 =
+ Utils.createVcard(
+ Utils.VERSION_30,
+ "Foo",
+ "Bar",
+ "+12345678901",
+ "111 Test Street;Test Town;CA;90210;USA",
+ "Foo@email.com");
+ String vcard2 =
+ Utils.createVcard(
+ Utils.VERSION_30,
+ "Baz",
+ "Bar",
+ "+12345678902",
+ "112 Test Street;Test Town;CA;90210;USA",
+ "Baz@email.com");
+ String phonebookString =
+ Utils.createPhonebook(Arrays.asList(new String[] {vcard1, vcard2}));
+
+ InputStream stream = toUtf8Stream(phonebookString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.SIM_PHONEBOOK_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_PHONEBOOK_PATH);
+ assertThat(phonebook.getCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testParseUnsupportedPhonebook_reportedAs21_parsingFails() throws IOException {
+ String vcard1 =
+ Utils.createVcard(
+ Utils.VERSION_UNSUPPORTED,
+ "Foo",
+ "Bar",
+ "+12345678901",
+ "111 Test Street;Test Town;CA;90210;USA",
+ "PORTED@email.com");
+ String vcard2 =
+ Utils.createVcard(
+ Utils.VERSION_UNSUPPORTED,
+ "Baz",
+ "Bar",
+ "+12345678902",
+ "112 Test Street;Test Town;CA;90210;USA",
+ "PORTED@email.com");
+ String phonebookString =
+ Utils.createPhonebook(Arrays.asList(new String[] {vcard1, vcard2}));
+
+ InputStream stream = toUtf8Stream(phonebookString);
+ PbapPhonebook phonebook =
+ new PbapPhonebook(
+ PbapPhonebook.SIM_PHONEBOOK_PATH,
+ PbapPhonebook.FORMAT_VCARD_21,
+ 0,
+ mMockAccount,
+ stream);
+
+ assertThat(phonebook.getPhonebook()).isEqualTo(PbapPhonebook.SIM_PHONEBOOK_PATH);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isNotNull();
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ // *********************************************************************************************
+ // * Debug/Dump/toString()
+ // *********************************************************************************************
+
+ @Test
+ public void testPhonebookToString() throws IOException {
+ PbapPhonebook phonebook = new PbapPhonebook(PbapPhonebook.LOCAL_PHONEBOOK_PATH);
+ String str = phonebook.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ // *********************************************************************************************
+ // * Utilities
+ // *********************************************************************************************
+
+ private InputStream toUtf8Stream(String s) {
+ return new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapSdpRecordTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapSdpRecordTest.java
new file mode 100644
index 0000000..d61ca70
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/PbapSdpRecordTest.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.annotation.SuppressLint;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.SdpPseRecord;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.TestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PbapSdpRecordTest {
+ private BluetoothAdapter mAdapter;
+ private BluetoothDevice mTestDevice;
+
+ private static final String SERVICE_NAME = "PSE SERVICE NAME";
+ private static final int L2CAP_PSM = 4101;
+ private static final int RFCOMM_CHANNEL = 5;
+ private static final int INVALID_L2CAP = -1;
+ private static final int INVALID_RFCOMM = -1;
+
+ private static final int SUPPORTED_REPOSITORIES =
+ PbapSdpRecord.REPOSITORY_LOCAL_PHONEBOOK
+ | PbapSdpRecord.REPOSITORY_SIM_CARD
+ | PbapSdpRecord.REPOSITORY_SPEED_DIAL
+ | PbapSdpRecord.REPOSITORY_FAVORITES;
+
+ private static final int SUPPORTED_FEATURES =
+ PbapSdpRecord.FEATURE_DOWNLOADING
+ | PbapSdpRecord.FEATURE_BROWSING
+ | PbapSdpRecord.FEATURE_DATABASE_IDENTIFIER
+ | PbapSdpRecord.FEATURE_FOLDER_VERSION_COUNTERS
+ | PbapSdpRecord.FEATURE_VCARD_SELECTING
+ | PbapSdpRecord.FEATURE_ENHANCED_MISSED_CALLS
+ | PbapSdpRecord.FEATURE_XBT_UCI_VCARD_PROPERTY
+ | PbapSdpRecord.FEATURE_XBT_UID_VCARD_PROPERTY
+ | PbapSdpRecord.FEATURE_CONTACT_REFERENCING
+ | PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT;
+
+ // For utility function testing-- -1 is FIELD_MISSING, and other negatives should be unknown
+ private static final int UNRECOGNIZED = -2;
+
+ @Before
+ public void setUp() throws Exception {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mTestDevice = TestUtils.getTestDevice(mAdapter, 1);
+ }
+
+ @Test
+ public void testMakeWithDevice() {
+ PbapSdpRecord record =
+ makeSdpRecord(INVALID_L2CAP, INVALID_RFCOMM, PbapSdpRecord.VERSION_1_0, 0, 0);
+ assertThat(record.getDevice()).isEqualTo(mTestDevice);
+ }
+
+ @Test
+ public void testMakeWithServiceName() {
+ PbapSdpRecord record =
+ makeSdpRecord(INVALID_L2CAP, INVALID_RFCOMM, PbapSdpRecord.VERSION_1_0, 0, 0);
+ assertThat(record.getServiceName()).isEqualTo(SERVICE_NAME);
+ }
+
+ @Test
+ public void testMakeVersion10() {
+ PbapSdpRecord record =
+ makeSdpRecord(INVALID_L2CAP, INVALID_RFCOMM, PbapSdpRecord.VERSION_1_0, 0, 0);
+ assertThat(record.getProfileVersion()).isEqualTo(PbapSdpRecord.VERSION_1_0);
+ }
+
+ @Test
+ public void testMakeVersion11() {
+ PbapSdpRecord record =
+ makeSdpRecord(INVALID_L2CAP, INVALID_RFCOMM, PbapSdpRecord.VERSION_1_1, 0, 0);
+ assertThat(record.getProfileVersion()).isEqualTo(PbapSdpRecord.VERSION_1_1);
+ }
+
+ @Test
+ public void testMakeVersion12() {
+ PbapSdpRecord record =
+ makeSdpRecord(INVALID_L2CAP, INVALID_RFCOMM, PbapSdpRecord.VERSION_1_2, 0, 0);
+ assertThat(record.getProfileVersion()).isEqualTo(PbapSdpRecord.VERSION_1_2);
+ }
+
+ @Test
+ public void testMakeL2capTransport() {
+ PbapSdpRecord record =
+ makeSdpRecord(L2CAP_PSM, INVALID_RFCOMM, PbapSdpRecord.VERSION_1_2, 0, 0);
+ assertThat(record.getL2capPsm()).isEqualTo(L2CAP_PSM);
+ assertThat(record.getRfcommChannelNumber()).isEqualTo(INVALID_RFCOMM);
+ }
+
+ @Test
+ public void testMakeRfcommTransport() {
+ PbapSdpRecord record =
+ makeSdpRecord(INVALID_L2CAP, RFCOMM_CHANNEL, PbapSdpRecord.VERSION_1_2, 0, 0);
+ assertThat(record.getL2capPsm()).isEqualTo(INVALID_L2CAP);
+ assertThat(record.getRfcommChannelNumber()).isEqualTo(RFCOMM_CHANNEL);
+ }
+
+ @Test
+ public void testMakeBothTransport() {
+ PbapSdpRecord record =
+ makeSdpRecord(L2CAP_PSM, RFCOMM_CHANNEL, PbapSdpRecord.VERSION_1_2, 0, 0);
+ assertThat(record.getL2capPsm()).isEqualTo(L2CAP_PSM);
+ assertThat(record.getRfcommChannelNumber()).isEqualTo(RFCOMM_CHANNEL);
+ }
+
+ @Test
+ public void testSupportedFeature_featureDownloading() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_DOWNLOADING,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_DOWNLOADING)).isTrue();
+ assertThat(record.getSupportedFeatures()).isEqualTo(PbapSdpRecord.FEATURE_DOWNLOADING);
+ }
+
+ @Test
+ public void testSupportedFeature_featureBrowsing() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_BROWSING,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_BROWSING)).isTrue();
+ assertThat(record.getSupportedFeatures()).isEqualTo(PbapSdpRecord.FEATURE_BROWSING);
+ }
+
+ @Test
+ public void testSupportedFeature_featureDatabaseIdentifier() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_DATABASE_IDENTIFIER,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_DATABASE_IDENTIFIER)).isTrue();
+ assertThat(record.getSupportedFeatures())
+ .isEqualTo(PbapSdpRecord.FEATURE_DATABASE_IDENTIFIER);
+ }
+
+ @Test
+ public void testSupportedFeature_featureFolderVersionCounters() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_FOLDER_VERSION_COUNTERS,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_FOLDER_VERSION_COUNTERS))
+ .isTrue();
+ assertThat(record.getSupportedFeatures())
+ .isEqualTo(PbapSdpRecord.FEATURE_FOLDER_VERSION_COUNTERS);
+ }
+
+ @Test
+ public void testSupportedFeature_featureVcardSelecting() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_VCARD_SELECTING,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_VCARD_SELECTING)).isTrue();
+ assertThat(record.getSupportedFeatures()).isEqualTo(PbapSdpRecord.FEATURE_VCARD_SELECTING);
+ }
+
+ @Test
+ public void testSupportedFeature_featureEnhancedMissedCalls() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_ENHANCED_MISSED_CALLS,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_ENHANCED_MISSED_CALLS)).isTrue();
+ assertThat(record.getSupportedFeatures())
+ .isEqualTo(PbapSdpRecord.FEATURE_ENHANCED_MISSED_CALLS);
+ }
+
+ @Test
+ public void testSupportedFeature_featureXbtUciVcardProperty() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_XBT_UCI_VCARD_PROPERTY,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_XBT_UCI_VCARD_PROPERTY))
+ .isTrue();
+ assertThat(record.getSupportedFeatures())
+ .isEqualTo(PbapSdpRecord.FEATURE_XBT_UCI_VCARD_PROPERTY);
+ }
+
+ @Test
+ public void testSupportedFeature_featureXbtUidVcardProperty() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_XBT_UID_VCARD_PROPERTY,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_XBT_UID_VCARD_PROPERTY))
+ .isTrue();
+ assertThat(record.getSupportedFeatures())
+ .isEqualTo(PbapSdpRecord.FEATURE_XBT_UID_VCARD_PROPERTY);
+ }
+
+ @Test
+ public void testSupportedFeature_featureContactReferencing() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_CONTACT_REFERENCING,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_CONTACT_REFERENCING)).isTrue();
+ assertThat(record.getSupportedFeatures())
+ .isEqualTo(PbapSdpRecord.FEATURE_CONTACT_REFERENCING);
+ }
+
+ @Test
+ public void testSupportedFeature_featureDefaultImageFormat() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT)).isTrue();
+ assertThat(record.getSupportedFeatures())
+ .isEqualTo(PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT);
+ }
+
+ @Test
+ public void testSupportedFeatures_allFeaturesSupported() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ SUPPORTED_FEATURES,
+ 0);
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_DOWNLOADING)).isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_BROWSING)).isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_DATABASE_IDENTIFIER)).isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_FOLDER_VERSION_COUNTERS))
+ .isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_VCARD_SELECTING)).isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_ENHANCED_MISSED_CALLS)).isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_XBT_UCI_VCARD_PROPERTY))
+ .isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_XBT_UID_VCARD_PROPERTY))
+ .isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_CONTACT_REFERENCING)).isTrue();
+ assertThat(record.isFeatureSupported(PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT)).isTrue();
+ assertThat(record.getSupportedFeatures()).isEqualTo(SUPPORTED_FEATURES);
+ }
+
+ @Test
+ public void testSupportedRepository_repositoryLocalPhonebook() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ 0,
+ PbapSdpRecord.REPOSITORY_LOCAL_PHONEBOOK);
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_LOCAL_PHONEBOOK)).isTrue();
+ assertThat(record.getSupportedRepositories())
+ .isEqualTo(PbapSdpRecord.REPOSITORY_LOCAL_PHONEBOOK);
+ }
+
+ @Test
+ public void testSupportedRepository_repositorySimCard() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ 0,
+ PbapSdpRecord.REPOSITORY_SIM_CARD);
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_SIM_CARD)).isTrue();
+ assertThat(record.getSupportedRepositories()).isEqualTo(PbapSdpRecord.REPOSITORY_SIM_CARD);
+ }
+
+ @Test
+ public void testSupportedRepository_repositorySpeedDial() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ 0,
+ PbapSdpRecord.REPOSITORY_SPEED_DIAL);
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_SPEED_DIAL)).isTrue();
+ assertThat(record.getSupportedRepositories())
+ .isEqualTo(PbapSdpRecord.REPOSITORY_SPEED_DIAL);
+ }
+
+ @Test
+ public void testSupportedRepository_repositoryFavorites() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ 0,
+ PbapSdpRecord.REPOSITORY_FAVORITES);
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_FAVORITES)).isTrue();
+ assertThat(record.getSupportedRepositories()).isEqualTo(PbapSdpRecord.REPOSITORY_FAVORITES);
+ }
+
+ @Test
+ public void testSupportedRepositories() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ 0,
+ SUPPORTED_REPOSITORIES);
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_LOCAL_PHONEBOOK)).isTrue();
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_SIM_CARD)).isTrue();
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_SPEED_DIAL)).isTrue();
+ assertThat(record.isRepositorySupported(PbapSdpRecord.REPOSITORY_FAVORITES)).isTrue();
+ assertThat(record.getSupportedRepositories()).isEqualTo(SUPPORTED_REPOSITORIES);
+ }
+
+ @Test
+ @SuppressLint("UnusedVariable")
+ public void testMakeWithNullDevice() {
+ assertThrows(
+ NullPointerException.class,
+ () -> {
+ PbapSdpRecord record =
+ new PbapSdpRecord(null, new SdpPseRecord(0, 0, 0, 0, 0, ""));
+ });
+ }
+
+ @Test
+ @SuppressLint("UnusedVariable")
+ public void testMakeWithNullRecord() {
+ assertThrows(
+ NullPointerException.class,
+ () -> {
+ PbapSdpRecord record = new PbapSdpRecord(mTestDevice, null);
+ });
+ }
+
+ @Test
+ public void testRecordToString() {
+ PbapSdpRecord record =
+ makeSdpRecord(
+ L2CAP_PSM,
+ RFCOMM_CHANNEL,
+ PbapSdpRecord.VERSION_1_2,
+ 0,
+ PbapSdpRecord.REPOSITORY_FAVORITES);
+ String str = record.toString();
+ assertThat(str).isNotNull();
+ assertThat(str.length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testVersionToStringUtility() {
+ assertThat(PbapSdpRecord.versionToString(PbapSdpRecord.VERSION_1_0)).isNotEmpty();
+ assertThat(PbapSdpRecord.versionToString(PbapSdpRecord.VERSION_1_1)).isNotEmpty();
+ assertThat(PbapSdpRecord.versionToString(PbapSdpRecord.VERSION_1_2)).isNotEmpty();
+ assertThat(PbapSdpRecord.versionToString(PbapSdpRecord.FIELD_MISSING)).isNotEmpty();
+ assertThat(PbapSdpRecord.versionToString(UNRECOGNIZED)).isNotEmpty();
+ }
+
+ @Test
+ public void testFeatureToStringUtility() {
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_DOWNLOADING)).isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_BROWSING)).isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_DATABASE_IDENTIFIER))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_FOLDER_VERSION_COUNTERS))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_VCARD_SELECTING))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_ENHANCED_MISSED_CALLS))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_XBT_UCI_VCARD_PROPERTY))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_XBT_UID_VCARD_PROPERTY))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_CONTACT_REFERENCING))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(PbapSdpRecord.FEATURE_DEFAULT_IMAGE_FORMAT))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.featureToString(UNRECOGNIZED)).isNotEmpty();
+ }
+
+ @Test
+ public void testRepositoryToStringUtility() {
+ assertThat(PbapSdpRecord.repositoryToString(PbapSdpRecord.REPOSITORY_LOCAL_PHONEBOOK))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.repositoryToString(PbapSdpRecord.REPOSITORY_SIM_CARD))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.repositoryToString(PbapSdpRecord.REPOSITORY_SPEED_DIAL))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.repositoryToString(PbapSdpRecord.REPOSITORY_FAVORITES))
+ .isNotEmpty();
+ assertThat(PbapSdpRecord.repositoryToString(UNRECOGNIZED)).isNotEmpty();
+ }
+
+ // *********************************************************************************************
+ // * Test Utilities
+ // *********************************************************************************************
+
+ private PbapSdpRecord makeSdpRecord(
+ int l2capPsm, int rfcommChnl, int version, int features, int repositories) {
+ SdpPseRecord sdpRecord =
+ new SdpPseRecord(
+ l2capPsm, rfcommChnl, version, features, repositories, SERVICE_NAME);
+ return new PbapSdpRecord(mTestDevice, sdpRecord);
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/RequestPullPhonebookMetadataTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/RequestPullPhonebookMetadataTest.java
new file mode 100644
index 0000000..5f50e76
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/RequestPullPhonebookMetadataTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.FakeObexServer;
+import com.android.obex.ApplicationParameter;
+import com.android.obex.ClientSession;
+import com.android.obex.HeaderSet;
+import com.android.obex.Operation;
+import com.android.obex.ResponseCodes;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+@RunWith(AndroidJUnit4.class)
+public class RequestPullPhonebookMetadataTest {
+ private static final String PHONEBOOK_NAME = "phonebook";
+ private static final short PHONEBOOK_SIZE = 200;
+
+ private FakePbapObexServer mServer;
+ private ClientSession mSession;
+ private RequestPullPhonebookMetadata mRequest;
+
+ @Before
+ public void setUp() throws IOException {
+ mServer = new FakePbapObexServer();
+ mSession = mServer.getClientSession();
+
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
+ PbapApplicationParameters.MAX_PHONEBOOK_SIZE,
+ /* startOffset= */ 0);
+ mRequest = new RequestPullPhonebookMetadata(PHONEBOOK_NAME, params);
+ }
+
+ @Test
+ public void getType_returnsTypeMetadataRequest() {
+ assertThat(mRequest.getType()).isEqualTo(PbapClientRequest.TYPE_PULL_PHONEBOOK_METADATA);
+ }
+
+ @Test
+ public void getResponseCode_beforeExecutingRequest_returnsNegativeOne() {
+ assertThat(mRequest.getResponseCode()).isEqualTo(-1);
+ }
+
+ @Test
+ public void execute_sessionConnectedAndResponseOk_returnsMetadata() throws IOException {
+ mSession.connect(null);
+ mServer.setSize(PHONEBOOK_SIZE);
+
+ mRequest.execute(mSession);
+
+ assertThat(mRequest.getResponseCode()).isEqualTo(ResponseCodes.OBEX_HTTP_OK);
+ assertThat(mRequest.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+
+ PbapPhonebookMetadata metadata = mRequest.getMetadata();
+ assertThat(metadata.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+ assertThat(metadata.getSize()).isEqualTo(200);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ }
+
+ @Test
+ public void execute_sessionConnectedAndResponseBad_returnsEmptyMetadata() throws IOException {
+ mSession.connect(null);
+ mServer.setResponseCode(ResponseCodes.OBEX_HTTP_BAD_REQUEST);
+ mRequest.execute(mSession);
+
+ assertThat(mRequest.getResponseCode()).isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST);
+ assertThat(mRequest.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+
+ PbapPhonebookMetadata metadata = mRequest.getMetadata();
+ assertThat(metadata.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+ assertThat(metadata.getSize()).isEqualTo(PbapPhonebookMetadata.INVALID_SIZE);
+ assertThat(metadata.getDatabaseIdentifier())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_DATABASE_IDENTIFIER);
+ assertThat(metadata.getPrimaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ assertThat(metadata.getSecondaryVersionCounter())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_VERSION_COUNTER);
+ }
+
+ @Test
+ public void execute_sessionNotConnected_throwsIOException() throws IOException {
+ assertThrows(IOException.class, () -> mRequest.execute(mSession));
+ assertThat(mRequest.getResponseCode()).isEqualTo(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR);
+ }
+
+ @Test
+ public void readResponseHeaders() {
+ try {
+ HeaderSet headerSet = new HeaderSet();
+ mRequest.readResponseHeaders(headerSet);
+ assertThat(mRequest.getMetadata().getSize())
+ .isEqualTo(PbapPhonebookMetadata.INVALID_SIZE);
+ } catch (Exception e) {
+ assertWithMessage("Exception should not happen.").fail();
+ }
+ }
+
+ // *********************************************************************************************
+ // * Fake PBAP Server
+ // *********************************************************************************************
+
+ private static class FakePbapObexServer extends FakeObexServer {
+ private static final byte SIZE_BYTES = 2;
+
+ private int mResponseCode = ResponseCodes.OBEX_HTTP_OK;
+ private short mSize = 0;
+
+ FakePbapObexServer() throws IOException {
+ super();
+ }
+
+ public void setResponseCode(int responseCode) {
+ mResponseCode = responseCode;
+ }
+
+ public void setSize(short size) {
+ mSize = size;
+ }
+
+ @Override
+ public int onGet(final Operation op) {
+ if (mResponseCode != ResponseCodes.OBEX_HTTP_OK) {
+ return mResponseCode;
+ }
+
+ ApplicationParameter params = new ApplicationParameter();
+ params.addTriplet(
+ PbapApplicationParameters.OAP_PHONEBOOK_SIZE,
+ SIZE_BYTES,
+ shortToByteArray(mSize));
+
+ HeaderSet replyHeaders = new HeaderSet();
+ replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, params.getHeader());
+ return sendResponse(op, replyHeaders, null);
+ }
+
+ public byte[] shortToByteArray(short s) {
+ ByteBuffer ret = ByteBuffer.allocate(2);
+ ret.putShort(s);
+ return ret.array();
+ }
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/RequestPullPhonebookTest.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/RequestPullPhonebookTest.java
new file mode 100644
index 0000000..d70060d
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/RequestPullPhonebookTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.accounts.Account;
+import android.util.Log;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.bluetooth.FakeObexServer;
+import com.android.obex.ClientSession;
+import com.android.obex.HeaderSet;
+import com.android.obex.Operation;
+import com.android.obex.ResponseCodes;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class RequestPullPhonebookTest {
+
+ private static final String PHONEBOOK_NAME = "phonebook";
+ private static final Account ACCOUNT = mock(Account.class);
+
+ private FakePbapObexServer mServer;
+ private ClientSession mSession;
+
+ private RequestPullPhonebook mRequest;
+
+ @Before
+ public void setUp() throws IOException {
+ mServer = new FakePbapObexServer();
+ mSession = mServer.getClientSession();
+
+ PbapApplicationParameters params =
+ new PbapApplicationParameters(
+ PbapApplicationParameters.PROPERTIES_ALL,
+ PbapPhonebook.FORMAT_VCARD_30,
+ PbapApplicationParameters.MAX_PHONEBOOK_SIZE,
+ /* startOffset= */ 0);
+ mRequest = new RequestPullPhonebook(PHONEBOOK_NAME, params, ACCOUNT);
+ }
+
+ @Test
+ public void getType_returnsTypeMetadataRequest() {
+ assertThat(mRequest.getType()).isEqualTo(PbapClientRequest.TYPE_PULL_PHONEBOOK);
+ }
+
+ @Test
+ public void getResponseCode_beforeExecutingRequest_returnsNegativeOne() {
+ assertThat(mRequest.getResponseCode()).isEqualTo(-1);
+ }
+
+ @Test
+ public void executeRequest_sessionConnectedWithContacts_returnsContacts() throws IOException {
+ mSession.connect(null);
+
+ String vcard =
+ Utils.createVcard(
+ Utils.VERSION_30,
+ "Foo",
+ "Bar",
+ "+1-234-567-8901",
+ "111 Test Street;Test Town;CA;90210;USA",
+ "Foo@email.com");
+ mServer.addContact(vcard);
+
+ mRequest.execute(mSession);
+
+ assertThat(mRequest.getResponseCode()).isEqualTo(ResponseCodes.OBEX_HTTP_OK);
+ assertThat(mRequest.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+
+ PbapPhonebook phonebook = mRequest.getContacts();
+ assertThat(phonebook).isNotNull();
+ assertThat(phonebook.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(1);
+ assertThat(phonebook.getList()).isNotEmpty();
+ }
+
+ @Test
+ public void execute_sessionConnectedAndResponseBad_returnsEmptyPhonebook() throws IOException {
+ mSession.connect(null);
+ mServer.setResponseCode(ResponseCodes.OBEX_HTTP_BAD_REQUEST);
+
+ mRequest.execute(mSession);
+
+ assertThat(mRequest.getResponseCode()).isEqualTo(ResponseCodes.OBEX_HTTP_BAD_REQUEST);
+ assertThat(mRequest.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+
+ PbapPhonebook phonebook = mRequest.getContacts();
+ assertThat(phonebook).isNotNull();
+ assertThat(phonebook.getPhonebook()).isEqualTo(PHONEBOOK_NAME);
+ assertThat(phonebook.getOffset()).isEqualTo(0);
+ assertThat(phonebook.getCount()).isEqualTo(0);
+ assertThat(phonebook.getList()).isEmpty();
+ }
+
+ // *********************************************************************************************
+ // * Fake PBAP Server
+ // *********************************************************************************************
+
+ private static class FakePbapObexServer extends FakeObexServer {
+ private static final String TAG = FakePbapObexServer.class.getSimpleName();
+
+ private int mResponseCode = ResponseCodes.OBEX_HTTP_OK;
+ private final List<String> mPhonebook = new ArrayList<>();
+
+ FakePbapObexServer() throws IOException {
+ super();
+ }
+
+ public void setResponseCode(int responseCode) {
+ mResponseCode = responseCode;
+ }
+
+ public void addContact(String vcard) {
+ mPhonebook.add(vcard);
+ }
+
+ @Override
+ public int onGet(final Operation op) {
+ Log.i(TAG, "onGet()");
+
+ if (mResponseCode != ResponseCodes.OBEX_HTTP_OK) {
+ return mResponseCode;
+ }
+
+ byte[] contacts = null;
+ if (mPhonebook.size() > 0) {
+ String phonebook = Utils.createPhonebook(mPhonebook);
+ contacts = phonebook.getBytes();
+ }
+
+ HeaderSet replyHeaders = new HeaderSet();
+ return sendResponse(op, replyHeaders, contacts);
+ }
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/pbapclient/Utils.java b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/Utils.java
new file mode 100644
index 0000000..fd97857
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/pbapclient/Utils.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.pbapclient;
+
+import java.util.List;
+
+public class Utils {
+ // VCard Version strings
+ public static final String VERSION_21 = "2.1";
+ public static final String VERSION_30 = "3.0";
+ public static final String VERSION_UNSUPPORTED = "4.0";
+
+ // Constants for creating VCard strings.
+ private static final String N = "N";
+ private static final String FN = "FN";
+ private static final String ADDR = "ADR;TYPE=HOME";
+ private static final String CELL = "TEL;TYPE=CELL";
+ private static final String EMAIL = "EMAIL;INTERNET";
+ private static final String TEL = "TEL;TYPE=0";
+
+ // Constants for creating a call history entry
+ public static final String MISSED_CALL = "MISSED";
+ public static final String INCOMING_CALL = "RECEIVED";
+ public static final String OUTGOING_CALL = "DIALED";
+ private static final String CALL_HISTORY = "X-IRMC-CALL-DATETIME";
+
+ public static final String ACCOUNT_TYPE =
+ "com.android.bluetooth.pbapclient";
+
+ /**
+ * Group a list of VCard entries or Call History entries into a full phonebook
+ *
+ * @param vcardStrings The list of VCard or call history strings to group into a phonebook
+ * @return A string representation of the entire phonebook
+ */
+ public static String createPhonebook(List<String> vcardStrings) {
+ StringBuilder sb = new StringBuilder();
+ for (String vcard : vcardStrings) {
+ sb.append(vcard).append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Create a VCard string fit for parsing
+ *
+ * <p>A null value in any field outside of name fields will cause it to be dropped from the
+ * entry.
+ *
+ * @param version the version of the VCard you want to create
+ * @param first the first name of the VCard you want to create
+ * @param last the last name of the VCard you want to create
+ * @param phone the phone number of the VCard you want to create
+ * @param addr the address of the VCard you want to create
+ * @param email the email of the VCard you want to create
+ * @return a VCard string, built with the information provided
+ */
+ public static String createVcard(
+ String version, String first, String last, String phone, String addr, String email) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN:VCARD\n");
+ sb.append("VERSION:").append(version).append("\n");
+
+ // Friendly name
+ sb.append(FN).append(":").append(first).append(" ").append(last).append("\n");
+
+ // Full name: “LastName;FirstName;MiddleName;Prefix;Suffix”
+ sb.append(N).append(":").append(last).append(";").append(first).append("\n");
+
+ if (phone != null) {
+ sb.append(CELL).append(":").append(phone).append("\n");
+ }
+
+ if (addr != null) {
+ sb.append(ADDR).append(":").append(addr).append("\n");
+ }
+
+ if (email != null) {
+ sb.append(EMAIL).append(":").append(email).append("\n");
+ }
+
+ sb.append("END:VCARD");
+
+ return sb.toString();
+ }
+
+ /**
+ * Create a call history entry string fit for parsing
+ *
+ * <p>A call history entry is a VCard with special fields to carry the type of call and the time
+ * the call occurred
+ *
+ * @param version the version of the call history entry you want to create
+ * @param type the type of the call history entry you want to create
+ * @param time the time of the call history entry, in the format "YYYYMMDDTHHMMSS"
+ * @param first the first name of the person who was called
+ * @param last the last name of the person who was called
+ * @param phone the phone number of the person who was called
+ */
+ public static String createCallHistory(
+ String version, String type, String time, String first, String last, String phone) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("BEGIN:VCARD\n");
+ sb.append("VERSION:").append(version).append("\n");
+
+ if (VERSION_30.equals(version)) {
+ sb.append(FN).append(":").append(first).append(" ").append(last).append("\n");
+ }
+
+ sb.append(N).append(":").append(last).append(";").append(first).append("\n");
+
+ sb.append(TEL).append(":").append(phone).append("\n");
+
+ // Time format: YYYYMMDDTHHMMSS -> 20050320T100000
+ if (VERSION_30.equals(version)) {
+ sb.append(CALL_HISTORY)
+ .append(";TYPE=")
+ .append(type)
+ .append(":")
+ .append(time)
+ .append("\n");
+ } else {
+ sb.append(CALL_HISTORY).append(";").append(type).append(":").append(time).append("\n");
+ }
+
+ sb.append("END:VCARD");
+
+ return sb.toString();
+ }
+}
diff --git a/flags/gap.aconfig b/flags/gap.aconfig
index e3da97a..646e844 100644
--- a/flags/gap.aconfig
+++ b/flags/gap.aconfig
@@ -30,13 +30,6 @@
}
flag {
- name: "gatt_cleanup_restricted_handles"
- namespace: "bluetooth"
- description: "Cleans up restricted handles when disconnected"
- bug: "323110155"
-}
-
-flag {
name: "phy_to_native"
namespace: "bluetooth"
description: "Expose advertising PHY settings to native layer"
diff --git a/flags/hap.aconfig b/flags/hap.aconfig
index 15cfd9c..3ce320f 100644
--- a/flags/hap.aconfig
+++ b/flags/hap.aconfig
@@ -33,3 +33,13 @@
description: "Allow user to control the preset of hearing aid devices"
bug: "306236481"
}
+
+flag {
+ name: "connect_hap_on_other_profile_connect"
+ namespace: "bluetooth"
+ description: "Try to connect HAP when other profile is getting connected"
+ bug: "379771539"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/sockets.aconfig b/flags/sockets.aconfig
index b27b6a5..5f00813 100644
--- a/flags/sockets.aconfig
+++ b/flags/sockets.aconfig
@@ -52,3 +52,13 @@
bug: "374358112"
is_exported: true
}
+
+flag {
+ name: "avoid_l2c_processing_while_stack_shutdown"
+ namespace: "bluetooth"
+ description: "Avoid l2cap processing while stack is shutdown"
+ bug: "379731768"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/framework/Android.bp b/framework/Android.bp
index 0526650..e6a14f7 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -90,9 +90,6 @@
"android.bluetooth",
"com.android.bluetooth.jarjar",
],
- plugins: [
- "error_prone_android_framework",
- ],
aconfig_declarations: [
"bluetooth_aconfig_flags",
],
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 10cb580..ba384ff 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -473,10 +473,12 @@
public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getAudioLocation(@NonNull android.bluetooth.BluetoothDevice);
+ method @FlaggedApi("com.android.bluetooth.flags.leaudio_broadcast_api_manage_primary_group") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getBroadcastToUnicastFallbackGroup();
method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BluetoothLeAudioCodecStatus getCodecStatus(int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean isInbandRingtoneEnabled(int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothLeAudio.Callback);
+ method @FlaggedApi("com.android.bluetooth.flags.leaudio_broadcast_api_manage_primary_group") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setBroadcastToUnicastFallbackGroup(int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setCodecConfigPreference(int, @NonNull android.bluetooth.BluetoothLeAudioCodecConfig, @NonNull android.bluetooth.BluetoothLeAudioCodecConfig);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setVolume(@IntRange(from=0, to=255) int);
@@ -1304,8 +1306,9 @@
}
public final class DistanceMeasurementManager {
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getChannelSoundingMaxSupportedSecurityLevel(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getLocalChannelSoundingMaxSupportedSecurityLevel();
+ method @Deprecated @FlaggedApi("com.android.bluetooth.flags.channel_sounding_25q2_apis") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getChannelSoundingMaxSupportedSecurityLevel(@NonNull android.bluetooth.BluetoothDevice);
+ method @FlaggedApi("com.android.bluetooth.flags.channel_sounding_25q2_apis") @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.Set<java.lang.Integer> getChannelSoundingSupportedSecurityLevels();
+ method @Deprecated @FlaggedApi("com.android.bluetooth.flags.channel_sounding_25q2_apis") @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getLocalChannelSoundingMaxSupportedSecurityLevel();
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.le.DistanceMeasurementMethod> getSupportedMethods();
method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.os.CancellationSignal startMeasurementSession(@NonNull android.bluetooth.le.DistanceMeasurementParams, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.le.DistanceMeasurementSession.Callback);
}
diff --git a/framework/java/android/bluetooth/BluetoothLeAudio.java b/framework/java/android/bluetooth/BluetoothLeAudio.java
index adecd2d..30d17d7 100644
--- a/framework/java/android/bluetooth/BluetoothLeAudio.java
+++ b/framework/java/android/bluetooth/BluetoothLeAudio.java
@@ -1430,4 +1430,77 @@
}
}
}
+
+ /**
+ * Sets broadcast to unicast fallback group.
+ *
+ * <p>In broadcast handover situations where unicast is unavailable, this group acts as the
+ * fallback.
+ *
+ * <p>A handover can occur when ongoing broadcast is interrupted with unicast streaming request.
+ *
+ * <p>On fallback group changed, {@link Callback#onBroadcastToUnicastFallbackGroupChanged} will
+ * be invoked.
+ *
+ * @param groupId the ID of the group to switch to if unicast fails during a broadcast handover,
+ * {@link #GROUP_ID_INVALID} when there should be no such fallback group.
+ * @see BluetoothLeAudio#getGroupId()
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP)
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
+ public void setBroadcastToUnicastFallbackGroup(int groupId) {
+ if (DBG) Log.d(TAG, "setBroadcastToUnicastFallbackGroup(" + groupId + ")");
+
+ final IBluetoothLeAudio service = getService();
+
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ } else if (mAdapter.isEnabled()) {
+ try {
+ service.setBroadcastToUnicastFallbackGroup(groupId, mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ }
+ }
+ }
+
+ /**
+ * Gets broadcast to unicast fallback group.
+ *
+ * <p>In broadcast handover situations where unicast is unavailable, this group acts as the
+ * fallback.
+ *
+ * <p>A broadcast handover can occur when a {@link BluetoothLeBroadcast#startBroadcast} call is
+ * successful and there's an active unicast group.
+ *
+ * @return groupId the ID of the fallback group, {@link #GROUP_ID_INVALID} when adapter is
+ * disabled
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP)
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
+ public int getBroadcastToUnicastFallbackGroup() {
+ if (DBG) Log.d(TAG, "getBroadcastToUnicastFallbackGroup()");
+
+ final IBluetoothLeAudio service = getService();
+
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ } else if (mAdapter.isEnabled()) {
+ try {
+ return service.getBroadcastToUnicastFallbackGroup(mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ }
+ }
+
+ return GROUP_ID_INVALID;
+ }
}
diff --git a/framework/java/android/bluetooth/le/ChannelSoundingParams.java b/framework/java/android/bluetooth/le/ChannelSoundingParams.java
index ab5b8b4..b6c9529 100644
--- a/framework/java/android/bluetooth/le/ChannelSoundingParams.java
+++ b/framework/java/android/bluetooth/le/ChannelSoundingParams.java
@@ -22,8 +22,10 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
/**
* The {@link ChannelSoundingParams} provide a way to adjust distance measurement preferences for
@@ -51,6 +53,7 @@
@interface LocationType {}
/** @hide */
+ @Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.SOURCE)
@IntDef(
value = {
diff --git a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java
index 7a5eb37..c5f07d2 100644
--- a/framework/java/android/bluetooth/le/DistanceMeasurementManager.java
+++ b/framework/java/android/bluetooth/le/DistanceMeasurementManager.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -35,12 +36,18 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.bluetooth.flags.Flags;
+
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
/**
* This class provides methods to perform distance measurement related operations. An application
@@ -164,8 +171,11 @@
* @param remoteDevice remote device of channel sounding
* @return max supported security level, {@link ChannelSoundingParams#CS_SECURITY_LEVEL_UNKNOWN}
* when Channel Sounding is not supported or encounters an internal error.
+ * @deprecated do not use it, this is meaningless, no alternative API.
* @hide
*/
+ @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
+ @Deprecated
@SystemApi
@RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
@@ -194,8 +204,11 @@
*
* @return max supported security level, {@link ChannelSoundingParams#CS_SECURITY_LEVEL_UNKNOWN}
* when Channel Sounding is not supported or encounters an internal error.
+ * @deprecated use {@link #getChannelSoundingSupportedSecurityLevels} instead.
* @hide
*/
+ @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
+ @Deprecated
@SystemApi
@RequiresBluetoothConnectPermission
@RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
@@ -214,6 +227,35 @@
return defaultValue;
}
+ /**
+ * Get the set of supported security levels of channel sounding.
+ *
+ * <p>See: https://bluetooth.com/specifications/specs/core60-html/
+ *
+ * @return the set of supported security levels, empty when Channel Sounding is not supported or
+ * encounters an internal error.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
+ @SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
+ public @NonNull Set<@CsSecurityLevel Integer> getChannelSoundingSupportedSecurityLevels() {
+ try {
+ IBluetoothGatt gatt = mBluetoothAdapter.getBluetoothGatt();
+ if (gatt == null) {
+ Log.e(TAG, "Bluetooth GATT is null");
+ return Collections.emptySet();
+ }
+ return Arrays.stream(gatt.getChannelSoundingSupportedSecurityLevels(mAttributionSource))
+ .boxed()
+ .collect(Collectors.toUnmodifiableSet());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get supported security Level - ", e);
+ }
+ return Collections.emptySet();
+ }
+
@SuppressLint("AndroidFrameworkBluetoothPermission")
private final IDistanceMeasurementCallback mCallbackWrapper =
new IDistanceMeasurementCallback.Stub() {
diff --git a/service/Android.bp b/service/Android.bp
index 0a8e169..ccb7f7d 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -18,7 +18,7 @@
java_defaults {
name: "service-bluetooth-buildflags",
- defaults: ["bluetooth_errorprone_rules"],
+ defaults: ["bluetooth_framework_errorprone_rules"],
lint: {
error_checks: [
diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
index 5e9cca4..a78d857 100644
--- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java
+++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
@@ -253,13 +253,12 @@
}
mName = name;
Log.v(TAG, "storeName(" + mName + "): Success");
- mContext.sendBroadcastAsUser(
+ Intent intent =
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());
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(
+ intent, UserHandle.ALL, BLUETOOTH_CONNECT, getTempAllowlistBroadcastOptions());
}
private void storeAddress(String address) {
@@ -2216,13 +2215,12 @@
if (mEnable) {
long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime;
String onDurationString =
- String.format(
- Locale.US,
+ android.bluetooth.BluetoothUtils.formatSimple(
"%02d:%02d:%02d.%03d",
- (int) (onDuration / (1000 * 60 * 60)),
- (int) ((onDuration / (1000 * 60)) % 60),
- (int) ((onDuration / 1000) % 60),
- (int) (onDuration % 1000));
+ onDuration / (1000 * 60 * 60),
+ (onDuration / (1000 * 60)) % 60,
+ (onDuration / 1000) % 60,
+ onDuration % 1000);
writer.println(" time since enabled: " + onDurationString);
}
diff --git a/service/src/com/android/server/bluetooth/BluetoothServiceBinder.java b/service/src/com/android/server/bluetooth/BluetoothServiceBinder.java
index 95b4b0c..bb0e951 100644
--- a/service/src/com/android/server/bluetooth/BluetoothServiceBinder.java
+++ b/service/src/com/android/server/bluetooth/BluetoothServiceBinder.java
@@ -16,8 +16,6 @@
package com.android.server.bluetooth;
-import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -30,7 +28,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetooth;
@@ -210,7 +207,6 @@
}
@Override
- @RequiresPermission(BLUETOOTH_CONNECT)
public String getName(AttributionSource source) {
requireNonNull(source, "AttributionSource cannot be null in getName");
@@ -229,7 +225,6 @@
}
@Override
- @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
public boolean onFactoryReset(AttributionSource source) {
requireNonNull(source, "AttributionSource cannot be null in onFactoryReset");
@@ -249,7 +244,6 @@
}
@Override
- @RequiresPermission(BLUETOOTH_CONNECT)
public boolean enableBle(AttributionSource source, IBinder token) {
requireNonNull(source, "AttributionSource cannot be null in enableBle");
requireNonNull(token, "IBinder cannot be null in enableBle");
@@ -273,7 +267,6 @@
}
@Override
- @RequiresPermission(BLUETOOTH_CONNECT)
public boolean disableBle(AttributionSource source, IBinder token) {
requireNonNull(source, "AttributionSource cannot be null in disableBle");
requireNonNull(token, "IBinder cannot be null in disableBle");
@@ -302,7 +295,6 @@
}
@Override
- @RequiresPermission(BLUETOOTH_PRIVILEGED)
public int setBtHciSnoopLogMode(int mode) {
BtPermissionUtils.enforcePrivileged(mContext);
@@ -310,7 +302,6 @@
}
@Override
- @RequiresPermission(BLUETOOTH_PRIVILEGED)
public int getBtHciSnoopLogMode() {
BtPermissionUtils.enforcePrivileged(mContext);
@@ -333,21 +324,18 @@
}
@Override
- @RequiresPermission(BLUETOOTH_PRIVILEGED)
public boolean isAutoOnSupported() {
BtPermissionUtils.enforcePrivileged(mContext);
return mBluetoothManagerService.isAutoOnSupported();
}
@Override
- @RequiresPermission(BLUETOOTH_PRIVILEGED)
public boolean isAutoOnEnabled() {
BtPermissionUtils.enforcePrivileged(mContext);
return mBluetoothManagerService.isAutoOnEnabled();
}
@Override
- @RequiresPermission(BLUETOOTH_PRIVILEGED)
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void setAutoOnEnabled(boolean status) {
BtPermissionUtils.enforcePrivileged(mContext);
@@ -355,7 +343,6 @@
}
@Override
- @RequiresPermission(DUMP)
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
if (mContext.checkCallingOrSelfPermission(DUMP) != PERMISSION_GRANTED) {
// TODO(b/280890575): Throws SecurityException instead
diff --git a/service/src/com/android/server/bluetooth/BluetoothShellCommand.java b/service/src/com/android/server/bluetooth/BluetoothShellCommand.java
index 1c258ef..08acddb 100644
--- a/service/src/com/android/server/bluetooth/BluetoothShellCommand.java
+++ b/service/src/com/android/server/bluetooth/BluetoothShellCommand.java
@@ -18,6 +18,7 @@
import static java.util.Objects.requireNonNull;
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.AttributionSource;
import android.os.Binder;
@@ -29,6 +30,7 @@
import java.io.PrintWriter;
+@SuppressLint("AndroidFrameworkRequiresPermission")
class BluetoothShellCommand extends BasicShellCommandHandler {
private static final String TAG = BluetoothShellCommand.class.getSimpleName();
diff --git a/service/src/com/android/server/bluetooth/BtPermissionUtils.java b/service/src/com/android/server/bluetooth/BtPermissionUtils.java
index c9ee6b3..b9e736b 100644
--- a/service/src/com/android/server/bluetooth/BtPermissionUtils.java
+++ b/service/src/com/android/server/bluetooth/BtPermissionUtils.java
@@ -77,7 +77,7 @@
*
* <p>Should be used in situations where the app op should not be noted.
*/
- @SuppressLint("AndroidFrameworkRequiresPermission")
+ @SuppressLint("AndroidFrameworkRequiresPermission") // This method enforces the permission
@RequiresPermission(BLUETOOTH_CONNECT)
static boolean checkConnectPermissionForDataDelivery(
Context ctx,
@@ -109,6 +109,7 @@
*
* <p>Return the error description if this caller is not allowed to toggle Bluetooth
*/
+ @RequiresPermission(BLUETOOTH_CONNECT)
String callerCanToggle(
Context ctx,
AttributionSource source,
@@ -168,6 +169,7 @@
return callingAppId == mSystemUiUid;
}
+ @SuppressLint("AndroidFrameworkRequiresPermission") // Permission is not enforced, only checked
private static boolean isPrivileged(Context ctx, int pid, int uid) {
return (ctx.checkPermission(BLUETOOTH_PRIVILEGED, pid, uid) == PERMISSION_GRANTED)
|| (ctx.getPackageManager().checkSignatures(uid, SYSTEM_UID) == SIGNATURE_MATCH);
@@ -209,7 +211,7 @@
}
UserHandle deviceOwnerUser = null;
ComponentName deviceOwnerComponent = null;
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser();
deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser();
@@ -227,7 +229,7 @@
}
private static boolean isSystem(Context ctx, String packageName, int uid) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
ApplicationInfo info =
ctx.getPackageManager()
diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java
index 8c4a2c9..2cd702f 100644
--- a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java
+++ b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java
@@ -46,6 +46,7 @@
import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.verify;
+import android.annotation.SuppressLint;
import android.app.PropertyInvalidatedCache;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
@@ -87,6 +88,7 @@
import java.util.stream.IntStream;
@RunWith(ParameterizedAndroidJunit4.class)
+@SuppressLint("AndroidFrameworkRequiresPermission")
public class BluetoothManagerServiceTest {
@Rule public final SetFlagsRule mSetFlagsRule;
diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothServiceBinderTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothServiceBinderTest.java
index 071c429..40e6f4b 100644
--- a/service/tests/src/com/android/server/bluetooth/BluetoothServiceBinderTest.java
+++ b/service/tests/src/com/android/server/bluetooth/BluetoothServiceBinderTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.quality.Strictness.STRICT_STUBS;
+import android.annotation.SuppressLint;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.bluetooth.IBluetoothManagerCallback;
@@ -77,6 +78,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
+@SuppressLint("AndroidFrameworkRequiresPermission")
public class BluetoothServiceBinderTest {
private static final String TAG = BluetoothServiceBinderTest.class.getSimpleName();
private static final String LOG_COMPAT_CHANGE = "android.permission.LOG_COMPAT_CHANGE";
diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java
index 7f1df5b..d2b290b 100644
--- a/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java
+++ b/service/tests/src/com/android/server/bluetooth/BluetoothShellCommandTest.java
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.os.Binder;
import android.os.RemoteException;
@@ -53,6 +54,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
+@SuppressLint("AndroidFrameworkRequiresPermission")
public class BluetoothShellCommandTest {
@Rule public final Expect expect = Expect.create();
diff --git a/system/audio_hal_interface/a2dp_encoding.h b/system/audio_hal_interface/a2dp_encoding.h
index 5c8e68c..d7812bb 100644
--- a/system/audio_hal_interface/a2dp_encoding.h
+++ b/system/audio_hal_interface/a2dp_encoding.h
@@ -198,8 +198,8 @@
} // namespace audio
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<::bluetooth::audio::a2dp::BluetoothAudioStatus>
: enum_formatter<::bluetooth::audio::a2dp::BluetoothAudioStatus> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/audio_hal_interface/a2dp_encoding_host.cc b/system/audio_hal_interface/a2dp_encoding_host.cc
index 65c5eba..2436aa0 100644
--- a/system/audio_hal_interface/a2dp_encoding_host.cc
+++ b/system/audio_hal_interface/a2dp_encoding_host.cc
@@ -48,12 +48,12 @@
A2DP_CTRL_GET_PRESENTATION_POSITION,
} tA2DP_CTRL_CMD;
-namespace fmt {
+namespace std {
template <>
struct formatter<tUIPC_EVENT> : enum_formatter<tUIPC_EVENT> {};
template <>
struct formatter<tA2DP_CTRL_CMD> : enum_formatter<tA2DP_CTRL_CMD> {};
-} // namespace fmt
+} // namespace std
namespace {
diff --git a/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc b/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc
index cde3eed..8f4d075 100644
--- a/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc
+++ b/system/audio_hal_interface/aidl/a2dp/a2dp_encoding_aidl.cc
@@ -40,14 +40,14 @@
A2DP_CTRL_GET_PRESENTATION_POSITION,
} tA2DP_CTRL_CMD;
-namespace fmt {
+namespace std {
template <>
struct formatter<tA2DP_CTRL_CMD> : enum_formatter<tA2DP_CTRL_CMD> {};
template <>
struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {};
template <>
struct formatter<audio_content_type_t> : enum_formatter<audio_content_type_t> {};
-} // namespace fmt
+} // namespace std
namespace bluetooth {
namespace audio {
diff --git a/system/audio_hal_interface/aidl/a2dp/client_interface_aidl.cc b/system/audio_hal_interface/aidl/a2dp/client_interface_aidl.cc
index 42af94d..6303bbd 100644
--- a/system/audio_hal_interface/aidl/a2dp/client_interface_aidl.cc
+++ b/system/audio_hal_interface/aidl/a2dp/client_interface_aidl.cc
@@ -215,7 +215,7 @@
}
log::info("IBluetoothAudioProvidersFactory::openProvider() returned {}{}",
- fmt::ptr(provider_.get()), (provider_->isRemote() ? " (remote)" : " (local)"));
+ std::format_ptr(provider_.get()), (provider_->isRemote() ? " (remote)" : " (local)"));
}
void BluetoothAudioClientInterface::binderDiedCallbackAidl(void* ptr) {
diff --git a/system/audio_hal_interface/aidl/audio_ctrl_ack.h b/system/audio_hal_interface/aidl/audio_ctrl_ack.h
index 5cd051c..336bb1f 100644
--- a/system/audio_hal_interface/aidl/audio_ctrl_ack.h
+++ b/system/audio_hal_interface/aidl/audio_ctrl_ack.h
@@ -61,7 +61,7 @@
} // namespace audio
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::audio::aidl::BluetoothAudioCtrlAck> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/audio_hal_interface/aidl/client_interface_aidl.cc b/system/audio_hal_interface/aidl/client_interface_aidl.cc
index e8b143f..176b355 100644
--- a/system/audio_hal_interface/aidl/client_interface_aidl.cc
+++ b/system/audio_hal_interface/aidl/client_interface_aidl.cc
@@ -182,7 +182,7 @@
}
log::info("IBluetoothAudioProvidersFactory::openProvider() returned {}{}",
- fmt::ptr(provider_.get()), (provider_->isRemote() ? " (remote)" : " (local)"));
+ std::format_ptr(provider_.get()), (provider_->isRemote() ? " (remote)" : " (local)"));
}
BluetoothAudioSinkClientInterface::BluetoothAudioSinkClientInterface(
diff --git a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc
index b6a7618..0cf9d82 100644
--- a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc
+++ b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc
@@ -24,12 +24,12 @@
#include "client_interface_aidl.h"
#include "osi/include/properties.h"
-namespace fmt {
+namespace std {
template <>
struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {};
template <>
struct formatter<audio_content_type_t> : enum_formatter<audio_content_type_t> {};
-} // namespace fmt
+} // namespace std
namespace {
diff --git a/system/audio_hal_interface/aidl/hfp_client_interface_aidl.h b/system/audio_hal_interface/aidl/hfp_client_interface_aidl.h
index 5dbf8ad..6b75870 100644
--- a/system/audio_hal_interface/aidl/hfp_client_interface_aidl.h
+++ b/system/audio_hal_interface/aidl/hfp_client_interface_aidl.h
@@ -170,8 +170,8 @@
} // namespace audio
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::audio::aidl::hfp::tHFP_CTRL_CMD>
: enum_formatter<bluetooth::audio::aidl::hfp::tHFP_CTRL_CMD> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/audio_hal_interface/hal_version_manager.cc b/system/audio_hal_interface/hal_version_manager.cc
index 2068b76..f9843df 100644
--- a/system/audio_hal_interface/hal_version_manager.cc
+++ b/system/audio_hal_interface/hal_version_manager.cc
@@ -112,7 +112,7 @@
"V2_1::IBluetoothAudioProvidersFactory::getService() failed");
log::info("V2_1::IBluetoothAudioProvidersFactory::getService() returned {}{}",
- fmt::ptr(providers_factory.get()),
+ std::format_ptr(providers_factory.get()),
(providers_factory->isRemote() ? " (remote)" : " (local)"));
return providers_factory;
}
@@ -129,7 +129,7 @@
"V2_0::IBluetoothAudioProvidersFactory::getService() failed");
log::info("V2_0::IBluetoothAudioProvidersFactory::getService() returned {}{}",
- fmt::ptr(providers_factory.get()),
+ std::format_ptr(providers_factory.get()),
(providers_factory->isRemote() ? " (remote)" : " (local)"));
guard.unlock();
return providers_factory;
diff --git a/system/audio_hal_interface/hidl/a2dp_encoding_hidl.cc b/system/audio_hal_interface/hidl/a2dp_encoding_hidl.cc
index 2926e73..62d5178 100644
--- a/system/audio_hal_interface/hidl/a2dp_encoding_hidl.cc
+++ b/system/audio_hal_interface/hidl/a2dp_encoding_hidl.cc
@@ -39,14 +39,14 @@
A2DP_CTRL_GET_PRESENTATION_POSITION,
} tA2DP_CTRL_CMD;
-namespace fmt {
+namespace std {
template <>
struct formatter<tA2DP_CTRL_CMD> : enum_formatter<tA2DP_CTRL_CMD> {};
template <>
struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {};
template <>
struct formatter<audio_content_type_t> : enum_formatter<audio_content_type_t> {};
-} // namespace fmt
+} // namespace std
namespace bluetooth {
namespace audio {
diff --git a/system/audio_hal_interface/hidl/client_interface_hidl.cc b/system/audio_hal_interface/hidl/client_interface_hidl.cc
index c698727..4bea626 100644
--- a/system/audio_hal_interface/hidl/client_interface_hidl.cc
+++ b/system/audio_hal_interface/hidl/client_interface_hidl.cc
@@ -314,7 +314,7 @@
}
log::info("IBluetoothAudioProvidersFactory::openProvider() returned {}{}",
- fmt::ptr(provider_.get()), (provider_->isRemote() ? " (remote)" : " (local)"));
+ std::format_ptr(provider_.get()), (provider_->isRemote() ? " (remote)" : " (local)"));
}
void BluetoothAudioClientInterface::FetchAudioProvider_2_1() {
@@ -376,7 +376,8 @@
}
log::info("IBluetoothAudioProvidersFactory::openProvider() returned {}{}",
- fmt::ptr(provider_2_1_.get()), (provider_2_1_->isRemote() ? " (remote)" : " (local)"));
+ std::format_ptr(provider_2_1_.get()),
+ (provider_2_1_->isRemote() ? " (remote)" : " (local)"));
}
BluetoothAudioSinkClientInterface::BluetoothAudioSinkClientInterface(
diff --git a/system/audio_hal_interface/hidl/client_interface_hidl.h b/system/audio_hal_interface/hidl/client_interface_hidl.h
index 09a9165..39347e7 100644
--- a/system/audio_hal_interface/hidl/client_interface_hidl.h
+++ b/system/audio_hal_interface/hidl/client_interface_hidl.h
@@ -266,8 +266,8 @@
} // namespace audio
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::audio::hidl::BluetoothAudioCtrlAck>
: enum_formatter<bluetooth::audio::hidl::BluetoothAudioCtrlAck> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc b/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc
index f80aac6..b745914 100644
--- a/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc
+++ b/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc
@@ -24,12 +24,12 @@
#include "client_interface_hidl.h"
#include "osi/include/properties.h"
-namespace fmt {
+namespace std {
template <>
struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {};
template <>
struct formatter<audio_content_type_t> : enum_formatter<audio_content_type_t> {};
-} // namespace fmt
+} // namespace std
namespace {
diff --git a/system/bta/ag/bta_ag_cmd.cc b/system/bta/ag/bta_ag_cmd.cc
index f5a09ec..af1df17 100644
--- a/system/bta/ag/bta_ag_cmd.cc
+++ b/system/bta/ag/bta_ag_cmd.cc
@@ -225,7 +225,7 @@
*p++ = '\n';
/* copy result code string */
- strlcpy(p, result->result_string, sizeof(buf) - 2);
+ osi_strlcpy(p, result->result_string, sizeof(buf) - 2);
if (p_scb->conn_service == BTA_AG_HSP) {
/* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
@@ -541,7 +541,7 @@
/* Add EOF */
trim_data[j] = '\0';
str_leng = str_leng - 4;
- strlcpy(unat_result, trim_data, str_leng + 1);
+ osi_strlcpy(unat_result, trim_data, str_leng + 1);
j = 0;
if (str_leng < 4) {
@@ -621,7 +621,7 @@
bta_ag_send_error(p_scb, BTA_AG_ERR_TEXT_TOO_LONG);
return;
}
- strlcpy(val.str, p_arg, sizeof(val.str));
+ osi_strlcpy(val.str, p_arg, sizeof(val.str));
/* call callback with event */
if (command_id & 0xff00) {
@@ -899,7 +899,7 @@
bta_ag_send_error(p_scb, BTA_AG_ERR_TEXT_TOO_LONG);
return;
}
- strlcpy(val.str, p_arg, sizeof(val.str));
+ osi_strlcpy(val.str, p_arg, sizeof(val.str));
/**
* Unless this this is a local event, by default we'll forward
@@ -1397,7 +1397,7 @@
val.hdr.app_id = p_scb->app_id;
val.hdr.status = BTA_AG_SUCCESS;
val.num = 0;
- strlcpy(val.str, p_arg, sizeof(val.str));
+ osi_strlcpy(val.str, p_arg, sizeof(val.str));
(*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG*)&val);
} else {
bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
diff --git a/system/bta/ag/bta_ag_int.h b/system/bta/ag/bta_ag_int.h
index 21d3936..ce9ff62 100644
--- a/system/bta/ag/bta_ag_int.h
+++ b/system/bta/ag/bta_ag_int.h
@@ -476,11 +476,11 @@
*/
void bta_ag_stream_suspended();
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_AG_SCO_APTX_SWB_SETTINGS> : enum_formatter<tBTA_AG_SCO_APTX_SWB_SETTINGS> {};
template <>
struct formatter<tBTA_AG_SCO> : enum_formatter<tBTA_AG_SCO> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_AG_INT_H */
diff --git a/system/bta/ag/bta_ag_main.cc b/system/bta/ag/bta_ag_main.cc
index a1143a5..2b95b5d 100644
--- a/system/bta/ag/bta_ag_main.cc
+++ b/system/bta/ag/bta_ag_main.cc
@@ -491,7 +491,7 @@
data.api_register.app_id = app_id;
for (int i = 0; i < BTA_AG_NUM_IDX; i++) {
if (!service_names[i].empty()) {
- strlcpy(data.api_register.p_name[i], service_names[i].c_str(), BTA_SERVICE_NAME_LEN);
+ osi_strlcpy(data.api_register.p_name[i], service_names[i].c_str(), BTA_SERVICE_NAME_LEN);
} else {
data.api_register.p_name[i][0] = 0;
}
diff --git a/system/bta/ag/bta_ag_rfc.cc b/system/bta/ag/bta_ag_rfc.cc
index 46b26b1..1943492 100644
--- a/system/bta/ag/bta_ag_rfc.cc
+++ b/system/bta/ag/bta_ag_rfc.cc
@@ -107,7 +107,7 @@
static void bta_ag_mgmt_cback(const tPORT_RESULT code, uint16_t port_handle, uint16_t handle) {
tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle);
log::verbose("code={}, port_handle={}, scb_handle={}, p_scb=0x{}", code, port_handle, handle,
- fmt::ptr(p_scb));
+ std::format_ptr(p_scb));
if (p_scb == nullptr) {
log::warn("cannot find scb, code={}, port_handle={}, handle={}", code, port_handle, handle);
return;
@@ -262,10 +262,10 @@
log::error(
"RFCOMM_CreateConnectionWithSecurity ERROR {}, p_scb={}, "
"services=0x{:x}, mgmt_cback_index={}",
- status, fmt::ptr(p_scb), services, management_callback_index);
+ status, std::format_ptr(p_scb), services, management_callback_index);
}
- log::verbose("p_scb=0x{}, services=0x{:04x}, mgmt_cback_index={}", fmt::ptr(p_scb), services,
- management_callback_index);
+ log::verbose("p_scb=0x{}, services=0x{:04x}, mgmt_cback_index={}", std::format_ptr(p_scb),
+ services, management_callback_index);
}
}
}
@@ -332,7 +332,7 @@
bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU, p_scb->peer_addr,
&(p_scb->conn_handle), bta_ag_mgmt_cback_tbl[management_callback_index],
BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
- log::verbose("p_scb=0x{}, conn_handle={}, mgmt_cback_index={}, status={}", fmt::ptr(p_scb),
+ log::verbose("p_scb=0x{}, conn_handle={}, mgmt_cback_index={}, status={}", std::format_ptr(p_scb),
p_scb->conn_handle, management_callback_index, status);
if (status == PORT_SUCCESS) {
bta_ag_setup_port(p_scb, p_scb->conn_handle);
diff --git a/system/bta/aics/include/aics/api.h b/system/bta/aics/include/aics/api.h
index b81132e..7eb76e5 100644
--- a/system/bta/aics/include/aics/api.h
+++ b/system/bta/aics/include/aics/api.h
@@ -51,9 +51,9 @@
GainMode parseGainModeField(uint8_t data);
} // namespace bluetooth::aics
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::aics::Mute> : enum_formatter<bluetooth::aics::Mute> {};
template <>
struct formatter<bluetooth::aics::GainMode> : enum_formatter<bluetooth::aics::GainMode> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc
index 0099c33..0378be7 100644
--- a/system/bta/av/bta_av_aact.cc
+++ b/system/bta/av/bta_av_aact.cc
@@ -367,7 +367,7 @@
uint16_t sec_len = 0;
log::verbose("peer_address: {} avdt_handle: {} event=0x{:x} scb_index={} p_scb={}", bd_addr,
- handle, event, scb_index, fmt::ptr(p_scb));
+ handle, event, scb_index, std::format_ptr(p_scb));
if (p_data) {
if (event == AVDT_SECURITY_IND_EVT) {
@@ -1926,7 +1926,7 @@
BT_HDR* p_buf;
log::info("peer {} bta_handle:0x{:x} audio_open_cnt:{}, p_data {} start:{}", p_scb->PeerAddress(),
- p_scb->hndl, bta_av_cb.audio_open_cnt, fmt::ptr(p_data), start);
+ p_scb->hndl, bta_av_cb.audio_open_cnt, std::format_ptr(p_data), start);
bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
BTM_unblock_role_switch_and_sniff_mode_for(p_scb->PeerAddress());
diff --git a/system/bta/av/bta_av_api.cc b/system/bta/av/bta_av_api.cc
index 8a47678..0f2fcbd 100644
--- a/system/bta/av/bta_av_api.cc
+++ b/system/bta/av/bta_av_api.cc
@@ -119,7 +119,7 @@
p_buf->hdr.layer_specific = chnl;
p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
if (p_service_name) {
- strlcpy(p_buf->p_service_name, p_service_name, BTA_SERVICE_NAME_LEN);
+ osi_strlcpy(p_buf->p_service_name, p_service_name, BTA_SERVICE_NAME_LEN);
} else {
p_buf->p_service_name[0] = 0;
}
diff --git a/system/bta/av/bta_av_int.h b/system/bta/av/bta_av_int.h
index 7d98cf2..c9c176c 100644
--- a/system/bta/av/bta_av_int.h
+++ b/system/bta/av/bta_av_int.h
@@ -807,9 +807,9 @@
void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
void bta_av_api_set_peer_sep(tBTA_AV_DATA* p_data);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_AV_RS_RES> : enum_formatter<tBTA_AV_RS_RES> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_AV_INT_H */
diff --git a/system/bta/av/bta_av_ssm.cc b/system/bta/av/bta_av_ssm.cc
index 84d9561..cbf83f5 100644
--- a/system/bta/av/bta_av_ssm.cc
+++ b/system/bta/av/bta_av_ssm.cc
@@ -440,13 +440,13 @@
if (previous_state != p_scb->state) {
log::info("peer {} p_scb={:#x}({}) AV event=0x{:x}({}) state={}({}) -> {}({})",
- p_scb->PeerAddress(), p_scb->hndl, fmt::ptr(p_scb), event, bta_av_evt_code(event),
- previous_state, bta_av_sst_code(previous_state), p_scb->state,
+ p_scb->PeerAddress(), p_scb->hndl, std::format_ptr(p_scb), event,
+ bta_av_evt_code(event), previous_state, bta_av_sst_code(previous_state), p_scb->state,
bta_av_sst_code(p_scb->state));
} else {
log::verbose("peer {} p_scb={:#x}({}) AV event=0x{:x}({}) state={}({})", p_scb->PeerAddress(),
- p_scb->hndl, fmt::ptr(p_scb), event, bta_av_evt_code(event), p_scb->state,
+ p_scb->hndl, std::format_ptr(p_scb), event, bta_av_evt_code(event), p_scb->state,
bta_av_sst_code(p_scb->state));
}
@@ -521,7 +521,7 @@
log::verbose("peer {} AV (hndl=0x{:x}) state={}({}) next state={}({}) p_scb={}",
p_scb->PeerAddress(), p_scb->hndl, p_scb->state, bta_av_sst_code(p_scb->state),
- next_state, bta_av_sst_code(next_state), fmt::ptr(p_scb));
+ next_state, bta_av_sst_code(next_state), std::format_ptr(p_scb));
p_scb->state = next_state;
}
diff --git a/system/bta/csis/csis_client.cc b/system/bta/csis/csis_client.cc
index d87dbb6..d38a232 100644
--- a/system/bta/csis/csis_client.cc
+++ b/system/bta/csis/csis_client.cc
@@ -19,6 +19,7 @@
#include <base/functional/callback.h>
#include <base/strings/string_number_conversions.h>
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <hardware/bt_csis.h>
#include <hardware/bt_gatt_types.h>
#include <stdio.h>
@@ -1918,7 +1919,9 @@
device->connecting_actively = false;
device->conn_id = evt.conn_id;
-
+ if (com::android::bluetooth::flags::gatt_queue_cleanup_connected()) {
+ BtaGattQueue::Clean(evt.conn_id);
+ }
/* Verify bond */
if (BTM_SecIsSecurityPending(device->addr)) {
/* if security collision happened, wait for encryption done
diff --git a/system/bta/dm/bta_dm_device_search.cc b/system/bta/dm/bta_dm_device_search.cc
index c80f763..7c2c30e 100644
--- a/system/bta/dm/bta_dm_device_search.cc
+++ b/system/bta/dm/bta_dm_device_search.cc
@@ -490,8 +490,9 @@
bta_dm_search_cb.peer_bdaddr = remote_bd_addr;
log::verbose("name_discover_done = {} p_btm_inq_info 0x{} state = {}, transport={}",
- bta_dm_search_cb.name_discover_done, fmt::ptr(bta_dm_search_cb.p_btm_inq_info),
- bta_dm_search_get_state(), transport);
+ bta_dm_search_cb.name_discover_done,
+ std::format_ptr(bta_dm_search_cb.p_btm_inq_info), bta_dm_search_get_state(),
+ transport);
if (bta_dm_search_cb.p_btm_inq_info) {
log::verbose("appl_knows_rem_name {}", bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);
diff --git a/system/bta/dm/bta_dm_device_search_int.h b/system/bta/dm/bta_dm_device_search_int.h
index 68df101..28e3fda 100644
--- a/system/bta/dm/bta_dm_device_search_int.h
+++ b/system/bta/dm/bta_dm_device_search_int.h
@@ -90,9 +90,9 @@
tBTA_DM_SEARCH_CBACK* p_csis_scan_cback;
} tBTA_DM_SEARCH_CB;
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_DM_DEV_SEARCH_EVT> : enum_formatter<tBTA_DM_DEV_SEARCH_EVT> {};
template <>
struct formatter<tBTA_DM_DEVICE_SEARCH_STATE> : enum_formatter<tBTA_DM_DEVICE_SEARCH_STATE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/dm/bta_dm_disc_int.h b/system/bta/dm/bta_dm_disc_int.h
index df8d2f2..6c89f89 100644
--- a/system/bta/dm/bta_dm_disc_int.h
+++ b/system/bta/dm/bta_dm_disc_int.h
@@ -131,10 +131,10 @@
void bta_dm_sdp_received_di(const RawAddress& bd_addr, tSDP_DI_GET_RECORD& di_record);
#endif
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_DM_DISC_EVT> : enum_formatter<tBTA_DM_DISC_EVT> {};
template <>
struct formatter<tBTA_DM_SERVICE_DISCOVERY_STATE>
: enum_formatter<tBTA_DM_SERVICE_DISCOVERY_STATE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/dm/bta_dm_disc_sdp.cc b/system/bta/dm/bta_dm_disc_sdp.cc
index f4b1b13..588e7af 100644
--- a/system/bta/dm/bta_dm_disc_sdp.cc
+++ b/system/bta/dm/bta_dm_disc_sdp.cc
@@ -264,7 +264,7 @@
// Copy the raw_data to the discovery result structure
if (p_sdp_db != NULL && p_sdp_db->raw_used != 0 && p_sdp_db->raw_data != NULL) {
log::verbose("raw_data used = 0x{:x} raw_data_ptr = 0x{}", p_sdp_db->raw_used,
- fmt::ptr(p_sdp_db->raw_data));
+ std::format_ptr(p_sdp_db->raw_data));
p_sdp_db->raw_data = NULL; // no need to free this - it is a global assigned.
p_sdp_db->raw_used = 0;
diff --git a/system/bta/dm/bta_dm_int.h b/system/bta/dm/bta_dm_int.h
index d775755..e79facd 100644
--- a/system/bta/dm/bta_dm_int.h
+++ b/system/bta/dm/bta_dm_int.h
@@ -365,9 +365,9 @@
uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num,
uint16_t timeout);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_DM_CONN_STATE> : enum_formatter<tBTA_DM_CONN_STATE> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_DM_INT_H */
diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc
index c1a8e95..37ecf8f 100644
--- a/system/bta/gatt/bta_gattc_act.cc
+++ b/system/bta/gatt/bta_gattc_act.cc
@@ -837,7 +837,8 @@
bta_gattc_send_mtu_response(p_clcb, p_data, current_mtu);
return;
case MTU_EXCHANGE_IN_PROGRESS:
- log::info("Enqueue MTU Request - waiting for response on p_clcb {}", fmt::ptr(p_clcb));
+ log::info("Enqueue MTU Request - waiting for response on p_clcb {}",
+ std::format_ptr(p_clcb));
/* MTU request is in progress and this one will not be sent to remote
* device. Just push back on the queue and response will be sent up to
* the upper layer when MTU Exchange will be completed.
@@ -1358,7 +1359,7 @@
auto outstanding_conn_ids = GATTC_GetAndRemoveListOfConnIdsWaitingForMtuRequest(p_clcb->bda);
for (auto conn_id : outstanding_conn_ids) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
- log::debug("Continue MTU request clcb {}", fmt::ptr(p_clcb));
+ log::debug("Continue MTU request clcb {}", std::format_ptr(p_clcb));
if (p_clcb) {
log::debug("Continue MTU request for client conn_id=0x{:04x}", conn_id);
bta_gattc_continue(p_clcb);
diff --git a/system/bta/gatt/bta_gattc_int.h b/system/bta/gatt/bta_gattc_int.h
index 070e9c5..1bfd741 100644
--- a/system/bta/gatt/bta_gattc_int.h
+++ b/system/bta/gatt/bta_gattc_int.h
@@ -532,7 +532,7 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_GATTC_CB_STATE> : enum_formatter<tBTA_GATTC_CB_STATE> {};
template <>
@@ -541,6 +541,6 @@
struct formatter<tBTA_GATTC_STATE> : enum_formatter<tBTA_GATTC_STATE> {};
template <>
struct formatter<RobustCachingSupport> : enum_formatter<RobustCachingSupport> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_GATTC_INT_H */
diff --git a/system/bta/gatt/bta_gattc_utils.cc b/system/bta/gatt/bta_gattc_utils.cc
index 70f528e..cf07f89 100644
--- a/system/bta/gatt/bta_gattc_utils.cc
+++ b/system/bta/gatt/bta_gattc_utils.cc
@@ -515,7 +515,7 @@
/* Handled, free command below and continue with a p_q_cmd_queue */
break;
case MTU_EXCHANGE_IN_PROGRESS:
- log::warn("Waiting p_clcb {}", fmt::ptr(p_clcb));
+ log::warn("Waiting p_clcb {}", std::format_ptr(p_clcb));
return;
case MTU_EXCHANGE_NOT_DONE_YET:
p_clcb->p_q_cmd_queue.pop_front();
diff --git a/system/bta/has/has_client.cc b/system/bta/has/has_client.cc
index 1c74e1f..74873bd 100644
--- a/system/bta/has/has_client.cc
+++ b/system/bta/has/has_client.cc
@@ -2008,7 +2008,9 @@
}
device->conn_id = evt.conn_id;
-
+ if (com::android::bluetooth::flags::gatt_queue_cleanup_connected()) {
+ BtaGattQueue::Clean(evt.conn_id);
+ }
if (BTM_SecIsSecurityPending(device->addr)) {
/* if security collision happened, wait for encryption done
* (BTA_GATTC_ENC_CMPL_CB_EVT)
diff --git a/system/bta/has/has_ctp.h b/system/bta/has/has_ctp.h
index 3de5b46..4b62426 100644
--- a/system/bta/has/has_ctp.h
+++ b/system/bta/has/has_ctp.h
@@ -257,9 +257,9 @@
} // namespace has
} // namespace bluetooth::le_audio
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::has::HasCtpNtf> : ostream_formatter {};
template <>
struct formatter<bluetooth::le_audio::has::HasCtpOp> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/has/has_preset.h b/system/bta/has/has_preset.h
index 48c6185..60d8942 100644
--- a/system/bta/has/has_preset.h
+++ b/system/bta/has/has_preset.h
@@ -99,7 +99,7 @@
} // namespace has
} // namespace bluetooth::le_audio
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::has::HasPreset> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/has/has_types.h b/system/bta/has/has_types.h
index 5041838..2a72098 100644
--- a/system/bta/has/has_types.h
+++ b/system/bta/has/has_types.h
@@ -402,7 +402,7 @@
} // namespace has
} // namespace bluetooth::le_audio
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::has::HasDevice> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/hd/bta_hd_api.cc b/system/bta/hd/bta_hd_api.cc
index aa42481..336c24e 100644
--- a/system/bta/hd/bta_hd_api.cc
+++ b/system/bta/hd/bta_hd_api.cc
@@ -111,19 +111,19 @@
p_buf->hdr.event = BTA_HD_API_REGISTER_APP_EVT;
if (p_app_info->p_name) {
- strlcpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
+ osi_strlcpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
} else {
p_buf->name[0] = '\0';
}
if (p_app_info->p_description) {
- strlcpy(p_buf->description, p_app_info->p_description, BTA_HD_APP_DESCRIPTION_LEN);
+ osi_strlcpy(p_buf->description, p_app_info->p_description, BTA_HD_APP_DESCRIPTION_LEN);
} else {
p_buf->description[0] = '\0';
}
if (p_app_info->p_provider) {
- strlcpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
+ osi_strlcpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
} else {
p_buf->provider[0] = '\0';
}
diff --git a/system/bta/hearing_aid/hearing_aid.cc b/system/bta/hearing_aid/hearing_aid.cc
index 9838ebd..e27b420 100644
--- a/system/bta/hearing_aid/hearing_aid.cc
+++ b/system/bta/hearing_aid/hearing_aid.cc
@@ -524,6 +524,10 @@
hearingDevice->conn_id = conn_id;
+ if (com::android::bluetooth::flags::gatt_queue_cleanup_connected()) {
+ BtaGattQueue::Clean(conn_id);
+ }
+
uint64_t hi_sync_id = hearingDevice->hi_sync_id;
// If there a background connection to the other device of a pair, promote
@@ -1705,7 +1709,7 @@
if (!strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp)) {
log::error("strftime fails. tm_sec={}, tm_min={}, tm_hour={}", tstamp->tm_sec,
tstamp->tm_min, tstamp->tm_hour);
- strlcpy(temptime, "UNKNOWN TIME", sizeof(temptime));
+ osi_strlcpy(temptime, "UNKNOWN TIME", sizeof(temptime));
}
snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime,
rssi_logs.timestamp.tv_nsec / 1000000);
diff --git a/system/bta/hearing_aid/hearing_aid_audio_source.cc b/system/bta/hearing_aid/hearing_aid_audio_source.cc
index 6ea05e7..d1d45d5 100644
--- a/system/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/system/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -42,14 +42,14 @@
using namespace bluetooth;
-namespace fmt {
+namespace std {
template <>
struct formatter<tUIPC_EVENT> : enum_formatter<tUIPC_EVENT> {};
template <>
struct formatter<tHEARING_AID_CTRL_ACK> : enum_formatter<tHEARING_AID_CTRL_ACK> {};
template <>
struct formatter<tHEARING_AID_CTRL_CMD> : enum_formatter<tHEARING_AID_CTRL_CMD> {};
-} // namespace fmt
+} // namespace std
namespace {
#define CASE_RETURN_STR(const) \
diff --git a/system/bta/hf_client/bta_hf_client_api.cc b/system/bta/hf_client/bta_hf_client_api.cc
index 65c4fce..6c9ca68 100644
--- a/system/bta/hf_client/bta_hf_client_api.cc
+++ b/system/bta/hf_client/bta_hf_client_api.cc
@@ -186,7 +186,7 @@
p_buf->uint32_val2 = val2;
if (str) {
- strlcpy(p_buf->str, str, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ osi_strlcpy(p_buf->str, str, BTA_HF_CLIENT_NUMBER_LEN + 1);
p_buf->str[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
} else {
p_buf->str[0] = '\0';
diff --git a/system/bta/hf_client/bta_hf_client_at.cc b/system/bta/hf_client/bta_hf_client_at.cc
index f002fbf..700e4ab 100644
--- a/system/bta/hf_client/bta_hf_client_at.cc
+++ b/system/bta/hf_client/bta_hf_client_at.cc
@@ -662,7 +662,7 @@
memset(&evt, 0, sizeof(evt));
- strlcpy(evt.operator_name.name, name, BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1);
+ osi_strlcpy(evt.operator_name.name, name, BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1);
evt.operator_name.name[BTA_HF_CLIENT_OPERATOR_NAME_LEN] = '\0';
evt.operator_name.bd_addr = client_cb->peer_addr;
@@ -684,7 +684,7 @@
memset(&evt, 0, sizeof(evt));
- strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ osi_strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
evt.number.bd_addr = client_cb->peer_addr;
@@ -706,7 +706,7 @@
memset(&evt, 0, sizeof(evt));
- strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ osi_strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
evt.number.bd_addr = client_cb->peer_addr;
@@ -759,7 +759,7 @@
if (number) {
evt.clcc.number_present = true;
- strlcpy(evt.clcc.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ osi_strlcpy(evt.clcc.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
evt.clcc.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
}
@@ -781,7 +781,7 @@
tBTA_HF_CLIENT evt = {};
evt.cnum.service = service;
- strlcpy(evt.cnum.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ osi_strlcpy(evt.cnum.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
evt.cnum.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
evt.cnum.bd_addr = client_cb->peer_addr;
@@ -791,7 +791,7 @@
void bta_hf_client_unknown_response(tBTA_HF_CLIENT_CB* client_cb, const char* evt_buffer) {
tBTA_HF_CLIENT evt = {};
- strlcpy(evt.unknown.event_string, evt_buffer, BTA_HF_CLIENT_UNKNOWN_EVENT_LEN + 1);
+ osi_strlcpy(evt.unknown.event_string, evt_buffer, BTA_HF_CLIENT_UNKNOWN_EVENT_LEN + 1);
evt.unknown.event_string[BTA_HF_CLIENT_UNKNOWN_EVENT_LEN] = '\0';
evt.unknown.bd_addr = client_cb->peer_addr;
@@ -813,7 +813,7 @@
memset(&evt, 0, sizeof(evt));
- strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ osi_strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
evt.number.bd_addr = client_cb->peer_addr;
@@ -1517,7 +1517,7 @@
char tmp_buf[BTA_HF_CLIENT_UNKNOWN_EVENT_LEN];
if (evt_size < BTA_HF_CLIENT_UNKNOWN_EVENT_LEN) {
- strlcpy(tmp_buf, start, evt_size);
+ osi_strlcpy(tmp_buf, start, evt_size);
bta_hf_client_unknown_response(client_cb, tmp_buf);
AT_CHECK_RN(end);
} else {
diff --git a/system/bta/hh/bta_hh_int.h b/system/bta/hh/bta_hh_int.h
index 2f9f502..2e5e185 100644
--- a/system/bta/hh/bta_hh_int.h
+++ b/system/bta/hh/bta_hh_int.h
@@ -325,9 +325,9 @@
void bta_hh_trace_dev_db(void);
#endif
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_HH_SERVICE_STATE> : enum_formatter<tBTA_HH_SERVICE_STATE> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/bta/include/bta_ag_api.h b/system/bta/include/bta_ag_api.h
index 04c5b66..5aa525c 100644
--- a/system/bta/include/bta_ag_api.h
+++ b/system/bta/include/bta_ag_api.h
@@ -647,9 +647,9 @@
void BTA_AgSetActiveDevice(const RawAddress& active_device_addr);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_AG_RES> : enum_formatter<tBTA_AG_RES> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_AG_API_H */
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index fbdf277..a0b9e2c 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -847,13 +847,13 @@
void DumpsysBtaDm(int fd);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_DM_SEARCH_EVT> : enum_formatter<tBTA_DM_SEARCH_EVT> {};
template <>
struct formatter<tBTA_DM_ACL_EVT> : enum_formatter<tBTA_DM_ACL_EVT> {};
template <>
struct formatter<tBTA_PREF_ROLES> : enum_formatter<tBTA_PREF_ROLES> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_API_H */
diff --git a/system/bta/include/bta_api_data_types.h b/system/bta/include/bta_api_data_types.h
index aa41dd3..1498374 100644
--- a/system/bta/include/bta_api_data_types.h
+++ b/system/bta/include/bta_api_data_types.h
@@ -63,7 +63,7 @@
RawAddress bd_addr;
} tBTA_DM_KEY_MISSING;
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_STATUS> : enum_formatter<tBTA_STATUS> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/include/bta_gatt_api.h b/system/bta/include/bta_gatt_api.h
index ba60da6..8a8a91d 100644
--- a/system/bta/include/bta_gatt_api.h
+++ b/system/bta/include/bta_gatt_api.h
@@ -1044,9 +1044,9 @@
// Adds bonded device for GATT server tracking service changes
void BTA_GATTS_InitBonded(void);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_GATTC_EVT> : enum_formatter<tBTA_GATTC_EVT> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_GATT_API_H */
diff --git a/system/bta/include/bta_hearing_aid_api.h b/system/bta/include/bta_hearing_aid_api.h
index 19e89f5..7314d2e 100644
--- a/system/bta/include/bta_hearing_aid_api.h
+++ b/system/bta/include/bta_hearing_aid_api.h
@@ -282,7 +282,7 @@
static void DebugDump(int fd);
};
-namespace fmt {
+namespace std {
template <>
struct formatter<connection_update_status_t> : enum_formatter<connection_update_status_t> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/include/bta_hh_api.h b/system/bta/include/bta_hh_api.h
index e59f80a..976c7d2 100644
--- a/system/bta/include/bta_hh_api.h
+++ b/system/bta/include/bta_hh_api.h
@@ -561,8 +561,8 @@
******************************************************************************/
void BTA_HhDump(int fd);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_HH_STATUS> : enum_formatter<tBTA_HH_STATUS> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_HH_API_H */
diff --git a/system/bta/include/bta_jv_api.h b/system/bta/include/bta_jv_api.h
index 1809bf9..4b43cbc 100644
--- a/system/bta/include/bta_jv_api.h
+++ b/system/bta/include/bta_jv_api.h
@@ -148,10 +148,10 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_JV_CONN_STATE> : enum_formatter<tBTA_JV_CONN_STATE> {};
-} // namespace fmt
+} // namespace std
/* JV Connection types */
enum class tBTA_JV_CONN_TYPE {
@@ -171,10 +171,10 @@
RETURN_UNKNOWN_TYPE_STRING(tBTA_JV_CONN_TYPE, type);
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_JV_CONN_TYPE> : enum_formatter<tBTA_JV_CONN_TYPE> {};
-} // namespace fmt
+} // namespace std
enum tBTA_JV_EVT : uint16_t {
/* Java I/F callback events */
diff --git a/system/bta/include/bta_sec_api.h b/system/bta/include/bta_sec_api.h
index 7446e72..a0f431f 100644
--- a/system/bta/include/bta_sec_api.h
+++ b/system/bta/include/bta_sec_api.h
@@ -484,7 +484,7 @@
******************************************************************************/
void BTA_DmSirkConfirmDeviceReply(const RawAddress& bd_addr, bool accept);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_DM_SEC_EVT> : enum_formatter<tBTA_DM_SEC_EVT> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/jv/bta_jv_act.cc b/system/bta/jv/bta_jv_act.cc
index 20e57bd..9d47152 100644
--- a/system/bta/jv/bta_jv_act.cc
+++ b/system/bta/jv/bta_jv_act.cc
@@ -308,7 +308,7 @@
return tBTA_JV_STATUS::FAILURE;
}
log::verbose("max_sess={}, curr_sess={}, p_pcb={}, user={}, state={}, jv handle=0x{:x}",
- p_cb->max_sess, p_cb->curr_sess, fmt::ptr(p_pcb), p_pcb->rfcomm_slot_id,
+ p_cb->max_sess, p_cb->curr_sess, std::format_ptr(p_pcb), p_pcb->rfcomm_slot_id,
p_pcb->state, p_pcb->handle);
if (p_cb->curr_sess <= 0) {
@@ -319,7 +319,7 @@
case BTA_JV_ST_CL_CLOSING:
case BTA_JV_ST_SR_CLOSING:
log::warn("return on closing, port state={}, scn={}, p_pcb={}, user_data={}", p_pcb->state,
- p_cb->scn, fmt::ptr(p_pcb), p_pcb->rfcomm_slot_id);
+ p_cb->scn, std::format_ptr(p_pcb), p_pcb->rfcomm_slot_id);
status = tBTA_JV_STATUS::FAILURE;
return status;
case BTA_JV_ST_CL_OPEN:
@@ -343,7 +343,7 @@
log::warn(
"failed, ignore port state= {}, scn={}, p_pcb= {}, jv handle=0x{:x}, "
"port_handle={}, user_data={}",
- p_pcb->state, p_cb->scn, fmt::ptr(p_pcb), p_pcb->handle, p_pcb->port_handle,
+ p_pcb->state, p_cb->scn, std::format_ptr(p_pcb), p_pcb->handle, p_pcb->port_handle,
p_pcb->rfcomm_slot_id);
status = tBTA_JV_STATUS::FAILURE;
break;
@@ -560,7 +560,7 @@
}
}
log::verbose("handle=0x{:x}, app_id={}, idx={}, BTA_JV_PM_MAX_NUM={}, pp_cb={}", jv_handle,
- app_id, i, BTA_JV_PM_MAX_NUM, fmt::ptr(pp_cb));
+ app_id, i, BTA_JV_PM_MAX_NUM, std::format_ptr(pp_cb));
break;
}
}
@@ -827,7 +827,8 @@
tSDP_DISC_REC* p_sdp_rec = NULL;
p_sdp_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb(
p_bta_jv_cfg->p_sdp_db, bta_jv_cb.sdp_cb.uuid, p_sdp_rec);
- log::verbose("bta_jv_cb.uuid={} p_sdp_rec={}", bta_jv_cb.sdp_cb.uuid, fmt::ptr(p_sdp_rec));
+ log::verbose("bta_jv_cb.uuid={} p_sdp_rec={}", bta_jv_cb.sdp_cb.uuid,
+ std::format_ptr(p_sdp_rec));
if (p_sdp_rec && get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec(
p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
bta_jv = {
@@ -1338,7 +1339,8 @@
static int bta_jv_port_data_co_cback(uint16_t port_handle, uint8_t* buf, uint16_t len, int type) {
tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
- log::verbose("p_cb={}, p_pcb={}, len={}, type={}", fmt::ptr(p_cb), fmt::ptr(p_pcb), len, type);
+ log::verbose("p_cb={}, p_pcb={}, len={}, type={}", std::format_ptr(p_cb), std::format_ptr(p_pcb),
+ len, type);
if (p_pcb != NULL) {
switch (type) {
case DATA_CO_CALLBACK_TYPE_INCOMING:
@@ -1588,13 +1590,13 @@
uint16_t lcid;
log::verbose("code={}, port_handle={}", code, port_handle);
if (NULL == p_cb || NULL == p_cb->p_cback) {
- log::error("p_cb={}, p_cb->p_cback={}", fmt::ptr(p_cb),
- fmt::ptr(p_cb ? p_cb->p_cback : nullptr));
+ log::error("p_cb={}, p_cb->p_cback={}", std::format_ptr(p_cb),
+ std::format_ptr(p_cb ? p_cb->p_cback : nullptr));
return;
}
uint32_t rfcomm_slot_id = p_pcb->rfcomm_slot_id;
log::verbose("code={}, port_handle=0x{:x}, handle=0x{:x}, p_pcb{}, user={}", code, port_handle,
- p_cb->handle, fmt::ptr(p_pcb), p_pcb->rfcomm_slot_id);
+ p_cb->handle, std::format_ptr(p_pcb), p_pcb->rfcomm_slot_id);
int status = PORT_CheckConnection(port_handle, &rem_bda, &lcid);
int failed = true;
@@ -1659,8 +1661,8 @@
tBTA_JV evt_data;
if (NULL == p_cb || NULL == p_cb->p_cback) {
- log::error("p_cb={}, p_cb->p_cback={}", fmt::ptr(p_cb),
- fmt::ptr(p_cb ? p_cb->p_cback : nullptr));
+ log::error("p_cb={}, p_cb->p_cback={}", std::format_ptr(p_cb),
+ std::format_ptr(p_cb ? p_cb->p_cback : nullptr));
return;
}
@@ -1861,7 +1863,7 @@
if (!find_rfc_pcb(rfcomm_slot_id, &p_cb, &p_pcb)) {
return;
}
- log::verbose("p_pcb={}, p_pcb->port_handle={}", fmt::ptr(p_pcb), p_pcb->port_handle);
+ log::verbose("p_pcb={}, p_pcb->port_handle={}", std::format_ptr(p_pcb), p_pcb->port_handle);
bta_jv_free_rfc_cb(p_cb, p_pcb);
}
@@ -1969,7 +1971,7 @@
******************************************************************************/
static void bta_jv_pm_state_change(tBTA_JV_PM_CB* p_cb, const tBTA_JV_CONN_STATE state) {
log::verbose("p_cb={}, handle=0x{:x}, busy/idle_state={}, app_id={}, conn_state={}",
- fmt::ptr(p_cb), p_cb->handle, p_cb->state, p_cb->app_id,
+ std::format_ptr(p_cb), p_cb->handle, p_cb->state, p_cb->app_id,
bta_jv_conn_state_text(state));
switch (state) {
diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc
index bcab997..8d5fbb1 100644
--- a/system/bta/le_audio/client.cc
+++ b/system/bta/le_audio/client.cc
@@ -213,10 +213,10 @@
return os;
}
-namespace fmt {
+namespace std {
template <>
struct formatter<AudioState> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
namespace {
void le_audio_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
@@ -828,7 +828,7 @@
}
}
- log::debug("New group {}, id: {}", fmt::ptr(new_group), new_group->group_id_);
+ log::debug("New group {}, id: {}", std::format_ptr(new_group), new_group->group_id_);
/* If device was in the group and it was not removed by the application,
* lets do it now
@@ -869,8 +869,8 @@
log::debug("group is null");
return;
}
- log::debug("Group {}, id: {}, size: {}, is cig_state {}", fmt::ptr(group), group->group_id_,
- group->Size(), ToString(group->cig.GetState()));
+ log::debug("Group {}, id: {}, size: {}, is cig_state {}", std::format_ptr(group),
+ group->group_id_, group->Size(), ToString(group->cig.GetState()));
if (group->IsEmpty() && (group->cig.GetState() == bluetooth::le_audio::types::CigState::NONE)) {
lastNotifiedGroupStreamStatusMap_.erase(group->group_id_);
aseGroups_.Remove(group->group_id_);
@@ -2309,6 +2309,9 @@
leAudioDevice->conn_id_ = conn_id;
leAudioDevice->mtu_ = mtu;
+ if (com::android::bluetooth::flags::gatt_queue_cleanup_connected()) {
+ BtaGattQueue::Clean(conn_id);
+ }
/* Remove device from the background connect (it might be either Allow list
* or TA) and add it again with reconnection_mode_. In case it is TA, we are
@@ -2688,7 +2691,8 @@
* issues
*/
if (group == nullptr || !group->IsEnabled()) {
- log::error("Group id {} ({}) disabled or null", leAudioDevice->group_id_, fmt::ptr(group));
+ log::error("Group id {} ({}) disabled or null", leAudioDevice->group_id_,
+ std::format_ptr(group));
return;
}
@@ -2802,7 +2806,7 @@
void OnServiceChangeEvent(const RawAddress& address) {
LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address);
if (!leAudioDevice) {
- log::warn("Skipping unknown leAudioDevice {} ({})", address, fmt::ptr(leAudioDevice));
+ log::warn("Skipping unknown leAudioDevice {} ({})", address, std::format_ptr(leAudioDevice));
return;
}
@@ -2861,7 +2865,7 @@
LeAudioDevice* leAudioDevice = leAudioDevices_.FindByAddress(address);
if (!leAudioDevice || (leAudioDevice->conn_id_ == GATT_INVALID_CONN_ID)) {
log::verbose("skipping unknown leAudioDevice, address {} ({})", address,
- fmt::ptr(leAudioDevice));
+ std::format_ptr(leAudioDevice));
return;
}
diff --git a/system/bta/le_audio/client_parser.h b/system/bta/le_audio/client_parser.h
index 1aaf4b3..e9e4756 100644
--- a/system/bta/le_audio/client_parser.h
+++ b/system/bta/le_audio/client_parser.h
@@ -22,6 +22,7 @@
#pragma once
+#include <memory>
#include <vector>
#include "le_audio_types.h"
diff --git a/system/bta/le_audio/codec_interface.h b/system/bta/le_audio/codec_interface.h
index 7e99fc9..8841bba 100644
--- a/system/bta/le_audio/codec_interface.h
+++ b/system/bta/le_audio/codec_interface.h
@@ -73,8 +73,8 @@
} // namespace bluetooth::le_audio
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::CodecInterface::Status>
: enum_formatter<bluetooth::le_audio::CodecInterface::Status> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/le_audio/codec_manager.cc b/system/bta/le_audio/codec_manager.cc
index eb0efb5..9977fec 100644
--- a/system/bta/le_audio/codec_manager.cc
+++ b/system/bta/le_audio/codec_manager.cc
@@ -211,8 +211,9 @@
bool UpdateActiveUnicastAudioHalClient(LeAudioSourceAudioHalClient* source_unicast_client,
LeAudioSinkAudioHalClient* sink_unicast_client,
bool is_active) {
- log::debug("local_source: {}, local_sink: {}, is_active: {}", fmt::ptr(source_unicast_client),
- fmt::ptr(sink_unicast_client), is_active);
+ log::debug("local_source: {}, local_sink: {}, is_active: {}",
+ std::format_ptr(source_unicast_client), std::format_ptr(sink_unicast_client),
+ is_active);
if (source_unicast_client == nullptr && sink_unicast_client == nullptr) {
return false;
@@ -221,13 +222,13 @@
if (is_active) {
if (source_unicast_client && unicast_local_source_hal_client != nullptr) {
log::error("Trying to override previous source hal client {}",
- fmt::ptr(unicast_local_source_hal_client));
+ std::format_ptr(unicast_local_source_hal_client));
return false;
}
if (sink_unicast_client && unicast_local_sink_hal_client != nullptr) {
log::error("Trying to override previous sink hal client {}",
- fmt::ptr(unicast_local_sink_hal_client));
+ std::format_ptr(unicast_local_sink_hal_client));
return false;
}
@@ -243,14 +244,16 @@
}
if (source_unicast_client && source_unicast_client != unicast_local_source_hal_client) {
- log::error("local source session does not match {} != {}", fmt::ptr(source_unicast_client),
- fmt::ptr(unicast_local_source_hal_client));
+ log::error("local source session does not match {} != {}",
+ std::format_ptr(source_unicast_client),
+ std::format_ptr(unicast_local_source_hal_client));
return false;
}
if (sink_unicast_client && sink_unicast_client != unicast_local_sink_hal_client) {
- log::error("local source session does not match {} != {}", fmt::ptr(sink_unicast_client),
- fmt::ptr(unicast_local_sink_hal_client));
+ log::error("local source session does not match {} != {}",
+ std::format_ptr(sink_unicast_client),
+ std::format_ptr(unicast_local_sink_hal_client));
return false;
}
@@ -267,7 +270,8 @@
bool UpdateActiveBroadcastAudioHalClient(LeAudioSourceAudioHalClient* source_broadcast_client,
bool is_active) {
- log::debug("local_source: {},is_active: {}", fmt::ptr(source_broadcast_client), is_active);
+ log::debug("local_source: {},is_active: {}", std::format_ptr(source_broadcast_client),
+ is_active);
if (source_broadcast_client == nullptr) {
return false;
@@ -276,7 +280,7 @@
if (is_active) {
if (broadcast_local_source_hal_client != nullptr) {
log::error("Trying to override previous source hal client {}",
- fmt::ptr(broadcast_local_source_hal_client));
+ std::format_ptr(broadcast_local_source_hal_client));
return false;
}
broadcast_local_source_hal_client = source_broadcast_client;
@@ -284,8 +288,9 @@
}
if (source_broadcast_client != broadcast_local_source_hal_client) {
- log::error("local source session does not match {} != {}", fmt::ptr(source_broadcast_client),
- fmt::ptr(broadcast_local_source_hal_client));
+ log::error("local source session does not match {} != {}",
+ std::format_ptr(source_broadcast_client),
+ std::format_ptr(broadcast_local_source_hal_client));
return false;
}
diff --git a/system/bta/le_audio/codec_manager.h b/system/bta/le_audio/codec_manager.h
index b41bb3b..1a86a9d 100644
--- a/system/bta/le_audio/codec_manager.h
+++ b/system/bta/le_audio/codec_manager.h
@@ -145,8 +145,8 @@
const CodecManager::UnicastConfigurationRequirements& req);
} // namespace bluetooth::le_audio
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::CodecManager::UnicastConfigurationRequirements>
: ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/le_audio/device_groups.cc b/system/bta/le_audio/device_groups.cc
index f1048b4..192f3e9 100644
--- a/system/bta/le_audio/device_groups.cc
+++ b/system/bta/le_audio/device_groups.cc
@@ -139,7 +139,7 @@
}
void LeAudioDeviceGroup::ClearSinksFromConfiguration(void) {
- log::info("Group {}, group_id {}", fmt::ptr(this), group_id_);
+ log::info("Group {}, group_id {}", std::format_ptr(this), group_id_);
auto direction = types::kLeAudioDirectionSink;
stream_conf.stream_params.get(direction).clear();
@@ -147,7 +147,7 @@
}
void LeAudioDeviceGroup::ClearSourcesFromConfiguration(void) {
- log::info("Group {}, group_id {}", fmt::ptr(this), group_id_);
+ log::info("Group {}, group_id {}", std::format_ptr(this), group_id_);
auto direction = types::kLeAudioDirectionSource;
stream_conf.stream_params.get(direction).clear();
@@ -1173,7 +1173,7 @@
}
uint8_t LeAudioDeviceGroup::CigConfiguration::GetFirstFreeCisId(CisType cis_type) const {
- log::info("Group: {}, group_id: {} cis_type: {}", fmt::ptr(group_), group_->group_id_,
+ log::info("Group: {}, group_id: {} cis_type: {}", std::format_ptr(group_), group_->group_id_,
static_cast<int>(cis_type));
for (size_t id = 0; id < cises.size(); id++) {
if (cises[id].addr.IsEmpty() && cises[id].type == cis_type) {
@@ -1243,7 +1243,7 @@
}
void LeAudioDeviceGroup::CigConfiguration::GenerateCisIds(LeAudioContextType context_type) {
- log::info("Group {}, group_id: {}, context_type: {}", fmt::ptr(group_), group_->group_id_,
+ log::info("Group {}, group_id: {}, context_type: {}", std::format_ptr(group_), group_->group_id_,
bluetooth::common::ToString(context_type));
if (cises.size() > 0) {
@@ -1439,7 +1439,7 @@
void LeAudioDeviceGroup::AssignCisConnHandlesToAses(LeAudioDevice* leAudioDevice) {
log::assert_that(leAudioDevice, "Invalid device");
- log::info("group: {}, group_id: {}, device: {}", fmt::ptr(this), group_id_,
+ log::info("group: {}, group_id: {}, device: {}", std::format_ptr(this), group_id_,
leAudioDevice->address_);
/* Assign all CIS connection handles to ases */
@@ -1470,7 +1470,7 @@
LeAudioDevice* leAudioDevice = GetFirstActiveDevice();
log::assert_that(leAudioDevice, "Shouldn't be called without an active device.");
- log::info("Group {}, group_id {}", fmt::ptr(this), group_id_);
+ log::info("Group {}, group_id {}", std::format_ptr(this), group_id_);
/* Assign all CIS connection handles to ases */
for (; leAudioDevice != nullptr; leAudioDevice = GetNextActiveDevice(leAudioDevice)) {
@@ -1482,7 +1482,7 @@
uint16_t conn_handle) {
log::assert_that(leAudioDevice, "Invalid device");
- log::info("Group {}, group_id {}, device: {}, conn_handle: {:#x}", fmt::ptr(group_),
+ log::info("Group {}, group_id {}, device: {}, conn_handle: {:#x}", std::format_ptr(group_),
group_->group_id_, leAudioDevice->address_, conn_handle);
for (struct bluetooth::le_audio::types::cis& cis_entry : cises) {
@@ -1747,8 +1747,9 @@
auto const max_required_device_cnt = NumOfAvailableForDirection(direction);
auto required_device_cnt = max_required_device_cnt;
- uint8_t active_ase_cnt = 0;
+ log::debug("Maximum {} device(s) required for {}", max_required_device_cnt, direction_str);
+ uint8_t active_ase_cnt = 0;
auto configuration_closure = [&](LeAudioDevice* dev) -> void {
/* For the moment, we configure only connected devices and when it is
* ready to stream i.e. All ASEs are discovered and dev is reported as
diff --git a/system/bta/le_audio/devices.cc b/system/bta/le_audio/devices.cc
index b5e9dee..e30ecbd 100644
--- a/system/bta/le_audio/devices.cc
+++ b/system/bta/le_audio/devices.cc
@@ -291,16 +291,17 @@
AudioLocations& group_audio_locations_memo,
const AudioContexts& metadata_context_types,
const std::vector<uint8_t>& ccid_lists, bool reuse_cis_id) {
+ auto direction_str = (direction == types::kLeAudioDirectionSink ? "Sink" : "Source");
/* First try to use the already configured ASE */
auto ase = GetFirstActiveAseByDirection(direction);
if (ase) {
- log::info("{}, using an already active ASE id={}", address_, ase->id);
+ log::info("{}, using an already active {} ASE id={}", address_, direction_str, ase->id);
} else {
ase = GetFirstInactiveAse(direction, reuse_cis_id);
}
if (!ase) {
- log::error("{}, unable to find an ASE to configure", address_);
+ log::error("{}, unable to find a {} ASE to configure", address_, direction_str);
PrintDebugState();
return false;
}
@@ -339,6 +340,8 @@
auto const& ase_cfg = ase_configs.at(i);
if (utils::IsCodecUsingLtvFormat(ase_cfg.codec.id) &&
!utils::GetConfigurationSupportedPac(pacs, ase_cfg.codec)) {
+ log::error("{}, No {} PAC found matching codec: {}. Stop the activation.", address_,
+ direction_str, common::ToString(ase_cfg.codec));
return false;
}
}
@@ -356,12 +359,15 @@
uint8_t max_required_ase_per_dev =
ase_configs.size() / num_of_devices + (ase_configs.size() % num_of_devices);
int needed_ase = std::min((int)(max_required_ase_per_dev), (int)(ase_configs.size()));
+ log::debug("{}, {} {} ASE(s) required for this configuration.", address_, needed_ase,
+ direction_str);
for (int i = 0; i < needed_ase; ++i) {
auto const& ase_cfg = ase_configs.at(i);
if (utils::IsCodecUsingLtvFormat(ase_cfg.codec.id) &&
!utils::GetConfigurationSupportedPac(pacs, ase_cfg.codec)) {
- log::error("{}, no matching PAC found. Stop the activation.", address_);
+ log::error("{}, No {} PAC found matching codec: {}. Stop the activation.", address_,
+ direction_str, common::ToString(ase_cfg.codec));
return false;
}
}
@@ -429,8 +435,8 @@
log::debug(
"device={}, activated ASE id={}, direction={}, max_sdu_size={}, "
"cis_id={}, target_latency={}",
- address_, ase->id, direction == 1 ? "snk" : "src", ase->qos_config.max_sdu_size,
- ase->cis_id, ase_cfg.qos.target_latency);
+ address_, ase->id, direction_str, ase->qos_config.max_sdu_size, ase->cis_id,
+ ase_cfg.qos.target_latency);
/* Try to use the already active ASE */
ase = GetNextActiveAseWithSameDirection(ase);
diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc
index c2398ff..2c7ecbb 100644
--- a/system/bta/le_audio/le_audio_client_test.cc
+++ b/system/bta/le_audio/le_audio_client_test.cc
@@ -1318,7 +1318,7 @@
log::info(
", sink ase to delete. Cis handle: {}, ase pointer: "
"{}",
- (int)(pair.first), fmt::ptr(+ases.sink));
+ (int)(pair.first), std::format_ptr(+ases.sink));
if (ases.sink) {
stream_conf->stream_params.sink.num_of_devices--;
stream_conf->stream_params.sink.num_of_channels -=
@@ -1342,7 +1342,7 @@
auto ases = leAudioDevice->GetAsesByCisConnHdl(pair.first);
log::info(", source to delete. Cis handle: {}, ase pointer: {}",
- (int)(pair.first), fmt::ptr(ases.source));
+ (int)(pair.first), std::format_ptr(ases.source));
if (ases.source) {
stream_conf->stream_params.source.num_of_devices--;
stream_conf->stream_params.source.num_of_channels -=
@@ -1378,7 +1378,7 @@
log::info(
", sink ase to delete. Cis handle: {}, ase "
"pointer: {}",
- (int)(pair.first), fmt::ptr(+ases.sink));
+ (int)(pair.first), std::format_ptr(+ases.sink));
if (ases.sink) {
stream_conf->stream_params.sink.num_of_devices--;
stream_conf->stream_params.sink.num_of_channels -=
@@ -1403,7 +1403,7 @@
log::info(
", source to delete. Cis handle: {}, ase pointer: "
"{}",
- (int)(pair.first), fmt::ptr(+ases.source));
+ (int)(pair.first), std::format_ptr(+ases.source));
if (ases.source) {
stream_conf->stream_params.source.num_of_devices--;
stream_conf->stream_params.source.num_of_channels -=
diff --git a/system/bta/le_audio/le_audio_health_status.h b/system/bta/le_audio/le_audio_health_status.h
index 62b6a17..95f0aba 100644
--- a/system/bta/le_audio/le_audio_health_status.h
+++ b/system/bta/le_audio/le_audio_health_status.h
@@ -159,11 +159,11 @@
}
} // namespace bluetooth::le_audio
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::LeAudioHealthDeviceStatType>
: enum_formatter<bluetooth::le_audio::LeAudioHealthDeviceStatType> {};
template <>
struct formatter<bluetooth::le_audio::LeAudioHealthGroupStatType>
: enum_formatter<bluetooth::le_audio::LeAudioHealthGroupStatType> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/le_audio/le_audio_types.h b/system/bta/le_audio/le_audio_types.h
index 85bb1be..a0c5f36 100644
--- a/system/bta/le_audio/le_audio_types.h
+++ b/system/bta/le_audio/le_audio_types.h
@@ -28,6 +28,7 @@
#include <bit>
#include <bitset>
#include <map>
+#include <memory>
#include <optional>
#include <string>
#include <variant>
@@ -1329,7 +1330,7 @@
uint8_t GetMaxCodecFramesPerSduFromPac(const types::acs_ac_record* pac_record);
} // namespace bluetooth::le_audio
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::DsaMode> : enum_formatter<bluetooth::le_audio::DsaMode> {};
template <>
@@ -1338,4 +1339,4 @@
template <>
struct formatter<bluetooth::le_audio::types::LeAudioConfigurationStrategy>
: enum_formatter<bluetooth::le_audio::types::LeAudioConfigurationStrategy> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/bta/le_audio/le_audio_utils.cc b/system/bta/le_audio/le_audio_utils.cc
index 14b123c..3b89926 100644
--- a/system/bta/le_audio/le_audio_utils.cc
+++ b/system/bta/le_audio/le_audio_utils.cc
@@ -34,7 +34,7 @@
using bluetooth::le_audio::types::AudioContexts;
using bluetooth::le_audio::types::LeAudioContextType;
-namespace fmt {
+namespace std {
template <>
struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {};
template <>
@@ -43,7 +43,7 @@
struct formatter<audio_source_t> : enum_formatter<audio_source_t> {};
template <>
struct formatter<audio_devices_t> : enum_formatter<audio_devices_t> {};
-} // namespace fmt
+} // namespace std
namespace bluetooth::le_audio {
namespace utils {
@@ -584,7 +584,7 @@
return false;
}
- log::debug(": Settings for format: 0x{:#02x} ", codec_id.coding_format);
+ log::debug("Verifying coding format: {:#02x} ", codec_id.coding_format);
if (utils::IsCodecUsingLtvFormat(codec_id)) {
log::assert_that(!pac.codec_spec_caps.IsEmpty(),
diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc
index 1f01b3b..cc59c4d 100644
--- a/system/bta/le_audio/state_machine.cc
+++ b/system/bta/le_audio/state_machine.cc
@@ -541,7 +541,7 @@
ToString(group->cig.GetState()));
group->cig.SetState(CigState::CREATED);
- log::info("Group: {}, id: {} cig state: {}, number of cis handles: {}", fmt::ptr(group),
+ log::info("Group: {}, id: {} cig state: {}, number of cis handles: {}", std::format_ptr(group),
group->group_id_, ToString(group->cig.GetState()),
static_cast<int>(conn_handles.size()));
@@ -793,17 +793,17 @@
}
void RemoveCigForGroup(LeAudioDeviceGroup* group) {
- log::debug("Group: {}, id: {} cig state: {}", fmt::ptr(group), group->group_id_,
+ log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
ToString(group->cig.GetState()));
if (group->cig.GetState() != CigState::CREATED) {
- log::warn("Group: {}, id: {} cig state: {} cannot be removed", fmt::ptr(group),
+ log::warn("Group: {}, id: {} cig state: {} cannot be removed", std::format_ptr(group),
group->group_id_, ToString(group->cig.GetState()));
return;
}
group->cig.SetState(CigState::REMOVING);
IsoManager::GetInstance()->RemoveCig(group->group_id_);
- log::debug("Group: {}, id: {} cig state: {}", fmt::ptr(group), group->group_id_,
+ log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
ToString(group->cig.GetState()));
log_history_->AddLogHistory(kLogStateMachineTag, group->group_id_, RawAddress::kEmpty,
kLogCigRemoveOp);
@@ -1501,12 +1501,12 @@
uint8_t packing, framing, sca;
std::vector<EXT_CIS_CFG> cis_cfgs;
- log::debug("Group: {}, id: {} cig state: {}", fmt::ptr(group), group->group_id_,
+ log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
ToString(group->cig.GetState()));
if (group->cig.GetState() != CigState::NONE) {
- log::warn("Group {}, id: {} has invalid cig state: {}", fmt::ptr(group), group->group_id_,
- ToString(group->cig.GetState()));
+ log::warn("Group {}, id: {} has invalid cig state: {}", std::format_ptr(group),
+ group->group_id_, ToString(group->cig.GetState()));
return false;
}
@@ -1620,7 +1620,7 @@
group->cig.SetState(CigState::CREATING);
IsoManager::GetInstance()->CreateCig(group->group_id_, std::move(param));
- log::debug("Group: {}, id: {} cig state: {}", fmt::ptr(group), group->group_id_,
+ log::debug("Group: {}, id: {} cig state: {}", std::format_ptr(group), group->group_id_,
ToString(group->cig.GetState()));
return true;
}
diff --git a/system/bta/sys/bta_sys.h b/system/bta/sys/bta_sys.h
index e1bca2f..e1a9e5e 100644
--- a/system/bta/sys/bta_sys.h
+++ b/system/bta/sys/bta_sys.h
@@ -260,11 +260,11 @@
void bta_sys_add_cust_uuid(const tBTA_CUSTOM_UUID& curr);
void bta_sys_remove_cust_uuid(const tBTA_CUSTOM_UUID& curr);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTA_SYS_ID> : enum_formatter<tBTA_SYS_ID> {};
template <>
struct formatter<tBTA_SYS_CONN_STATUS> : enum_formatter<tBTA_SYS_CONN_STATUS> {};
-} // namespace fmt
+} // namespace std
#endif /* BTA_SYS_H */
diff --git a/system/bta/test/bta_api_test.cc b/system/bta/test/bta_api_test.cc
index 0075fa5..ccf8bdf 100644
--- a/system/bta/test/bta_api_test.cc
+++ b/system/bta/test/bta_api_test.cc
@@ -18,10 +18,10 @@
#include <base/functional/bind.h>
#include <base/location.h>
-#include <fmt/format.h>
#include <gtest/gtest.h>
#include <cstdint>
+#include <format>
#include <utility>
#include <vector>
@@ -47,7 +47,7 @@
for (const auto& status : statuses) {
ASSERT_STREQ(status.second.c_str(), bta_status_text(status.first).c_str());
}
- auto unknown = fmt::format("UNKNOWN[{}]", std::numeric_limits<uint8_t>::max());
+ auto unknown = std::format("UNKNOWN[{}]", std::numeric_limits<uint8_t>::max());
ASSERT_STREQ(
unknown.c_str(),
bta_status_text(static_cast<tBTA_STATUS>(std::numeric_limits<uint8_t>::max())).c_str());
diff --git a/system/bta/test/bta_disc_test.cc b/system/bta/test/bta_disc_test.cc
index 0979226..72e446c 100644
--- a/system/bta/test/bta_disc_test.cc
+++ b/system/bta/test/bta_disc_test.cc
@@ -20,7 +20,6 @@
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <flag_macros.h>
-#include <fmt/format.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sys/socket.h>
diff --git a/system/bta/test/bta_dm_test.cc b/system/bta/test/bta_dm_test.cc
index e4d2fb9..91a8390 100644
--- a/system/bta/test/bta_dm_test.cc
+++ b/system/bta/test/bta_dm_test.cc
@@ -19,10 +19,10 @@
#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <flag_macros.h>
-#include <fmt/format.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <format>
#include <string>
#include "bta/dm/bta_dm_device_search_int.h"
@@ -427,11 +427,10 @@
for (const auto& event : events) {
ASSERT_STREQ(event.second.c_str(), bta_dm_search_evt_text(event.first).c_str());
}
- ASSERT_STREQ(
- fmt::format("UNKNOWN[{}]", std::numeric_limits<uint8_t>::max()).c_str(),
- bta_dm_search_evt_text(
- static_cast<tBTA_DM_SEARCH_EVT>(std::numeric_limits<uint8_t>::max()))
- .c_str());
+ ASSERT_STREQ(std::format("UNKNOWN[{}]", std::numeric_limits<uint8_t>::max()).c_str(),
+ bta_dm_search_evt_text(
+ static_cast<tBTA_DM_SEARCH_EVT>(std::numeric_limits<uint8_t>::max()))
+ .c_str());
}
TEST_F(BtaDmTest, bta_dm_remote_name_cmpl) {
diff --git a/system/bta/test/bta_gatt_client_test.cc b/system/bta/test/bta_gatt_client_test.cc
index 5dca105..3c19614 100644
--- a/system/bta/test/bta_gatt_client_test.cc
+++ b/system/bta/test/bta_gatt_client_test.cc
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include <fmt/format.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sys/socket.h>
+#include <format>
#include <string>
#include "bta/dm/bta_dm_gatt_client.h"
@@ -54,11 +54,11 @@
};
// C string
- gatt_history_callback(fmt::format("{}", a[0].c_str()));
+ gatt_history_callback(std::format("{}", a[0].c_str()));
// Cpp string
gatt_history_callback(a[1]);
// Third entry for "fun"
- gatt_history_callback(fmt::format("{}", a[2].c_str()));
+ gatt_history_callback(std::format("{}", a[2].c_str()));
std::vector<bluetooth::common::TimestampedEntry<std::string>> history =
bluetooth::legacy::testing::PullCopyOfGattHistory();
diff --git a/system/bta/test/bta_sec_test.cc b/system/bta/test/bta_sec_test.cc
index ddf83e5..20b82cc 100644
--- a/system/bta/test/bta_sec_test.cc
+++ b/system/bta/test/bta_sec_test.cc
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <fmt/format.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sys/socket.h>
diff --git a/system/btcore/src/property.cc b/system/btcore/src/property.cc
index 5592b14..0379229 100644
--- a/system/btcore/src/property.cc
+++ b/system/btcore/src/property.cc
@@ -205,7 +205,7 @@
property->val = osi_calloc(len + 1);
if (type == BT_PROPERTY_BDNAME) {
- strlcpy((char*)property->val, (const char*)val, len);
+ osi_strlcpy((char*)property->val, (const char*)val, len);
} else {
memcpy(property->val, val, len);
}
diff --git a/system/btif/co/bta_hh_co.cc b/system/btif/co/bta_hh_co.cc
index 12735b6..52cdb17 100644
--- a/system/btif/co/bta_hh_co.cc
+++ b/system/btif/co/bta_hh_co.cc
@@ -986,7 +986,7 @@
// Create and send hid descriptor to kernel
ev.type = UHID_CREATE2;
- strlcpy((char*)ev.u.create2.name, dev_name, sizeof(ev.u.create2.name));
+ osi_strlcpy((char*)ev.u.create2.name, dev_name, sizeof(ev.u.create2.name));
// TODO (b/258090765) fix: ToString -> ToColonSepHexString
snprintf((char*)ev.u.create2.uniq, sizeof(ev.u.create2.uniq), "%s",
p_dev->link_spec.addrt.bda.ToString().c_str());
diff --git a/system/btif/co/bta_pan_co.cc b/system/btif/co/bta_pan_co.cc
index 5581492..2928373 100644
--- a/system/btif/co/bta_pan_co.cc
+++ b/system/btif/co/bta_pan_co.cc
@@ -122,7 +122,7 @@
log::error("cannot find pan connection");
return;
} else if (conn->state != PAN_STATE_OPEN) {
- log::error("conn is not opened, conn:{}, conn->state:{}", fmt::ptr(conn), conn->state);
+ log::error("conn is not opened, conn:{}, conn->state:{}", std::format_ptr(conn), conn->state);
return;
}
diff --git a/system/btif/include/btif_a2dp_sink.h b/system/btif/include/btif_a2dp_sink.h
index 2c71f65..81d4bff 100644
--- a/system/btif/include/btif_a2dp_sink.h
+++ b/system/btif/include/btif_a2dp_sink.h
@@ -133,9 +133,9 @@
// Get audio track handle
void* btif_a2dp_sink_get_audio_track(void);
-namespace fmt {
+namespace std {
template <>
struct formatter<btif_a2dp_sink_focus_state_t> : enum_formatter<btif_a2dp_sink_focus_state_t> {};
-} // namespace fmt
+} // namespace std
#endif /* BTIF_A2DP_SINK_H */
diff --git a/system/btif/include/btif_bqr.h b/system/btif/include/btif_bqr.h
index 38bfa8b..e1ec64c 100644
--- a/system/btif/include/btif_bqr.h
+++ b/system/btif/include/btif_bqr.h
@@ -530,10 +530,10 @@
} // namespace bqr
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::bqr::BqrReportAction>
: enum_formatter<bluetooth::bqr::BqrReportAction> {};
template <>
struct formatter<bluetooth::bqr::BqrVseSubEvt> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/btif/include/btif_hd.h b/system/btif/include/btif_hd.h
index 0558118..feaa678 100644
--- a/system/btif/include/btif_hd.h
+++ b/system/btif/include/btif_hd.h
@@ -45,9 +45,9 @@
void btif_hd_remove_device(RawAddress bd_addr);
void btif_hd_service_registration();
-namespace fmt {
+namespace std {
template <>
struct formatter<BTIF_HD_STATUS> : enum_formatter<BTIF_HD_STATUS> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h
index a0774c5..c55dded 100644
--- a/system/btif/include/btif_hh.h
+++ b/system/btif/include/btif_hh.h
@@ -173,9 +173,9 @@
void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data);
} // namespace bluetooth::legacy::testing
-namespace fmt {
+namespace std {
template <>
struct formatter<BTIF_HH_STATUS> : enum_formatter<BTIF_HH_STATUS> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/btif/src/btif_a2dp.cc b/system/btif/src/btif_a2dp.cc
index f7632bf..63e6c6c 100644
--- a/system/btif/src/btif_a2dp.cc
+++ b/system/btif/src/btif_a2dp.cc
@@ -52,7 +52,7 @@
bool btif_a2dp_on_started(const RawAddress& peer_addr, tBTA_AV_START* p_av_start,
const A2dpType local_a2dp_type) {
- log::info("## ON A2DP STARTED ## peer {} p_av_start:{}", peer_addr, fmt::ptr(p_av_start));
+ log::info("## ON A2DP STARTED ## peer {} p_av_start:{}", peer_addr, std::format_ptr(p_av_start));
if (p_av_start == NULL) {
auto status = BluetoothAudioStatus::SUCCESS;
@@ -95,7 +95,7 @@
}
void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend, const A2dpType local_a2dp_type) {
- log::info("## ON A2DP STOPPED ## p_av_suspend={}", fmt::ptr(p_av_suspend));
+ log::info("## ON A2DP STOPPED ## p_av_suspend={}", std::format_ptr(p_av_suspend));
const uint8_t peer_type_sep = btif_av_get_peer_sep(local_a2dp_type);
if (peer_type_sep == AVDT_TSEP_SRC) {
@@ -111,7 +111,7 @@
}
void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend, const A2dpType local_a2dp_type) {
- log::info("## ON A2DP SUSPENDED ## p_av_suspend={}", fmt::ptr(p_av_suspend));
+ log::info("## ON A2DP SUSPENDED ## p_av_suspend={}", std::format_ptr(p_av_suspend));
const uint8_t peer_type_sep = btif_av_get_peer_sep(local_a2dp_type);
if (peer_type_sep == AVDT_TSEP_SRC) {
btif_a2dp_sink_on_suspended(p_av_suspend);
diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc
index ce8d74f..34d081c 100644
--- a/system/btif/src/btif_av.cc
+++ b/system/btif/src/btif_av.cc
@@ -1553,7 +1553,8 @@
if ((btif_a2dp_sink_get_audio_track() != nullptr) &&
(peer->PeerAddress() != peer_address)) {
log::info("there is another peer with audio track({}), another={}, peer={}",
- fmt::ptr(btif_a2dp_sink_get_audio_track()), peer->PeerAddress(), peer_address);
+ std::format_ptr(btif_a2dp_sink_get_audio_track()), peer->PeerAddress(),
+ peer_address);
connected++;
}
break;
diff --git a/system/btif/src/btif_core.cc b/system/btif/src/btif_core.cc
index c5a723d..73fe810 100644
--- a/system/btif/src/btif_core.cc
+++ b/system/btif/src/btif_core.cc
@@ -379,7 +379,7 @@
}
static void btif_core_storage_adapter_write(bt_property_t* prop) {
- log::verbose("type: {}, len {}, {}", prop->type, prop->len, fmt::ptr(prop->val));
+ log::verbose("type: {}, len {}, {}", prop->type, prop->len, std::format_ptr(prop->val));
bt_status_t status = btif_storage_set_adapter_property(prop);
GetInterfaceToProfiles()->events->invoke_adapter_properties_cb(status, 1, prop);
}
@@ -550,7 +550,7 @@
void btif_set_adapter_property(bt_property_t* property) {
log::verbose("btif_set_adapter_property type: {}, len {}, {}", property->type, property->len,
- fmt::ptr(property->val));
+ std::format_ptr(property->val));
switch (property->type) {
case BT_PROPERTY_BDNAME: {
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 70762b7..f50bd55 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -177,11 +177,11 @@
ServiceDiscoveryState sdp_over_classic;
};
-namespace fmt {
+namespace std {
template <>
struct formatter<btif_dm_pairing_cb_t::ServiceDiscoveryState>
: enum_formatter<btif_dm_pairing_cb_t::ServiceDiscoveryState> {};
-} // namespace fmt
+} // namespace std
// TODO(jpawlowski): unify ?
// btif_dm_local_key_id_t == tBTM_BLE_LOCAL_ID_KEYS == tBTA_BLE_LOCAL_ID_KEYS
diff --git a/system/btif/src/btif_hd.cc b/system/btif/src/btif_hd.cc
index 8b2a673..321e57b 100644
--- a/system/btif/src/btif_hd.cc
+++ b/system/btif/src/btif_hd.cc
@@ -414,11 +414,11 @@
}
app_info.p_name = (char*)osi_calloc(BTIF_HD_APP_NAME_LEN);
- strlcpy(app_info.p_name, p_app_param->name, BTIF_HD_APP_NAME_LEN);
+ osi_strlcpy(app_info.p_name, p_app_param->name, BTIF_HD_APP_NAME_LEN);
app_info.p_description = (char*)osi_calloc(BTIF_HD_APP_DESCRIPTION_LEN);
- strlcpy(app_info.p_description, p_app_param->description, BTIF_HD_APP_DESCRIPTION_LEN);
+ osi_strlcpy(app_info.p_description, p_app_param->description, BTIF_HD_APP_DESCRIPTION_LEN);
app_info.p_provider = (char*)osi_calloc(BTIF_HD_APP_PROVIDER_LEN);
- strlcpy(app_info.p_provider, p_app_param->provider, BTIF_HD_APP_PROVIDER_LEN);
+ osi_strlcpy(app_info.p_provider, p_app_param->provider, BTIF_HD_APP_PROVIDER_LEN);
app_info.subclass = p_app_param->subclass;
app_info.descriptor.dl_len = p_app_param->desc_list_len;
app_info.descriptor.dsc_list = (uint8_t*)osi_malloc(app_info.descriptor.dl_len);
diff --git a/system/btif/src/btif_pan.cc b/system/btif/src/btif_pan.cc
index 1f0bcb1..1b45e9e 100644
--- a/system/btif/src/btif_pan.cc
+++ b/system/btif/src/btif_pan.cc
@@ -294,7 +294,7 @@
// set mac addr
memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, devname, IFNAMSIZ);
+ osi_strlcpy(ifr.ifr_name, devname, IFNAMSIZ);
err = ioctl(sk, SIOCGIFHWADDR, &ifr);
if (err < 0) {
log::error("Could not get network hardware for interface:{}, errno:{}", devname,
@@ -303,7 +303,7 @@
return -1;
}
- strlcpy(ifr.ifr_name, devname, IFNAMSIZ);
+ osi_strlcpy(ifr.ifr_name, devname, IFNAMSIZ);
memcpy(ifr.ifr_hwaddr.sa_data, addr.address, 6);
/* The IEEE has specified that the most significant bit of the most
@@ -329,7 +329,7 @@
// bring it up
memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, devname, IF_NAMESIZE);
+ osi_strlcpy(ifr.ifr_name, devname, IF_NAMESIZE);
ifr.ifr_flags |= IFF_UP;
ifr.ifr_flags |= IFF_MULTICAST;
@@ -356,7 +356,7 @@
}
memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, devname, IF_NAMESIZE);
+ osi_strlcpy(ifr.ifr_name, devname, IF_NAMESIZE);
ifr.ifr_flags &= ~IFF_UP;
@@ -395,7 +395,7 @@
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- strlcpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
+ osi_strlcpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
/* try to create the device */
err = ioctl(fd, TUNSETIFF, (void*)&ifr);
@@ -470,7 +470,7 @@
static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN* p_data) {
log::verbose("btpan_open_conn: local_role:{}, peer_role: {}, handle:{}, conn: {}",
p_data->open.local_role, p_data->open.peer_role, p_data->open.handle,
- fmt::ptr(conn));
+ std::format_ptr(conn));
if (conn == NULL) {
conn = btpan_new_conn(p_data->open.handle, p_data->open.bd_addr, p_data->open.local_role,
@@ -500,7 +500,7 @@
}
static void btpan_close_conn(btpan_conn_t* conn) {
- log::verbose("btpan_close_conn: {}", fmt::ptr(conn));
+ log::verbose("btpan_close_conn: {}", std::format_ptr(conn));
if (conn && conn->state == PAN_STATE_OPEN) {
log::verbose("btpan_close_conn: PAN_STATE_OPEN");
diff --git a/system/btif/src/btif_profile_queue.cc b/system/btif/src/btif_profile_queue.cc
index 38d00f4..3e6e0aa 100644
--- a/system/btif/src/btif_profile_queue.cc
+++ b/system/btif/src/btif_profile_queue.cc
@@ -55,7 +55,7 @@
: address_(address), uuid_(uuid), busy_(false), connect_cb_(connect_cb) {}
std::string ToString() const {
- return fmt::format("address={} UUID={:04X} busy={}", address_, uuid_, busy_);
+ return std::format("address={} UUID={:04X} busy={}", address_, uuid_, busy_);
}
const RawAddress& address() const { return address_; }
diff --git a/system/btif/src/btif_sdp_server.cc b/system/btif/src/btif_sdp_server.cc
index c7c2918..6d3dfd4 100644
--- a/system/btif/src/btif_sdp_server.cc
+++ b/system/btif/src/btif_sdp_server.cc
@@ -72,10 +72,10 @@
bluetooth_sdp_record* record_data;
} sdp_slot_t;
-namespace fmt {
+namespace std {
template <>
struct formatter<sdp_state_t> : enum_formatter<sdp_state_t> {};
-} // namespace fmt
+} // namespace std
#define MAX_SDP_SLOTS 128
static sdp_slot_t sdp_slots[MAX_SDP_SLOTS];
diff --git a/system/btif/src/btif_sock_rfc.cc b/system/btif/src/btif_sock_rfc.cc
index 3b50ca5..e8bf6b4 100644
--- a/system/btif/src/btif_sock_rfc.cc
+++ b/system/btif/src/btif_sock_rfc.cc
@@ -235,7 +235,7 @@
slot->service_uuid = uuid;
if (name && *name) {
- strlcpy(slot->service_name, name, sizeof(slot->service_name));
+ osi_strlcpy(slot->service_name, name, sizeof(slot->service_name));
} else {
memset(slot->service_name, 0, sizeof(slot->service_name));
}
@@ -742,7 +742,8 @@
break;
}
if (p_data->scn == 0) {
- log::error("Unable to allocate scn: all resources exhausted. slot found: {}", fmt::ptr(rs));
+ log::error("Unable to allocate scn: all resources exhausted. slot found: {}",
+ std::format_ptr(rs));
cleanup_rfc_slot(rs);
break;
}
@@ -789,7 +790,7 @@
}
if (!create_server_sdp_record(slot)) {
- log::error("cannot start server, slot found: {}", fmt::ptr(slot));
+ log::error("cannot start server, slot found: {}", std::format_ptr(slot));
cleanup_rfc_slot(slot);
break;
}
diff --git a/system/common/message_loop_thread.h b/system/common/message_loop_thread.h
index 3c842a0..301a484 100644
--- a/system/common/message_loop_thread.h
+++ b/system/common/message_loop_thread.h
@@ -217,7 +217,7 @@
} // namespace common
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::common::MessageLoopThread> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/common/metrics.cc b/system/common/metrics.cc
index 90539a7..49b73a0 100644
--- a/system/common/metrics.cc
+++ b/system/common/metrics.cc
@@ -42,7 +42,7 @@
#include "osi/include/osi.h"
#include "types/raw_address.h"
-namespace fmt {
+namespace std {
template <>
struct formatter<android::bluetooth::DirectionEnum>
: enum_formatter<android::bluetooth::DirectionEnum> {};
@@ -58,7 +58,7 @@
template <>
struct formatter<android::bluetooth::DeviceInfoSrcEnum>
: enum_formatter<android::bluetooth::DeviceInfoSrcEnum> {};
-} // namespace fmt
+} // namespace std
namespace bluetooth {
namespace common {
diff --git a/system/device/Android.bp b/system/device/Android.bp
index 1a5d72a..5411561 100644
--- a/system/device/Android.bp
+++ b/system/device/Android.bp
@@ -109,6 +109,7 @@
"libchrome",
"libflagtest",
"libgmock",
+ "libosi",
"server_configurable_flags",
],
header_libs: ["libbluetooth_headers"],
diff --git a/system/device/src/device_iot_config.cc b/system/device/src/device_iot_config.cc
index 2da612a..4513e68 100644
--- a/system/device/src/device_iot_config.cc
+++ b/system/device/src/device_iot_config.cc
@@ -219,7 +219,7 @@
return false;
}
- strlcpy(value, stored_value->c_str(), *size_bytes);
+ osi_strlcpy(value, stored_value->c_str(), *size_bytes);
*size_bytes = strlen(value) + 1;
return true;
diff --git a/system/device/src/interop.cc b/system/device/src/interop.cc
index 344198f..1c8798e 100644
--- a/system/device/src/interop.cc
+++ b/system/device/src/interop.cc
@@ -181,10 +181,10 @@
} entry_type;
} interop_db_entry_t;
-namespace fmt {
+namespace std {
template <>
struct formatter<interop_bl_type> : enum_formatter<interop_bl_type> {};
-} // namespace fmt
+} // namespace std
static const char* interop_feature_string_(const interop_feature_t feature);
static void interop_free_entry_(void* data);
@@ -264,7 +264,7 @@
void interop_database_clear() {
log::debug("interop_is_initialized: {} interop_list: {}", interop_is_initialized,
- fmt::ptr(interop_list));
+ std::format_ptr(interop_list));
if (interop_is_initialized && interop_list) {
for (int feature = BEGINNING_OF_INTEROP_LIST; feature != END_OF_INTEROP_LIST; feature++) {
@@ -825,7 +825,7 @@
if ((token = strtok_r(str, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
trim(token);
- strlcpy(bdaddrstr, token, KEY_MAX_LENGTH);
+ osi_strlcpy(bdaddrstr, token, KEY_MAX_LENGTH);
} else {
return false;
}
@@ -845,7 +845,7 @@
if ((token = strtok_r(str, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
trim(token);
- strlcpy(addr_start_str, token, 18);
+ osi_strlcpy(addr_start_str, token, 18);
if (!RawAddress::FromString(addr_start_str, *addr_start)) {
return false;
}
@@ -855,7 +855,7 @@
if ((token = strtok_r(NULL, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
trim(token);
- strlcpy(addr_end_str, token, 18);
+ osi_strlcpy(addr_end_str, token, 18);
if (RawAddress::FromString(addr_end_str, *addr_end)) {
ret_value = true;
}
@@ -870,7 +870,7 @@
if ((token = strtok_r(str, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
trim(token);
- strlcpy(bdaddrstr, token, KEY_MAX_LENGTH);
+ osi_strlcpy(bdaddrstr, token, KEY_MAX_LENGTH);
} else {
return false;
}
@@ -931,7 +931,7 @@
interop_db_entry_t* entry = (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
entry->bl_type = INTEROP_BL_TYPE_NAME;
entry->bl_entry_type = entry_type;
- strlcpy(entry->entry_type.name_entry.name, key, sizeof(entry->entry_type.name_entry.name));
+ osi_strlcpy(entry->entry_type.name_entry.name, key, sizeof(entry->entry_type.name_entry.name));
entry->entry_type.name_entry.feature = (interop_feature_t)feature;
entry->entry_type.name_entry.length = strlen(key);
interop_database_add_(entry, false);
@@ -965,7 +965,7 @@
return false;
}
- strlcpy(tmp_key, key, VALID_VNDR_PRDT_LEN + 1);
+ osi_strlcpy(tmp_key, key, VALID_VNDR_PRDT_LEN + 1);
if (!get_vendor_product_id(tmp_key, &vendor_id, &product_id)) {
log::warn("Error in parsing vendor/product id {}", key);
return false;
@@ -988,7 +988,7 @@
return false;
}
- strlcpy(tmp_key, key, KEY_MAX_LENGTH);
+ osi_strlcpy(tmp_key, key, KEY_MAX_LENGTH);
if (!get_addr_maxlat(tmp_key, bdaddr_str, &max_lat)) {
log::warn("Error in parsing address and max_lat {}", key);
return false;
@@ -1049,7 +1049,7 @@
return false;
}
- strlcpy(tmp_key, key, KEY_MAX_LENGTH);
+ osi_strlcpy(tmp_key, key, KEY_MAX_LENGTH);
if (!get_addr_lmp_ver(tmp_key, bdaddr_str, &lmp_ver, &lmp_sub_ver)) {
log::warn("Error in parsing address and lmp_ver {}", key);
return false;
@@ -1092,7 +1092,7 @@
return false;
}
- strlcpy(tmp_key, key, VALID_ADDR_RANGE_LEN + 1);
+ osi_strlcpy(tmp_key, key, VALID_ADDR_RANGE_LEN + 1);
if (!get_addr_range(tmp_key, &addr_start, &addr_end)) {
log::warn("key: {} addr_start {} or addr end {} is added to interop list", key, addr_start,
addr_end);
@@ -1178,7 +1178,7 @@
interop_db_entry_t* entry = (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
entry->bl_type = INTEROP_BL_TYPE_NAME;
entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
- strlcpy(entry->entry_type.name_entry.name, name, sizeof(entry->entry_type.name_entry.name));
+ osi_strlcpy(entry->entry_type.name_entry.name, name, sizeof(entry->entry_type.name_entry.name));
entry->entry_type.name_entry.feature = (interop_feature_t)feature;
entry->entry_type.name_entry.length = name_length;
interop_database_add_(entry, true);
@@ -1262,11 +1262,11 @@
char trim_name[KEY_MAX_LENGTH] = {'\0'};
log::assert_that(name != nullptr, "assert failed: name != nullptr");
- strlcpy(trim_name, name, KEY_MAX_LENGTH);
+ osi_strlcpy(trim_name, name, KEY_MAX_LENGTH);
interop_db_entry_t entry;
entry.bl_type = INTEROP_BL_TYPE_NAME;
- strlcpy(entry.entry_type.name_entry.name, trim(trim_name), KEY_MAX_LENGTH);
+ osi_strlcpy(entry.entry_type.name_entry.name, trim(trim_name), KEY_MAX_LENGTH);
entry.entry_type.name_entry.feature = (interop_feature_t)feature;
entry.entry_type.name_entry.length = strlen(entry.entry_type.name_entry.name);
@@ -1404,7 +1404,7 @@
entry.bl_type = INTEROP_BL_TYPE_NAME;
entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
- strlcpy(entry.entry_type.name_entry.name, name, 20);
+ osi_strlcpy(entry.entry_type.name_entry.name, name, 20);
entry.entry_type.name_entry.feature = (interop_feature_t)feature;
entry.entry_type.name_entry.length = strlen(entry.entry_type.name_entry.name);
if (interop_database_remove_(&entry)) {
diff --git a/system/gd/hal/snoop_logger.cc b/system/gd/hal/snoop_logger.cc
index 0fc1939..d08ad0b 100644
--- a/system/gd/hal/snoop_logger.cc
+++ b/system/gd/hal/snoop_logger.cc
@@ -1409,12 +1409,12 @@
evt_code == static_cast<uint8_t>(hci::EventCode::VENDOR_SPECIFIC)) {
uint8_t subevt_code = packet[2];
std::string message =
- fmt::format("BTSL:{}/{}/{}/{:02x}/{:02x}", static_cast<uint8_t>(type),
+ std::format("BTSL:{}/{}/{}/{:02x}/{:02x}", static_cast<uint8_t>(type),
static_cast<uint8_t>(direction), packet.size(), evt_code, subevt_code);
ATRACE_INSTANT_FOR_TRACK(LOG_TAG, message.c_str());
} else {
- std::string message = fmt::format("BTSL:{}/{}/{}/{:02x}", static_cast<uint8_t>(type),
+ std::string message = std::format("BTSL:{}/{}/{}/{:02x}", static_cast<uint8_t>(type),
static_cast<uint8_t>(direction), packet.size(), evt_code);
ATRACE_INSTANT_FOR_TRACK(LOG_TAG, message.c_str());
@@ -1423,7 +1423,7 @@
case PacketType::CMD: {
uint16_t op_code = packet[0] | (packet[1] << 8);
- std::string message = fmt::format("BTSL:{}/{}/{}/{:04x}", static_cast<uint8_t>(type),
+ std::string message = std::format("BTSL:{}/{}/{}/{:04x}", static_cast<uint8_t>(type),
static_cast<uint8_t>(direction), packet.size(), op_code);
ATRACE_INSTANT_FOR_TRACK(LOG_TAG, message.c_str());
@@ -1432,15 +1432,15 @@
uint16_t handle = (packet[0] | (packet[1] << 8)) & 0x0fff;
uint8_t pb_flag = (packet[1] & 0x30) >> 4;
- std::string message = fmt::format("BTSL:{}/{}/{}/{:03x}/{}", static_cast<uint8_t>(type),
- static_cast<uint8_t>(direction), packet.size(), handle,
- pb_flag);
+ std::string message =
+ std::format("BTSL:{}/{}/{}/{:03x}/{}", static_cast<uint8_t>(type),
+ static_cast<uint8_t>(direction), packet.size(), handle, pb_flag);
ATRACE_INSTANT_FOR_TRACK(LOG_TAG, message.c_str());
} break;
case PacketType::ISO:
case PacketType::SCO: {
- std::string message = fmt::format("BTSL:{}/{}/{}", static_cast<uint8_t>(type),
+ std::string message = std::format("BTSL:{}/{}/{}", static_cast<uint8_t>(type),
static_cast<uint8_t>(direction), packet.size());
ATRACE_INSTANT_FOR_TRACK(LOG_TAG, message.c_str());
diff --git a/system/gd/hal/snoop_logger.h b/system/gd/hal/snoop_logger.h
index bcd406c..f3a4add 100644
--- a/system/gd/hal/snoop_logger.h
+++ b/system/gd/hal/snoop_logger.h
@@ -343,8 +343,8 @@
} // namespace hal
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::hal::profile_type_t> : enum_formatter<bluetooth::hal::profile_type_t> {
};
-} // namespace fmt
+} // namespace std
diff --git a/system/gd/hci/acl_manager/round_robin_scheduler.h b/system/gd/hci/acl_manager/round_robin_scheduler.h
index 8d51ccd..61be5f1 100644
--- a/system/gd/hci/acl_manager/round_robin_scheduler.h
+++ b/system/gd/hci/acl_manager/round_robin_scheduler.h
@@ -89,8 +89,8 @@
} // namespace hci
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::hci::acl_manager::RoundRobinScheduler::ConnectionType>
: enum_formatter<bluetooth::hci::acl_manager::RoundRobinScheduler::ConnectionType> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/gd/hci/address.h b/system/gd/hci/address.h
index d3626fd..b7e2bde 100644
--- a/system/gd/hci/address.h
+++ b/system/gd/hci/address.h
@@ -114,15 +114,15 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::hci::Address> : formatter<std::string> {
template <class Context>
typename Context::iterator format(const bluetooth::hci::Address& address, Context& ctx) const {
std::string repr = address.ToRedactedStringForLogging();
- return fmt::formatter<std::string>::format(repr, ctx);
+ return std::formatter<std::string>::format(repr, ctx);
}
};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>
diff --git a/system/gd/hci/address_with_type.h b/system/gd/hci/address_with_type.h
index 0c3eb5e..c196989 100644
--- a/system/gd/hci/address_with_type.h
+++ b/system/gd/hci/address_with_type.h
@@ -155,16 +155,16 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::hci::AddressWithType> : formatter<std::string> {
template <class Context>
typename Context::iterator format(const bluetooth::hci::AddressWithType& address,
Context& ctx) const {
std::string repr = address.ToRedactedStringForLogging();
- return fmt::formatter<std::string>::format(repr, ctx);
+ return std::formatter<std::string>::format(repr, ctx);
}
};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>
diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc
index 1f88332..38415f5 100644
--- a/system/gd/hci/controller.cc
+++ b/system/gd/hci/controller.cc
@@ -1560,9 +1560,9 @@
template <typename OutputT>
void Controller::impl::dump(OutputT&& out) const {
- fmt::format_to(out, "\nHCI Controller Dumpsys:\n");
+ std::format_to(out, "\nHCI Controller Dumpsys:\n");
- fmt::format_to(out,
+ std::format_to(out,
" local_version_information:\n"
" hci_version: {}\n"
" hci_revision: 0x{:x}\n"
@@ -1575,7 +1575,7 @@
local_version_information_.lmp_subversion_,
local_version_information_.manufacturer_name_);
- fmt::format_to(out,
+ std::format_to(out,
" buffer_size:\n"
" acl_data_packet_length: {}\n"
" total_num_acl_data_packets: {}\n"
@@ -1583,7 +1583,7 @@
" total_num_sco_data_packets: {}\n",
acl_buffer_length_, acl_buffers_, sco_buffer_length_, sco_buffers_);
- fmt::format_to(out,
+ std::format_to(out,
" le_buffer_size:\n"
" le_acl_data_packet_length: {}\n"
" total_num_le_acl_data_packets: {}\n"
@@ -1592,7 +1592,7 @@
le_buffer_size_.le_data_packet_length_, le_buffer_size_.total_num_le_packets_,
iso_buffer_size_.le_data_packet_length_, iso_buffer_size_.total_num_le_packets_);
- fmt::format_to(out,
+ std::format_to(out,
" le_maximum_data_length:\n"
" supported_max_tx_octets: {}\n"
" supported_max_tx_time: {}\n"
@@ -1603,7 +1603,7 @@
le_maximum_data_length_.supported_max_rx_octets_,
le_maximum_data_length_.supported_max_rx_time_);
- fmt::format_to(out,
+ std::format_to(out,
" le_accept_list_size: {}\n"
" le_resolving_list_size: {}\n"
" le_maximum_advertising_data_length: {}\n"
@@ -1615,7 +1615,7 @@
le_suggested_default_data_length_, le_number_supported_advertising_sets_,
le_periodic_advertiser_list_size_, le_supported_states_);
- fmt::format_to(out,
+ std::format_to(out,
" local_supported_features:\n"
" page0: 0x{:016x}\n"
" page1: 0x{:016x}\n"
@@ -1625,16 +1625,16 @@
extended_lmp_features_array_[0], extended_lmp_features_array_[1],
extended_lmp_features_array_[2], le_local_supported_features_);
- fmt::format_to(out, " local_supported_commands: [");
+ std::format_to(out, " local_supported_commands: [");
for (size_t i = 0; i < local_supported_commands_.size(); i++) {
if ((i % 8) == 0) {
- fmt::format_to(out, "\n ");
+ std::format_to(out, "\n ");
}
- fmt::format_to(out, " 0x{:02x},", local_supported_commands_[i]);
+ std::format_to(out, " 0x{:02x},", local_supported_commands_[i]);
}
- fmt::format_to(out, "\n ]\n");
+ std::format_to(out, "\n ]\n");
- fmt::format_to(
+ std::format_to(
out,
" vendor_capabilities:\n"
" is_supported: {}\n"
diff --git a/system/gd/hci/distance_measurement_manager.h b/system/gd/hci/distance_measurement_manager.h
index 70739c3..93f0f5a 100644
--- a/system/gd/hci/distance_measurement_manager.h
+++ b/system/gd/hci/distance_measurement_manager.h
@@ -119,8 +119,8 @@
} // namespace hci
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::hci::DistanceMeasurementMethod>
: enum_formatter<bluetooth::hci::DistanceMeasurementMethod> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/gd/hci/facade/le_acl_manager_facade.cc b/system/gd/hci/facade/le_acl_manager_facade.cc
index e80cad4..3e7ff96 100644
--- a/system/gd/hci/facade/le_acl_manager_facade.cc
+++ b/system/gd/hci/facade/le_acl_manager_facade.cc
@@ -36,11 +36,11 @@
using ::bluetooth::packet::RawBuilder;
-namespace fmt {
+namespace std {
template <>
struct formatter<blueberry::facade::BluetoothAddressTypeEnum>
: enum_formatter<blueberry::facade::BluetoothAddressTypeEnum> {};
-} // namespace fmt
+} // namespace std
namespace bluetooth {
namespace hci {
diff --git a/system/gd/hci/le_advertising_manager.h b/system/gd/hci/le_advertising_manager.h
index 52d0802..aa3fbbd 100644
--- a/system/gd/hci/le_advertising_manager.h
+++ b/system/gd/hci/le_advertising_manager.h
@@ -185,8 +185,8 @@
} // namespace hci
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::hci::AdvertiserAddressType>
: enum_formatter<bluetooth::hci::AdvertiserAddressType> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc
index 6956365..d4185ef 100644
--- a/system/gd/os/android/metrics.cc
+++ b/system/gd/os/android/metrics.cc
@@ -31,7 +31,7 @@
#include "hardware/bt_av.h"
#include "hci/hci_packets.h"
-namespace fmt {
+namespace std {
template <>
struct formatter<android::bluetooth::DirectionEnum>
: enum_formatter<android::bluetooth::DirectionEnum> {};
@@ -51,7 +51,7 @@
struct formatter<android::bluetooth::EventType> : enum_formatter<android::bluetooth::EventType> {};
template <>
struct formatter<android::bluetooth::State> : enum_formatter<android::bluetooth::State> {};
-} // namespace fmt
+} // namespace std
namespace bluetooth {
namespace os {
diff --git a/system/gd/os/internal/wakelock_native.h b/system/gd/os/internal/wakelock_native.h
index 82c7069..f1eedbc 100644
--- a/system/gd/os/internal/wakelock_native.h
+++ b/system/gd/os/internal/wakelock_native.h
@@ -52,8 +52,8 @@
} // namespace os
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::os::internal::WakelockNative::StatusCode>
: enum_formatter<bluetooth::os::internal::WakelockNative::StatusCode> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/gd/os/linux_generic/alarm.cc b/system/gd/os/linux_generic/alarm.cc
index 46c06e5..b4de209 100644
--- a/system/gd/os/linux_generic/alarm.cc
+++ b/system/gd/os/linux_generic/alarm.cc
@@ -86,9 +86,9 @@
lock.unlock();
if (com::android::bluetooth::flags::non_wake_alarm_for_rpa_rotation() && bytes_read == -1) {
- log::info("No data to read.");
+ log::debug("No data to read.");
if (errno == EAGAIN || errno == EWOULDBLOCK) {
- log::info("Alarm is already canceled or rescheduled.");
+ log::debug("Alarm is already canceled or rescheduled.");
return;
}
}
diff --git a/system/gd/packet/parser/gen_cpp.cc b/system/gd/packet/parser/gen_cpp.cc
index 199624f..7dd2dee 100644
--- a/system/gd/packet/parser/gen_cpp.cc
+++ b/system/gd/packet/parser/gen_cpp.cc
@@ -271,7 +271,7 @@
namespace_prefix += "::";
}
- out_file << "#if __has_include(<bluetooth/log.h>)" << std::endl << "namespace fmt {" << std::endl;
+ out_file << "#if __has_include(<bluetooth/log.h>)" << std::endl << "namespace std {" << std::endl;
for (const auto& e : decls.type_defs_queue_) {
if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
const auto* enum_def = static_cast<const EnumDef*>(e.second);
@@ -281,7 +281,7 @@
<< std::endl;
}
}
- out_file << "} // namespace fmt" << std::endl
+ out_file << "} // namespace std" << std::endl
<< "#endif // __has_include(<bluetooth/log.h>)" << std::endl;
out_file.close();
diff --git a/system/include/hardware/avrcp/avrcp_logging_helper.h b/system/include/hardware/avrcp/avrcp_logging_helper.h
index 5ae1f40..c53d2ec 100644
--- a/system/include/hardware/avrcp/avrcp_logging_helper.h
+++ b/system/include/hardware/avrcp/avrcp_logging_helper.h
@@ -41,7 +41,7 @@
CASE_RETURN_TEXT(CType::CHANGED);
CASE_RETURN_TEXT(CType::INTERIM);
default:
- return fmt::format("Unknown CType: 0x{:x}", (uint8_t)type);
+ return std::format("Unknown CType: 0x{:x}", (uint8_t)type);
}
}
@@ -56,7 +56,7 @@
CASE_RETURN_TEXT(Opcode::SUBUNIT_INFO);
CASE_RETURN_TEXT(Opcode::PASS_THROUGH);
default:
- return fmt::format("Unknown Opcode: 0x{:x}", (uint8_t)opcode);
+ return std::format("Unknown Opcode: 0x{:x}", (uint8_t)opcode);
}
}
@@ -78,7 +78,7 @@
CASE_RETURN_TEXT(CommandPdu::SET_ADDRESSED_PLAYER);
CASE_RETURN_TEXT(CommandPdu::PLAY_ITEM);
default:
- return fmt::format("Unknown Command PDU: 0x{:x}", (uint8_t)pdu);
+ return std::format("Unknown Command PDU: 0x{:x}", (uint8_t)pdu);
}
}
@@ -90,7 +90,7 @@
switch (type) {
CASE_RETURN_TEXT(PacketType::SINGLE);
default:
- return fmt::format("Unknown Packet Type: 0x{:x}", (uint8_t)type);
+ return std::format("Unknown Packet Type: 0x{:x}", (uint8_t)type);
}
}
@@ -103,7 +103,7 @@
CASE_RETURN_TEXT(Capability::COMPANY_ID);
CASE_RETURN_TEXT(Capability::EVENTS_SUPPORTED);
default:
- return fmt::format("Unknown Capability: 0x{:x}", (uint8_t)cap);
+ return std::format("Unknown Capability: 0x{:x}", (uint8_t)cap);
}
}
@@ -123,7 +123,7 @@
CASE_RETURN_TEXT(Event::UIDS_CHANGED);
CASE_RETURN_TEXT(Event::VOLUME_CHANGED);
default:
- return fmt::format("Unknown Event: 0x{:x}", (uint8_t)event);
+ return std::format("Unknown Event: 0x{:x}", (uint8_t)event);
}
}
@@ -142,7 +142,7 @@
CASE_RETURN_TEXT(Attribute::PLAYING_TIME);
CASE_RETURN_TEXT(Attribute::DEFAULT_COVER_ART);
default:
- return fmt::format("Unknown Attribute Value: 0x{:x}", (uint32_t)attr);
+ return std::format("Unknown Attribute Value: 0x{:x}", (uint32_t)attr);
}
}
@@ -176,7 +176,7 @@
CASE_RETURN_TEXT(Status::NO_AVAILABLE_PLAYERS);
CASE_RETURN_TEXT(Status::ADDRESSED_PLAYER_CHANGED);
default:
- return fmt::format("Unknown Status: 0x{:x}", (uint8_t)status);
+ return std::format("Unknown Status: 0x{:x}", (uint8_t)status);
}
}
@@ -191,7 +191,7 @@
CASE_RETURN_TEXT(BrowsePdu::CHANGE_PATH);
CASE_RETURN_TEXT(BrowsePdu::GET_ITEM_ATTRIBUTES);
default:
- return fmt::format("Unknown Browse PDU: 0x{:x}", (uint8_t)pdu);
+ return std::format("Unknown Browse PDU: 0x{:x}", (uint8_t)pdu);
}
}
@@ -206,7 +206,7 @@
CASE_RETURN_TEXT(Scope::SEARCH);
CASE_RETURN_TEXT(Scope::NOW_PLAYING);
default:
- return fmt::format("Unknown Scope: 0x{:x}", (uint8_t)scope);
+ return std::format("Unknown Scope: 0x{:x}", (uint8_t)scope);
}
}
@@ -217,7 +217,7 @@
CASE_RETURN_TEXT(Direction::UP);
CASE_RETURN_TEXT(Direction::DOWN);
default:
- return fmt::format("Unknown Direction: 0x{:x}", (uint8_t)dir);
+ return std::format("Unknown Direction: 0x{:x}", (uint8_t)dir);
}
}
@@ -230,7 +230,7 @@
CASE_RETURN_TEXT(KeyState::PUSHED);
CASE_RETURN_TEXT(KeyState::RELEASED);
default:
- return fmt::format("Unknown KeyState: 0x{:x}", (uint8_t)state);
+ return std::format("Unknown KeyState: 0x{:x}", (uint8_t)state);
}
}
@@ -245,7 +245,7 @@
CASE_RETURN_TEXT(PlayerAttribute::SHUFFLE);
CASE_RETURN_TEXT(PlayerAttribute::SCAN);
}
- return fmt::format("Unknown Player Attribute: 0x{:x}", (uint8_t)attr);
+ return std::format("Unknown Player Attribute: 0x{:x}", (uint8_t)attr);
}
inline std::ostream& operator<<(std::ostream& os, const PlayerAttribute& attr) {
@@ -259,7 +259,7 @@
CASE_RETURN_TEXT(PlayerRepeatValue::ALL);
CASE_RETURN_TEXT(PlayerRepeatValue::GROUP);
}
- return fmt::format("Unknown Player Repeat Value: 0x{:x}", (uint8_t)val);
+ return std::format("Unknown Player Repeat Value: 0x{:x}", (uint8_t)val);
}
inline std::ostream& operator<<(std::ostream& os, const PlayerRepeatValue& val) {
@@ -272,7 +272,7 @@
CASE_RETURN_TEXT(PlayerShuffleValue::ALL);
CASE_RETURN_TEXT(PlayerShuffleValue::GROUP);
}
- return fmt::format("Unknown Player Shuffle Value: 0x{:x}", (uint8_t)val);
+ return std::format("Unknown Player Shuffle Value: 0x{:x}", (uint8_t)val);
}
inline std::ostream& operator<<(std::ostream& os, const PlayerShuffleValue& val) {
@@ -282,7 +282,7 @@
} // namespace avrcp
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::avrcp::CType> : ostream_formatter {};
template <>
@@ -313,4 +313,4 @@
struct formatter<bluetooth::avrcp::PlayerRepeatValue> : ostream_formatter {};
template <>
struct formatter<bluetooth::avrcp::PlayerShuffleValue> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h
index 5ae5549..5593e6b 100644
--- a/system/include/hardware/bluetooth.h
+++ b/system/include/hardware/bluetooth.h
@@ -1000,7 +1000,7 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bt_status_t> : enum_formatter<bt_status_t> {};
template <>
@@ -1009,7 +1009,7 @@
struct formatter<bt_bond_state_t> : enum_formatter<bt_bond_state_t> {};
template <>
struct formatter<bt_property_type_t> : enum_formatter<bt_property_type_t> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/include/hardware/bt_av.h b/system/include/hardware/bt_av.h
index c6a9d7a..b839cb0 100644
--- a/system/include/hardware/bt_av.h
+++ b/system/include/hardware/bt_av.h
@@ -21,6 +21,7 @@
#include <hardware/bluetooth.h>
#include <optional>
+#include <sstream>
#include <vector>
#include "types/raw_address.h"
@@ -286,7 +287,7 @@
__END_DECLS
-namespace fmt {
+namespace std {
template <>
struct formatter<btav_connection_state_t> : enum_formatter<btav_connection_state_t> {};
template <>
@@ -306,6 +307,6 @@
template <>
struct formatter<btav_a2dp_scmst_enable_status_t>
: enum_formatter<btav_a2dp_scmst_enable_status_t> {};
-} // namespace fmt
+} // namespace std
#endif /* ANDROID_INCLUDE_BT_AV_H */
diff --git a/system/include/hardware/bt_common_types.h b/system/include/hardware/bt_common_types.h
index e3d6b39..d7b6cc4 100644
--- a/system/include/hardware/bt_common_types.h
+++ b/system/include/hardware/bt_common_types.h
@@ -150,10 +150,10 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bt_gatt_db_attribute_type_t> : enum_formatter<bt_gatt_db_attribute_type_t> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
#endif /* ANDROID_INCLUDE_BT_COMMON_TYPES_H */
diff --git a/system/include/hardware/bt_gmap.h b/system/include/hardware/bt_gmap.h
index bc3e669..7d722fb 100644
--- a/system/include/hardware/bt_gmap.h
+++ b/system/include/hardware/bt_gmap.h
@@ -44,7 +44,7 @@
} // namespace gmap
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::gmap::RolesBitMask> : enum_formatter<bluetooth::gmap::RolesBitMask> {};
template <>
@@ -53,4 +53,4 @@
template <>
struct formatter<bluetooth::gmap::UGGFeatureBitMask>
: enum_formatter<bluetooth::gmap::UGGFeatureBitMask> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/include/hardware/bt_hd.h b/system/include/hardware/bt_hd.h
index f86e2ee..0a4c78f 100644
--- a/system/include/hardware/bt_hd.h
+++ b/system/include/hardware/bt_hd.h
@@ -120,10 +120,10 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bthd_report_type_t> : enum_formatter<bthd_report_type_t> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/include/hardware/bt_hf.h b/system/include/hardware/bt_hf.h
index 48771e2..48ff4d1 100644
--- a/system/include/hardware/bt_hf.h
+++ b/system/include/hardware/bt_hf.h
@@ -118,7 +118,7 @@
} // namespace headset
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::headset::bthf_connection_state_t>
: enum_formatter<bluetooth::headset::bthf_connection_state_t> {};
@@ -149,4 +149,4 @@
template <>
struct formatter<bluetooth::headset::bthf_swb_config_t>
: enum_formatter<bluetooth::headset::bthf_swb_config_t> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/include/hardware/bt_hf_client.h b/system/include/hardware/bt_hf_client.h
index fe4c98b..24a1c10 100644
--- a/system/include/hardware/bt_hf_client.h
+++ b/system/include/hardware/bt_hf_client.h
@@ -384,8 +384,8 @@
bt_status_t (*send_android_at)(const RawAddress* bd_addr, const char* arg);
} bthf_client_interface_t;
-namespace fmt {
+namespace std {
template <>
struct formatter<bthf_client_connection_state_t> : enum_formatter<bthf_client_connection_state_t> {
};
-} // namespace fmt
+} // namespace std
diff --git a/system/include/hardware/bt_hh.h b/system/include/hardware/bt_hh.h
index b326fc1..38f41ff 100644
--- a/system/include/hardware/bt_hh.h
+++ b/system/include/hardware/bt_hh.h
@@ -232,14 +232,14 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bthh_connection_state_t> : enum_formatter<bthh_connection_state_t> {};
template <>
struct formatter<bthh_protocol_mode_t> : enum_formatter<bthh_protocol_mode_t> {};
template <>
struct formatter<bthh_report_type_t> : enum_formatter<bthh_report_type_t> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/include/hardware/bt_le_audio.h b/system/include/hardware/bt_le_audio.h
index 8feb83f..91ce17c 100644
--- a/system/include/hardware/bt_le_audio.h
+++ b/system/include/hardware/bt_le_audio.h
@@ -547,7 +547,7 @@
} /* namespace le_audio */
} /* namespace bluetooth */
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::le_audio::btle_audio_codec_index_t>
: enum_formatter<bluetooth::le_audio::btle_audio_codec_index_t> {};
@@ -566,4 +566,4 @@
template <>
struct formatter<bluetooth::le_audio::GroupStreamStatus>
: enum_formatter<bluetooth::le_audio::GroupStreamStatus> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/include/hardware/bt_pan.h b/system/include/hardware/bt_pan.h
index 95ce4ac..bf8d6151 100644
--- a/system/include/hardware/bt_pan.h
+++ b/system/include/hardware/bt_pan.h
@@ -83,10 +83,10 @@
void (*cleanup)(void);
} btpan_interface_t;
-namespace fmt {
+namespace std {
template <>
struct formatter<btpan_connection_state_t> : enum_formatter<btpan_connection_state_t> {};
template <>
struct formatter<btpan_control_state_t> : enum_formatter<btpan_control_state_t> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/include/hardware/bt_rc.h b/system/include/hardware/bt_rc.h
index d6a984e..7438c93 100644
--- a/system/include/hardware/bt_rc.h
+++ b/system/include/hardware/bt_rc.h
@@ -680,7 +680,7 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<btrc_status_t> : enum_formatter<btrc_status_t> {};
template <>
@@ -689,7 +689,7 @@
struct formatter<btrc_remote_features_t> : enum_formatter<btrc_remote_features_t> {};
template <>
struct formatter<btrc_notification_type_t> : enum_formatter<btrc_notification_type_t> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/include/hardware/bt_sdp.h b/system/include/hardware/bt_sdp.h
index 8246bc7..d595637 100644
--- a/system/include/hardware/bt_sdp.h
+++ b/system/include/hardware/bt_sdp.h
@@ -178,9 +178,9 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth_sdp_types> : enum_formatter<bluetooth_sdp_types> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/include/hardware/bt_sock.h b/system/include/hardware/bt_sock.h
index fd28ff3..ad8cc45 100644
--- a/system/include/hardware/bt_sock.h
+++ b/system/include/hardware/bt_sock.h
@@ -125,9 +125,9 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<btsock_type_t> : enum_formatter<btsock_type_t> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/include/hardware/bt_vc.h b/system/include/hardware/bt_vc.h
index 10ede4f..50adebe 100644
--- a/system/include/hardware/bt_vc.h
+++ b/system/include/hardware/bt_vc.h
@@ -150,11 +150,11 @@
} /* namespace vc */
} /* namespace bluetooth */
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::vc::VolumeInputType> : enum_formatter<bluetooth::vc::VolumeInputType> {
};
template <>
struct formatter<bluetooth::vc::VolumeInputStatus>
: enum_formatter<bluetooth::vc::VolumeInputStatus> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/include/macros.h b/system/include/macros.h
index 1bf83cd..9fb3891 100644
--- a/system/include/macros.h
+++ b/system/include/macros.h
@@ -27,11 +27,11 @@
#define CASE_RETURN_STRING(enumerator) \
case enumerator: \
- return fmt::format(#enumerator "(0x{:x})", static_cast<uint64_t>(enumerator))
+ return std::format(#enumerator "(0x{:x})", static_cast<uint64_t>(enumerator))
#define CASE_RETURN_STRING_HEX04(enumerator) \
case enumerator: \
- return fmt::format(#enumerator "(0x{:04x})", static_cast<uint64_t>(enumerator))
+ return std::format(#enumerator "(0x{:04x})", static_cast<uint64_t>(enumerator))
#define RETURN_UNKNOWN_TYPE_STRING(type, variable) \
- return fmt::format("Unknown {}(0x{:x})", #type, static_cast<uint64_t>(variable))
+ return std::format("Unknown {}(0x{:x})", #type, static_cast<uint64_t>(variable))
diff --git a/system/log/include/bluetooth/log.h b/system/log/include/bluetooth/log.h
index b8921c6..34cb605 100644
--- a/system/log/include/bluetooth/log.h
+++ b/system/log/include/bluetooth/log.h
@@ -16,9 +16,10 @@
#pragma once
-#include <fmt/core.h>
-#include <fmt/ranges.h>
-#include <fmt/std.h>
+#include <atomic>
+#include <format>
+#include <sstream>
+#include <string_view>
#ifndef LOG_TAG
#define LOG_TAG "bluetooth"
@@ -53,8 +54,8 @@
/// Write a single log line.
/// The implementation of this function is dependent on the backend.
-void vlog(Level level, char const* tag, source_location location, fmt::string_view fmt,
- fmt::format_args vargs);
+void vlog(Level level, char const* tag, source_location location, std::string_view fmt,
+ std::format_args vargs);
/// Capture invalid parameter values that would cause runtime
/// formatting errors.
@@ -85,16 +86,15 @@
template <Level level, typename... T>
struct log {
- log(fmt::format_string<T...> fmt, T&&... args, source_location location = source_location()) {
- vlog(level, LOG_TAG, location, static_cast<fmt::string_view>(fmt),
- fmt::make_format_args(format_replace(args)...));
+ log(std::format_string<T...> fmt, T&&... args, source_location location = source_location()) {
+ vlog(level, LOG_TAG, location, fmt.get(), std::make_format_args(format_replace(args)...));
}
};
#if (__cplusplus >= 202002L && defined(__GNUC__) && !defined(__clang__))
template <int level, typename... T>
-log(fmt::format_string<T...>, T&&...) -> log<level, T...>;
+log(std::format_string<T...>, T&&...) -> log<level, T...>;
#endif
@@ -139,61 +139,60 @@
};
template <typename... T>
-error(fmt::format_string<T...>, T&&...) -> error<T...>;
+error(std::format_string<T...>, T&&...) -> error<T...>;
template <typename... T>
-warn(fmt::format_string<T...>, T&&...) -> warn<T...>;
+warn(std::format_string<T...>, T&&...) -> warn<T...>;
template <typename... T>
-info(fmt::format_string<T...>, T&&...) -> info<T...>;
+info(std::format_string<T...>, T&&...) -> info<T...>;
template <typename... T>
-debug(fmt::format_string<T...>, T&&...) -> debug<T...>;
+debug(std::format_string<T...>, T&&...) -> debug<T...>;
template <typename... T>
-verbose(fmt::format_string<T...>, T&&...) -> verbose<T...>;
+verbose(std::format_string<T...>, T&&...) -> verbose<T...>;
#endif // GCC / C++20
[[noreturn]] [[maybe_unused]] static void fatal(
- fmt::format_string<> fmt,
+ std::format_string<> fmt,
log_internal::source_location location = log_internal::source_location()) {
- vlog(log_internal::kFatal, LOG_TAG, location, static_cast<fmt::string_view>(fmt),
- fmt::make_format_args());
+ vlog(log_internal::kFatal, LOG_TAG, location, fmt.get(), std::make_format_args());
std::abort(); // Enforce [[noreturn]]
}
template <typename T0>
[[noreturn]] [[maybe_unused]] static void fatal(
- fmt::format_string<T0> fmt, T0&& arg0,
+ std::format_string<T0> fmt, T0&& arg0,
log_internal::source_location location = log_internal::source_location()) {
- vlog(log_internal::kFatal, LOG_TAG, location, static_cast<fmt::string_view>(fmt),
- fmt::make_format_args(log_internal::format_replace(arg0)));
+ vlog(log_internal::kFatal, LOG_TAG, location, fmt.get(),
+ std::make_format_args(log_internal::format_replace(arg0)));
std::abort(); // Enforce [[noreturn]]
}
template <typename T0, typename T1>
[[noreturn]] [[maybe_unused]] static void fatal(
- fmt::format_string<T0, T1> fmt, T0&& arg0, T1&& arg1,
+ std::format_string<T0, T1> fmt, T0&& arg0, T1&& arg1,
log_internal::source_location location = log_internal::source_location()) {
- vlog(log_internal::kFatal, LOG_TAG, location, static_cast<fmt::string_view>(fmt),
- fmt::make_format_args(log_internal::format_replace(arg0),
+ vlog(log_internal::kFatal, LOG_TAG, location, fmt.get(),
+ std::make_format_args(log_internal::format_replace(arg0),
log_internal::format_replace(arg1)));
std::abort(); // Enforce [[noreturn]]
}
template <typename T0, typename T1, typename T2>
[[noreturn]] [[maybe_unused]] static void fatal(
- fmt::format_string<T0, T1, T2> fmt, T0&& arg0, T1&& arg1, T2&& arg2,
+ std::format_string<T0, T1, T2> fmt, T0&& arg0, T1&& arg1, T2&& arg2,
log_internal::source_location location = log_internal::source_location()) {
- vlog(log_internal::kFatal, LOG_TAG, location, static_cast<fmt::string_view>(fmt),
- fmt::make_format_args(log_internal::format_replace(arg0), log_internal::format_replace(arg1),
+ vlog(log_internal::kFatal, LOG_TAG, location, fmt.get(),
+ std::make_format_args(log_internal::format_replace(arg0), log_internal::format_replace(arg1),
log_internal::format_replace(arg2)));
std::abort(); // Enforce [[noreturn]]
}
template <typename T0, typename T1, typename T2, typename T3>
[[noreturn]] [[maybe_unused]] static void fatal(
- fmt::format_string<T0, T1, T2, T3> fmt, T0&& arg0, T1&& arg1, T2&& arg2, T3&& arg3,
+ std::format_string<T0, T1, T2, T3> fmt, T0&& arg0, T1&& arg1, T2&& arg2, T3&& arg3,
log_internal::source_location location = log_internal::source_location()) {
- vlog(log_internal::kFatal, LOG_TAG, location, static_cast<fmt::string_view>(fmt),
- fmt::make_format_args(log_internal::format_replace(arg0), log_internal::format_replace(arg1),
+ vlog(log_internal::kFatal, LOG_TAG, location, fmt.get(),
+ std::make_format_args(log_internal::format_replace(arg0), log_internal::format_replace(arg1),
log_internal::format_replace(arg2),
log_internal::format_replace(arg3)));
std::abort(); // Enforce [[noreturn]]
@@ -201,21 +200,63 @@
template <typename... T>
struct assert_that {
- assert_that(bool cond, fmt::format_string<T...> fmt, T&&... args,
+ assert_that(bool cond, std::format_string<T...> fmt, T&&... args,
log_internal::source_location location = log_internal::source_location()) {
if (!cond) {
- vlog(log_internal::kFatal, LOG_TAG, location, static_cast<fmt::string_view>(fmt),
- fmt::make_format_args(log_internal::format_replace(args)...));
+ vlog(log_internal::kFatal, LOG_TAG, location, fmt.get(),
+ std::make_format_args(log_internal::format_replace(args)...));
}
}
};
template <typename... T>
-assert_that(bool, fmt::format_string<T...>, T&&...) -> assert_that<T...>;
+assert_that(bool, std::format_string<T...>, T&&...) -> assert_that<T...>;
} // namespace bluetooth::log
-namespace fmt {
+namespace std {
+
+/// Helper to format a pointer value as the memory address.
+/// Use this helper as `std::format("{}", std::format_ptr(value));`.
+template <typename T>
+const void* format_ptr(T* ptr) {
+ return reinterpret_cast<const void*>(ptr);
+}
+
+/// Derive formatter for std::atomic<T> types where T is formattable.
+/// The formatter uses the default memory order `std::memory_order_seq_cst`
+/// for reading the value.
+template <typename T, typename CharT>
+struct formatter<std::atomic<T>, CharT> : formatter<T, CharT> {
+ template <typename Context>
+ auto format(const std::atomic<T>& v, Context& ctx) const -> decltype(ctx.out()) {
+ return formatter<T, CharT>::format(v.load(), ctx);
+ }
+};
+
+/// Default formatter implementation for formatting
+/// types overloading the ostream `operator<<`.
+///
+/// Enable this formatter in the code by declaring:
+/// ```
+/// template<>
+/// struct std::formatter<T> : ostream_formatter {};
+/// ```
+template <typename CharT>
+struct basic_ostream_formatter : formatter<basic_string_view<CharT>, CharT> {
+ void set_debug_format() = delete;
+
+ template <typename T, typename Context>
+ auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
+ auto&& output = std::basic_stringstream<CharT>();
+ output.imbue(std::locale::classic()); // The default is always unlocalized.
+ output << value;
+ output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+ return formatter<basic_string_view<CharT>, CharT>::format(output.str(), ctx);
+ }
+};
+
+using ostream_formatter = basic_ostream_formatter<char>;
/// Default formatter implementation for formatting
/// enum class values to the underlying type.
@@ -223,13 +264,13 @@
/// Enable this formatter in the code by declaring:
/// ```
/// template<>
-/// struct fmt::formatter<EnumT> : enum_formatter<EnumT> {};
+/// struct std::formatter<EnumT> : enum_formatter<EnumT> {};
/// ```
template <typename EnumT, class CharT = char>
-struct enum_formatter : fmt::formatter<std::underlying_type_t<EnumT>, CharT> {
+struct enum_formatter : std::formatter<std::underlying_type_t<EnumT>, CharT> {
template <class Context>
typename Context::iterator format(EnumT value, Context& ctx) const {
- return fmt::formatter<std::underlying_type_t<EnumT>, CharT>::format(
+ return std::formatter<std::underlying_type_t<EnumT>, CharT>::format(
static_cast<std::underlying_type_t<EnumT>>(value), ctx);
}
};
@@ -241,14 +282,14 @@
/// Enable this formatter in the code by declaring:
/// ```
/// template<>
-/// struct fmt::formatter<T> : string_formatter<T, &T_to_str> {};
+/// struct std::formatter<T> : string_formatter<T, &T_to_str> {};
/// ```
template <typename T, std::string (*F)(const T&), class CharT = char>
-struct string_formatter : fmt::formatter<std::string> {
+struct string_formatter : std::formatter<std::string> {
template <class Context>
typename Context::iterator format(const T& value, Context& ctx) const {
- return fmt::formatter<std::string>::format(F(value), ctx);
+ return std::formatter<std::string>::format(F(value), ctx);
}
};
-} // namespace fmt
+} // namespace std
diff --git a/system/log/src/truncating_buffer_test.cc b/system/log/src/truncating_buffer_test.cc
index a0b4a09..3940a08 100644
--- a/system/log/src/truncating_buffer_test.cc
+++ b/system/log/src/truncating_buffer_test.cc
@@ -18,17 +18,18 @@
#include "truncating_buffer.h"
-#include <fmt/format.h>
#include <gtest/gtest.h>
+#include <format>
+
using namespace bluetooth::log_internal;
TEST(TruncatingBufferTest, 1byte) {
EXPECT_EQ(sizeof("ab"), 3);
truncating_buffer<2> buffer_1;
truncating_buffer<3> buffer_2;
- fmt::format_to(std::back_insert_iterator(buffer_1), "ab");
- fmt::format_to(std::back_insert_iterator(buffer_2), "ab");
+ std::format_to(std::back_insert_iterator(buffer_1), "ab");
+ std::format_to(std::back_insert_iterator(buffer_2), "ab");
EXPECT_STREQ(buffer_1.c_str(), "a");
EXPECT_STREQ(buffer_2.c_str(), "ab");
}
@@ -38,9 +39,9 @@
truncating_buffer<3> buffer_1;
truncating_buffer<4> buffer_2;
truncating_buffer<5> buffer_3;
- fmt::format_to(std::back_insert_iterator(buffer_1), "αβ");
- fmt::format_to(std::back_insert_iterator(buffer_2), "αβ");
- fmt::format_to(std::back_insert_iterator(buffer_3), "αβ");
+ std::format_to(std::back_insert_iterator(buffer_1), "αβ");
+ std::format_to(std::back_insert_iterator(buffer_2), "αβ");
+ std::format_to(std::back_insert_iterator(buffer_3), "αβ");
EXPECT_STREQ(buffer_1.c_str(), "α");
EXPECT_STREQ(buffer_2.c_str(), "α");
EXPECT_STREQ(buffer_3.c_str(), "αβ");
@@ -52,10 +53,10 @@
truncating_buffer<5> buffer_2;
truncating_buffer<6> buffer_3;
truncating_buffer<7> buffer_4;
- fmt::format_to(std::back_insert_iterator(buffer_1), "ພຮ");
- fmt::format_to(std::back_insert_iterator(buffer_2), "ພຮ");
- fmt::format_to(std::back_insert_iterator(buffer_3), "ພຮ");
- fmt::format_to(std::back_insert_iterator(buffer_4), "ພຮ");
+ std::format_to(std::back_insert_iterator(buffer_1), "ພຮ");
+ std::format_to(std::back_insert_iterator(buffer_2), "ພຮ");
+ std::format_to(std::back_insert_iterator(buffer_3), "ພຮ");
+ std::format_to(std::back_insert_iterator(buffer_4), "ພຮ");
EXPECT_STREQ(buffer_1.c_str(), "ພ");
EXPECT_STREQ(buffer_2.c_str(), "ພ");
EXPECT_STREQ(buffer_3.c_str(), "ພ");
@@ -69,11 +70,11 @@
truncating_buffer<7> buffer_3;
truncating_buffer<8> buffer_4;
truncating_buffer<9> buffer_5;
- fmt::format_to(std::back_insert_iterator(buffer_1), "𐎡𐎪");
- fmt::format_to(std::back_insert_iterator(buffer_2), "𐎡𐎪");
- fmt::format_to(std::back_insert_iterator(buffer_3), "𐎡𐎪");
- fmt::format_to(std::back_insert_iterator(buffer_4), "𐎡𐎪");
- fmt::format_to(std::back_insert_iterator(buffer_5), "𐎡𐎪");
+ std::format_to(std::back_insert_iterator(buffer_1), "𐎡𐎪");
+ std::format_to(std::back_insert_iterator(buffer_2), "𐎡𐎪");
+ std::format_to(std::back_insert_iterator(buffer_3), "𐎡𐎪");
+ std::format_to(std::back_insert_iterator(buffer_4), "𐎡𐎪");
+ std::format_to(std::back_insert_iterator(buffer_5), "𐎡𐎪");
EXPECT_STREQ(buffer_1.c_str(), "𐎡");
EXPECT_STREQ(buffer_2.c_str(), "𐎡");
EXPECT_STREQ(buffer_3.c_str(), "𐎡");
diff --git a/system/log/src/vlog_android.cc b/system/log/src/vlog_android.cc
index 6f4ef34..53b195c 100644
--- a/system/log/src/vlog_android.cc
+++ b/system/log/src/vlog_android.cc
@@ -25,8 +25,8 @@
static constexpr size_t kBufferSize = 1024;
-void vlog(Level level, char const* tag, source_location location, fmt::string_view fmt,
- fmt::format_args vargs) {
+void vlog(Level level, char const* tag, source_location location, std::string_view fmt,
+ std::format_args vargs) {
// Check if log is enabled.
if (!__android_log_is_loggable(level, "bluetooth", ANDROID_LOG_INFO)) {
return;
@@ -44,9 +44,9 @@
// In order to have consistent logs we include it manually in the log
// message.
truncating_buffer<kBufferSize> buffer;
- fmt::format_to(std::back_insert_iterator(buffer), "{}:{} {}: ", file_name, location.line,
+ std::format_to(std::back_insert_iterator(buffer), "{}:{} {}: ", file_name, location.line,
location.function_name);
- fmt::vformat_to(std::back_insert_iterator(buffer), fmt, vargs);
+ std::vformat_to(std::back_insert_iterator(buffer), fmt, vargs);
// Send message to liblog.
struct __android_log_message message = {
diff --git a/system/log/src/vlog_syslog.cc b/system/log/src/vlog_syslog.cc
index 73d7ec6..890fc39 100644
--- a/system/log/src/vlog_syslog.cc
+++ b/system/log/src/vlog_syslog.cc
@@ -48,8 +48,8 @@
// Default value for $MaxMessageSize for rsyslog.
static constexpr size_t kBufferSize = 8192;
-void vlog(Level level, char const* tag, source_location location, fmt::string_view fmt,
- fmt::format_args vargs) {
+void vlog(Level level, char const* tag, source_location location, std::string_view fmt,
+ std::format_args vargs) {
// Filter out logs that don't meet level requirement.
Level current_level = GetLogLevelForTag(tag);
if (level < current_level) {
@@ -82,11 +82,11 @@
truncating_buffer<kBufferSize> buffer;
// Format file, line.
- fmt::format_to(std::back_insert_iterator(buffer), "{} {}:{} {}: ", tag, location.file_name,
+ std::format_to(std::back_insert_iterator(buffer), "{} {}:{} {}: ", tag, location.file_name,
location.line, location.function_name);
// Format message.
- fmt::vformat_to(std::back_insert_iterator(buffer), fmt, vargs);
+ std::vformat_to(std::back_insert_iterator(buffer), fmt, vargs);
// Print to vsyslog.
syslog(LOG_USER | severity, "%s", buffer.c_str());
diff --git a/system/main/shim/acl.cc b/system/main/shim/acl.cc
index 44c3a05..da5afc6 100644
--- a/system/main/shim/acl.cc
+++ b/system/main/shim/acl.cc
@@ -123,16 +123,16 @@
};
} // namespace std
-namespace fmt {
+namespace std {
template <>
struct formatter<ConnectAddressWithType> : formatter<std::string> {
template <class Context>
typename Context::iterator format(const ConnectAddressWithType& address, Context& ctx) const {
std::string repr = address.ToRedactedStringForLogging();
- return fmt::formatter<std::string>::format(repr, ctx);
+ return std::formatter<std::string>::format(repr, ctx);
}
};
-} // namespace fmt
+} // namespace std
namespace {
diff --git a/system/osi/include/compat.h b/system/osi/include/compat.h
index 78c2948..6fbefc3 100644
--- a/system/osi/include/compat.h
+++ b/system/osi/include/compat.h
@@ -25,7 +25,7 @@
/// Supplied by bionic and glibc>=2.38
/// This declaration is added simplify clang-tidy
/// misc-include-cleaner check.
-extern "C" size_t strlcpy(char* dst, const char* src, size_t siz);
+size_t osi_strlcpy(char* dst, const char* src, size_t size);
#if __GLIBC__
diff --git a/system/osi/src/compat.cc b/system/osi/src/compat.cc
index d4cbe5c..97e812a 100644
--- a/system/osi/src/compat.cc
+++ b/system/osi/src/compat.cc
@@ -54,17 +54,14 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#endif /* __GLIBC__ */
/*
- * Glibc added strlcpy() starting with 2.38, so skip it if glibc >= 2.38.
- */
-#if !(__GLIBC_PREREQ(2, 38))
-/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
-extern "C" size_t strlcpy(char* dst, const char* src, size_t siz) {
+size_t osi_strlcpy(char* dst, const char* src, size_t siz) {
char* d = dst;
const char* s = src;
size_t n = siz;
@@ -89,5 +86,3 @@
return s - src - 1; /* count does not include NUL */
}
-#endif /* !(__GLIBC_PREREQ(2, 38)) */
-#endif /* __GLIBC__ */
diff --git a/system/osi/test/fuzzers/compat/fuzz_compat.cc b/system/osi/test/fuzzers/compat/fuzz_compat.cc
index cf209cc..3df5924 100644
--- a/system/osi/test/fuzzers/compat/fuzz_compat.cc
+++ b/system/osi/test/fuzzers/compat/fuzz_compat.cc
@@ -49,7 +49,7 @@
// Copy, then concat
size_t len_to_cpy = dataProvider.ConsumeIntegralInRange<size_t>(0, buf_size);
- strlcpy(reinterpret_cast<char*>(dst_buf), reinterpret_cast<char*>(bytes.data()), len_to_cpy);
+ osi_strlcpy(reinterpret_cast<char*>(dst_buf), reinterpret_cast<char*>(bytes.data()), len_to_cpy);
// Clear out our dest buffer
free(dst_buf);
diff --git a/system/pdl/hci/include/hci/address.h b/system/pdl/hci/include/hci/address.h
index 8e27da1..bc9c8d9 100644
--- a/system/pdl/hci/include/hci/address.h
+++ b/system/pdl/hci/include/hci/address.h
@@ -114,15 +114,15 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::hci::Address> : formatter<std::string> {
template <class Context>
typename Context::iterator format(const bluetooth::hci::Address& address, Context& ctx) const {
std::string repr = address.ToRedactedStringForLogging();
- return fmt::formatter<std::string>::format(repr, ctx);
+ return std::formatter<std::string>::format(repr, ctx);
}
};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/profile/avrcp/avrcp_sdp_service.h b/system/profile/avrcp/avrcp_sdp_service.h
index dace6b8..6f4b9ef 100644
--- a/system/profile/avrcp/avrcp_sdp_service.h
+++ b/system/profile/avrcp/avrcp_sdp_service.h
@@ -19,6 +19,7 @@
#include <bluetooth/log.h>
#include <cstdint>
+#include <memory>
#include "avrcp_sdp_records.h"
diff --git a/system/profile/avrcp/device.cc b/system/profile/avrcp/device.cc
index 0201858..a5012e8 100644
--- a/system/profile/avrcp/device.cc
+++ b/system/profile/avrcp/device.cc
@@ -44,7 +44,7 @@
extern bool btif_av_src_sink_coexist_enabled(void);
template <>
-struct fmt::formatter<bluetooth::avrcp::PlayState> : enum_formatter<bluetooth::avrcp::PlayState> {};
+struct std::formatter<bluetooth::avrcp::PlayState> : enum_formatter<bluetooth::avrcp::PlayState> {};
namespace bluetooth {
namespace avrcp {
diff --git a/system/rust/src/gatt/ffi/gatt_shim.h b/system/rust/src/gatt/ffi/gatt_shim.h
index 0ddbab0..e159831 100644
--- a/system/rust/src/gatt/ffi/gatt_shim.h
+++ b/system/rust/src/gatt/ffi/gatt_shim.h
@@ -58,8 +58,8 @@
} // namespace gatt
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::gatt::AttributeBackingType>
: enum_formatter<bluetooth::gatt::AttributeBackingType> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/a2dp/a2dp_aac_encoder.cc b/system/stack/a2dp/a2dp_aac_encoder.cc
index db455cd..841ef48 100644
--- a/system/stack/a2dp/a2dp_aac_encoder.cc
+++ b/system/stack/a2dp/a2dp_aac_encoder.cc
@@ -49,10 +49,10 @@
using namespace bluetooth;
-namespace fmt {
+namespace std {
template <>
struct formatter<AACENC_ERROR> : enum_formatter<AACENC_ERROR> {};
-} // namespace fmt
+} // namespace std
typedef struct {
uint32_t sample_rate;
diff --git a/system/stack/a2dp/a2dp_codec_config.cc b/system/stack/a2dp/a2dp_codec_config.cc
index 2469cbc..9155dab 100644
--- a/system/stack/a2dp/a2dp_codec_config.cc
+++ b/system/stack/a2dp/a2dp_codec_config.cc
@@ -1665,7 +1665,7 @@
break;
}
- return fmt::format("Unsupported codec type: {:x}", codec_type);
+ return std::format("Unsupported codec type: {:x}", codec_type);
}
int A2DP_GetEecoderEffectiveFrameSize(const uint8_t* p_codec_info) {
diff --git a/system/stack/a2dp/a2dp_sbc_decoder.cc b/system/stack/a2dp/a2dp_sbc_decoder.cc
index b3d2881..d59f4ae 100644
--- a/system/stack/a2dp/a2dp_sbc_decoder.cc
+++ b/system/stack/a2dp/a2dp_sbc_decoder.cc
@@ -31,10 +31,10 @@
using namespace bluetooth;
-namespace fmt {
+namespace std {
template <>
struct formatter<OI_STATUS> : enum_formatter<OI_STATUS> {};
-} // namespace fmt
+} // namespace std
typedef struct {
OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
diff --git a/system/stack/a2dp/a2dp_vendor.cc b/system/stack/a2dp/a2dp_vendor.cc
index 74f1b5c..28a27c7 100644
--- a/system/stack/a2dp/a2dp_vendor.cc
+++ b/system/stack/a2dp/a2dp_vendor.cc
@@ -541,5 +541,5 @@
// Add checks based on <vendor_id, codec_id>
- return fmt::format("Unsupported codec vendor_id: 0x{:x} codec_id: 0x{:x}", vendor_id, codec_id);
+ return std::format("Unsupported codec vendor_id: 0x{:x} codec_id: 0x{:x}", vendor_id, codec_id);
}
diff --git a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc
index 0571216..9c13d50 100644
--- a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc
+++ b/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc
@@ -34,10 +34,10 @@
using namespace bluetooth;
-namespace fmt {
+namespace std {
template <>
struct formatter<LDACBT_SMPL_FMT_T> : enum_formatter<LDACBT_SMPL_FMT_T> {};
-} // namespace fmt
+} // namespace std
//
// Decoder for LDAC Source Codec
diff --git a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc
index c2a04d6..4dd4a6e 100644
--- a/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc
+++ b/system/stack/a2dp/a2dp_vendor_ldac_encoder.cc
@@ -61,10 +61,10 @@
using namespace bluetooth;
-namespace fmt {
+namespace std {
template <>
struct formatter<LDACBT_SMPL_FMT_T> : enum_formatter<LDACBT_SMPL_FMT_T> {};
-} // namespace fmt
+} // namespace std
typedef struct {
uint32_t sample_rate;
diff --git a/system/stack/avct/avct_api.cc b/system/stack/avct/avct_api.cc
index 2c3db70..33d5812 100644
--- a/system/stack/avct/avct_api.cc
+++ b/system/stack/avct/avct_api.cc
@@ -457,7 +457,7 @@
if (ccb.p_lcb) { // tAVCT_LCB
LOG_DUMPSYS(fd,
" Link : peer:%s lcid:0x%04x sm_state:%-24s ch_state:%s conflict_lcid:0x%04x",
- fmt::format("{}", ccb.p_lcb->peer_addr).c_str(), ccb.p_lcb->ch_lcid,
+ std::format("{}", ccb.p_lcb->peer_addr).c_str(), ccb.p_lcb->ch_lcid,
avct_sm_state_text(ccb.p_lcb->state).c_str(),
avct_ch_state_text(ccb.p_lcb->ch_state).c_str(), ccb.p_lcb->conflict_lcid);
} else {
@@ -467,7 +467,7 @@
if (ccb.p_bcb) { // tAVCT_BCB
LOG_DUMPSYS(fd,
" Browse: peer:%s lcid:0x%04x sm_state:%-24s ch_state:%s conflict_lcid:0x%04x",
- fmt::format("{}", ccb.p_bcb->peer_addr).c_str(), ccb.p_bcb->ch_lcid,
+ std::format("{}", ccb.p_bcb->peer_addr).c_str(), ccb.p_bcb->ch_lcid,
avct_sm_state_text(ccb.p_bcb->state).c_str(),
avct_ch_state_text(ccb.p_bcb->ch_state).c_str(), ccb.p_bcb->conflict_lcid);
} else {
diff --git a/system/stack/avdt/avdt_ad.cc b/system/stack/avdt/avdt_ad.cc
index 92535cb..36b395d 100644
--- a/system/stack/avdt/avdt_ad.cc
+++ b/system/stack/avdt/avdt_ad.cc
@@ -289,8 +289,8 @@
AvdtpScb* p_scb;
tAVDT_SCB_TC_CLOSE close;
- log::verbose("p_tbl: {} state: {} tcid: {} type: {} ccb_idx: {} scb_hdl: {}", fmt::ptr(p_tbl),
- tc_state_text(p_tbl->state), p_tbl->tcid,
+ log::verbose("p_tbl: {} state: {} tcid: {} type: {} ccb_idx: {} scb_hdl: {}",
+ std::format_ptr(p_tbl), tc_state_text(p_tbl->state), p_tbl->tcid,
tc_type_text(avdt_ad_tcid_to_type(p_tbl->tcid)), p_tbl->ccb_idx,
avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
@@ -338,8 +338,8 @@
tAVDT_OPEN open;
tAVDT_EVT_HDR evt;
- log::verbose("p_tbl: {} state: {} tcid: {} type: {} ccb_idx: {} scb_hdl: {}", fmt::ptr(p_tbl),
- tc_state_text(p_tbl->state), p_tbl->tcid,
+ log::verbose("p_tbl: {} state: {} tcid: {} type: {} ccb_idx: {} scb_hdl: {}",
+ std::format_ptr(p_tbl), tc_state_text(p_tbl->state), p_tbl->tcid,
tc_type_text(avdt_ad_tcid_to_type(p_tbl->tcid)), p_tbl->ccb_idx,
avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
@@ -401,7 +401,7 @@
AvdtpScb* p_scb;
log::verbose("p_tbl: {} state: {} tcid: {} type: {} ccb_idx: {} scb_hdl: {} is_congested: {}",
- fmt::ptr(p_tbl), tc_state_text(p_tbl->state), p_tbl->tcid,
+ std::format_ptr(p_tbl), tc_state_text(p_tbl->state), p_tbl->tcid,
tc_type_text(avdt_ad_tcid_to_type(p_tbl->tcid)), p_tbl->ccb_idx,
avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl, is_congested);
@@ -515,7 +515,7 @@
p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
p_tbl->my_mtu = kAvdtpMtu;
- log::verbose("p_tbl: {} state: {} tcid: {} type: {} role: {} my_mtu: {}", fmt::ptr(p_tbl),
+ log::verbose("p_tbl: {} state: {} tcid: {} type: {} role: {} my_mtu: {}", std::format_ptr(p_tbl),
tc_state_text(p_tbl->state), p_tbl->tcid, tc_type_text(type), role, p_tbl->my_mtu);
if (type != AVDT_CHAN_SIG) {
@@ -574,9 +574,9 @@
AvdtpTransportChannel* p_tbl;
p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
- log::verbose("p_tbl: {} state: {} tcid: {} type: {} ccb_idx: {} scb_hdl: {}", fmt::ptr(p_tbl),
- tc_state_text(p_tbl->state), p_tbl->tcid, tc_type_text(type), p_tbl->ccb_idx,
- avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+ log::verbose("p_tbl: {} state: {} tcid: {} type: {} ccb_idx: {} scb_hdl: {}",
+ std::format_ptr(p_tbl), tc_state_text(p_tbl->state), p_tbl->tcid, tc_type_text(type),
+ p_tbl->ccb_idx, avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
switch (p_tbl->state) {
case AVDT_AD_ST_UNUSED:
diff --git a/system/stack/avdt/avdt_ccb.cc b/system/stack/avdt/avdt_ccb.cc
index e478243..66eae28 100644
--- a/system/stack/avdt/avdt_ccb.cc
+++ b/system/stack/avdt/avdt_ccb.cc
@@ -366,7 +366,7 @@
int i;
log::verbose("CCB ccb={} event={} state={} p_ccb={}", avdt_ccb_to_idx(p_ccb),
- avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state], fmt::ptr(p_ccb));
+ avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state], std::format_ptr(p_ccb));
/* look up the state table for the current state */
state_table = avdt_ccb_st_tbl[p_ccb->state];
@@ -457,7 +457,7 @@
}
p_ccb->Allocate(bd_addr);
log::verbose("allocated (index {}) peer={} p_ccb={}", channel_index, p_ccb->peer_addr,
- fmt::ptr(p_ccb));
+ std::format_ptr(p_ccb));
return p_ccb;
}
@@ -484,7 +484,7 @@
******************************************************************************/
void avdt_ccb_dealloc(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* /* p_data */) {
log::verbose("deallocated (index {}) peer={} p_ccb={}", avdt_ccb_to_idx(p_ccb), p_ccb->peer_addr,
- fmt::ptr(p_ccb));
+ std::format_ptr(p_ccb));
p_ccb->ResetCcb();
}
diff --git a/system/stack/avdt/avdt_ccb_act.cc b/system/stack/avdt/avdt_ccb_act.cc
index 9f8557f..168d7ee 100644
--- a/system/stack/avdt/avdt_ccb_act.cc
+++ b/system/stack/avdt/avdt_ccb_act.cc
@@ -1026,7 +1026,7 @@
tAVDT_CTRL avdt_ctrl;
log::verbose("peer {} BtaAvScbIndex={} p_ccb={}", p_ccb->peer_addr, p_ccb->BtaAvScbIndex(),
- fmt::ptr(p_ccb));
+ std::format_ptr(p_ccb));
p_ccb->ll_opened = true;
if (!p_ccb->p_conn_cback) {
diff --git a/system/stack/avdt/avdt_int.h b/system/stack/avdt/avdt_int.h
index 09eb424..09aa557 100644
--- a/system/stack/avdt/avdt_int.h
+++ b/system/stack/avdt/avdt_int.h
@@ -352,12 +352,12 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tTRANSPORT_CHANNEL_STATE> : enum_formatter<tTRANSPORT_CHANNEL_STATE> {};
template <>
struct formatter<tTRANSPORT_CHANNEL_TYPE> : enum_formatter<tTRANSPORT_CHANNEL_TYPE> {};
-} // namespace fmt
+} // namespace std
/*****************************************************************************
* data types
diff --git a/system/stack/avdt/avdt_scb.cc b/system/stack/avdt/avdt_scb.cc
index 67be1b9..6f4eefa 100644
--- a/system/stack/avdt/avdt_scb.cc
+++ b/system/stack/avdt/avdt_scb.cc
@@ -760,8 +760,8 @@
uint8_t action;
log::verbose("SCB hdl={} event={}/{} state={} p_avdt_scb={} scb_index={}", avdt_scb_to_hdl(p_scb),
- event, avdt_scb_evt_str[event], avdt_scb_st_str[p_scb->state], fmt::ptr(p_scb),
- p_scb->stream_config.scb_index);
+ event, avdt_scb_evt_str[event], avdt_scb_st_str[p_scb->state],
+ std::format_ptr(p_scb), p_scb->stream_config.scb_index);
/* Check that we only send AVDT_SCB_API_WRITE_REQ_EVT to the active stream
* device */
@@ -925,7 +925,7 @@
return nullptr;
}
- log::verbose("SCB for handle {} found: p_scb={} scb_index={}", hdl, fmt::ptr(p_scb),
+ log::verbose("SCB for handle {} found: p_scb={} scb_index={}", hdl, std::format_ptr(p_scb),
p_scb->stream_config.scb_index);
return p_scb;
}
diff --git a/system/stack/avdt/avdt_scb_act.cc b/system/stack/avdt/avdt_scb_act.cc
index 4f7c1f5..45a7a41 100644
--- a/system/stack/avdt/avdt_scb_act.cc
+++ b/system/stack/avdt/avdt_scb_act.cc
@@ -553,7 +553,7 @@
*
******************************************************************************/
void avdt_scb_hdl_setconfig_cmd(AvdtpScb* p_scb, tAVDT_SCB_EVT* p_data) {
- log::verbose("p_scb->in_use={} p_avdt_scb={} scb_index={}", p_scb->in_use, fmt::ptr(p_scb),
+ log::verbose("p_scb->in_use={} p_avdt_scb={} scb_index={}", p_scb->in_use, std::format_ptr(p_scb),
p_scb->stream_config.scb_index);
if (p_scb->in_use) {
@@ -586,8 +586,8 @@
log::error(
"mismatch in AVDTP SCB/CCB state: (p_scb->p_ccb={} != p_ccb={}): "
"p_scb={} scb_handle={} ccb_idx={}",
- fmt::ptr(p_scb->p_ccb), fmt::ptr(p_ccb), fmt::ptr(p_scb), p_scb->ScbHandle(),
- p_data->msg.config_cmd.hdr.ccb_idx);
+ std::format_ptr(p_scb->p_ccb), std::format_ptr(p_ccb), std::format_ptr(p_scb),
+ p_scb->ScbHandle(), p_data->msg.config_cmd.hdr.ccb_idx);
avdt_scb_rej_not_in_use(p_scb, p_data);
return;
}
@@ -1016,7 +1016,7 @@
void avdt_scb_snd_abort_req(AvdtpScb* p_scb, tAVDT_SCB_EVT* /* p_data */) {
tAVDT_EVT_HDR hdr;
- log::verbose("p_scb->p_ccb={}", fmt::ptr(p_scb->p_ccb));
+ log::verbose("p_scb->p_ccb={}", std::format_ptr(p_scb->p_ccb));
if (p_scb->p_ccb != NULL) {
p_scb->role = AVDT_CLOSE_INT;
@@ -1286,8 +1286,8 @@
log::error(
"mismatch in AVDTP SCB/CCB state: (p_scb->p_ccb={} != p_ccb={}): "
"p_scb={} scb_handle={} ccb_idx={}",
- fmt::ptr(p_scb->p_ccb), fmt::ptr(p_ccb), fmt::ptr(p_scb), p_scb->ScbHandle(),
- p_data->msg.config_cmd.hdr.ccb_idx);
+ std::format_ptr(p_scb->p_ccb), std::format_ptr(p_ccb), std::format_ptr(p_scb),
+ p_scb->ScbHandle(), p_data->msg.config_cmd.hdr.ccb_idx);
avdt_scb_rej_not_in_use(p_scb, p_data);
return;
}
diff --git a/system/stack/avrc/avrc_api.cc b/system/stack/avrc/avrc_api.cc
index 273017d..13184ed 100644
--- a/system/stack/avrc/avrc_api.cc
+++ b/system/stack/avrc/avrc_api.cc
@@ -199,7 +199,7 @@
p_next_cmd->layer_specific &= 0xFF; /* AVCT_DATA_CTRL or AVCT_DATA_BROWSE */
log::verbose("AVRC: Dequeuing command 0x{} (handle=0x{:02x}, label=0x{:02x})",
- fmt::ptr(p_next_cmd), handle, next_label);
+ std::format_ptr(p_next_cmd), handle, next_label);
/* Send the message */
if ((AVCT_MsgReq(handle, next_label, AVCT_CMD, p_next_cmd)) == AVCT_SUCCESS) {
@@ -1309,8 +1309,8 @@
* command
* is received (exception is continuation request command
* must sent that to get additional response frags) */
- log::verbose("AVRC: Enqueuing command 0x{} (handle=0x{:02x}, label=0x{:02x})", fmt::ptr(p_pkt),
- handle, label);
+ log::verbose("AVRC: Enqueuing command 0x{} (handle=0x{:02x}, label=0x{:02x})",
+ std::format_ptr(p_pkt), handle, label);
/* label in BT_HDR (will need this later when the command is dequeued) */
p_pkt->layer_specific = (label << 8) | (p_pkt->layer_specific & 0xFF);
diff --git a/system/stack/avrc/avrc_bld_ct.cc b/system/stack/avrc/avrc_bld_ct.cc
index 7ad5f17..d641607 100644
--- a/system/stack/avrc/avrc_bld_ct.cc
+++ b/system/stack/avrc/avrc_bld_ct.cc
@@ -582,8 +582,8 @@
bool alloc = false;
log::verbose("AVRC_BldCommand: pdu={:x} status={:x}", p_cmd->cmd.pdu, p_cmd->cmd.status);
if (!p_cmd || !pp_pkt) {
- log::verbose("AVRC_BldCommand. Invalid parameters passed. p_cmd={}, pp_pkt={}", fmt::ptr(p_cmd),
- fmt::ptr(pp_pkt));
+ log::verbose("AVRC_BldCommand. Invalid parameters passed. p_cmd={}, pp_pkt={}",
+ std::format_ptr(p_cmd), std::format_ptr(pp_pkt));
return AVRC_STS_BAD_PARAM;
}
diff --git a/system/stack/avrc/avrc_bld_tg.cc b/system/stack/avrc/avrc_bld_tg.cc
index b90a833..d07ff65 100644
--- a/system/stack/avrc/avrc_bld_tg.cc
+++ b/system/stack/avrc/avrc_bld_tg.cc
@@ -66,7 +66,7 @@
tAVRC_STS status = AVRC_STS_NO_ERROR;
if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id))) {
- log::error("bad parameter. p_rsp: {}", fmt::ptr(p_rsp));
+ log::error("bad parameter. p_rsp: {}", std::format_ptr(p_rsp));
status = AVRC_STS_BAD_PARAM;
return status;
}
@@ -1359,8 +1359,8 @@
uint16_t peer_mtu;
if (!p_rsp || !pp_pkt) {
- log::verbose("Invalid parameters passed. p_rsp={}, pp_pkt={}", fmt::ptr(p_rsp),
- fmt::ptr(pp_pkt));
+ log::verbose("Invalid parameters passed. p_rsp={}, pp_pkt={}", std::format_ptr(p_rsp),
+ std::format_ptr(pp_pkt));
return AVRC_STS_BAD_PARAM;
}
diff --git a/system/stack/bnep/bnep_utils.cc b/system/stack/bnep/bnep_utils.cc
index 921e169..0740451 100644
--- a/system/stack/bnep/bnep_utils.cc
+++ b/system/stack/bnep/bnep_utils.cc
@@ -724,7 +724,8 @@
if (rem_len != NULL) {
*rem_len = 0;
}
- log::verbose("invalid packet: p = {} rem_len = {}", fmt::ptr(p), fmt::ptr(rem_len));
+ log::verbose("invalid packet: p = {} rem_len = {}", std::format_ptr(p),
+ std::format_ptr(rem_len));
return NULL;
}
uint16_t rem_len_orig = *rem_len;
diff --git a/system/stack/btm/btm_ble_sec.cc b/system/stack/btm/btm_ble_sec.cc
index 71a0aef..7ae82b3 100644
--- a/system/stack/btm/btm_ble_sec.cc
+++ b/system/stack/btm/btm_ble_sec.cc
@@ -102,7 +102,7 @@
p_dev_rec->conn_params.peripheral_latency = BTM_BLE_CONN_PARAM_UNDEF;
log::debug("Device added, handle=0x{:x}, p_dev_rec={}, bd_addr={}", p_dev_rec->ble_hci_handle,
- fmt::ptr(p_dev_rec), bd_addr);
+ std::format_ptr(p_dev_rec), bd_addr);
if (com::android::bluetooth::flags::name_discovery_for_le_pairing() &&
btif_storage_get_stored_remote_name(bd_addr,
@@ -1793,7 +1793,7 @@
BTM_CMAC_TLEN_SIZE, p_mac);
p_rec->sec_rec.increment_sign_counter(true);
- log::verbose("p_mac = {}", fmt::ptr(p_mac));
+ log::verbose("p_mac = {}", std::format_ptr(p_mac));
log::verbose("p_mac[0]=0x{:02x} p_mac[1]=0x{:02x} p_mac[2]=0x{:02x} p_mac[3]=0x{:02x}", *p_mac,
*(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
log::verbose("p_mac[4]=0x{:02x} p_mac[5]=0x{:02x} p_mac[6]=0x{:02x} p_mac[7]=0x{:02x}",
diff --git a/system/stack/btm/btm_ble_sec.h b/system/stack/btm/btm_ble_sec.h
index 25e5e8f..cae6548 100644
--- a/system/stack/btm/btm_ble_sec.h
+++ b/system/stack/btm/btm_ble_sec.h
@@ -68,8 +68,8 @@
tBTM_STATUS btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm, bool is_originator,
tBTM_SEC_CALLBACK* p_callback, void* p_ref_data);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTM_BLE_SEC_REQ_ACT>
: string_formatter<tBTM_BLE_SEC_REQ_ACT, &btm_ble_sec_req_act_text> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc
index d4edde0..6712527 100644
--- a/system/stack/btm/btm_dev.cc
+++ b/system/stack/btm/btm_dev.cc
@@ -90,9 +90,9 @@
if (!p_dev_rec) {
p_dev_rec = btm_sec_allocate_dev_rec();
log::info(
- "Caching new record from config file device: {}, dev_class: 0x{:02x}, "
+ "Caching new record from config file device: {}, dev_class: {:02x}:{:02x}:{:02x}, "
"link_key_type: 0x{:x}",
- bd_addr, fmt::join(dev_class, ""), key_type);
+ bd_addr, dev_class[0], dev_class[1], dev_class[2], key_type);
p_dev_rec->bd_addr = bd_addr;
p_dev_rec->hci_handle =
@@ -109,9 +109,9 @@
}
} else {
log::info(
- "Caching existing record from config file device: {}, dev_class: "
- "0x{:02x}, link_key_type: 0x{:x}",
- bd_addr, fmt::join(dev_class, ""), key_type);
+ "Caching existing record from config file device: {},"
+ " dev_class: {:02x}:{:02x}:{:02x}, link_key_type: 0x{:x}",
+ bd_addr, dev_class[0], dev_class[1], dev_class[2], key_type);
/* "Bump" timestamp for existing record */
p_dev_rec->timestamp = btm_sec_cb.dev_rec_count++;
diff --git a/system/stack/btm/btm_iso_impl.h b/system/stack/btm/btm_iso_impl.h
index 5e563e9..cdda94f 100644
--- a/system/stack/btm/btm_iso_impl.h
+++ b/system/stack/btm/btm_iso_impl.h
@@ -95,11 +95,11 @@
iso_impl() {
iso_credits_ = shim::GetController()->GetControllerIsoBufferSize().total_num_le_packets_;
iso_buffer_size_ = shim::GetController()->GetControllerIsoBufferSize().le_data_packet_length_;
- log::info("{} created, iso credits: {}, buffer size: {}.", fmt::ptr(this), iso_credits_.load(),
- iso_buffer_size_);
+ log::info("{} created, iso credits: {}, buffer size: {}.", std::format_ptr(this),
+ iso_credits_.load(), iso_buffer_size_);
}
- ~iso_impl() { log::info("{} removed.", fmt::ptr(this)); }
+ ~iso_impl() { log::info("{} removed.", std::format_ptr(this)); }
void handle_register_cis_callbacks(CigCallbacks* callbacks) {
log::assert_that(callbacks != nullptr, "Invalid CIG callbacks");
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index d19b9ae..7c329b4 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -396,7 +396,7 @@
*
******************************************************************************/
bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) {
- log::info("p_cb_info->p_le_callback == 0x{}", fmt::ptr(p_cb_info->p_le_callback));
+ log::info("p_cb_info->p_le_callback == 0x{}", std::format_ptr(p_cb_info->p_le_callback));
if (p_cb_info->p_le_callback) {
log::verbose("SMP_Register( btm_proc_smp_cback )");
SMP_Register(btm_proc_smp_cback);
@@ -410,7 +410,7 @@
}
btm_sec_cb.api = *p_cb_info;
- log::info("btm_sec_cb.api.p_le_callback = 0x{}", fmt::ptr(btm_sec_cb.api.p_le_callback));
+ log::info("btm_sec_cb.api.p_le_callback = 0x{}", std::format_ptr(btm_sec_cb.api.p_le_callback));
log::verbose("application registered");
return true;
}
@@ -1611,8 +1611,8 @@
rc = btm_sec_execute_procedure(p_dev_rec);
if (rc != tBTM_STATUS::BTM_CMD_STARTED) {
- log::verbose("p_dev_rec={}, clearing callback. old p_callback={}", fmt::ptr(p_dev_rec),
- fmt::ptr(p_dev_rec->sec_rec.p_callback));
+ log::verbose("p_dev_rec={}, clearing callback. old p_callback={}", std::format_ptr(p_dev_rec),
+ std::format_ptr(p_dev_rec->sec_rec.p_callback));
p_dev_rec->sec_rec.p_callback = NULL;
(*p_callback)(bd_addr, transport, p_dev_rec->sec_rec.p_ref_data, rc);
}
@@ -2048,8 +2048,8 @@
p_dev_rec->sec_rec.classic_link = tSECURITY_STATE::IDLE;
- log::verbose("clearing callback. p_dev_rec={}, p_callback={}", fmt::ptr(p_dev_rec),
- fmt::ptr(p_dev_rec->sec_rec.p_callback));
+ log::verbose("clearing callback. p_dev_rec={}, p_callback={}", std::format_ptr(p_dev_rec),
+ std::format_ptr(p_dev_rec->sec_rec.p_callback));
p_dev_rec->sec_rec.p_callback = NULL;
}
@@ -2252,7 +2252,7 @@
if ((btm_sec_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) &&
(btm_sec_cb.pairing_bda == bd_addr)) {
log::verbose("delayed pin now being requested flags:0x{:x}, (p_pin_callback=0x{})",
- btm_sec_cb.pairing_flags, fmt::ptr(btm_sec_cb.api.p_pin_callback));
+ btm_sec_cb.pairing_flags, std::format_ptr(btm_sec_cb.api.p_pin_callback));
if ((btm_sec_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0 &&
btm_sec_cb.api.p_pin_callback) {
@@ -3356,8 +3356,8 @@
if (!p_dev_rec->sec_rec.is_security_state_bredr_encrypting()) {
if (tSECURITY_STATE::DELAY_FOR_ENC == p_dev_rec->sec_rec.classic_link) {
p_dev_rec->sec_rec.classic_link = tSECURITY_STATE::IDLE;
- log::verbose("clearing callback. p_dev_rec={}, p_callback={}", fmt::ptr(p_dev_rec),
- fmt::ptr(p_dev_rec->sec_rec.p_callback));
+ log::verbose("clearing callback. p_dev_rec={}, p_callback={}", std::format_ptr(p_dev_rec),
+ std::format_ptr(p_dev_rec->sec_rec.p_callback));
p_dev_rec->sec_rec.p_callback = NULL;
l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
return;
@@ -4364,7 +4364,8 @@
log::warn(
"btm_sec_pin_code_request(): Pairing disabled:{}; PIN callback:{}, Dev "
"Rec:{}!",
- p_cb->pairing_disabled, fmt::ptr(p_cb->api.p_pin_callback), fmt::ptr(p_dev_rec));
+ p_cb->pairing_disabled, std::format_ptr(p_cb->api.p_pin_callback),
+ std::format_ptr(p_dev_rec));
btsnd_hcic_pin_code_neg_reply(p_bda);
} else {
diff --git a/system/stack/btm/btm_sec_cb.cc b/system/stack/btm/btm_sec_cb.cc
index ac86e7f..c40d8fe 100644
--- a/system/stack/btm/btm_sec_cb.cc
+++ b/system/stack/btm/btm_sec_cb.cc
@@ -256,7 +256,7 @@
if (is_originator) {
p_srec->orig_mx_chan_id = mx_chan_id;
- strlcpy((char*)p_srec->orig_service_name, p_name, BT_MAX_SERVICE_NAME_LEN + 1);
+ osi_strlcpy((char*)p_srec->orig_service_name, p_name, BT_MAX_SERVICE_NAME_LEN + 1);
/* clear out the old setting, just in case it exists */
{
p_srec->security_flags &=
@@ -285,7 +285,7 @@
p_out_serv = p_srec;
} else {
p_srec->term_mx_chan_id = mx_chan_id;
- strlcpy((char*)p_srec->term_service_name, p_name, BT_MAX_SERVICE_NAME_LEN + 1);
+ osi_strlcpy((char*)p_srec->term_service_name, p_name, BT_MAX_SERVICE_NAME_LEN + 1);
/* clear out the old setting, just in case it exists */
{
p_srec->security_flags &= ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
diff --git a/system/stack/btm/btm_sec_int_types.h b/system/stack/btm/btm_sec_int_types.h
index 8d960d6..02f7b5a 100644
--- a/system/stack/btm/btm_sec_int_types.h
+++ b/system/stack/btm/btm_sec_int_types.h
@@ -100,7 +100,7 @@
typedef uint8_t tBTM_SEC_ACTION;
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTM_PAIRING_STATE> : enum_formatter<tBTM_PAIRING_STATE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/btm/hfp_msbc_decoder.cc b/system/stack/btm/hfp_msbc_decoder.cc
index 21666b4..ccfbeea 100644
--- a/system/stack/btm/hfp_msbc_decoder.cc
+++ b/system/stack/btm/hfp_msbc_decoder.cc
@@ -32,10 +32,10 @@
using namespace bluetooth;
-namespace fmt {
+namespace std {
template <>
struct formatter<OI_STATUS> : enum_formatter<OI_STATUS> {};
-} // namespace fmt
+} // namespace std
typedef struct {
OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
diff --git a/system/stack/btm/neighbor_inquiry.h b/system/stack/btm/neighbor_inquiry.h
index be4face..d4a13e9 100644
--- a/system/stack/btm/neighbor_inquiry.h
+++ b/system/stack/btm/neighbor_inquiry.h
@@ -235,7 +235,7 @@
bool btm_inq_find_bdaddr(const RawAddress& p_bda);
tINQ_DB_ENT* btm_inq_db_find(const RawAddress& p_bda);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTM_INQUIRY_CMPL::STATUS> : enum_formatter<tBTM_INQUIRY_CMPL::STATUS> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/btm/security_device_record.h b/system/stack/btm/security_device_record.h
index e660890..d72e1c0 100644
--- a/system/stack/btm/security_device_record.h
+++ b/system/stack/btm/security_device_record.h
@@ -381,9 +381,9 @@
tBTM_SEC_REC sec_rec;
};
-namespace fmt {
+namespace std {
template <>
struct formatter<tSECURITY_STATE> : string_formatter<tSECURITY_STATE, &security_state_text> {};
template <>
struct formatter<tBLE_RAND_ADDR_TYPE> : enum_formatter<tBLE_RAND_ADDR_TYPE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h
index 92c5cce..c746695 100644
--- a/system/stack/eatt/eatt_impl.h
+++ b/system/stack/eatt/eatt_impl.h
@@ -922,7 +922,8 @@
}
void upper_tester_connect(const RawAddress& bd_addr, eatt_device* eatt_dev, uint8_t role) {
- log::info("L2CAP Upper tester enabled, {} ({}), role: {}({})", bd_addr, fmt::ptr(eatt_dev),
+ log::info("L2CAP Upper tester enabled, {} ({}), role: {}({})", bd_addr,
+ std::format_ptr(eatt_dev),
role == HCI_ROLE_CENTRAL ? "HCI_ROLE_CENTRAL" : "HCI_ROLE_PERIPHERAL", role);
auto num_of_chan = stack_config_get_interface()->get_pts_l2cap_ecoc_initial_chan_cnt();
diff --git a/system/stack/gatt/att_protocol.cc b/system/stack/gatt/att_protocol.cc
index 8360b81..2a5825b 100644
--- a/system/stack/gatt/att_protocol.cc
+++ b/system/stack/gatt/att_protocol.cc
@@ -470,7 +470,7 @@
if (gatt_tcb_is_cid_busy(tcb, p_clcb->cid) && cmd_code != GATT_HANDLE_VALUE_CONF) {
if (gatt_cmd_enq(tcb, p_clcb, true, cmd_code, p_cmd)) {
- log::debug("Enqueued ATT command {} conn_id=0x{:04x}, cid={}", fmt::ptr(p_clcb),
+ log::debug("Enqueued ATT command {} conn_id=0x{:04x}, cid={}", std::format_ptr(p_clcb),
p_clcb->conn_id, p_clcb->cid);
return GATT_CMD_STARTED;
}
@@ -484,7 +484,7 @@
tGATT_STATUS att_ret = attp_send_msg_to_l2cap(tcb, p_clcb->cid, p_cmd);
if (att_ret != GATT_CONGESTED && att_ret != GATT_SUCCESS) {
log::warn("Unable to send ATT command to l2cap layer {} conn_id=0x{:04x}, cid={}",
- fmt::ptr(p_clcb), p_clcb->conn_id, p_clcb->cid);
+ std::format_ptr(p_clcb), p_clcb->conn_id, p_clcb->cid);
return GATT_INTERNAL_ERROR;
}
@@ -492,7 +492,7 @@
return att_ret;
}
- log::debug("Starting ATT response timer {} conn_id=0x{:04x}, cid={}", fmt::ptr(p_clcb),
+ log::debug("Starting ATT response timer {} conn_id=0x{:04x}, cid={}", std::format_ptr(p_clcb),
p_clcb->conn_id, p_clcb->cid);
gatt_start_rsp_timer(p_clcb);
if (!gatt_cmd_enq(tcb, p_clcb, false, cmd_code, NULL)) {
diff --git a/system/stack/gatt/gatt_cl.cc b/system/stack/gatt/gatt_cl.cc
index 6093d57..9a24181 100644
--- a/system/stack/gatt/gatt_cl.cc
+++ b/system/stack/gatt/gatt_cl.cc
@@ -1075,7 +1075,7 @@
}
} else /* exception, should not happen */
{
- log::error("attr offset = {} p_attr_buf = {}", offset, fmt::ptr(p_clcb->p_attr_buf));
+ log::error("attr offset = {} p_attr_buf = {}", offset, std::format_ptr(p_clcb->p_attr_buf));
gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void*)p_clcb->p_attr_buf);
}
}
diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h
index 88c8b88..3ceaa21 100644
--- a/system/stack/gatt/gatt_int.h
+++ b/system/stack/gatt/gatt_int.h
@@ -702,9 +702,9 @@
} // namespace legacy
} // namespace bluetooth
-namespace fmt {
+namespace std {
template <>
struct formatter<tGATT_CH_STATE> : enum_formatter<tGATT_CH_STATE> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/stack/gatt/gatt_sr.cc b/system/stack/gatt/gatt_sr.cc
index 8b67f2e..aad7b1f 100644
--- a/system/stack/gatt/gatt_sr.cc
+++ b/system/stack/gatt/gatt_sr.cc
@@ -145,7 +145,7 @@
/* Double check in case any buffers are queued */
log::verbose("gatt_dequeue_sr_cmd cid: 0x{:x}", cid);
if (p_cmd->p_rsp_msg) {
- log::error("free tcb.sr_cmd.p_rsp_msg = {}", fmt::ptr(p_cmd->p_rsp_msg));
+ log::error("free tcb.sr_cmd.p_rsp_msg = {}", std::format_ptr(p_cmd->p_rsp_msg));
}
osi_free_and_reset((void**)&p_cmd->p_rsp_msg);
diff --git a/system/stack/gatt/gatt_utils.cc b/system/stack/gatt/gatt_utils.cc
index 73e08dc..73880e3 100644
--- a/system/stack/gatt/gatt_utils.cc
+++ b/system/stack/gatt/gatt_utils.cc
@@ -1254,8 +1254,8 @@
if (!p_tcb->pending_enc_clcb.empty()) {
for (size_t i = 0; i < p_tcb->pending_enc_clcb.size(); i++) {
if (p_tcb->pending_enc_clcb.at(i) == p_clcb) {
- log::warn("Removing clcb ({}) for conn id=0x{:04x} from pending_enc_clcb", fmt::ptr(p_clcb),
- p_clcb->conn_id);
+ log::warn("Removing clcb ({}) for conn id=0x{:04x} from pending_enc_clcb",
+ std::format_ptr(p_clcb), p_clcb->conn_id);
p_tcb->pending_enc_clcb.at(i) = NULL;
break;
}
@@ -1287,14 +1287,14 @@
if (iter->to_send) {
/* If command was not send, just remove the entire element */
cl_cmd_q_p->erase(iter);
- log::warn("Removing scheduled clcb ({}) for conn_id=0x{:04x}", fmt::ptr(p_clcb),
+ log::warn("Removing scheduled clcb ({}) for conn_id=0x{:04x}", std::format_ptr(p_clcb),
p_clcb->conn_id);
} else {
/* If command has been sent, just invalidate p_clcb pointer for proper
* response handling */
iter->p_clcb = NULL;
log::warn("Invalidating clcb ({}) for already sent request on conn_id=0x{:04x}",
- fmt::ptr(p_clcb), p_clcb->conn_id);
+ std::format_ptr(p_clcb), p_clcb->conn_id);
}
}
/*******************************************************************************
@@ -1815,7 +1815,7 @@
(*p_cmpl_cb)(conn_id, op, status, &cb_data);
} else {
log::warn("not sent out op={} p_disc_cmpl_cb:{} p_cmpl_cb:{}", operation,
- fmt::ptr(p_disc_cmpl_cb), fmt::ptr(p_cmpl_cb));
+ std::format_ptr(p_disc_cmpl_cb), std::format_ptr(p_cmpl_cb));
}
}
diff --git a/system/stack/hid/hid_conn.h b/system/stack/hid/hid_conn.h
index 77d0fa6..1611db4 100644
--- a/system/stack/hid/hid_conn.h
+++ b/system/stack/hid/hid_conn.h
@@ -78,9 +78,9 @@
#define HIDD_SEC_CHN 3
-namespace fmt {
+namespace std {
template <>
struct formatter<tHID_CONN_STATE> : enum_formatter<tHID_CONN_STATE> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/stack/include/a2dp_constants.h b/system/stack/include/a2dp_constants.h
index 090c25a..e766fff 100644
--- a/system/stack/include/a2dp_constants.h
+++ b/system/stack/include/a2dp_constants.h
@@ -167,11 +167,11 @@
A2DP_NOT_SUPPORTED_CODEC_PARAMETER = 0xE3,
};
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::a2dp::CodecId> : enum_formatter<bluetooth::a2dp::CodecId> {};
template <>
struct formatter<tA2DP_CODEC_TYPE> : enum_formatter<tA2DP_CODEC_TYPE> {};
template <>
struct formatter<tA2DP_STATUS> : enum_formatter<tA2DP_STATUS> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/bt_name.h b/system/stack/include/bt_name.h
index c9749f0..bf4119b 100644
--- a/system/stack/include/bt_name.h
+++ b/system/stack/include/bt_name.h
@@ -28,8 +28,8 @@
constexpr size_t kBdNameLength = static_cast<size_t>(BD_NAME_LEN);
inline size_t bd_name_copy(BD_NAME bd_name_dest, const BD_NAME bd_name_src) {
- return strlcpy(reinterpret_cast<char*>(bd_name_dest), reinterpret_cast<const char*>(bd_name_src),
- kBdNameLength + 1);
+ return osi_strlcpy(reinterpret_cast<char*>(bd_name_dest),
+ reinterpret_cast<const char*>(bd_name_src), kBdNameLength + 1);
}
inline void bd_name_clear(BD_NAME bd_name) { *bd_name = {0}; }
inline bool bd_name_is_empty(const BD_NAME bd_name) { return bd_name[0] == '\0'; }
@@ -40,7 +40,8 @@
return;
}
- size_t src_len = strlcpy(reinterpret_cast<char*>(bd_name_dest), bd_name_char, sizeof(BD_NAME));
+ size_t src_len =
+ osi_strlcpy(reinterpret_cast<char*>(bd_name_dest), bd_name_char, sizeof(BD_NAME));
if (src_len < sizeof(BD_NAME) - 1) {
/* Zero the remaining destination memory */
memset(bd_name_dest + src_len, 0, sizeof(BD_NAME) - src_len);
diff --git a/system/stack/include/bt_psm_types.h b/system/stack/include/bt_psm_types.h
index 3f07161..a781188 100644
--- a/system/stack/include/bt_psm_types.h
+++ b/system/stack/include/bt_psm_types.h
@@ -70,7 +70,7 @@
inline std::string psm_to_text(uint16_t psm) { return bt_psm_text(static_cast<tBT_PSM>(psm)); }
-namespace fmt {
+namespace std {
template <>
struct formatter<tBT_PSM> : enum_formatter<tBT_PSM> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/btm_api_types.h b/system/stack/include/btm_api_types.h
index 3f167bb..2c2ccf2 100644
--- a/system/stack/include/btm_api_types.h
+++ b/system/stack/include/btm_api_types.h
@@ -197,7 +197,7 @@
CASE_RETURN_TEXT(tBTA_AG_UUID_CODEC::UUID_CODEC_MSBC);
CASE_RETURN_TEXT(tBTA_AG_UUID_CODEC::UUID_CODEC_LC3);
default:
- return fmt::format("UNKNOWN Codec with id {}",
+ return std::format("UNKNOWN Codec with id {}",
static_cast<std::underlying_type_t<tBTA_AG_UUID_CODEC>>(result));
}
}
diff --git a/system/stack/include/btm_ble_api_types.h b/system/stack/include/btm_ble_api_types.h
index db5ae7a..9a16797 100644
--- a/system/stack/include/btm_ble_api_types.h
+++ b/system/stack/include/btm_ble_api_types.h
@@ -517,9 +517,9 @@
typedef void(tBTM_BLE_CTRL_FEATURES_CBACK)(tHCI_STATUS status);
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTM_BLE_CONN_TYPE> : enum_formatter<tBTM_BLE_CONN_TYPE> {};
-} // namespace fmt
+} // namespace std
#endif // BTM_BLE_API_TYPES_H
diff --git a/system/stack/include/btm_sec_api_types.h b/system/stack/include/btm_sec_api_types.h
index 6b21574..d04974f2 100644
--- a/system/stack/include/btm_sec_api_types.h
+++ b/system/stack/include/btm_sec_api_types.h
@@ -525,9 +525,9 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTM_BLE_SEC_ACT> : enum_formatter<tBTM_BLE_SEC_ACT> {};
template <>
struct formatter<tBTM_BOND_TYPE> : enum_formatter<tBTM_BOND_TYPE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/btm_status.h b/system/stack/include/btm_status.h
index 97247dc..a33a4b6 100644
--- a/system/stack/include/btm_status.h
+++ b/system/stack/include/btm_status.h
@@ -98,7 +98,7 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tBTM_STATUS> : enum_formatter<tBTM_STATUS> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/gatt_api.h b/system/stack/include/gatt_api.h
index 804d639..3b751e1 100644
--- a/system/stack/include/gatt_api.h
+++ b/system/stack/include/gatt_api.h
@@ -1287,7 +1287,7 @@
void gatt_tcb_dump(int fd);
-namespace fmt {
+namespace std {
template <>
struct formatter<GattStatus> : enum_formatter<GattStatus> {};
template <>
@@ -1298,6 +1298,6 @@
struct formatter<tGATT_OP_CODE> : enum_formatter<tGATT_OP_CODE> {};
template <>
struct formatter<tGATT_DISC_TYPE> : enum_formatter<tGATT_DISC_TYPE> {};
-} // namespace fmt
+} // namespace std
#endif /* GATT_API_H */
diff --git a/system/stack/include/hci_error_code.h b/system/stack/include/hci_error_code.h
index 04ebb47..3d4b50c 100644
--- a/system/stack/include/hci_error_code.h
+++ b/system/stack/include/hci_error_code.h
@@ -247,7 +247,7 @@
return static_cast<tHCI_REASON>(reason_code);
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tHCI_ERROR_CODE> : enum_formatter<tHCI_ERROR_CODE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/hiddefs.h b/system/stack/include/hiddefs.h
index 4e8743d..583c302 100644
--- a/system/stack/include/hiddefs.h
+++ b/system/stack/include/hiddefs.h
@@ -181,9 +181,9 @@
tSDP_DISC_REC* p_sdp_layer_rec;
} tHID_DEV_SDP_INFO;
-namespace fmt {
+namespace std {
template <>
struct formatter<tHID_STATUS> : enum_formatter<tHID_STATUS> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/stack/include/l2cap_types.h b/system/stack/include/l2cap_types.h
index e0927e9..311dab7 100644
--- a/system/stack/include/l2cap_types.h
+++ b/system/stack/include/l2cap_types.h
@@ -163,9 +163,9 @@
constexpr uint16_t L2CAP_LE_MAX_MPS = 65533;
constexpr uint16_t L2CAP_LE_CREDIT_MAX = 65535;
-namespace fmt {
+namespace std {
template <>
struct formatter<tL2CAP_LATENCY> : enum_formatter<tL2CAP_LATENCY> {};
template <>
struct formatter<tL2CAP_PRIORITY> : enum_formatter<tL2CAP_PRIORITY> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/l2cdefs.h b/system/stack/include/l2cdefs.h
index b598529..88ed7a7 100644
--- a/system/stack/include/l2cdefs.h
+++ b/system/stack/include/l2cdefs.h
@@ -545,11 +545,11 @@
/* Mask for sequence numbers (range 0 - 63) */
#define L2CAP_FCR_SEQ_MODULO 0x3F
-namespace fmt {
+namespace std {
template <>
struct formatter<tL2CAP_CONN> : enum_formatter<tL2CAP_CONN> {};
template <>
struct formatter<tL2CAP_CID_FIXED> : enum_formatter<tL2CAP_CID_FIXED> {};
template <>
struct formatter<tL2CAP_LE_RESULT_CODE> : enum_formatter<tL2CAP_LE_RESULT_CODE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/pan_api.h b/system/stack/include/pan_api.h
index 677ab44..9246f2a 100644
--- a/system/stack/include/pan_api.h
+++ b/system/stack/include/pan_api.h
@@ -422,9 +422,9 @@
void PAN_Dumpsys(int fd);
-namespace fmt {
+namespace std {
template <>
struct formatter<tPAN_RESULT> : enum_formatter<tPAN_RESULT> {};
-} // namespace fmt
+} // namespace std
#endif /* PAN_API_H */
diff --git a/system/stack/include/port_api.h b/system/stack/include/port_api.h
index ae511a4..e298674 100644
--- a/system/stack/include/port_api.h
+++ b/system/stack/include/port_api.h
@@ -179,10 +179,10 @@
RETURN_UNKNOWN_TYPE_STRING(tPORT_RESULT, result);
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tPORT_RESULT> : enum_formatter<tPORT_RESULT> {};
-} // namespace fmt
+} // namespace std
typedef void(tPORT_MGMT_CALLBACK)(const tPORT_RESULT code, uint16_t port_handle);
diff --git a/system/stack/include/sdp_status.h b/system/stack/include/sdp_status.h
index d709dd5..cebcd96 100644
--- a/system/stack/include/sdp_status.h
+++ b/system/stack/include/sdp_status.h
@@ -87,7 +87,7 @@
}
const auto sdp_result_text = sdp_status_text;
-namespace fmt {
+namespace std {
template <>
struct formatter<tSDP_STATUS> : enum_formatter<tSDP_STATUS> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/include/smp_api_types.h b/system/stack/include/smp_api_types.h
index 693faa8..922de8b 100644
--- a/system/stack/include/smp_api_types.h
+++ b/system/stack/include/smp_api_types.h
@@ -228,13 +228,13 @@
* Manager requires verification from CSIP.*/
typedef tBTM_STATUS(tSMP_SIRK_CALLBACK)(const RawAddress& bd_addr);
-namespace fmt {
+namespace std {
template <>
struct formatter<tSMP_OOB_DATA_TYPE> : enum_formatter<tSMP_OOB_DATA_TYPE> {};
template <>
struct formatter<tSMP_SEC_LEVEL> : enum_formatter<tSMP_SEC_LEVEL> {};
template <>
struct formatter<tSMP_EVT> : enum_formatter<tSMP_EVT> {};
-} // namespace fmt
+} // namespace std
#endif // SMP_API_TYPES_H
diff --git a/system/stack/include/smp_status.h b/system/stack/include/smp_status.h
index dce8778..5c8b6f1 100644
--- a/system/stack/include/smp_status.h
+++ b/system/stack/include/smp_status.h
@@ -95,7 +95,7 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tSMP_STATUS> : enum_formatter<tSMP_STATUS> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/l2cap/l2c_api.cc b/system/stack/l2cap/l2c_api.cc
index 99b0276..2b67132 100644
--- a/system/stack/l2cap/l2c_api.cc
+++ b/system/stack/l2cap/l2c_api.cc
@@ -320,7 +320,7 @@
p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_BR_EDR);
/* currently use BR/EDR for ERTM mode l2cap connection */
if (p_lcb == nullptr) {
- log::warn("connection not started for PSM=0x{:x}, p_lcb={}", psm, fmt::ptr(p_lcb));
+ log::warn("connection not started for PSM=0x{:x}, p_lcb={}", psm, std::format_ptr(p_lcb));
return 0;
}
l2cu_create_conn_br_edr(p_lcb);
@@ -520,7 +520,7 @@
if ((p_lcb == NULL)
/* currently use BR/EDR for ERTM mode l2cap connection */
|| (!l2cu_create_conn_le(p_lcb))) {
- log::warn("conn not started for PSM: 0x{:04x} p_lcb: 0x{}", psm, fmt::ptr(p_lcb));
+ log::warn("conn not started for PSM: 0x{:04x} p_lcb: 0x{}", psm, std::format_ptr(p_lcb));
return 0;
}
}
@@ -1540,7 +1540,7 @@
"L2CA_FlushChannel (FLUSH) CID: 0x{:04x} NumToFlush: {} QC: {} "
"pFirst: 0x{}",
lcid, num_to_flush, fixed_queue_length(p_ccb->xmit_hold_q),
- fmt::ptr(fixed_queue_try_peek_first(p_ccb->xmit_hold_q)));
+ std::format_ptr(fixed_queue_try_peek_first(p_ccb->xmit_hold_q)));
} else {
log::verbose("L2CA_FlushChannel (QUERY) CID: 0x{:04x}", lcid);
}
diff --git a/system/stack/l2cap/l2c_csm.cc b/system/stack/l2cap/l2c_csm.cc
index ba43876..42b451c 100644
--- a/system/stack/l2cap/l2c_csm.cc
+++ b/system/stack/l2cap/l2c_csm.cc
@@ -1688,7 +1688,8 @@
log::error(
"empty queue: p_ccb = {} p_ccb->in_use = {} p_ccb->chnl_state = {} "
"p_ccb->local_cid = {} p_ccb->remote_cid = {}",
- fmt::ptr(p_ccb), p_ccb->in_use, p_ccb->chnl_state, p_ccb->local_cid, p_ccb->remote_cid);
+ std::format_ptr(p_ccb), p_ccb->in_use, p_ccb->chnl_state, p_ccb->local_cid,
+ p_ccb->remote_cid);
} else {
fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf);
}
diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h
index 02a1fa6..0077cab 100644
--- a/system/stack/l2cap/l2c_int.h
+++ b/system/stack/l2cap/l2c_int.h
@@ -854,11 +854,11 @@
uint16_t peripheral_latency, uint16_t cont_num,
uint16_t timeout);
-namespace fmt {
+namespace std {
template <>
struct formatter<tL2C_LINK_STATE> : enum_formatter<tL2C_LINK_STATE> {};
template <>
struct formatter<tL2CEVT> : enum_formatter<tL2CEVT> {};
template <>
struct formatter<tL2C_CHNL_STATE> : enum_formatter<tL2C_CHNL_STATE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/l2cap/l2c_utils.cc b/system/stack/l2cap/l2c_utils.cc
index 0e923a5..3a057ec 100644
--- a/system/stack/l2cap/l2c_utils.cc
+++ b/system/stack/l2cap/l2c_utils.cc
@@ -1165,7 +1165,7 @@
if ((!p_ccb->in_use) || (p_q == NULL)) {
log::error("CID: 0x{:04x} ERROR in_use: {} p_lcb: {}", p_ccb->local_cid, p_ccb->in_use,
- fmt::ptr(p_ccb->p_lcb));
+ std::format_ptr(p_ccb->p_lcb));
return;
}
@@ -1251,8 +1251,8 @@
log::error(
"l2cu_dequeue_ccb CID: 0x{:04x} ERROR in_use: {} p_lcb: 0x{} p_q: "
"0x{} p_q->p_first_ccb: 0x{}",
- p_ccb->local_cid, p_ccb->in_use, fmt::ptr(p_ccb->p_lcb), fmt::ptr(p_q),
- fmt::ptr(p_q ? p_q->p_first_ccb : 0));
+ p_ccb->local_cid, p_ccb->in_use, std::format_ptr(p_ccb->p_lcb), std::format_ptr(p_q),
+ std::format_ptr(p_q ? p_q->p_first_ccb : 0));
return;
}
@@ -2602,7 +2602,7 @@
tL2C_CCB* p_next_ccb;
int xx;
- log::verbose("l2cu_resubmit_pending_sec_req p_bda: 0x{}", fmt::ptr(p_bda));
+ log::verbose("l2cu_resubmit_pending_sec_req p_bda: 0x{}", std::format_ptr(p_bda));
/* If we are called with a BDA, only resubmit for that BDA */
if (p_bda) {
diff --git a/system/stack/pan/pan_int.h b/system/stack/pan/pan_int.h
index f64f2ae..32d832a 100644
--- a/system/stack/pan/pan_int.h
+++ b/system/stack/pan/pan_int.h
@@ -128,9 +128,9 @@
/******************************************************************************/
-namespace fmt {
+namespace std {
template <>
struct formatter<tPAN_STATE> : enum_formatter<tPAN_STATE> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/stack/rfcomm/port_api.cc b/system/stack/rfcomm/port_api.cc
index 6676eac..6786e88 100644
--- a/system/stack/rfcomm/port_api.cc
+++ b/system/stack/rfcomm/port_api.cc
@@ -143,7 +143,7 @@
"bd_addr={}, scn={}, is_server={}, mtu={}, uuid=0x{:x}, dlci={}, p_mcb={}, port={}",
static_cast<int>(p_port->state), static_cast<int>(p_port->rfc.state),
p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0, bd_addr, scn, is_server, mtu,
- uuid, dlci, fmt::ptr(p_mcb), p_port->handle);
+ uuid, dlci, std::format_ptr(p_mcb), p_port->handle);
*p_handle = p_port->handle;
return PORT_ALREADY_OPENED;
}
@@ -214,7 +214,8 @@
log::info(
"bd_addr={}, scn={}, is_server={}, mtu={}, uuid=0x{:x}, dlci={}, "
"signal_state=0x{:x}, p_port={}",
- bd_addr, scn, is_server, mtu, uuid, dlci, p_port->default_signal_state, fmt::ptr(p_port));
+ bd_addr, scn, is_server, mtu, uuid, dlci, p_port->default_signal_state,
+ std::format_ptr(p_port));
// If this is not initiator of the connection need to just wait
if (p_port->is_server) {
@@ -410,7 +411,7 @@
*
******************************************************************************/
int PORT_SetDataCOCallback(uint16_t handle, tPORT_DATA_CO_CALLBACK* p_port_cb) {
- log::verbose("handle:{} cb 0x{}", handle, fmt::ptr(p_port_cb));
+ log::verbose("handle:{} cb 0x{}", handle, std::format_ptr(p_port_cb));
tPORT* p_port = get_port_from_handle(handle);
if (p_port == nullptr) {
@@ -445,7 +446,7 @@
return PORT_BAD_HANDLE;
}
log::verbose("handle={}, in_use={}, port_state={}, p_mcb={}, peer_ready={}, rfc_state={}", handle,
- p_port->in_use, p_port->state, fmt::ptr(p_port->rfc.p_mcb),
+ p_port->in_use, p_port->state, std::format_ptr(p_port->rfc.p_mcb),
p_port->rfc.p_mcb ? p_port->rfc.p_mcb->peer_ready : -1, p_port->rfc.state);
if (!p_port->in_use || (p_port->state == PORT_CONNECTION_STATE_CLOSED)) {
diff --git a/system/stack/rfcomm/port_int.h b/system/stack/rfcomm/port_int.h
index f4773d5..8fcbf84 100644
--- a/system/stack/rfcomm/port_int.h
+++ b/system/stack/rfcomm/port_int.h
@@ -141,10 +141,10 @@
RETURN_UNKNOWN_TYPE_STRING(tPORT_CONNECTION_STATE, state);
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tPORT_CONNECTION_STATE> : enum_formatter<tPORT_CONNECTION_STATE> {};
-} // namespace fmt
+} // namespace std
/*
* Define control block containing information about PORT connection
diff --git a/system/stack/rfcomm/port_rfc.cc b/system/stack/rfcomm/port_rfc.cc
index be15fb1..1f8ba0b 100644
--- a/system/stack/rfcomm/port_rfc.cc
+++ b/system/stack/rfcomm/port_rfc.cc
@@ -65,7 +65,7 @@
*
******************************************************************************/
int port_open_continue(tPORT* p_port) {
- log::verbose("port_open_continue, p_port:{}", fmt::ptr(p_port));
+ log::verbose("port_open_continue, p_port:{}", std::format_ptr(p_port));
/* Check if multiplexer channel has already been established */
tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
@@ -263,7 +263,8 @@
p_port = &rfc_cb.port.port[0];
for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
if ((p_port->rfc.p_mcb == NULL) || (p_port->rfc.p_mcb == p_mcb)) {
- log::verbose("PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:{}", fmt::ptr(p_mcb));
+ log::verbose("PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:{}",
+ std::format_ptr(p_mcb));
RFCOMM_StartRsp(p_mcb, RFCOMM_SUCCESS);
return;
}
@@ -289,7 +290,7 @@
p_port = port_find_dlci_port(dlci);
if (!p_port) {
log::error("Disconnect RFCOMM, port not found, dlci={}, p_mcb={}, bd_addr={}", dlci,
- fmt::ptr(p_mcb), p_mcb->bd_addr);
+ std::format_ptr(p_mcb), p_mcb->bd_addr);
/* If the port cannot be opened, send a DM. Per Errata 1205 */
rfc_send_dm(p_mcb, dlci, false);
/* check if this is the last port open, some headsets have
@@ -416,8 +417,8 @@
void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
- log::verbose("p_mcb:{}, dlci:{} mtu:{}i, p_port:{}, bd_addr:{}", fmt::ptr(p_mcb), dlci, mtu,
- fmt::ptr(p_port), p_mcb->bd_addr);
+ log::verbose("p_mcb:{}, dlci:{} mtu:{}i, p_port:{}, bd_addr:{}", std::format_ptr(p_mcb), dlci,
+ mtu, std::format_ptr(p_port), p_mcb->bd_addr);
if (!p_port) {
/* This can be a first request for this port */
@@ -787,7 +788,7 @@
int i;
log::verbose("PORT_DataInd with data length {}, p_mcb:{},p_port:{},dlci:{}", p_buf->len,
- fmt::ptr(p_mcb), fmt::ptr(p_port), dlci);
+ std::format_ptr(p_mcb), std::format_ptr(p_port), dlci);
if (!p_port) {
osi_free(p_buf);
return;
diff --git a/system/stack/rfcomm/port_utils.cc b/system/stack/rfcomm/port_utils.cc
index 88276d0..25e1da9 100644
--- a/system/stack/rfcomm/port_utils.cc
+++ b/system/stack/rfcomm/port_utils.cc
@@ -86,7 +86,7 @@
p_port->bd_addr = bd_addr;
rfc_cb.rfc.last_port_index = port_index;
log::verbose("rfc_cb.port.port[{}]:{} chosen, last_port_index:{}, bd_addr={}", port_index,
- fmt::ptr(p_port), rfc_cb.rfc.last_port_index, bd_addr);
+ std::format_ptr(p_port), rfc_cb.rfc.last_port_index, bd_addr);
return p_port;
}
}
@@ -199,7 +199,7 @@
*
******************************************************************************/
void port_release_port(tPORT* p_port) {
- log::verbose("p_port: {} state: {} keep_handle: {}", fmt::ptr(p_port), p_port->rfc.state,
+ log::verbose("p_port: {} state: {} keep_handle: {}", std::format_ptr(p_port), p_port->rfc.state,
p_port->keep_port_handle);
mutex_global_lock();
@@ -280,7 +280,8 @@
for (tRFC_MCB& mcb : rfc_cb.port.rfc_mcb) {
if ((mcb.state != RFC_MX_STATE_IDLE) && (mcb.bd_addr == bd_addr)) {
/* Multiplexer channel found do not change anything */
- log::verbose("found, bd_addr:{}, rfc_mcb:{}, lcid:0x{:x}", bd_addr, fmt::ptr(&mcb), mcb.lcid);
+ log::verbose("found, bd_addr:{}, rfc_mcb:{}, lcid:0x{:x}", bd_addr, std::format_ptr(&mcb),
+ mcb.lcid);
return &mcb;
}
}
@@ -307,14 +308,15 @@
}
if (dlci > RFCOMM_MAX_DLCI) {
- log::warn("DLCI {} is too large, bd_addr={}, p_mcb={}", dlci, p_mcb->bd_addr, fmt::ptr(p_mcb));
+ log::warn("DLCI {} is too large, bd_addr={}, p_mcb={}", dlci, p_mcb->bd_addr,
+ std::format_ptr(p_mcb));
return nullptr;
}
uint8_t handle = p_mcb->port_handles[dlci];
if (handle == 0) {
log::info("Cannot find allocated RFCOMM app port for DLCI {} on {}, p_mcb={}", dlci,
- p_mcb->bd_addr, fmt::ptr(p_mcb));
+ p_mcb->bd_addr, std::format_ptr(p_mcb));
return nullptr;
}
return &rfc_cb.port.port[handle - 1];
diff --git a/system/stack/rfcomm/rfc_event.h b/system/stack/rfcomm/rfc_event.h
index 64c4e79..f8c7666 100644
--- a/system/stack/rfcomm/rfc_event.h
+++ b/system/stack/rfcomm/rfc_event.h
@@ -124,11 +124,11 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tRFC_EVENT> : enum_formatter<tRFC_EVENT> {};
template <>
struct formatter<tRFC_MX_EVENT> : enum_formatter<tRFC_MX_EVENT> {};
template <>
struct formatter<tRFC_PORT_EVENT> : enum_formatter<tRFC_PORT_EVENT> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/rfcomm/rfc_l2cap_if.cc b/system/stack/rfcomm/rfc_l2cap_if.cc
index 8b96d26..5b7fc00 100644
--- a/system/stack/rfcomm/rfc_l2cap_if.cc
+++ b/system/stack/rfcomm/rfc_l2cap_if.cc
@@ -268,13 +268,13 @@
/* If the frame did not pass validation just ignore it */
if (event == RFC_EVENT_BAD_FRAME) {
log::warn("Bad RFCOMM frame from lcid=0x{:x}, bd_addr={}, p_mcb={}", lcid, p_mcb->bd_addr,
- fmt::ptr(p_mcb));
+ std::format_ptr(p_mcb));
osi_free(p_buf);
return;
}
if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
- log::verbose("handle multiplexer event {}, p_mcb={}", event, fmt::ptr(p_mcb));
+ log::verbose("handle multiplexer event {}, p_mcb={}", event, std::format_ptr(p_mcb));
/* Take special care of the Multiplexer Control Messages */
if (event == RFC_EVENT_UIH) {
rfc_process_mx_message(p_mcb, p_buf);
@@ -293,11 +293,11 @@
/* If this is a SABME on new port, check if any app is waiting for it */
if (event != RFC_EVENT_SABME) {
log::warn("no for none-SABME event, lcid=0x{:x}, bd_addr={}, p_mcb={}", lcid, p_mcb->bd_addr,
- fmt::ptr(p_mcb));
+ std::format_ptr(p_mcb));
if ((p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) ||
(!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr)) {
log::error("Disconnecting RFCOMM, lcid=0x{:x}, bd_addr={}, p_mcb={}", lcid, p_mcb->bd_addr,
- fmt::ptr(p_mcb));
+ std::format_ptr(p_mcb));
rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
}
osi_free(p_buf);
@@ -309,13 +309,14 @@
log::error(
"Disconnecting RFCOMM, no port for dlci {}, lcid=0x{:x}, bd_addr={}, "
"p_mcb={}",
- rfc_cb.rfc.rx_frame.dlci, lcid, p_mcb->bd_addr, fmt::ptr(p_mcb));
+ rfc_cb.rfc.rx_frame.dlci, lcid, p_mcb->bd_addr, std::format_ptr(p_mcb));
rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, true);
osi_free(p_buf);
return;
}
log::verbose("port_handles[dlci={}]:{}->{}, p_mcb={}", rfc_cb.rfc.rx_frame.dlci,
- p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci], p_port->handle, fmt::ptr(p_mcb));
+ p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci], p_port->handle,
+ std::format_ptr(p_mcb));
p_mcb->port_handles[rfc_cb.rfc.rx_frame.dlci] = p_port->handle;
p_port->rfc.p_mcb = p_mcb;
}
diff --git a/system/stack/rfcomm/rfc_port_fsm.cc b/system/stack/rfcomm/rfc_port_fsm.cc
index 6313abf..0f3ec06 100644
--- a/system/stack/rfcomm/rfc_port_fsm.cc
+++ b/system/stack/rfcomm/rfc_port_fsm.cc
@@ -642,7 +642,8 @@
if (p_mcb->state != RFC_MX_STATE_DISC_WAIT_UA) {
PORT_ParNegInd(p_mcb, dlci, p_frame->u.pn.mtu, p_frame->u.pn.conv_layer, p_frame->u.pn.k);
} else {
- log::warn("MX PN while disconnecting, bd_addr={}, p_mcb={}", p_mcb->bd_addr, fmt::ptr(p_mcb));
+ log::warn("MX PN while disconnecting, bd_addr={}, p_mcb={}", p_mcb->bd_addr,
+ std::format_ptr(p_mcb));
rfc_send_dm(p_mcb, dlci, false);
}
@@ -651,7 +652,7 @@
/* If we are not awaiting response just ignore it */
tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if ((p_port == nullptr) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) {
- log::warn(": Ignore unwanted response, p_mcb={}, bd_addr={}, dlci={}", fmt::ptr(p_mcb),
+ log::warn(": Ignore unwanted response, p_mcb={}, bd_addr={}, dlci={}", std::format_ptr(p_mcb),
p_mcb->bd_addr, dlci);
return;
}
diff --git a/system/stack/rfcomm/rfc_state.h b/system/stack/rfcomm/rfc_state.h
index 32afa29..847c7d0 100644
--- a/system/stack/rfcomm/rfc_state.h
+++ b/system/stack/rfcomm/rfc_state.h
@@ -68,10 +68,10 @@
}
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tRFC_MX_STATE> : enum_formatter<tRFC_MX_STATE> {};
template <>
struct formatter<tRFC_PORT_STATE> : enum_formatter<tRFC_PORT_STATE> {};
-} // namespace fmt
+} // namespace std
diff --git a/system/stack/rfcomm/rfc_ts_frames.cc b/system/stack/rfcomm/rfc_ts_frames.cc
index ea57abf..e9df718 100644
--- a/system/stack/rfcomm/rfc_ts_frames.cc
+++ b/system/stack/rfcomm/rfc_ts_frames.cc
@@ -683,7 +683,7 @@
}
if (mx_len != length) {
- log::error("Bad MX frame, p_mcb={}, bd_addr={}", fmt::ptr(p_mcb), p_mcb->bd_addr);
+ log::error("Bad MX frame, p_mcb={}, bd_addr={}", std::format_ptr(p_mcb), p_mcb->bd_addr);
osi_free(p_buf);
return;
}
@@ -692,7 +692,8 @@
switch (p_rx_frame->type) {
case RFCOMM_MX_PN:
if (length != RFCOMM_MX_PN_LEN) {
- log::error("Invalid PN length, p_mcb={}, bd_addr={}", fmt::ptr(p_mcb), p_mcb->bd_addr);
+ log::error("Invalid PN length, p_mcb={}, bd_addr={}", std::format_ptr(p_mcb),
+ p_mcb->bd_addr);
break;
}
@@ -708,7 +709,7 @@
if (!p_rx_frame->dlci || !RFCOMM_VALID_DLCI(p_rx_frame->dlci) ||
(p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU) || (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU)) {
- log::error("Bad PN frame, p_mcb={}, bd_addr={}", fmt::ptr(p_mcb), p_mcb->bd_addr);
+ log::error("Bad PN frame, p_mcb={}, bd_addr={}", std::format_ptr(p_mcb), p_mcb->bd_addr);
break;
}
diff --git a/system/stack/rfcomm/rfc_utils.cc b/system/stack/rfcomm/rfc_utils.cc
index 2342089..29b8925 100644
--- a/system/stack/rfcomm/rfc_utils.cc
+++ b/system/stack/rfcomm/rfc_utils.cc
@@ -145,7 +145,7 @@
log::verbose(
"rfc_alloc_multiplexer_channel:is_initiator:{}, found, state:{}, "
"p_mcb:{}",
- is_initiator, rfc_cb.port.rfc_mcb[i].state, fmt::ptr(&rfc_cb.port.rfc_mcb[i]));
+ is_initiator, rfc_cb.port.rfc_mcb[i].state, std::format_ptr(&rfc_cb.port.rfc_mcb[i]));
return &rfc_cb.port.rfc_mcb[i];
}
}
@@ -166,7 +166,7 @@
log::verbose(
"rfc_alloc_multiplexer_channel:is_initiator:{}, create new p_mcb:{}, "
"index:{}",
- is_initiator, fmt::ptr(&rfc_cb.port.rfc_mcb[j]), j);
+ is_initiator, std::format_ptr(&rfc_cb.port.rfc_mcb[j]), j);
p_mcb->mcb_timer = alarm_new("rfcomm_mcb.mcb_timer");
p_mcb->cmd_q = fixed_queue_new(SIZE_MAX);
@@ -416,8 +416,9 @@
/* if passed a buffer queue it */
if (p_buf != NULL) {
if (p_mcb->cmd_q == NULL) {
- log::error("empty queue: p_mcb = {} p_mcb->lcid = {} cached p_mcb = {}", fmt::ptr(p_mcb),
- p_mcb->lcid, fmt::ptr(rfc_find_lcid_mcb(p_mcb->lcid)));
+ log::error("empty queue: p_mcb = {} p_mcb->lcid = {} cached p_mcb = {}",
+ std::format_ptr(p_mcb), p_mcb->lcid,
+ std::format_ptr(rfc_find_lcid_mcb(p_mcb->lcid)));
}
fixed_queue_enqueue(p_mcb->cmd_q, p_buf);
}
diff --git a/system/stack/sdp/sdp_api.cc b/system/stack/sdp/sdp_api.cc
index 589a7eb..093dddd 100644
--- a/system/stack/sdp/sdp_api.cc
+++ b/system/stack/sdp/sdp_api.cc
@@ -81,7 +81,7 @@
if (p_db == NULL || (sizeof(tSDP_DISCOVERY_DB) > len) || num_attr > SDP_MAX_ATTR_FILTERS ||
num_uuid > SDP_MAX_UUID_FILTERS) {
log::error("SDP_InitDiscoveryDb Illegal param: p_db {}, len {}, num_uuid {}, num_attr {}",
- fmt::ptr(p_db), len, num_uuid, num_attr);
+ std::format_ptr(p_db), len, num_uuid, num_attr);
return false;
}
@@ -1124,7 +1124,7 @@
if (conn_cb.device_address == RawAddress::kEmpty) {
return;
}
- LOG_DUMPSYS(fd, "peer:%s discovery_state:%s", fmt::format("{}", conn_cb.device_address).c_str(),
+ LOG_DUMPSYS(fd, "peer:%s discovery_state:%s", std::format("{}", conn_cb.device_address).c_str(),
sdp_disc_wait_text(conn_cb.disc_state).c_str());
LOG_DUMPSYS(fd, " connection_state:%s connection_flags:0x%02x mtu:%hu l2cap_cid:%hu",
sdp_state_text(conn_cb.con_state).c_str(), conn_cb.con_flags, conn_cb.rem_mtu_size,
diff --git a/system/stack/sdp/sdp_db.cc b/system/stack/sdp/sdp_db.cc
index dbb8ba7..8ecdf9e 100644
--- a/system/stack/sdp/sdp_db.cc
+++ b/system/stack/sdp/sdp_db.cc
@@ -288,22 +288,22 @@
snprintf(&num_array[i * 2], sizeof(num_array) - i * 2, "%02X", (uint8_t)(p_val[i]));
}
log::verbose("SDP_AddAttribute: handle:{:X}, id:{:04X}, type:{}, len:{}, p_val:{}, *p_val:{}",
- handle, attr_id, attr_type, attr_len, fmt::ptr(p_val), num_array);
+ handle, attr_id, attr_type, attr_len, std::format_ptr(p_val), num_array);
} else if (attr_type == BOOLEAN_DESC_TYPE) {
log::verbose("SDP_AddAttribute: handle:{:X}, id:{:04X}, type:{}, len:{}, p_val:{}, *p_val:{}",
- handle, attr_id, attr_type, attr_len, fmt::ptr(p_val), *p_val);
+ handle, attr_id, attr_type, attr_len, std::format_ptr(p_val), *p_val);
} else if ((attr_type == TEXT_STR_DESC_TYPE) || (attr_type == URL_DESC_TYPE)) {
if (p_val[attr_len - 1] == '\0') {
log::verbose(
"SDP_AddAttribute: handle:{:X}, id:{:04X}, type:{}, len:{}, p_val:{}, *p_val:{}",
- handle, attr_id, attr_type, attr_len, fmt::ptr(p_val), (char*)p_val);
+ handle, attr_id, attr_type, attr_len, std::format_ptr(p_val), (char*)p_val);
} else {
log::verbose("SDP_AddAttribute: handle:{:X}, id:{:04X}, type:{}, len:{}, p_val:{}", handle,
- attr_id, attr_type, attr_len, fmt::ptr(p_val));
+ attr_id, attr_type, attr_len, std::format_ptr(p_val));
}
} else {
log::verbose("SDP_AddAttribute: handle:{:X}, id:{:04X}, type:{}, len:{}, p_val:{}", handle,
- attr_id, attr_type, attr_len, fmt::ptr(p_val));
+ attr_id, attr_type, attr_len, std::format_ptr(p_val));
}
}
diff --git a/system/stack/smp/smp_int.h b/system/stack/smp/smp_int.h
index dd51c0d..7725bd7 100644
--- a/system/stack/smp/smp_int.h
+++ b/system/stack/smp/smp_int.h
@@ -502,13 +502,13 @@
void smp_clear_local_oob_data();
bool smp_has_local_oob_data();
-namespace fmt {
+namespace std {
template <>
struct formatter<tSMP_EVENT> : enum_formatter<tSMP_EVENT> {};
template <>
struct formatter<tSMP_OPCODE> : enum_formatter<tSMP_OPCODE> {};
template <>
struct formatter<tSMP_ASSO_MODEL> : enum_formatter<tSMP_ASSO_MODEL> {};
-} // namespace fmt
+} // namespace std
#endif /* SMP_INT_H */
diff --git a/system/test/headless/headless.cc b/system/test/headless/headless.cc
index 5f0d820..f115ddd 100644
--- a/system/test/headless/headless.cc
+++ b/system/test/headless/headless.cc
@@ -84,7 +84,7 @@
}
}
log::info("num_callbacks:{} status:{} num_properties:{} properties:{}", num_callbacks,
- bt_status_text(status), num_properties, fmt::ptr(properties));
+ bt_status_text(status), num_properties, std::format_ptr(properties));
}
void remote_device_properties(bt_status_t status, RawAddress* bd_addr, int num_properties,
@@ -100,7 +100,7 @@
}
}
log::info("num_callbacks:{} status:{} device:{} num_properties:{} properties:{}", num_callbacks,
- bt_status_text(status), STR(*bd_addr), num_properties, fmt::ptr(properties));
+ bt_status_text(status), STR(*bd_addr), num_properties, std::format_ptr(properties));
}
// Aggregate disparate variables from callback API into unified single structure
@@ -114,7 +114,7 @@
}
}
log::info("Device found callback: num_properties:{} properties:{}", num_properties,
- fmt::ptr(properties));
+ std::format_ptr(properties));
}
void discovery_state_changed(bt_discovery_state_t state) {
diff --git a/system/test/headless/interface.h b/system/test/headless/interface.h
index 11c314c..47e5484 100644
--- a/system/test/headless/interface.h
+++ b/system/test/headless/interface.h
@@ -98,7 +98,8 @@
: callback_params_t(name, callback_type) {
for (int i = 0; i < num_properties; i++) {
log::debug("Processing property {}/{} {} type:{} val:{}", i, num_properties,
- fmt::ptr(&properties[i]), properties[i].type, fmt::ptr(properties[i].val));
+ std::format_ptr(&properties[i]), properties[i].type,
+ std::format_ptr(properties[i].val));
property_queue_.push_back(bluetooth::test::headless::property_factory(properties[i]));
}
}
@@ -132,7 +133,7 @@
uint16_t acl_handle;
std::string ToString() const override {
- return fmt::format(
+ return std::format(
"status:{} remote_bd_addr:{} state:{} transport:{} reason:{}"
" direction:{} handle:{}",
bt_status_text(status), remote_bd_addr.ToString(),
@@ -153,7 +154,7 @@
bt_discovery_state_t state;
std::string ToString() const override {
- return fmt::format("state:{}", bt_discovery_state_text(state));
+ return std::format("state:{}", bt_discovery_state_text(state));
}
};
@@ -168,7 +169,7 @@
bt_status_t status;
std::string ToString() const override {
- return fmt::format("status:{} num_properties:{}", bt_status_text(status), num_properties());
+ return std::format("status:{} num_properties:{}", bt_status_text(status), num_properties());
}
};
@@ -187,7 +188,7 @@
RawAddress bd_addr;
std::string ToString() const override {
- return fmt::format("status:{} bd_addr:{} num_properties:{}", bt_status_text(status),
+ return std::format("status:{} bd_addr:{} num_properties:{}", bt_status_text(status),
bd_addr.ToString(), num_properties());
}
};
@@ -201,7 +202,7 @@
virtual ~device_found_params_t() {}
std::string ToString() const override {
- return fmt::format("num_properties:{}", num_properties());
+ return std::format("num_properties:{}", num_properties());
}
};
diff --git a/system/test/headless/property.h b/system/test/headless/property.h
index 8227979..6af17a2 100644
--- a/system/test/headless/property.h
+++ b/system/test/headless/property.h
@@ -99,7 +99,7 @@
public:
virtual std::string ToString() const override {
- return fmt::format("Unimplemented property type:{} name:{}", type, bt_property_type_text(type));
+ return std::format("Unimplemented property type:{} name:{}", type, bt_property_type_text(type));
}
};
@@ -119,7 +119,7 @@
}
virtual std::string ToString() const override {
- return fmt::format("Number of uuids:{}", get_uuids().size());
+ return std::format("Number of uuids:{}", get_uuids().size());
}
private:
@@ -136,7 +136,7 @@
return std::string(s);
}
- virtual std::string ToString() const override { return fmt::format("Name:{}", get_name()); }
+ virtual std::string ToString() const override { return std::format("Name:{}", get_name()); }
};
struct bdaddr_t : public bt_property_t {
@@ -153,7 +153,7 @@
}
virtual std::string ToString() const override {
- return fmt::format("bd_addr:{}", get_addr().ToString());
+ return std::format("bd_addr:{}", get_addr().ToString());
}
};
@@ -168,7 +168,7 @@
}
virtual std::string ToString() const override {
- return fmt::format("cod:0x{:04x}", get_class_of_device());
+ return std::format("cod:0x{:04x}", get_class_of_device());
}
};
@@ -183,7 +183,7 @@
}
virtual std::string ToString() const override {
- return fmt::format("tod:0x{:04x}", get_type_of_device());
+ return std::format("tod:0x{:04x}", get_type_of_device());
}
};
diff --git a/system/test/headless/stopwatch.h b/system/test/headless/stopwatch.h
index e2b549c..d7f5e36 100644
--- a/system/test/headless/stopwatch.h
+++ b/system/test/headless/stopwatch.h
@@ -40,7 +40,7 @@
std::string ToString() { return ToString(""); }
std::string ToString(const std::string& comment) {
- return fmt::format("{}: {} ms {}", name_, static_cast<unsigned long>(LapMs()), comment);
+ return std::format("{}: {} ms {}", name_, static_cast<unsigned long>(LapMs()), comment);
}
private:
diff --git a/system/test/headless/utils/power_mode_client.h b/system/test/headless/utils/power_mode_client.h
index 1f66c63..d27c59e 100644
--- a/system/test/headless/utils/power_mode_client.h
+++ b/system/test/headless/utils/power_mode_client.h
@@ -66,7 +66,7 @@
tHCI_STATUS hci_status;
std::string ToString() const {
- return fmt::format("bd_addr:{} pm_status:{} value:{} hci_status:{}", bd_addr.ToString(),
+ return std::format("bd_addr:{} pm_status:{} value:{} hci_status:{}", bd_addr.ToString(),
power_mode_status_text(status), value, hci_status_code_text(hci_status));
}
};
diff --git a/system/test/stub/osi.cc b/system/test/stub/osi.cc
index 17accc1..c087497 100644
--- a/system/test/stub/osi.cc
+++ b/system/test/stub/osi.cc
@@ -346,18 +346,18 @@
bool alarm_is_scheduled(const alarm_t* alarm) {
inc_func_call_count(__func__);
- auto iter =
- find_if(previous_fake_osi_alarms_.begin(), previous_fake_osi_alarms_.end(),
- [alarm](auto const& a) {
- bluetooth::log::debug("iter: {} == {} ?", fmt::ptr(a.alarm), fmt::ptr(alarm));
- return a.alarm == alarm;
- });
+ auto iter = find_if(previous_fake_osi_alarms_.begin(), previous_fake_osi_alarms_.end(),
+ [alarm](auto const& a) {
+ bluetooth::log::debug("iter: {} == {} ?", std::format_ptr(a.alarm),
+ std::format_ptr(alarm));
+ return a.alarm == alarm;
+ });
if (iter != previous_fake_osi_alarms_.end()) {
return true;
}
- bluetooth::log::debug(" {} == {} ?", fmt::ptr(fake_osi_alarm_set_on_mloop_.alarm),
- fmt::ptr(alarm));
+ bluetooth::log::debug(" {} == {} ?", std::format_ptr(fake_osi_alarm_set_on_mloop_.alarm),
+ std::format_ptr(alarm));
return fake_osi_alarm_set_on_mloop_.alarm == alarm;
}
@@ -371,14 +371,14 @@
auto iter = find_if(previous_fake_osi_alarms_.begin(), previous_fake_osi_alarms_.end(),
[alarm](auto const& a) { return a.alarm == alarm; });
if (iter != previous_fake_osi_alarms_.end()) {
- bluetooth::log::debug(" clearing alarm {} ", fmt::ptr(iter->alarm));
+ bluetooth::log::debug(" clearing alarm {} ", std::format_ptr(iter->alarm));
previous_fake_osi_alarms_.erase(iter);
return;
}
}
if (fake_osi_alarm_set_on_mloop_.alarm == alarm || alarm == nullptr) {
- bluetooth::log::debug(" clearing alarm {} ", fmt::ptr(alarm));
+ bluetooth::log::debug(" clearing alarm {} ", std::format_ptr(alarm));
fake_osi_alarm_set_on_mloop_.alarm = nullptr;
fake_osi_alarm_set_on_mloop_.interval_ms = 0;
fake_osi_alarm_set_on_mloop_.cb = nullptr;
@@ -412,11 +412,11 @@
inc_func_call_count(__func__);
if (fake_osi_alarm_set_on_mloop_.alarm != nullptr) {
- bluetooth::log::info("Queuing alarm {}", fmt::ptr(fake_osi_alarm_set_on_mloop_.alarm));
+ bluetooth::log::info("Queuing alarm {}", std::format_ptr(fake_osi_alarm_set_on_mloop_.alarm));
previous_fake_osi_alarms_.push_back(fake_osi_alarm_set_on_mloop_);
}
- bluetooth::log::info("Adding alarm {}", fmt::ptr(alarm));
+ bluetooth::log::info("Adding alarm {}", std::format_ptr(alarm));
fake_osi_alarm_set_on_mloop_.alarm = alarm;
fake_osi_alarm_set_on_mloop_.interval_ms = interval_ms;
fake_osi_alarm_set_on_mloop_.cb = cb;
diff --git a/system/types/ble_address_with_type.h b/system/types/ble_address_with_type.h
index 1c9869a..18f7cd0 100644
--- a/system/types/ble_address_with_type.h
+++ b/system/types/ble_address_with_type.h
@@ -170,13 +170,13 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<tBLE_BD_ADDR> : formatter<std::string> {
template <class Context>
typename Context::iterator format(const tBLE_BD_ADDR& address, Context& ctx) const {
std::string repr = address.ToRedactedStringForLogging();
- return fmt::formatter<std::string>::format(repr, ctx);
+ return std::formatter<std::string>::format(repr, ctx);
}
};
template <>
@@ -184,10 +184,10 @@
template <class Context>
typename Context::iterator format(const tAclLinkSpec& address, Context& ctx) const {
std::string repr = address.ToRedactedStringForLogging();
- return fmt::formatter<std::string>::format(repr, ctx);
+ return std::formatter<std::string>::format(repr, ctx);
}
};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>
diff --git a/system/types/bluetooth/uuid.h b/system/types/bluetooth/uuid.h
index 9c09441..eab8bb1 100644
--- a/system/types/bluetooth/uuid.h
+++ b/system/types/bluetooth/uuid.h
@@ -150,9 +150,9 @@
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<bluetooth::Uuid> : ostream_formatter {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/types/bt_transport.h b/system/types/bt_transport.h
index 403e85d..a787a57 100644
--- a/system/types/bt_transport.h
+++ b/system/types/bt_transport.h
@@ -40,9 +40,9 @@
RETURN_UNKNOWN_TYPE_STRING(tBT_TRANSPORT, transport);
}
-namespace fmt {
+namespace std {
template <>
struct formatter<tBT_TRANSPORT> : enum_formatter<tBT_TRANSPORT> {};
-} // namespace fmt
+} // namespace std
#endif
diff --git a/system/types/hci_role.h b/system/types/hci_role.h
index bbedb23..0a68582 100644
--- a/system/types/hci_role.h
+++ b/system/types/hci_role.h
@@ -53,9 +53,9 @@
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<tHCI_ROLE> : enum_formatter<tHCI_ROLE> {};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)
diff --git a/system/types/raw_address.h b/system/types/raw_address.h
index 60ff23f..2a8540b 100644
--- a/system/types/raw_address.h
+++ b/system/types/raw_address.h
@@ -113,15 +113,15 @@
#if __has_include(<bluetooth/log.h>)
#include <bluetooth/log.h>
-namespace fmt {
+namespace std {
template <>
struct formatter<RawAddress> : formatter<std::string> {
template <class Context>
typename Context::iterator format(const RawAddress& address, Context& ctx) const {
std::string repr = address.ToRedactedStringForLogging();
- return fmt::formatter<std::string>::format(repr, ctx);
+ return std::formatter<std::string>::format(repr, ctx);
}
};
-} // namespace fmt
+} // namespace std
#endif // __has_include(<bluetooth/log.h>)