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