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