1 /* 2 * Copyright (C) 2012 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; 18 19 import static android.Manifest.permission.BLUETOOTH_CONNECT; 20 import static android.Manifest.permission.BLUETOOTH_SCAN; 21 22 import android.bluetooth.BluetoothA2dp; 23 import android.bluetooth.BluetoothA2dpSink; 24 import android.bluetooth.BluetoothAdapter; 25 import android.bluetooth.BluetoothAvrcpController; 26 import android.bluetooth.BluetoothClass; 27 import android.bluetooth.BluetoothDevice; 28 import android.bluetooth.BluetoothHeadset; 29 import android.bluetooth.BluetoothHeadsetClient; 30 import android.bluetooth.BluetoothHearingAid; 31 import android.bluetooth.BluetoothHidDevice; 32 import android.bluetooth.BluetoothHidHost; 33 import android.bluetooth.BluetoothMap; 34 import android.bluetooth.BluetoothMapClient; 35 import android.bluetooth.BluetoothPan; 36 import android.bluetooth.BluetoothPbap; 37 import android.bluetooth.BluetoothPbapClient; 38 import android.bluetooth.BluetoothProfile; 39 import android.bluetooth.BluetoothSap; 40 import android.bluetooth.BufferConstraint; 41 import android.bluetooth.BufferConstraints; 42 import android.content.BroadcastReceiver; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.os.ParcelUuid; 47 import android.os.SystemProperties; 48 import android.os.UserHandle; 49 import android.util.Log; 50 import android.util.Pair; 51 52 import androidx.annotation.VisibleForTesting; 53 54 import com.android.bluetooth.BluetoothStatsLog; 55 import com.android.bluetooth.Utils; 56 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 57 58 import java.io.FileDescriptor; 59 import java.io.PrintWriter; 60 import java.util.ArrayList; 61 import java.util.HashMap; 62 import java.util.List; 63 import java.util.concurrent.CopyOnWriteArrayList; 64 65 class AdapterProperties { 66 private static final boolean DBG = true; 67 private static final boolean VDBG = false; 68 private static final String TAG = "AdapterProperties"; 69 70 private static final String MAX_CONNECTED_AUDIO_DEVICES_PROPERTY = 71 "persist.bluetooth.maxconnectedaudiodevices"; 72 static final int MAX_CONNECTED_AUDIO_DEVICES_LOWER_BOND = 1; 73 private static final int MAX_CONNECTED_AUDIO_DEVICES_UPPER_BOUND = 5; 74 private static final String A2DP_OFFLOAD_SUPPORTED_PROPERTY = 75 "ro.bluetooth.a2dp_offload.supported"; 76 private static final String A2DP_OFFLOAD_DISABLED_PROPERTY = 77 "persist.bluetooth.a2dp_offload.disabled"; 78 79 private static final long DEFAULT_DISCOVERY_TIMEOUT_MS = 12800; 80 private static final int BD_ADDR_LEN = 6; // in bytes 81 82 private volatile String mName; 83 private volatile byte[] mAddress; 84 private volatile BluetoothClass mBluetoothClass; 85 private volatile int mScanMode; 86 private volatile int mDiscoverableTimeout; 87 private volatile ParcelUuid[] mUuids; 88 private volatile int mLocalIOCapability = BluetoothAdapter.IO_CAPABILITY_UNKNOWN; 89 private volatile int mLocalIOCapabilityBLE = BluetoothAdapter.IO_CAPABILITY_UNKNOWN; 90 91 private CopyOnWriteArrayList<BluetoothDevice> mBondedDevices = 92 new CopyOnWriteArrayList<BluetoothDevice>(); 93 94 private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting; 95 private final HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState = 96 new HashMap<>(); 97 98 private volatile int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED; 99 private volatile int mState = BluetoothAdapter.STATE_OFF; 100 private int mMaxConnectedAudioDevices = 1; 101 private boolean mA2dpOffloadEnabled = false; 102 103 private AdapterService mService; 104 private boolean mDiscovering; 105 private long mDiscoveryEndMs; //< Time (ms since epoch) that discovery ended or will end. 106 private RemoteDevices mRemoteDevices; 107 private BluetoothAdapter mAdapter; 108 //TODO - all hw capabilities to be exposed as a class 109 private int mNumOfAdvertisementInstancesSupported; 110 private boolean mRpaOffloadSupported; 111 private int mNumOfOffloadedIrkSupported; 112 private int mNumOfOffloadedScanFilterSupported; 113 private int mOffloadedScanResultStorageBytes; 114 private int mVersSupported; 115 private int mTotNumOfTrackableAdv; 116 private boolean mIsExtendedScanSupported; 117 private boolean mIsDebugLogSupported; 118 private boolean mIsActivityAndEnergyReporting; 119 private boolean mIsLe2MPhySupported; 120 private boolean mIsLeCodedPhySupported; 121 private boolean mIsLeExtendedAdvertisingSupported; 122 private boolean mIsLePeriodicAdvertisingSupported; 123 private int mLeMaximumAdvertisingDataLength; 124 125 private int mIsDynamicAudioBufferSizeSupported; 126 private int mDynamicAudioBufferSizeSupportedCodecsGroup1; 127 private int mDynamicAudioBufferSizeSupportedCodecsGroup2; 128 private List<BufferConstraint> mBufferConstraintList; 129 130 private boolean mReceiverRegistered; 131 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 132 @Override 133 public void onReceive(Context context, Intent intent) { 134 String action = intent.getAction(); 135 if (action == null) { 136 Log.w(TAG, "Received intent with null action"); 137 return; 138 } 139 switch (action) { 140 case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: 141 sendConnectionStateChange(BluetoothProfile.HEADSET, intent); 142 break; 143 case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED: 144 sendConnectionStateChange(BluetoothProfile.A2DP, intent); 145 break; 146 case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED: 147 sendConnectionStateChange(BluetoothProfile.HEADSET_CLIENT, intent); 148 break; 149 case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED: 150 sendConnectionStateChange(BluetoothProfile.HEARING_AID, intent); 151 break; 152 case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED: 153 sendConnectionStateChange(BluetoothProfile.A2DP_SINK, intent); 154 break; 155 case BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED: 156 sendConnectionStateChange(BluetoothProfile.HID_DEVICE, intent); 157 break; 158 case BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED: 159 sendConnectionStateChange(BluetoothProfile.HID_HOST, intent); 160 break; 161 case BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED: 162 sendConnectionStateChange(BluetoothProfile.AVRCP_CONTROLLER, intent); 163 break; 164 case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED: 165 sendConnectionStateChange(BluetoothProfile.PAN, intent); 166 break; 167 case BluetoothMap.ACTION_CONNECTION_STATE_CHANGED: 168 sendConnectionStateChange(BluetoothProfile.MAP, intent); 169 break; 170 case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED: 171 sendConnectionStateChange(BluetoothProfile.MAP_CLIENT, intent); 172 break; 173 case BluetoothSap.ACTION_CONNECTION_STATE_CHANGED: 174 sendConnectionStateChange(BluetoothProfile.SAP, intent); 175 break; 176 case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED: 177 sendConnectionStateChange(BluetoothProfile.PBAP_CLIENT, intent); 178 break; 179 case BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED: 180 sendConnectionStateChange(BluetoothProfile.PBAP, intent); 181 break; 182 default: 183 Log.w(TAG, "Received unknown intent " + intent); 184 break; 185 } 186 } 187 }; 188 189 // Lock for all getters and setters. 190 // If finer grained locking is needer, more locks 191 // can be added here. 192 private final Object mObject = new Object(); 193 AdapterProperties(AdapterService service)194 AdapterProperties(AdapterService service) { 195 mService = service; 196 mAdapter = BluetoothAdapter.getDefaultAdapter(); 197 invalidateBluetoothCaches(); 198 } 199 init(RemoteDevices remoteDevices)200 public void init(RemoteDevices remoteDevices) { 201 mProfileConnectionState.clear(); 202 mRemoteDevices = remoteDevices; 203 204 // Get default max connected audio devices from config.xml in frameworks/base/core 205 int configDefaultMaxConnectedAudioDevices = mService.getResources().getInteger( 206 com.android.internal.R.integer.config_bluetooth_max_connected_audio_devices); 207 // Override max connected audio devices if MAX_CONNECTED_AUDIO_DEVICES_PROPERTY is set 208 int propertyOverlayedMaxConnectedAudioDevices = 209 SystemProperties.getInt(MAX_CONNECTED_AUDIO_DEVICES_PROPERTY, 210 configDefaultMaxConnectedAudioDevices); 211 // Make sure the final value of max connected audio devices is within allowed range 212 mMaxConnectedAudioDevices = Math.min(Math.max(propertyOverlayedMaxConnectedAudioDevices, 213 MAX_CONNECTED_AUDIO_DEVICES_LOWER_BOND), MAX_CONNECTED_AUDIO_DEVICES_UPPER_BOUND); 214 Log.i(TAG, "init(), maxConnectedAudioDevices, default=" 215 + configDefaultMaxConnectedAudioDevices + ", propertyOverlayed=" 216 + propertyOverlayedMaxConnectedAudioDevices + ", finalValue=" 217 + mMaxConnectedAudioDevices); 218 219 mA2dpOffloadEnabled = 220 SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false) 221 && !SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false); 222 223 IntentFilter filter = new IntentFilter(); 224 filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 225 filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED); 226 filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); 227 filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 228 filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED); 229 filter.addAction(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED); 230 filter.addAction(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED); 231 filter.addAction(BluetoothAvrcpController.ACTION_CONNECTION_STATE_CHANGED); 232 filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 233 filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED); 234 filter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED); 235 filter.addAction(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED); 236 filter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED); 237 mService.registerReceiver(mReceiver, filter); 238 mReceiverRegistered = true; 239 invalidateBluetoothCaches(); 240 } 241 cleanup()242 public void cleanup() { 243 mRemoteDevices = null; 244 mProfileConnectionState.clear(); 245 if (mReceiverRegistered) { 246 mService.unregisterReceiver(mReceiver); 247 mReceiverRegistered = false; 248 } 249 mService = null; 250 mBondedDevices.clear(); 251 invalidateBluetoothCaches(); 252 } invalidateGetProfileConnectionStateCache()253 private static void invalidateGetProfileConnectionStateCache() { 254 BluetoothAdapter.invalidateGetProfileConnectionStateCache(); 255 } invalidateIsOffloadedFilteringSupportedCache()256 private static void invalidateIsOffloadedFilteringSupportedCache() { 257 BluetoothAdapter.invalidateIsOffloadedFilteringSupportedCache(); 258 } invalidateGetConnectionStateCache()259 private static void invalidateGetConnectionStateCache() { 260 BluetoothAdapter.invalidateGetAdapterConnectionStateCache(); 261 } invalidateGetBondStateCache()262 private static void invalidateGetBondStateCache() { 263 BluetoothDevice.invalidateBluetoothGetBondStateCache(); 264 } invalidateBluetoothCaches()265 private static void invalidateBluetoothCaches() { 266 invalidateGetProfileConnectionStateCache(); 267 invalidateIsOffloadedFilteringSupportedCache(); 268 invalidateGetConnectionStateCache(); 269 invalidateGetBondStateCache(); 270 } 271 272 @Override clone()273 public Object clone() throws CloneNotSupportedException { 274 throw new CloneNotSupportedException(); 275 } 276 277 /** 278 * @return the mName 279 */ getName()280 String getName() { 281 return mName; 282 } 283 284 /** 285 * Set the local adapter property - name 286 * @param name the name to set 287 */ setName(String name)288 boolean setName(String name) { 289 synchronized (mObject) { 290 return mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME, 291 name.getBytes()); 292 } 293 } 294 295 /** 296 * Set the Bluetooth Class of Device (CoD) of the adapter. 297 * 298 * <p>Bluetooth stack stores some adapter properties in native BT stack storage and some in the 299 * Java Android stack. Bluetooth CoD is stored in the Android layer through 300 * {@link android.provider.Settings.Global#BLUETOOTH_CLASS_OF_DEVICE}. 301 * 302 * <p>Due to this, the getAdapterPropertyNative and adapterPropertyChangedCallback methods don't 303 * actually update mBluetoothClass. Hence, we update the field mBluetoothClass every time we 304 * successfully update BluetoothClass. 305 * 306 * @param bluetoothClass BluetoothClass of the device 307 */ setBluetoothClass(BluetoothClass bluetoothClass)308 boolean setBluetoothClass(BluetoothClass bluetoothClass) { 309 synchronized (mObject) { 310 boolean result = 311 mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE, 312 bluetoothClass.getClassOfDeviceBytes()); 313 314 if (result) { 315 mBluetoothClass = bluetoothClass; 316 } 317 318 return result; 319 } 320 } 321 322 /** 323 * @return the BluetoothClass of the Bluetooth adapter. 324 */ getBluetoothClass()325 BluetoothClass getBluetoothClass() { 326 synchronized (mObject) { 327 return mBluetoothClass; 328 } 329 } 330 setIoCapability(int capability)331 boolean setIoCapability(int capability) { 332 synchronized (mObject) { 333 boolean result = mService.setAdapterPropertyNative( 334 AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS, Utils.intToByteArray(capability)); 335 336 if (result) { 337 mLocalIOCapability = capability; 338 } 339 340 return result; 341 } 342 } 343 getIoCapability()344 int getIoCapability() { 345 synchronized (mObject) { 346 return mLocalIOCapability; 347 } 348 } 349 setLeIoCapability(int capability)350 boolean setLeIoCapability(int capability) { 351 synchronized (mObject) { 352 boolean result = mService.setAdapterPropertyNative( 353 AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS_BLE, 354 Utils.intToByteArray(capability)); 355 356 if (result) { 357 mLocalIOCapabilityBLE = capability; 358 } 359 360 return result; 361 } 362 } 363 getLeIoCapability()364 int getLeIoCapability() { 365 synchronized (mObject) { 366 return mLocalIOCapabilityBLE; 367 } 368 } 369 370 /** 371 * @return the mScanMode 372 */ getScanMode()373 int getScanMode() { 374 return mScanMode; 375 } 376 377 /** 378 * Set the local adapter property - scanMode 379 * 380 * @param scanMode the ScanMode to set 381 */ setScanMode(int scanMode)382 boolean setScanMode(int scanMode) { 383 synchronized (mObject) { 384 return mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE, 385 Utils.intToByteArray(scanMode)); 386 } 387 } 388 389 /** 390 * @return the mUuids 391 */ getUuids()392 ParcelUuid[] getUuids() { 393 return mUuids; 394 } 395 396 /** 397 * @return the mAddress 398 */ getAddress()399 byte[] getAddress() { 400 return mAddress; 401 } 402 403 /** 404 * @param connectionState the mConnectionState to set 405 */ setConnectionState(int connectionState)406 void setConnectionState(int connectionState) { 407 mConnectionState = connectionState; 408 invalidateGetConnectionStateCache(); 409 } 410 411 /** 412 * @return the mConnectionState 413 */ getConnectionState()414 int getConnectionState() { 415 return mConnectionState; 416 } 417 418 /** 419 * @param mState the mState to set 420 */ setState(int state)421 void setState(int state) { 422 debugLog("Setting state to " + BluetoothAdapter.nameForState(state)); 423 mState = state; 424 } 425 426 /** 427 * @return the mState 428 */ getState()429 int getState() { 430 return mState; 431 } 432 433 /** 434 * @return the mNumOfAdvertisementInstancesSupported 435 */ getNumOfAdvertisementInstancesSupported()436 int getNumOfAdvertisementInstancesSupported() { 437 return mNumOfAdvertisementInstancesSupported; 438 } 439 440 /** 441 * @return the mRpaOffloadSupported 442 */ isRpaOffloadSupported()443 boolean isRpaOffloadSupported() { 444 return mRpaOffloadSupported; 445 } 446 447 /** 448 * @return the mNumOfOffloadedIrkSupported 449 */ getNumOfOffloadedIrkSupported()450 int getNumOfOffloadedIrkSupported() { 451 return mNumOfOffloadedIrkSupported; 452 } 453 454 /** 455 * @return the mNumOfOffloadedScanFilterSupported 456 */ getNumOfOffloadedScanFilterSupported()457 int getNumOfOffloadedScanFilterSupported() { 458 return mNumOfOffloadedScanFilterSupported; 459 } 460 461 /** 462 * @return the mOffloadedScanResultStorageBytes 463 */ getOffloadedScanResultStorage()464 int getOffloadedScanResultStorage() { 465 return mOffloadedScanResultStorageBytes; 466 } 467 468 /** 469 * @return tx/rx/idle activity and energy info 470 */ isActivityAndEnergyReportingSupported()471 boolean isActivityAndEnergyReportingSupported() { 472 return mIsActivityAndEnergyReporting; 473 } 474 475 /** 476 * @return the mIsLe2MPhySupported 477 */ isLe2MPhySupported()478 boolean isLe2MPhySupported() { 479 return mIsLe2MPhySupported; 480 } 481 482 /** 483 * @return the mIsLeCodedPhySupported 484 */ isLeCodedPhySupported()485 boolean isLeCodedPhySupported() { 486 return mIsLeCodedPhySupported; 487 } 488 489 /** 490 * @return the mIsLeExtendedAdvertisingSupported 491 */ isLeExtendedAdvertisingSupported()492 boolean isLeExtendedAdvertisingSupported() { 493 return mIsLeExtendedAdvertisingSupported; 494 } 495 496 /** 497 * @return the mIsLePeriodicAdvertisingSupported 498 */ isLePeriodicAdvertisingSupported()499 boolean isLePeriodicAdvertisingSupported() { 500 return mIsLePeriodicAdvertisingSupported; 501 } 502 503 /** 504 * @return the getLeMaximumAdvertisingDataLength 505 */ getLeMaximumAdvertisingDataLength()506 int getLeMaximumAdvertisingDataLength() { 507 return mLeMaximumAdvertisingDataLength; 508 } 509 510 /** 511 * @return total number of trackable advertisements 512 */ getTotalNumOfTrackableAdvertisements()513 int getTotalNumOfTrackableAdvertisements() { 514 return mTotNumOfTrackableAdv; 515 } 516 517 /** 518 * @return the maximum number of connected audio devices 519 */ getMaxConnectedAudioDevices()520 int getMaxConnectedAudioDevices() { 521 return mMaxConnectedAudioDevices; 522 } 523 524 /** 525 * @return A2DP offload support 526 */ isA2dpOffloadEnabled()527 boolean isA2dpOffloadEnabled() { 528 return mA2dpOffloadEnabled; 529 } 530 531 /** 532 * @return Dynamic Audio Buffer support 533 */ getDynamicBufferSupport()534 int getDynamicBufferSupport() { 535 if (!mA2dpOffloadEnabled) { 536 // TODO: Enable Dynamic Audio Buffer for A2DP software encoding when ready. 537 mIsDynamicAudioBufferSizeSupported = 538 BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE; 539 } else { 540 if ((mDynamicAudioBufferSizeSupportedCodecsGroup1 != 0) 541 || (mDynamicAudioBufferSizeSupportedCodecsGroup2 != 0)) { 542 mIsDynamicAudioBufferSizeSupported = 543 BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD; 544 } else { 545 mIsDynamicAudioBufferSizeSupported = 546 BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE; 547 } 548 } 549 return mIsDynamicAudioBufferSizeSupported; 550 } 551 552 /** 553 * @return Dynamic Audio Buffer Capability 554 */ getBufferConstraints()555 BufferConstraints getBufferConstraints() { 556 return new BufferConstraints(mBufferConstraintList); 557 } 558 559 /** 560 * Set the dynamic audio buffer size 561 * 562 * @param codec the codecs to set 563 * @param size the size to set 564 */ setBufferLengthMillis(int codec, int value)565 boolean setBufferLengthMillis(int codec, int value) { 566 return mService.setBufferLengthMillisNative(codec, value); 567 } 568 569 /** 570 * @return the mBondedDevices 571 */ getBondedDevices()572 BluetoothDevice[] getBondedDevices() { 573 BluetoothDevice[] bondedDeviceList = new BluetoothDevice[0]; 574 try { 575 bondedDeviceList = mBondedDevices.toArray(bondedDeviceList); 576 } catch (ArrayStoreException ee) { 577 errorLog("Error retrieving bonded device array"); 578 } 579 infoLog("getBondedDevices: length=" + bondedDeviceList.length); 580 return bondedDeviceList; 581 } 582 583 // This function shall be invoked from BondStateMachine whenever the bond 584 // state changes. 585 @VisibleForTesting onBondStateChanged(BluetoothDevice device, int state)586 void onBondStateChanged(BluetoothDevice device, int state) { 587 if (device == null) { 588 Log.w(TAG, "onBondStateChanged, device is null"); 589 return; 590 } 591 try { 592 byte[] addrByte = Utils.getByteAddress(device); 593 DeviceProperties prop = mRemoteDevices.getDeviceProperties(device); 594 if (prop == null) { 595 prop = mRemoteDevices.addDeviceProperties(addrByte); 596 } 597 prop.setBondState(state); 598 599 if (state == BluetoothDevice.BOND_BONDED) { 600 // add if not already in list 601 if (!mBondedDevices.contains(device)) { 602 debugLog("Adding bonded device:" + device); 603 mBondedDevices.add(device); 604 } 605 } else if (state == BluetoothDevice.BOND_NONE) { 606 // remove device from list 607 if (mBondedDevices.remove(device)) { 608 debugLog("Removing bonded device:" + device); 609 } else { 610 debugLog("Failed to remove device: " + device); 611 } 612 } 613 invalidateGetBondStateCache(); 614 } catch (Exception ee) { 615 Log.w(TAG, "onBondStateChanged: Exception ", ee); 616 } 617 } 618 getDiscoverableTimeout()619 int getDiscoverableTimeout() { 620 return mDiscoverableTimeout; 621 } 622 setDiscoverableTimeout(int timeout)623 boolean setDiscoverableTimeout(int timeout) { 624 synchronized (mObject) { 625 return mService.setAdapterPropertyNative( 626 AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT, 627 Utils.intToByteArray(timeout)); 628 } 629 } 630 getProfileConnectionState(int profile)631 int getProfileConnectionState(int profile) { 632 synchronized (mObject) { 633 Pair<Integer, Integer> p = mProfileConnectionState.get(profile); 634 if (p != null) { 635 return p.first; 636 } 637 return BluetoothProfile.STATE_DISCONNECTED; 638 } 639 } 640 discoveryEndMillis()641 long discoveryEndMillis() { 642 return mDiscoveryEndMs; 643 } 644 isDiscovering()645 boolean isDiscovering() { 646 return mDiscovering; 647 } 648 sendConnectionStateChange(int profile, Intent connIntent)649 private void sendConnectionStateChange(int profile, Intent connIntent) { 650 BluetoothDevice device = connIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 651 int prevState = connIntent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); 652 int state = connIntent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 653 Log.d(TAG, 654 "PROFILE_CONNECTION_STATE_CHANGE: profile=" + profile + ", device=" + device + ", " 655 + prevState + " -> " + state); 656 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_CONNECTION_STATE_CHANGED, state, 657 0 /* deprecated */, profile, mService.obfuscateAddress(device), 658 mService.getMetricId(device)); 659 660 if (!isNormalStateTransition(prevState, state)) { 661 Log.w(TAG, 662 "PROFILE_CONNECTION_STATE_CHANGE: unexpected transition for profile=" + profile 663 + ", device=" + device + ", " + prevState + " -> " + state); 664 } 665 sendConnectionStateChange(device, profile, state, prevState); 666 } 667 sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevState)668 void sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevState) { 669 if (!validateProfileConnectionState(state) || !validateProfileConnectionState(prevState)) { 670 // Previously, an invalid state was broadcast anyway, 671 // with the invalid state converted to -1 in the intent. 672 // Better to log an error and not send an intent with 673 // invalid contents or set mAdapterConnectionState to -1. 674 errorLog("sendConnectionStateChange: invalid state transition " + prevState + " -> " 675 + state); 676 return; 677 } 678 679 synchronized (mObject) { 680 updateProfileConnectionState(profile, state, prevState); 681 682 if (updateCountersAndCheckForConnectionStateChange(state, prevState)) { 683 int newAdapterState = convertToAdapterState(state); 684 int prevAdapterState = convertToAdapterState(prevState); 685 setConnectionState(newAdapterState); 686 687 Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 688 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 689 intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, newAdapterState); 690 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, prevAdapterState); 691 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 692 Log.d(TAG, "ADAPTER_CONNECTION_STATE_CHANGE: " + device + ": " + prevAdapterState 693 + " -> " + newAdapterState); 694 if (!isNormalStateTransition(prevState, state)) { 695 Log.w(TAG, "ADAPTER_CONNECTION_STATE_CHANGE: unexpected transition for profile=" 696 + profile + ", device=" + device + ", " + prevState + " -> " + state); 697 } 698 mService.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_CONNECT, 699 Utils.getTempAllowlistBroadcastOptions()); 700 } 701 } 702 } 703 validateProfileConnectionState(int state)704 private boolean validateProfileConnectionState(int state) { 705 return (state == BluetoothProfile.STATE_DISCONNECTED 706 || state == BluetoothProfile.STATE_CONNECTING 707 || state == BluetoothProfile.STATE_CONNECTED 708 || state == BluetoothProfile.STATE_DISCONNECTING); 709 } 710 convertToAdapterState(int state)711 private static int convertToAdapterState(int state) { 712 switch (state) { 713 case BluetoothProfile.STATE_DISCONNECTED: 714 return BluetoothAdapter.STATE_DISCONNECTED; 715 case BluetoothProfile.STATE_DISCONNECTING: 716 return BluetoothAdapter.STATE_DISCONNECTING; 717 case BluetoothProfile.STATE_CONNECTED: 718 return BluetoothAdapter.STATE_CONNECTED; 719 case BluetoothProfile.STATE_CONNECTING: 720 return BluetoothAdapter.STATE_CONNECTING; 721 } 722 Log.e(TAG, "convertToAdapterState, unknow state " + state); 723 return -1; 724 } 725 isNormalStateTransition(int prevState, int nextState)726 private static boolean isNormalStateTransition(int prevState, int nextState) { 727 switch (prevState) { 728 case BluetoothProfile.STATE_DISCONNECTED: 729 return nextState == BluetoothProfile.STATE_CONNECTING; 730 case BluetoothProfile.STATE_CONNECTED: 731 return nextState == BluetoothProfile.STATE_DISCONNECTING; 732 case BluetoothProfile.STATE_DISCONNECTING: 733 case BluetoothProfile.STATE_CONNECTING: 734 return (nextState == BluetoothProfile.STATE_DISCONNECTED) || (nextState 735 == BluetoothProfile.STATE_CONNECTED); 736 default: 737 return false; 738 } 739 } 740 updateCountersAndCheckForConnectionStateChange(int state, int prevState)741 private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) { 742 switch (prevState) { 743 case BluetoothProfile.STATE_CONNECTING: 744 if (mProfilesConnecting > 0) { 745 mProfilesConnecting--; 746 } else { 747 Log.e(TAG, "mProfilesConnecting " + mProfilesConnecting); 748 throw new IllegalStateException( 749 "Invalid state transition, " + prevState + " -> " + state); 750 } 751 break; 752 753 case BluetoothProfile.STATE_CONNECTED: 754 if (mProfilesConnected > 0) { 755 mProfilesConnected--; 756 } else { 757 Log.e(TAG, "mProfilesConnected " + mProfilesConnected); 758 throw new IllegalStateException( 759 "Invalid state transition, " + prevState + " -> " + state); 760 } 761 break; 762 763 case BluetoothProfile.STATE_DISCONNECTING: 764 if (mProfilesDisconnecting > 0) { 765 mProfilesDisconnecting--; 766 } else { 767 Log.e(TAG, "mProfilesDisconnecting " + mProfilesDisconnecting); 768 throw new IllegalStateException( 769 "Invalid state transition, " + prevState + " -> " + state); 770 } 771 break; 772 } 773 774 switch (state) { 775 case BluetoothProfile.STATE_CONNECTING: 776 mProfilesConnecting++; 777 return (mProfilesConnected == 0 && mProfilesConnecting == 1); 778 779 case BluetoothProfile.STATE_CONNECTED: 780 mProfilesConnected++; 781 return (mProfilesConnected == 1); 782 783 case BluetoothProfile.STATE_DISCONNECTING: 784 mProfilesDisconnecting++; 785 return (mProfilesConnected == 0 && mProfilesDisconnecting == 1); 786 787 case BluetoothProfile.STATE_DISCONNECTED: 788 return (mProfilesConnected == 0 && mProfilesConnecting == 0); 789 790 default: 791 return true; 792 } 793 } 794 updateProfileConnectionState(int profile, int newState, int oldState)795 private void updateProfileConnectionState(int profile, int newState, int oldState) { 796 // mProfileConnectionState is a hashmap - 797 // <Integer, Pair<Integer, Integer>> 798 // The key is the profile, the value is a pair. first element 799 // is the state and the second element is the number of devices 800 // in that state. 801 int numDev = 1; 802 int newHashState = newState; 803 boolean update = true; 804 805 // The following conditions are considered in this function: 806 // 1. If there is no record of profile and state - update 807 // 2. If a new device's state is current hash state - increment 808 // number of devices in the state. 809 // 3. If a state change has happened to Connected or Connecting 810 // (if current state is not connected), update. 811 // 4. If numDevices is 1 and that device state is being updated, update 812 // 5. If numDevices is > 1 and one of the devices is changing state, 813 // decrement numDevices but maintain oldState if it is Connected or 814 // Connecting 815 Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile); 816 if (stateNumDev != null) { 817 int currHashState = stateNumDev.first; 818 numDev = stateNumDev.second; 819 820 if (newState == currHashState) { 821 numDev++; 822 } else if (newState == BluetoothProfile.STATE_CONNECTED || ( 823 newState == BluetoothProfile.STATE_CONNECTING 824 && currHashState != BluetoothProfile.STATE_CONNECTED)) { 825 numDev = 1; 826 } else if (numDev == 1 && oldState == currHashState) { 827 update = true; 828 } else if (numDev > 1 && oldState == currHashState) { 829 numDev--; 830 831 if (currHashState == BluetoothProfile.STATE_CONNECTED 832 || currHashState == BluetoothProfile.STATE_CONNECTING) { 833 newHashState = currHashState; 834 } 835 } else { 836 update = false; 837 } 838 } 839 840 if (update) { 841 mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState, numDev)); 842 invalidateGetProfileConnectionStateCache(); 843 } 844 } 845 adapterPropertyChangedCallback(int[] types, byte[][] values)846 void adapterPropertyChangedCallback(int[] types, byte[][] values) { 847 Intent intent; 848 int type; 849 byte[] val; 850 for (int i = 0; i < types.length; i++) { 851 val = values[i]; 852 type = types[i]; 853 infoLog("adapterPropertyChangedCallback with type:" + type + " len:" + val.length); 854 synchronized (mObject) { 855 switch (type) { 856 case AbstractionLayer.BT_PROPERTY_BDNAME: 857 mName = new String(val); 858 intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 859 intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, mName); 860 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 861 mService.sendBroadcastAsUser(intent, UserHandle.ALL, 862 BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); 863 debugLog("Name is: " + mName); 864 break; 865 case AbstractionLayer.BT_PROPERTY_BDADDR: 866 mAddress = val; 867 String address = Utils.getAddressStringFromByte(mAddress); 868 intent = new Intent(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); 869 intent.putExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS, address); 870 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 871 mService.sendBroadcastAsUser(intent, UserHandle.ALL, 872 BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions()); 873 break; 874 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 875 if (val == null || val.length != 3) { 876 debugLog("Invalid BT CoD value from stack."); 877 return; 878 } 879 int bluetoothClass = 880 ((int) val[0] << 16) + ((int) val[1] << 8) + (int) val[2]; 881 if (bluetoothClass != 0) { 882 mBluetoothClass = new BluetoothClass(bluetoothClass); 883 } 884 debugLog("BT Class:" + mBluetoothClass); 885 break; 886 case AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE: 887 int mode = Utils.byteArrayToInt(val, 0); 888 mScanMode = AdapterService.convertScanModeFromHal(mode); 889 intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 890 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mScanMode); 891 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 892 mService.sendBroadcast(intent, BLUETOOTH_SCAN, 893 Utils.getTempAllowlistBroadcastOptions()); 894 debugLog("Scan Mode:" + mScanMode); 895 break; 896 case AbstractionLayer.BT_PROPERTY_UUIDS: 897 mUuids = Utils.byteArrayToUuid(val); 898 break; 899 case AbstractionLayer.BT_PROPERTY_ADAPTER_BONDED_DEVICES: 900 int number = val.length / BD_ADDR_LEN; 901 byte[] addrByte = new byte[BD_ADDR_LEN]; 902 for (int j = 0; j < number; j++) { 903 System.arraycopy(val, j * BD_ADDR_LEN, addrByte, 0, BD_ADDR_LEN); 904 onBondStateChanged(mAdapter.getRemoteDevice( 905 Utils.getAddressStringFromByte(addrByte)), 906 BluetoothDevice.BOND_BONDED); 907 } 908 break; 909 case AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: 910 mDiscoverableTimeout = Utils.byteArrayToInt(val, 0); 911 debugLog("Discoverable Timeout:" + mDiscoverableTimeout); 912 break; 913 914 case AbstractionLayer.BT_PROPERTY_LOCAL_LE_FEATURES: 915 updateFeatureSupport(val); 916 break; 917 918 case AbstractionLayer.BT_PROPERTY_DYNAMIC_AUDIO_BUFFER: 919 updateDynamicAudioBufferSupport(val); 920 break; 921 922 case AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS: 923 mLocalIOCapability = Utils.byteArrayToInt(val); 924 debugLog("mLocalIOCapability set to " + mLocalIOCapability); 925 break; 926 927 case AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS_BLE: 928 mLocalIOCapabilityBLE = Utils.byteArrayToInt(val); 929 debugLog("mLocalIOCapabilityBLE set to " + mLocalIOCapabilityBLE); 930 break; 931 932 default: 933 errorLog("Property change not handled in Java land:" + type); 934 } 935 } 936 } 937 } 938 updateFeatureSupport(byte[] val)939 private void updateFeatureSupport(byte[] val) { 940 mVersSupported = ((0xFF & ((int) val[1])) << 8) + (0xFF & ((int) val[0])); 941 mNumOfAdvertisementInstancesSupported = (0xFF & ((int) val[3])); 942 mRpaOffloadSupported = ((0xFF & ((int) val[4])) != 0); 943 mNumOfOffloadedIrkSupported = (0xFF & ((int) val[5])); 944 mNumOfOffloadedScanFilterSupported = (0xFF & ((int) val[6])); 945 mIsActivityAndEnergyReporting = ((0xFF & ((int) val[7])) != 0); 946 mOffloadedScanResultStorageBytes = ((0xFF & ((int) val[9])) << 8) + (0xFF & ((int) val[8])); 947 mTotNumOfTrackableAdv = ((0xFF & ((int) val[11])) << 8) + (0xFF & ((int) val[10])); 948 mIsExtendedScanSupported = ((0xFF & ((int) val[12])) != 0); 949 mIsDebugLogSupported = ((0xFF & ((int) val[13])) != 0); 950 mIsLe2MPhySupported = ((0xFF & ((int) val[14])) != 0); 951 mIsLeCodedPhySupported = ((0xFF & ((int) val[15])) != 0); 952 mIsLeExtendedAdvertisingSupported = ((0xFF & ((int) val[16])) != 0); 953 mIsLePeriodicAdvertisingSupported = ((0xFF & ((int) val[17])) != 0); 954 mLeMaximumAdvertisingDataLength = 955 (0xFF & ((int) val[18])) + ((0xFF & ((int) val[19])) << 8); 956 mDynamicAudioBufferSizeSupportedCodecsGroup1 = 957 ((0xFF & ((int) val[21])) << 8) + (0xFF & ((int) val[20])); 958 mDynamicAudioBufferSizeSupportedCodecsGroup2 = 959 ((0xFF & ((int) val[23])) << 8) + (0xFF & ((int) val[22])); 960 961 Log.d(TAG, "BT_PROPERTY_LOCAL_LE_FEATURES: update from BT controller" 962 + " mNumOfAdvertisementInstancesSupported = " 963 + mNumOfAdvertisementInstancesSupported + " mRpaOffloadSupported = " 964 + mRpaOffloadSupported + " mNumOfOffloadedIrkSupported = " 965 + mNumOfOffloadedIrkSupported + " mNumOfOffloadedScanFilterSupported = " 966 + mNumOfOffloadedScanFilterSupported + " mOffloadedScanResultStorageBytes= " 967 + mOffloadedScanResultStorageBytes + " mIsActivityAndEnergyReporting = " 968 + mIsActivityAndEnergyReporting + " mVersSupported = " + mVersSupported 969 + " mTotNumOfTrackableAdv = " + mTotNumOfTrackableAdv 970 + " mIsExtendedScanSupported = " + mIsExtendedScanSupported 971 + " mIsDebugLogSupported = " + mIsDebugLogSupported + " mIsLe2MPhySupported = " 972 + mIsLe2MPhySupported + " mIsLeCodedPhySupported = " + mIsLeCodedPhySupported 973 + " mIsLeExtendedAdvertisingSupported = " + mIsLeExtendedAdvertisingSupported 974 + " mIsLePeriodicAdvertisingSupported = " + mIsLePeriodicAdvertisingSupported 975 + " mLeMaximumAdvertisingDataLength = " + mLeMaximumAdvertisingDataLength 976 + " mDynamicAudioBufferSizeSupportedCodecsGroup1 = " 977 + mDynamicAudioBufferSizeSupportedCodecsGroup1 978 + " mDynamicAudioBufferSizeSupportedCodecsGroup2 = " 979 + mDynamicAudioBufferSizeSupportedCodecsGroup2); 980 invalidateIsOffloadedFilteringSupportedCache(); 981 } 982 updateDynamicAudioBufferSupport(byte[] val)983 private void updateDynamicAudioBufferSupport(byte[] val) { 984 // bufferConstraints is the table indicates the capability of all the codecs 985 // with buffer time. The raw is codec number, and the column is buffer type. There are 3 986 // buffer types - default/maximum/minimum. 987 // The maximum number of raw is BUFFER_CODEC_MAX_NUM(32). 988 // The maximum number of column is BUFFER_TYPE_MAX(3). 989 // The array element indicates the buffer time, the size is two octet. 990 mBufferConstraintList = new ArrayList<BufferConstraint>(); 991 992 for (int i = 0; i < BufferConstraints.BUFFER_CODEC_MAX_NUM; i++) { 993 int defaultBufferTime = ((0xFF & ((int) val[i * 6 + 1])) << 8) 994 + (0xFF & ((int) val[i * 6])); 995 int maximumBufferTime = ((0xFF & ((int) val[i * 6 + 3])) << 8) 996 + (0xFF & ((int) val[i * 6 + 2])); 997 int minimumBufferTime = ((0xFF & ((int) val[i * 6 + 5])) << 8) 998 + (0xFF & ((int) val[i * 6 + 4])); 999 BufferConstraint bufferConstraint = new BufferConstraint(defaultBufferTime, 1000 maximumBufferTime, minimumBufferTime); 1001 mBufferConstraintList.add(bufferConstraint); 1002 } 1003 } 1004 onBluetoothReady()1005 void onBluetoothReady() { 1006 debugLog("onBluetoothReady, state=" + BluetoothAdapter.nameForState(getState()) 1007 + ", ScanMode=" + mScanMode); 1008 1009 synchronized (mObject) { 1010 // Reset adapter and profile connection states 1011 setConnectionState(BluetoothAdapter.STATE_DISCONNECTED); 1012 mProfileConnectionState.clear(); 1013 invalidateGetProfileConnectionStateCache(); 1014 mProfilesConnected = 0; 1015 mProfilesConnecting = 0; 1016 mProfilesDisconnecting = 0; 1017 // adapterPropertyChangedCallback has already been received. Set the scan mode. 1018 setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE); 1019 // This keeps NV up-to date on first-boot after flash. 1020 setDiscoverableTimeout(mDiscoverableTimeout); 1021 } 1022 } 1023 onBleDisable()1024 void onBleDisable() { 1025 // Sequence BLE_ON to STATE_OFF - that is _complete_ OFF state. 1026 debugLog("onBleDisable"); 1027 // Set the scan_mode to NONE (no incoming connections). 1028 setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE); 1029 } 1030 discoveryStateChangeCallback(int state)1031 void discoveryStateChangeCallback(int state) { 1032 infoLog("Callback:discoveryStateChangeCallback with state:" + state); 1033 synchronized (mObject) { 1034 Intent intent; 1035 if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) { 1036 mDiscovering = false; 1037 mService.clearDiscoveringPackages(); 1038 mDiscoveryEndMs = System.currentTimeMillis(); 1039 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 1040 mService.sendBroadcast(intent, BLUETOOTH_SCAN, 1041 Utils.getTempAllowlistBroadcastOptions()); 1042 } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) { 1043 mDiscovering = true; 1044 mDiscoveryEndMs = System.currentTimeMillis() + DEFAULT_DISCOVERY_TIMEOUT_MS; 1045 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 1046 mService.sendBroadcast(intent, BLUETOOTH_SCAN, 1047 Utils.getTempAllowlistBroadcastOptions()); 1048 } 1049 } 1050 } 1051 dump(FileDescriptor fd, PrintWriter writer, String[] args)1052 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1053 writer.println(TAG); 1054 writer.println(" " + "Name: " + getName()); 1055 writer.println(" " + "Address: " + Utils.getAddressStringFromByte(mAddress)); 1056 writer.println(" " + "BluetoothClass: " + getBluetoothClass()); 1057 writer.println(" " + "ScanMode: " + dumpScanMode(getScanMode())); 1058 writer.println(" " + "ConnectionState: " + dumpConnectionState(getConnectionState())); 1059 writer.println(" " + "State: " + BluetoothAdapter.nameForState(getState())); 1060 writer.println(" " + "MaxConnectedAudioDevices: " + getMaxConnectedAudioDevices()); 1061 writer.println(" " + "A2dpOffloadEnabled: " + mA2dpOffloadEnabled); 1062 writer.println(" " + "Discovering: " + mDiscovering); 1063 writer.println(" " + "DiscoveryEndMs: " + mDiscoveryEndMs); 1064 1065 writer.println(" " + "Bonded devices:"); 1066 for (BluetoothDevice device : mBondedDevices) { 1067 writer.println( 1068 " " + device.getAddress() + " [" + dumpDeviceType(device.getType()) + "] " 1069 + Utils.getName(device)); 1070 } 1071 } 1072 dumpDeviceType(int deviceType)1073 private String dumpDeviceType(int deviceType) { 1074 switch (deviceType) { 1075 case BluetoothDevice.DEVICE_TYPE_UNKNOWN: 1076 return " ???? "; 1077 case BluetoothDevice.DEVICE_TYPE_CLASSIC: 1078 return "BR/EDR"; 1079 case BluetoothDevice.DEVICE_TYPE_LE: 1080 return " LE "; 1081 case BluetoothDevice.DEVICE_TYPE_DUAL: 1082 return " DUAL "; 1083 default: 1084 return "Invalid device type: " + deviceType; 1085 } 1086 } 1087 dumpConnectionState(int state)1088 private String dumpConnectionState(int state) { 1089 switch (state) { 1090 case BluetoothAdapter.STATE_DISCONNECTED: 1091 return "STATE_DISCONNECTED"; 1092 case BluetoothAdapter.STATE_DISCONNECTING: 1093 return "STATE_DISCONNECTING"; 1094 case BluetoothAdapter.STATE_CONNECTING: 1095 return "STATE_CONNECTING"; 1096 case BluetoothAdapter.STATE_CONNECTED: 1097 return "STATE_CONNECTED"; 1098 default: 1099 return "Unknown Connection State " + state; 1100 } 1101 } 1102 dumpScanMode(int scanMode)1103 private String dumpScanMode(int scanMode) { 1104 switch (scanMode) { 1105 case BluetoothAdapter.SCAN_MODE_NONE: 1106 return "SCAN_MODE_NONE"; 1107 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 1108 return "SCAN_MODE_CONNECTABLE"; 1109 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 1110 return "SCAN_MODE_CONNECTABLE_DISCOVERABLE"; 1111 default: 1112 return "Unknown Scan Mode " + scanMode; 1113 } 1114 } 1115 infoLog(String msg)1116 private static void infoLog(String msg) { 1117 if (VDBG) { 1118 Log.i(TAG, msg); 1119 } 1120 } 1121 debugLog(String msg)1122 private static void debugLog(String msg) { 1123 if (DBG) { 1124 Log.d(TAG, msg); 1125 } 1126 } 1127 errorLog(String msg)1128 private static void errorLog(String msg) { 1129 Log.e(TAG, msg); 1130 } 1131 } 1132