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