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