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