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