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