diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2022-03-23 05:40:11 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-03-23 05:40:11 +0000 |
commit | 9d938ae08e4b818c9ab62ea23d06c41efe3f0e3c (patch) | |
tree | 74b5153a7df97955a6164aa3e17942ff6f3cd544 | |
parent | 897e2ef5880f5ceabac4863d6111013610b5e286 (diff) | |
parent | 2f52d18c6a1cf0a2005dc53eb87a1886d629d071 (diff) |
Merge "More metadata for spatial audio and fast pair" am: 81a78d9f3e am: 20756a9aa9 am: 2f52d18c6a
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/1998179
Change-Id: Ied125d9dd48e9eb1c99ccef6075ef0bd9657438b
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; } /** |