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