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