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