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