1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.btservice.storage; 18 19 import android.bluetooth.BluetoothA2dp; 20 import android.bluetooth.BluetoothA2dp.OptionalCodecsPreferenceStatus; 21 import android.bluetooth.BluetoothA2dp.OptionalCodecsSupportStatus; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.BluetoothProfile; 24 import android.bluetooth.BluetoothUtils; 25 26 import androidx.annotation.NonNull; 27 import androidx.room.Embedded; 28 import androidx.room.Entity; 29 import androidx.room.PrimaryKey; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 33 import java.util.ArrayList; 34 import java.util.List; 35 36 /** 37 * @hide 38 */ 39 @Entity(tableName = "metadata") 40 @VisibleForTesting 41 public class Metadata { 42 @PrimaryKey 43 @NonNull 44 private String address; 45 46 public boolean migrated; 47 48 @Embedded 49 public ProfilePrioritiesEntity profileConnectionPolicies; 50 51 @Embedded 52 @NonNull 53 public CustomizedMetadataEntity publicMetadata; 54 55 public @OptionalCodecsSupportStatus int a2dpSupportsOptionalCodecs; 56 public @OptionalCodecsPreferenceStatus int a2dpOptionalCodecsEnabled; 57 58 public long last_active_time; 59 public boolean is_active_a2dp_device; 60 61 @Embedded 62 public AudioPolicyEntity audioPolicyMetadata; 63 64 /** 65 * The preferred profile to be used for {@link BluetoothDevice#AUDIO_MODE_OUTPUT_ONLY}. This can 66 * be either {@link BluetoothProfile#A2DP} or {@link BluetoothProfile#LE_AUDIO}. This value is 67 * only used if the remote device supports both A2DP and LE Audio and both transports are 68 * connected and active. 69 */ 70 public int preferred_output_only_profile; 71 72 /** 73 * The preferred profile to be used for {@link BluetoothDevice#AUDIO_MODE_DUPLEX}. This can 74 * be either {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#LE_AUDIO}. This value 75 * is only used if the remote device supports both HFP and LE Audio and both transports are 76 * connected and active. 77 */ 78 public int preferred_duplex_profile; 79 Metadata(String address)80 Metadata(String address) { 81 this.address = address; 82 migrated = false; 83 profileConnectionPolicies = new ProfilePrioritiesEntity(); 84 publicMetadata = new CustomizedMetadataEntity(); 85 a2dpSupportsOptionalCodecs = BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN; 86 a2dpOptionalCodecsEnabled = BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN; 87 last_active_time = MetadataDatabase.sCurrentConnectionNumber++; 88 is_active_a2dp_device = true; 89 audioPolicyMetadata = new AudioPolicyEntity(); 90 preferred_output_only_profile = 0; 91 preferred_duplex_profile = 0; 92 } 93 94 /** 95 * @hide 96 */ 97 @VisibleForTesting getAddress()98 public String getAddress() { 99 return address; 100 } 101 102 /** 103 * Returns the anonymized hardware address. The first three octets will be suppressed for 104 * anonymization. 105 * <p> For example, "XX:XX:XX:AA:BB:CC". 106 * 107 * @return Anonymized bluetooth hardware address as string 108 */ 109 @NonNull getAnonymizedAddress()110 public String getAnonymizedAddress() { 111 return BluetoothUtils.toAnonymizedAddress(address); 112 } 113 setProfileConnectionPolicy(int profile, int connectionPolicy)114 void setProfileConnectionPolicy(int profile, int connectionPolicy) { 115 // We no longer support BluetoothProfile.PRIORITY_AUTO_CONNECT and are merging it into 116 // BluetoothProfile.CONNECTION_POLICY_ALLOWED 117 if (connectionPolicy > BluetoothProfile.CONNECTION_POLICY_ALLOWED) { 118 connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED; 119 } 120 121 switch (profile) { 122 case BluetoothProfile.A2DP: 123 profileConnectionPolicies.a2dp_connection_policy = connectionPolicy; 124 break; 125 case BluetoothProfile.A2DP_SINK: 126 profileConnectionPolicies.a2dp_sink_connection_policy = connectionPolicy; 127 break; 128 case BluetoothProfile.HEADSET: 129 profileConnectionPolicies.hfp_connection_policy = connectionPolicy; 130 break; 131 case BluetoothProfile.HEADSET_CLIENT: 132 profileConnectionPolicies.hfp_client_connection_policy = connectionPolicy; 133 break; 134 case BluetoothProfile.HID_HOST: 135 profileConnectionPolicies.hid_host_connection_policy = connectionPolicy; 136 break; 137 case BluetoothProfile.PAN: 138 profileConnectionPolicies.pan_connection_policy = connectionPolicy; 139 break; 140 case BluetoothProfile.PBAP: 141 profileConnectionPolicies.pbap_connection_policy = connectionPolicy; 142 break; 143 case BluetoothProfile.PBAP_CLIENT: 144 profileConnectionPolicies.pbap_client_connection_policy = connectionPolicy; 145 break; 146 case BluetoothProfile.MAP: 147 profileConnectionPolicies.map_connection_policy = connectionPolicy; 148 break; 149 case BluetoothProfile.MAP_CLIENT: 150 profileConnectionPolicies.map_client_connection_policy = connectionPolicy; 151 break; 152 case BluetoothProfile.SAP: 153 profileConnectionPolicies.sap_connection_policy = connectionPolicy; 154 break; 155 case BluetoothProfile.HEARING_AID: 156 profileConnectionPolicies.hearing_aid_connection_policy = connectionPolicy; 157 break; 158 case BluetoothProfile.HAP_CLIENT: 159 profileConnectionPolicies.hap_client_connection_policy = connectionPolicy; 160 break; 161 case BluetoothProfile.LE_AUDIO: 162 profileConnectionPolicies.le_audio_connection_policy = connectionPolicy; 163 break; 164 case BluetoothProfile.VOLUME_CONTROL: 165 profileConnectionPolicies.volume_control_connection_policy = connectionPolicy; 166 break; 167 case BluetoothProfile.CSIP_SET_COORDINATOR: 168 profileConnectionPolicies.csip_set_coordinator_connection_policy = connectionPolicy; 169 break; 170 case BluetoothProfile.LE_CALL_CONTROL: 171 profileConnectionPolicies.le_call_control_connection_policy = connectionPolicy; 172 break; 173 case BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT: 174 profileConnectionPolicies.bass_client_connection_policy = connectionPolicy; 175 break; 176 case BluetoothProfile.BATTERY: 177 profileConnectionPolicies.battery_connection_policy = connectionPolicy; 178 break; 179 default: 180 throw new IllegalArgumentException("invalid profile " + profile); 181 } 182 } 183 184 /** 185 * @hide 186 */ 187 @VisibleForTesting getProfileConnectionPolicy(int profile)188 public int getProfileConnectionPolicy(int profile) { 189 switch (profile) { 190 case BluetoothProfile.A2DP: 191 return profileConnectionPolicies.a2dp_connection_policy; 192 case BluetoothProfile.A2DP_SINK: 193 return profileConnectionPolicies.a2dp_sink_connection_policy; 194 case BluetoothProfile.HEADSET: 195 return profileConnectionPolicies.hfp_connection_policy; 196 case BluetoothProfile.HEADSET_CLIENT: 197 return profileConnectionPolicies.hfp_client_connection_policy; 198 case BluetoothProfile.HID_HOST: 199 return profileConnectionPolicies.hid_host_connection_policy; 200 case BluetoothProfile.PAN: 201 return profileConnectionPolicies.pan_connection_policy; 202 case BluetoothProfile.PBAP: 203 return profileConnectionPolicies.pbap_connection_policy; 204 case BluetoothProfile.PBAP_CLIENT: 205 return profileConnectionPolicies.pbap_client_connection_policy; 206 case BluetoothProfile.MAP: 207 return profileConnectionPolicies.map_connection_policy; 208 case BluetoothProfile.MAP_CLIENT: 209 return profileConnectionPolicies.map_client_connection_policy; 210 case BluetoothProfile.SAP: 211 return profileConnectionPolicies.sap_connection_policy; 212 case BluetoothProfile.HEARING_AID: 213 return profileConnectionPolicies.hearing_aid_connection_policy; 214 case BluetoothProfile.HAP_CLIENT: 215 return profileConnectionPolicies.hap_client_connection_policy; 216 case BluetoothProfile.LE_AUDIO: 217 return profileConnectionPolicies.le_audio_connection_policy; 218 case BluetoothProfile.VOLUME_CONTROL: 219 return profileConnectionPolicies.volume_control_connection_policy; 220 case BluetoothProfile.CSIP_SET_COORDINATOR: 221 return profileConnectionPolicies.csip_set_coordinator_connection_policy; 222 case BluetoothProfile.LE_CALL_CONTROL: 223 return profileConnectionPolicies.le_call_control_connection_policy; 224 case BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT: 225 return profileConnectionPolicies.bass_client_connection_policy; 226 case BluetoothProfile.BATTERY: 227 return profileConnectionPolicies.battery_connection_policy; 228 } 229 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 230 } 231 setCustomizedMeta(int key, byte[] value)232 void setCustomizedMeta(int key, byte[] value) { 233 switch (key) { 234 case BluetoothDevice.METADATA_MANUFACTURER_NAME: 235 publicMetadata.manufacturer_name = value; 236 break; 237 case BluetoothDevice.METADATA_MODEL_NAME: 238 publicMetadata.model_name = value; 239 break; 240 case BluetoothDevice.METADATA_SOFTWARE_VERSION: 241 publicMetadata.software_version = value; 242 break; 243 case BluetoothDevice.METADATA_HARDWARE_VERSION: 244 publicMetadata.hardware_version = value; 245 break; 246 case BluetoothDevice.METADATA_COMPANION_APP: 247 publicMetadata.companion_app = value; 248 break; 249 case BluetoothDevice.METADATA_MAIN_ICON: 250 publicMetadata.main_icon = value; 251 break; 252 case BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET: 253 publicMetadata.is_untethered_headset = value; 254 break; 255 case BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON: 256 publicMetadata.untethered_left_icon = value; 257 break; 258 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON: 259 publicMetadata.untethered_right_icon = value; 260 break; 261 case BluetoothDevice.METADATA_UNTETHERED_CASE_ICON: 262 publicMetadata.untethered_case_icon = value; 263 break; 264 case BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY: 265 publicMetadata.untethered_left_battery = value; 266 break; 267 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY: 268 publicMetadata.untethered_right_battery = value; 269 break; 270 case BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY: 271 publicMetadata.untethered_case_battery = value; 272 break; 273 case BluetoothDevice.METADATA_UNTETHERED_LEFT_CHARGING: 274 publicMetadata.untethered_left_charging = value; 275 break; 276 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING: 277 publicMetadata.untethered_right_charging = value; 278 break; 279 case BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING: 280 publicMetadata.untethered_case_charging = value; 281 break; 282 case BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI: 283 publicMetadata.enhanced_settings_ui_uri = value; 284 break; 285 case BluetoothDevice.METADATA_DEVICE_TYPE: 286 publicMetadata.device_type = value; 287 break; 288 case BluetoothDevice.METADATA_MAIN_BATTERY: 289 publicMetadata.main_battery = value; 290 break; 291 case BluetoothDevice.METADATA_MAIN_CHARGING: 292 publicMetadata.main_charging = value; 293 break; 294 case BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD: 295 publicMetadata.main_low_battery_threshold = value; 296 break; 297 case BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD: 298 publicMetadata.untethered_left_low_battery_threshold = value; 299 break; 300 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD: 301 publicMetadata.untethered_right_low_battery_threshold = value; 302 break; 303 case BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD: 304 publicMetadata.untethered_case_low_battery_threshold = value; 305 break; 306 case BluetoothDevice.METADATA_SPATIAL_AUDIO: 307 publicMetadata.spatial_audio = value; 308 break; 309 case BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS: 310 publicMetadata.fastpair_customized = value; 311 break; 312 case BluetoothDevice.METADATA_LE_AUDIO: 313 publicMetadata.le_audio = value; 314 break; 315 case BluetoothDevice.METADATA_GMCS_CCCD: 316 publicMetadata.gmcs_cccd = value; 317 break; 318 case BluetoothDevice.METADATA_GTBS_CCCD: 319 publicMetadata.gtbs_cccd = value; 320 break; 321 } 322 } 323 324 /** 325 * @hide 326 */ 327 @VisibleForTesting getCustomizedMeta(int key)328 public byte[] getCustomizedMeta(int key) { 329 byte[] value = null; 330 switch (key) { 331 case BluetoothDevice.METADATA_MANUFACTURER_NAME: 332 value = publicMetadata.manufacturer_name; 333 break; 334 case BluetoothDevice.METADATA_MODEL_NAME: 335 value = publicMetadata.model_name; 336 break; 337 case BluetoothDevice.METADATA_SOFTWARE_VERSION: 338 value = publicMetadata.software_version; 339 break; 340 case BluetoothDevice.METADATA_HARDWARE_VERSION: 341 value = publicMetadata.hardware_version; 342 break; 343 case BluetoothDevice.METADATA_COMPANION_APP: 344 value = publicMetadata.companion_app; 345 break; 346 case BluetoothDevice.METADATA_MAIN_ICON: 347 value = publicMetadata.main_icon; 348 break; 349 case BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET: 350 value = publicMetadata.is_untethered_headset; 351 break; 352 case BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON: 353 value = publicMetadata.untethered_left_icon; 354 break; 355 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON: 356 value = publicMetadata.untethered_right_icon; 357 break; 358 case BluetoothDevice.METADATA_UNTETHERED_CASE_ICON: 359 value = publicMetadata.untethered_case_icon; 360 break; 361 case BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY: 362 value = publicMetadata.untethered_left_battery; 363 break; 364 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY: 365 value = publicMetadata.untethered_right_battery; 366 break; 367 case BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY: 368 value = publicMetadata.untethered_case_battery; 369 break; 370 case BluetoothDevice.METADATA_UNTETHERED_LEFT_CHARGING: 371 value = publicMetadata.untethered_left_charging; 372 break; 373 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING: 374 value = publicMetadata.untethered_right_charging; 375 break; 376 case BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING: 377 value = publicMetadata.untethered_case_charging; 378 break; 379 case BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI: 380 value = publicMetadata.enhanced_settings_ui_uri; 381 break; 382 case BluetoothDevice.METADATA_DEVICE_TYPE: 383 value = publicMetadata.device_type; 384 break; 385 case BluetoothDevice.METADATA_MAIN_BATTERY: 386 value = publicMetadata.main_battery; 387 break; 388 case BluetoothDevice.METADATA_MAIN_CHARGING: 389 value = publicMetadata.main_charging; 390 break; 391 case BluetoothDevice.METADATA_MAIN_LOW_BATTERY_THRESHOLD: 392 value = publicMetadata.main_low_battery_threshold; 393 break; 394 case BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD: 395 value = publicMetadata.untethered_left_low_battery_threshold; 396 break; 397 case BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD: 398 value = publicMetadata.untethered_right_low_battery_threshold; 399 break; 400 case BluetoothDevice.METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD: 401 value = publicMetadata.untethered_case_low_battery_threshold; 402 break; 403 case BluetoothDevice.METADATA_SPATIAL_AUDIO: 404 value = publicMetadata.spatial_audio; 405 break; 406 case BluetoothDevice.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS: 407 value = publicMetadata.fastpair_customized; 408 break; 409 case BluetoothDevice.METADATA_LE_AUDIO: 410 value = publicMetadata.le_audio; 411 break; 412 case BluetoothDevice.METADATA_GMCS_CCCD: 413 value = publicMetadata.gmcs_cccd; 414 break; 415 case BluetoothDevice.METADATA_GTBS_CCCD: 416 value = publicMetadata.gtbs_cccd; 417 break; 418 } 419 return value; 420 } 421 getChangedCustomizedMeta()422 List<Integer> getChangedCustomizedMeta() { 423 List<Integer> list = new ArrayList<>(); 424 for (int key = 0; key <= BluetoothDevice.getMaxMetadataKey(); key++) { 425 if (getCustomizedMeta(key) != null) { 426 list.add(key); 427 } 428 } 429 return list; 430 } 431 toString()432 public String toString() { 433 StringBuilder builder = new StringBuilder(); 434 builder.append(getAnonymizedAddress()) 435 .append(" last_active_time=" + last_active_time) 436 .append(" {profile connection policy(") 437 .append(profileConnectionPolicies) 438 .append("), optional codec(support=") 439 .append(a2dpSupportsOptionalCodecs) 440 .append("|enabled=") 441 .append(a2dpOptionalCodecsEnabled) 442 .append("), custom metadata(") 443 .append(publicMetadata) 444 .append("), hfp client audio policy(") 445 .append(audioPolicyMetadata) 446 .append(")}"); 447 448 return builder.toString(); 449 } 450 } 451