summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java8
-rw-r--r--android/app/src/com/android/bluetooth/btservice/storage/Metadata.java12
-rw-r--r--android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java20
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java32
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/113.json334
-rw-r--r--framework/java/android/bluetooth/BluetoothDevice.java21
6 files changed, 423 insertions, 4 deletions
diff --git a/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java b/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java
index 2bb71efea8..554e0753fc 100644
--- a/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java
+++ b/android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java
@@ -44,6 +44,8 @@ class CustomizedMetadataEntity {
public byte[] untethered_left_low_battery_threshold;
public byte[] untethered_right_low_battery_threshold;
public byte[] untethered_case_low_battery_threshold;
+ public byte[] spatial_audio;
+ public byte[] fastpair_customized;
public String toString() {
StringBuilder builder = new StringBuilder();
@@ -94,7 +96,11 @@ class CustomizedMetadataEntity {
.append("|untethered_right_low_battery_threshold=")
.append(metadataToString(untethered_right_low_battery_threshold))
.append("|untethered_case_low_battery_threshold=")
- .append(metadataToString(untethered_case_low_battery_threshold));
+ .append(metadataToString(untethered_case_low_battery_threshold))
+ .append("|spatial_audio=")
+ .append(metadataToString(spatial_audio))
+ .append("|fastpair_customized=")
+ .append(metadataToString(fastpair_customized));
return builder.toString();
}
diff --git a/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java b/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java
index 36d6b43cae..2b7f0d5809 100644
--- a/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java
+++ b/android/app/src/com/android/bluetooth/btservice/storage/Metadata.java
@@ -254,6 +254,12 @@ class Metadata {
case BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD:
publicMetadata.untethered_case_low_battery_threshold = value;
break;
+ case BluetoothDevice.METADATA_SPATIAL_AUDIO:
+ publicMetadata.spatial_audio = value;
+ break;
+ case BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS:
+ publicMetadata.fastpair_customized = value;
+ break;
}
}
@@ -332,6 +338,12 @@ class Metadata {
case BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD:
value = publicMetadata.untethered_case_low_battery_threshold;
break;
+ case BluetoothDevice.METADATA_SPATIAL_AUDIO:
+ value = publicMetadata.spatial_audio;
+ break;
+ case BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS:
+ value = publicMetadata.fastpair_customized;
+ break;
}
return value;
}
diff --git a/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java b/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java
index 91338179f2..a2db277c0d 100644
--- a/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java
+++ b/android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java
@@ -33,7 +33,7 @@ import java.util.List;
/**
* MetadataDatabase is a Room database stores Bluetooth persistence data
*/
-@Database(entities = {Metadata.class}, version = 112)
+@Database(entities = {Metadata.class}, version = 113)
public abstract class MetadataDatabase extends RoomDatabase {
/**
* The metadata database file name
@@ -65,6 +65,7 @@ public abstract class MetadataDatabase extends RoomDatabase {
.addMigrations(MIGRATION_109_110)
.addMigrations(MIGRATION_110_111)
.addMigrations(MIGRATION_111_112)
+ .addMigrations(MIGRATION_112_113)
.allowMainThreadQueries()
.build();
}
@@ -465,4 +466,21 @@ public abstract class MetadataDatabase extends RoomDatabase {
}
}
};
+
+ @VisibleForTesting
+ static final Migration MIGRATION_112_113 = new Migration(112, 113) {
+ @Override
+ public void migrate(SupportSQLiteDatabase database) {
+ try {
+ database.execSQL("ALTER TABLE metadata ADD COLUMN `spatial_audio` BLOB");
+ database.execSQL("ALTER TABLE metadata ADD COLUMN `fastpair_customized` BLOB");
+ } catch (SQLException ex) {
+ // Check if user has new schema, but is just missing the version update
+ Cursor cursor = database.query("SELECT * FROM metadata");
+ if (cursor == null || cursor.getColumnIndex("spatial_audio") == -1) {
+ throw ex;
+ }
+ }
+ }
+ };
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
index eb046d832e..42498b47c0 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/DatabaseManagerTest.java
@@ -381,6 +381,10 @@ public final class DatabaseManagerTest {
testSetGetCustomMetaCase(false,
BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
value, true);
+ testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_SPATIAL_AUDIO,
+ value, true);
+ testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
+ value, true);
testSetGetCustomMetaCase(false, badKey, value, false);
// Device is in database
@@ -435,6 +439,10 @@ public final class DatabaseManagerTest {
testSetGetCustomMetaCase(true,
BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
value, true);
+ testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_SPATIAL_AUDIO,
+ value, true);
+ testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
+ value, true);
}
@Test
@@ -1151,6 +1159,30 @@ public final class DatabaseManagerTest {
}
}
+ @Test
+ public void testDatabaseMigration_112_113() throws IOException {
+ // Create a database with version 112
+ SupportSQLiteDatabase db = testHelper.createDatabase(DB_NAME, 112);
+ // insert a device to the database
+ ContentValues device = new ContentValues();
+ device.put("address", TEST_BT_ADDR);
+ device.put("migrated", false);
+ assertThat(db.insert("metadata", SQLiteDatabase.CONFLICT_IGNORE, device),
+ CoreMatchers.not(-1));
+ // Migrate database from 112 to 113
+ db.close();
+ db = testHelper.runMigrationsAndValidate(DB_NAME, 113, true,
+ MetadataDatabase.MIGRATION_112_113);
+ Cursor cursor = db.query("SELECT * FROM metadata");
+ assertHasColumn(cursor, "spatial_audio", true);
+ assertHasColumn(cursor, "fastpair_customized", true);
+ while (cursor.moveToNext()) {
+ // Check the new columns was added with default value
+ assertColumnBlobData(cursor, "spatial_audio", null);
+ assertColumnBlobData(cursor, "fastpair_customized", null);
+ }
+ }
+
/**
* Helper function to check whether the database has the expected column
*/
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/113.json b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/113.json
new file mode 100644
index 0000000000..08c9ca145c
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/storage/schemas/com.android.bluetooth.btservice.storage.MetadataDatabase/113.json
@@ -0,0 +1,334 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 113,
+ "identityHash": "1949f73d922d80a81335edc130b9871d",
+ "entities": [
+ {
+ "tableName": "metadata",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT NOT NULL, `migrated` INTEGER NOT NULL, `a2dpSupportsOptionalCodecs` INTEGER NOT NULL, `a2dpOptionalCodecsEnabled` INTEGER NOT NULL, `last_active_time` INTEGER NOT NULL, `is_active_a2dp_device` INTEGER NOT NULL, `a2dp_connection_policy` INTEGER, `a2dp_sink_connection_policy` INTEGER, `hfp_connection_policy` INTEGER, `hfp_client_connection_policy` INTEGER, `hid_host_connection_policy` INTEGER, `pan_connection_policy` INTEGER, `pbap_connection_policy` INTEGER, `pbap_client_connection_policy` INTEGER, `map_connection_policy` INTEGER, `sap_connection_policy` INTEGER, `hearing_aid_connection_policy` INTEGER, `hap_client_connection_policy` INTEGER, `map_client_connection_policy` INTEGER, `le_audio_connection_policy` INTEGER, `volume_control_connection_policy` INTEGER, `csip_set_coordinator_connection_policy` INTEGER, `le_call_control_connection_policy` INTEGER, `bass_client_connection_policy` INTEGER, `battery_connection_policy` INTEGER, `manufacturer_name` BLOB, `model_name` BLOB, `software_version` BLOB, `hardware_version` BLOB, `companion_app` BLOB, `main_icon` BLOB, `is_untethered_headset` BLOB, `untethered_left_icon` BLOB, `untethered_right_icon` BLOB, `untethered_case_icon` BLOB, `untethered_left_battery` BLOB, `untethered_right_battery` BLOB, `untethered_case_battery` BLOB, `untethered_left_charging` BLOB, `untethered_right_charging` BLOB, `untethered_case_charging` BLOB, `enhanced_settings_ui_uri` BLOB, `device_type` BLOB, `main_battery` BLOB, `main_charging` BLOB, `main_low_battery_threshold` BLOB, `untethered_left_low_battery_threshold` BLOB, `untethered_right_low_battery_threshold` BLOB, `untethered_case_low_battery_threshold` BLOB, `spatial_audio` BLOB, `fastpair_customized` BLOB, PRIMARY KEY(`address`))",
+ "fields": [
+ {
+ "fieldPath": "address",
+ "columnName": "address",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "migrated",
+ "columnName": "migrated",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "a2dpSupportsOptionalCodecs",
+ "columnName": "a2dpSupportsOptionalCodecs",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "a2dpOptionalCodecsEnabled",
+ "columnName": "a2dpOptionalCodecsEnabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "last_active_time",
+ "columnName": "last_active_time",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "is_active_a2dp_device",
+ "columnName": "is_active_a2dp_device",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.a2dp_connection_policy",
+ "columnName": "a2dp_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.a2dp_sink_connection_policy",
+ "columnName": "a2dp_sink_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.hfp_connection_policy",
+ "columnName": "hfp_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.hfp_client_connection_policy",
+ "columnName": "hfp_client_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.hid_host_connection_policy",
+ "columnName": "hid_host_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.pan_connection_policy",
+ "columnName": "pan_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.pbap_connection_policy",
+ "columnName": "pbap_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.pbap_client_connection_policy",
+ "columnName": "pbap_client_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.map_connection_policy",
+ "columnName": "map_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.sap_connection_policy",
+ "columnName": "sap_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.hearing_aid_connection_policy",
+ "columnName": "hearing_aid_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.hap_client_connection_policy",
+ "columnName": "hap_client_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.map_client_connection_policy",
+ "columnName": "map_client_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.le_audio_connection_policy",
+ "columnName": "le_audio_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.volume_control_connection_policy",
+ "columnName": "volume_control_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.csip_set_coordinator_connection_policy",
+ "columnName": "csip_set_coordinator_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.le_call_control_connection_policy",
+ "columnName": "le_call_control_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.bass_client_connection_policy",
+ "columnName": "bass_client_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "profileConnectionPolicies.battery_connection_policy",
+ "columnName": "battery_connection_policy",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.manufacturer_name",
+ "columnName": "manufacturer_name",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.model_name",
+ "columnName": "model_name",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.software_version",
+ "columnName": "software_version",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.hardware_version",
+ "columnName": "hardware_version",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.companion_app",
+ "columnName": "companion_app",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.main_icon",
+ "columnName": "main_icon",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.is_untethered_headset",
+ "columnName": "is_untethered_headset",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_left_icon",
+ "columnName": "untethered_left_icon",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_right_icon",
+ "columnName": "untethered_right_icon",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_case_icon",
+ "columnName": "untethered_case_icon",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_left_battery",
+ "columnName": "untethered_left_battery",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_right_battery",
+ "columnName": "untethered_right_battery",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_case_battery",
+ "columnName": "untethered_case_battery",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_left_charging",
+ "columnName": "untethered_left_charging",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_right_charging",
+ "columnName": "untethered_right_charging",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_case_charging",
+ "columnName": "untethered_case_charging",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.enhanced_settings_ui_uri",
+ "columnName": "enhanced_settings_ui_uri",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.device_type",
+ "columnName": "device_type",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.main_battery",
+ "columnName": "main_battery",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.main_charging",
+ "columnName": "main_charging",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.main_low_battery_threshold",
+ "columnName": "main_low_battery_threshold",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_left_low_battery_threshold",
+ "columnName": "untethered_left_low_battery_threshold",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_right_low_battery_threshold",
+ "columnName": "untethered_right_low_battery_threshold",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.untethered_case_low_battery_threshold",
+ "columnName": "untethered_case_low_battery_threshold",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.spatial_audio",
+ "columnName": "spatial_audio",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicMetadata.fastpair_customized",
+ "columnName": "fastpair_customized",
+ "affinity": "BLOB",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "address"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1949f73d922d80a81335edc130b9871d')"
+ ]
+ }
+} \ No newline at end of file
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java
index 5b197763c6..4d416f2052 100644
--- a/framework/java/android/bluetooth/BluetoothDevice.java
+++ b/framework/java/android/bluetooth/BluetoothDevice.java
@@ -507,7 +507,9 @@ public final class BluetoothDevice implements Parcelable, Attributable {
METADATA_MAIN_LOW_BATTERY_THRESHOLD,
METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
- METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD})
+ METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
+ METADATA_SPATIAL_AUDIO,
+ METADATA_FAST_PAIR_CUSTOMIZED_FIELDS})
@Retention(RetentionPolicy.SOURCE)
public @interface MetadataKey{}
@@ -717,6 +719,21 @@ public final class BluetoothDevice implements Parcelable, Attributable {
@SystemApi
public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23;
+
+ /**
+ * The metadata of the audio spatial data.
+ * Data type should be {@link Byte} array.
+ * @hide
+ */
+ public static final int METADATA_SPATIAL_AUDIO = 24;
+
+ /**
+ * The metadata of the Fast Pair for any custmized feature.
+ * Data type should be {@link Byte} array.
+ * @hide
+ */
+ public static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
+
/**
* Device type which is used in METADATA_DEVICE_TYPE
* Indicates this Bluetooth device is a standard Bluetooth accessory or
@@ -3222,7 +3239,7 @@ public final class BluetoothDevice implements Parcelable, Attributable {
* @hide
*/
public static @MetadataKey int getMaxMetadataKey() {
- return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD;
+ return METADATA_FAST_PAIR_CUSTOMIZED_FIELDS;
}
/**