1 /* 2 * Copyright (C) 2008 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 /** 18 * TODO: Move this to 19 * java/services/com/android/server/BluetoothService.java 20 * and make the contructor package private again. 21 * 22 * @hide 23 */ 24 25 package android.server; 26 27 import android.bluetooth.BluetoothAdapter; 28 import android.bluetooth.BluetoothClass; 29 import android.bluetooth.BluetoothDevice; 30 import android.bluetooth.BluetoothHeadset; 31 import android.bluetooth.BluetoothSocket; 32 import android.bluetooth.BluetoothUuid; 33 import android.bluetooth.IBluetooth; 34 import android.bluetooth.IBluetoothCallback; 35 import android.os.ParcelUuid; 36 import android.content.BroadcastReceiver; 37 import android.content.ContentResolver; 38 import android.content.Context; 39 import android.content.Intent; 40 import android.content.IntentFilter; 41 import android.os.Binder; 42 import android.os.IBinder; 43 import android.os.Handler; 44 import android.os.Message; 45 import android.os.RemoteException; 46 import android.os.ServiceManager; 47 import android.os.SystemService; 48 import android.provider.Settings; 49 import android.util.Log; 50 51 import com.android.internal.app.IBatteryStats; 52 53 import java.io.FileDescriptor; 54 import java.io.PrintWriter; 55 import java.io.UnsupportedEncodingException; 56 import java.util.ArrayList; 57 import java.util.Arrays; 58 import java.util.HashMap; 59 import java.util.Iterator; 60 import java.util.Map; 61 62 public class BluetoothService extends IBluetooth.Stub { 63 private static final String TAG = "BluetoothService"; 64 private static final boolean DBG = false; 65 66 private int mNativeData; 67 private BluetoothEventLoop mEventLoop; 68 private IntentFilter mIntentFilter; 69 private boolean mIsAirplaneSensitive; 70 private int mBluetoothState; 71 private boolean mRestart = false; // need to call enable() after disable() 72 private boolean mIsDiscovering; 73 74 private BluetoothAdapter mAdapter; // constant after init() 75 private final BondState mBondState = new BondState(); // local cache of bondings 76 private final IBatteryStats mBatteryStats; 77 private final Context mContext; 78 79 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 80 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 81 82 private static final int MESSAGE_REGISTER_SDP_RECORDS = 1; 83 private static final int MESSAGE_FINISH_DISABLE = 2; 84 private static final int MESSAGE_UUID_INTENT = 3; 85 private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4; 86 87 // The timeout used to sent the UUIDs Intent 88 // This timeout should be greater than the page timeout 89 private static final int UUID_INTENT_DELAY = 6000; 90 91 /** Always retrieve RFCOMM channel for these SDP UUIDs */ 92 private static final ParcelUuid[] RFCOMM_UUIDS = { 93 BluetoothUuid.Handsfree, 94 BluetoothUuid.HSP, 95 BluetoothUuid.ObexObjectPush }; 96 97 98 private final Map<String, String> mAdapterProperties; 99 private final HashMap<String, Map<String, String>> mDeviceProperties; 100 101 private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache; 102 private final ArrayList<String> mUuidIntentTracker; 103 private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker; 104 105 private final HashMap<Integer, Integer> mServiceRecordToPid; 106 107 private static class RemoteService { 108 public String address; 109 public ParcelUuid uuid; RemoteService(String address, ParcelUuid uuid)110 public RemoteService(String address, ParcelUuid uuid) { 111 this.address = address; 112 this.uuid = uuid; 113 } 114 @Override equals(Object o)115 public boolean equals(Object o) { 116 if (o instanceof RemoteService) { 117 RemoteService service = (RemoteService)o; 118 return address.equals(service.address) && uuid.equals(service.uuid); 119 } 120 return false; 121 } 122 } 123 124 static { classInitNative()125 classInitNative(); 126 } 127 BluetoothService(Context context)128 public BluetoothService(Context context) { 129 mContext = context; 130 131 // Need to do this in place of: 132 // mBatteryStats = BatteryStatsService.getService(); 133 // Since we can not import BatteryStatsService from here. This class really needs to be 134 // moved to java/services/com/android/server/ 135 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 136 137 initializeNativeDataNative(); 138 139 if (isEnabledNative() == 1) { 140 Log.w(TAG, "Bluetooth daemons already running - runtime restart? "); 141 disableNative(); 142 } 143 144 mBluetoothState = BluetoothAdapter.STATE_OFF; 145 mIsDiscovering = false; 146 mAdapterProperties = new HashMap<String, String>(); 147 mDeviceProperties = new HashMap<String, Map<String,String>>(); 148 149 mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>(); 150 mUuidIntentTracker = new ArrayList<String>(); 151 mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); 152 mServiceRecordToPid = new HashMap<Integer, Integer>(); 153 registerForAirplaneMode(); 154 } 155 initAfterRegistration()156 public synchronized void initAfterRegistration() { 157 mAdapter = BluetoothAdapter.getDefaultAdapter(); 158 mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this); 159 } 160 161 @Override finalize()162 protected void finalize() throws Throwable { 163 if (mIsAirplaneSensitive) { 164 mContext.unregisterReceiver(mReceiver); 165 } 166 try { 167 cleanupNativeDataNative(); 168 } finally { 169 super.finalize(); 170 } 171 } 172 isEnabled()173 public boolean isEnabled() { 174 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 175 return mBluetoothState == BluetoothAdapter.STATE_ON; 176 } 177 getBluetoothState()178 public int getBluetoothState() { 179 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 180 return mBluetoothState; 181 } 182 183 184 /** 185 * Bring down bluetooth and disable BT in settings. Returns true on success. 186 */ disable()187 public boolean disable() { 188 return disable(true); 189 } 190 191 /** 192 * Bring down bluetooth. Returns true on success. 193 * 194 * @param saveSetting If true, persist the new setting 195 */ disable(boolean saveSetting)196 public synchronized boolean disable(boolean saveSetting) { 197 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 198 199 switch (mBluetoothState) { 200 case BluetoothAdapter.STATE_OFF: 201 return true; 202 case BluetoothAdapter.STATE_ON: 203 break; 204 default: 205 return false; 206 } 207 if (mEnableThread != null && mEnableThread.isAlive()) { 208 return false; 209 } 210 setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); 211 mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS); 212 213 // Allow 3 seconds for profiles to gracefully disconnect 214 // TODO: Introduce a callback mechanism so that each profile can notify 215 // BluetoothService when it is done shutting down 216 mHandler.sendMessageDelayed( 217 mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); 218 return true; 219 } 220 221 finishDisable(boolean saveSetting)222 private synchronized void finishDisable(boolean saveSetting) { 223 if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) { 224 return; 225 } 226 mEventLoop.stop(); 227 tearDownNativeDataNative(); 228 disableNative(); 229 230 // mark in progress bondings as cancelled 231 for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) { 232 mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 233 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 234 } 235 236 // update mode 237 Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 238 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE); 239 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 240 241 mIsDiscovering = false; 242 mAdapterProperties.clear(); 243 mServiceRecordToPid.clear(); 244 245 if (saveSetting) { 246 persistBluetoothOnSetting(false); 247 } 248 249 setBluetoothState(BluetoothAdapter.STATE_OFF); 250 251 // Log bluetooth off to battery stats. 252 long ident = Binder.clearCallingIdentity(); 253 try { 254 mBatteryStats.noteBluetoothOff(); 255 } catch (RemoteException e) { 256 } finally { 257 Binder.restoreCallingIdentity(ident); 258 } 259 260 if (mRestart) { 261 mRestart = false; 262 enable(); 263 } 264 } 265 266 /** Bring up BT and persist BT on in settings */ enable()267 public boolean enable() { 268 return enable(true); 269 } 270 271 /** 272 * Enable this Bluetooth device, asynchronously. 273 * This turns on/off the underlying hardware. 274 * 275 * @param saveSetting If true, persist the new state of BT in settings 276 * @return True on success (so far) 277 */ enable(boolean saveSetting)278 public synchronized boolean enable(boolean saveSetting) { 279 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 280 "Need BLUETOOTH_ADMIN permission"); 281 282 // Airplane mode can prevent Bluetooth radio from being turned on. 283 if (mIsAirplaneSensitive && isAirplaneModeOn()) { 284 return false; 285 } 286 if (mBluetoothState != BluetoothAdapter.STATE_OFF) { 287 return false; 288 } 289 if (mEnableThread != null && mEnableThread.isAlive()) { 290 return false; 291 } 292 setBluetoothState(BluetoothAdapter.STATE_TURNING_ON); 293 mEnableThread = new EnableThread(saveSetting); 294 mEnableThread.start(); 295 return true; 296 } 297 298 /** Forcibly restart Bluetooth if it is on */ restart()299 /* package */ synchronized void restart() { 300 if (mBluetoothState != BluetoothAdapter.STATE_ON) { 301 return; 302 } 303 mRestart = true; 304 if (!disable(false)) { 305 mRestart = false; 306 } 307 } 308 setBluetoothState(int state)309 private synchronized void setBluetoothState(int state) { 310 if (state == mBluetoothState) { 311 return; 312 } 313 314 if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state); 315 316 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 317 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState); 318 intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); 319 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 320 321 mBluetoothState = state; 322 323 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 324 } 325 326 private final Handler mHandler = new Handler() { 327 @Override 328 public void handleMessage(Message msg) { 329 switch (msg.what) { 330 case MESSAGE_REGISTER_SDP_RECORDS: 331 if (!isEnabled()) { 332 return; 333 } 334 // SystemService.start() forks sdptool to register service 335 // records. It can fail to register some records if it is 336 // forked multiple times in a row, probably because there is 337 // some race in sdptool or bluez when operated in parallel. 338 // As a workaround, delay 500ms between each fork of sdptool. 339 // TODO: Don't fork sdptool in order to regsiter service 340 // records, use a DBUS call instead. 341 switch (msg.arg1) { 342 case 1: 343 Log.d(TAG, "Registering hsag record"); 344 SystemService.start("hsag"); 345 mHandler.sendMessageDelayed( 346 mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500); 347 break; 348 case 2: 349 Log.d(TAG, "Registering hfag record"); 350 SystemService.start("hfag"); 351 mHandler.sendMessageDelayed( 352 mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500); 353 break; 354 case 3: 355 Log.d(TAG, "Registering opush record"); 356 SystemService.start("opush"); 357 mHandler.sendMessageDelayed( 358 mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500); 359 break; 360 case 4: 361 Log.d(TAG, "Registering pbap record"); 362 SystemService.start("pbap"); 363 break; 364 } 365 break; 366 case MESSAGE_FINISH_DISABLE: 367 finishDisable(msg.arg1 != 0); 368 break; 369 case MESSAGE_UUID_INTENT: 370 String address = (String)msg.obj; 371 if (address != null) { 372 sendUuidIntent(address); 373 makeServiceChannelCallbacks(address); 374 } 375 break; 376 case MESSAGE_DISCOVERABLE_TIMEOUT: 377 int mode = msg.arg1; 378 if (isEnabled()) { 379 // TODO: Switch back to the previous scan mode 380 // This is ok for now, because we only use 381 // CONNECTABLE and CONNECTABLE_DISCOVERABLE 382 setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1); 383 } 384 break; 385 } 386 } 387 }; 388 389 private EnableThread mEnableThread; 390 391 private class EnableThread extends Thread { 392 private final boolean mSaveSetting; EnableThread(boolean saveSetting)393 public EnableThread(boolean saveSetting) { 394 mSaveSetting = saveSetting; 395 } run()396 public void run() { 397 boolean res = (enableNative() == 0); 398 if (res) { 399 int retryCount = 2; 400 boolean running = false; 401 while ((retryCount-- > 0) && !running) { 402 mEventLoop.start(); 403 // it may take a momement for the other thread to do its 404 // thing. Check periodically for a while. 405 int pollCount = 5; 406 while ((pollCount-- > 0) && !running) { 407 if (mEventLoop.isEventLoopRunning()) { 408 running = true; 409 break; 410 } 411 try { 412 Thread.sleep(100); 413 } catch (InterruptedException e) {} 414 } 415 } 416 if (!running) { 417 log("bt EnableThread giving up"); 418 res = false; 419 disableNative(); 420 } 421 } 422 423 424 if (res) { 425 if (!setupNativeDataNative()) { 426 return; 427 } 428 if (mSaveSetting) { 429 persistBluetoothOnSetting(true); 430 } 431 mIsDiscovering = false; 432 mBondState.loadBondState(); 433 mHandler.sendMessageDelayed( 434 mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000); 435 436 // Log bluetooth on to battery stats. 437 long ident = Binder.clearCallingIdentity(); 438 try { 439 mBatteryStats.noteBluetoothOn(); 440 } catch (RemoteException e) { 441 } finally { 442 Binder.restoreCallingIdentity(ident); 443 } 444 } 445 446 mEnableThread = null; 447 448 setBluetoothState(res ? 449 BluetoothAdapter.STATE_ON : 450 BluetoothAdapter.STATE_OFF); 451 452 if (res) { 453 // Update mode 454 String[] propVal = {"Pairable", getProperty("Pairable")}; 455 mEventLoop.onPropertyChanged(propVal); 456 } 457 458 if (mIsAirplaneSensitive && isAirplaneModeOn()) { 459 disable(false); 460 } 461 462 } 463 } 464 persistBluetoothOnSetting(boolean bluetoothOn)465 private void persistBluetoothOnSetting(boolean bluetoothOn) { 466 long origCallerIdentityToken = Binder.clearCallingIdentity(); 467 Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 468 bluetoothOn ? 1 : 0); 469 Binder.restoreCallingIdentity(origCallerIdentityToken); 470 } 471 getBondState()472 /* package */ BondState getBondState() { 473 return mBondState; 474 } 475 476 /** local cache of bonding state. 477 /* we keep our own state to track the intermediate state BONDING, which 478 /* bluez does not track. 479 * All addreses must be passed in upper case. 480 */ 481 public class BondState { 482 private final HashMap<String, Integer> mState = new HashMap<String, Integer>(); 483 private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>(); 484 private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>(); 485 // List of all the vendor_id prefix of Bluetooth addresses for 486 // which auto pairing is not attempted. 487 // The following companies are included in the list below: 488 // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi), 489 // Parrot, Zhongshan General K-mate Electronics, Great Well 490 // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi, 491 // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura), 492 // Continental Automotive, Harman/Becker, Panasonic/Kyushu Ten, 493 // BMW (Motorola PCS) 494 private final ArrayList<String> mAutoPairingAddressBlacklist = 495 new ArrayList<String>(Arrays.asList( 496 "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F", 497 "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8", 498 "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04", 499 "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59", 500 "00:0A:30", "00:1E:AE", "00:1C:D7", "00:80:F0", "00:12:8A" 501 )); 502 503 // List of names of Bluetooth devices for which auto pairing should be 504 // disabled. 505 private final ArrayList<String> mAutoPairingExactNameBlacklist = 506 new ArrayList<String>(Arrays.asList( 507 "Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3")); 508 509 private final ArrayList<String> mAutoPairingPartialNameBlacklist = 510 new ArrayList<String>(Arrays.asList( 511 "BMW", "Audi")); 512 513 // If this is an outgoing connection, store the address. 514 // There can be only 1 pending outgoing connection at a time, 515 private String mPendingOutgoingBonding; 516 setPendingOutgoingBonding(String address)517 private synchronized void setPendingOutgoingBonding(String address) { 518 mPendingOutgoingBonding = address; 519 } 520 getPendingOutgoingBonding()521 public synchronized String getPendingOutgoingBonding() { 522 return mPendingOutgoingBonding; 523 } 524 loadBondState()525 public synchronized void loadBondState() { 526 if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) { 527 return; 528 } 529 String []bonds = null; 530 String val = getProperty("Devices"); 531 if (val != null) { 532 bonds = val.split(","); 533 } 534 if (bonds == null) { 535 return; 536 } 537 mState.clear(); 538 if (DBG) log("found " + bonds.length + " bonded devices"); 539 for (String device : bonds) { 540 mState.put(getAddressFromObjectPath(device).toUpperCase(), 541 BluetoothDevice.BOND_BONDED); 542 } 543 } 544 setBondState(String address, int state)545 public synchronized void setBondState(String address, int state) { 546 setBondState(address, state, 0); 547 } 548 549 /** reason is ignored unless state == BOND_NOT_BONDED */ setBondState(String address, int state, int reason)550 public synchronized void setBondState(String address, int state, int reason) { 551 int oldState = getBondState(address); 552 if (oldState == state) { 553 return; 554 } 555 556 // Check if this was an pending outgoing bonding. 557 // If yes, reset the state. 558 if (oldState == BluetoothDevice.BOND_BONDING) { 559 if (address.equals(mPendingOutgoingBonding)) { 560 mPendingOutgoingBonding = null; 561 } 562 } 563 564 if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" + 565 reason + ")"); 566 Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 567 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 568 intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state); 569 intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 570 if (state == BluetoothDevice.BOND_NONE) { 571 if (reason <= 0) { 572 Log.w(TAG, "setBondState() called to unbond device, but reason code is " + 573 "invalid. Overriding reason code with BOND_RESULT_REMOVED"); 574 reason = BluetoothDevice.UNBOND_REASON_REMOVED; 575 } 576 intent.putExtra(BluetoothDevice.EXTRA_REASON, reason); 577 mState.remove(address); 578 } else { 579 mState.put(address, state); 580 } 581 582 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 583 } 584 isAutoPairingBlacklisted(String address)585 public boolean isAutoPairingBlacklisted(String address) { 586 for (String blacklistAddress : mAutoPairingAddressBlacklist) { 587 if (address.startsWith(blacklistAddress)) return true; 588 } 589 590 String name = getRemoteName(address); 591 if (name != null) { 592 for (String blacklistName : mAutoPairingExactNameBlacklist) { 593 if (name.equals(blacklistName)) return true; 594 } 595 596 for (String blacklistName : mAutoPairingPartialNameBlacklist) { 597 if (name.startsWith(blacklistName)) return true; 598 } 599 } 600 return false; 601 } 602 getBondState(String address)603 public synchronized int getBondState(String address) { 604 Integer state = mState.get(address); 605 if (state == null) { 606 return BluetoothDevice.BOND_NONE; 607 } 608 return state.intValue(); 609 } 610 listInState(int state)611 /*package*/ synchronized String[] listInState(int state) { 612 ArrayList<String> result = new ArrayList<String>(mState.size()); 613 for (Map.Entry<String, Integer> e : mState.entrySet()) { 614 if (e.getValue().intValue() == state) { 615 result.add(e.getKey()); 616 } 617 } 618 return result.toArray(new String[result.size()]); 619 } 620 addAutoPairingFailure(String address)621 public synchronized void addAutoPairingFailure(String address) { 622 if (!mAutoPairingFailures.contains(address)) { 623 mAutoPairingFailures.add(address); 624 } 625 } 626 isAutoPairingAttemptsInProgress(String address)627 public synchronized boolean isAutoPairingAttemptsInProgress(String address) { 628 return getAttempt(address) != 0; 629 } 630 clearPinAttempts(String address)631 public synchronized void clearPinAttempts(String address) { 632 mPinAttempt.remove(address); 633 } 634 hasAutoPairingFailed(String address)635 public synchronized boolean hasAutoPairingFailed(String address) { 636 return mAutoPairingFailures.contains(address); 637 } 638 getAttempt(String address)639 public synchronized int getAttempt(String address) { 640 Integer attempt = mPinAttempt.get(address); 641 if (attempt == null) { 642 return 0; 643 } 644 return attempt.intValue(); 645 } 646 attempt(String address)647 public synchronized void attempt(String address) { 648 Integer attempt = mPinAttempt.get(address); 649 int newAttempt; 650 if (attempt == null) { 651 newAttempt = 1; 652 } else { 653 newAttempt = attempt.intValue() + 1; 654 } 655 mPinAttempt.put(address, new Integer(newAttempt)); 656 } 657 658 } 659 toBondStateString(int bondState)660 private static String toBondStateString(int bondState) { 661 switch (bondState) { 662 case BluetoothDevice.BOND_NONE: 663 return "not bonded"; 664 case BluetoothDevice.BOND_BONDING: 665 return "bonding"; 666 case BluetoothDevice.BOND_BONDED: 667 return "bonded"; 668 default: 669 return "??????"; 670 } 671 } 672 isAdapterPropertiesEmpty()673 /*package*/ synchronized boolean isAdapterPropertiesEmpty() { 674 return mAdapterProperties.isEmpty(); 675 } 676 getAllProperties()677 /*package*/synchronized void getAllProperties() { 678 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 679 mAdapterProperties.clear(); 680 681 String properties[] = (String [])getAdapterPropertiesNative(); 682 // The String Array consists of key-value pairs. 683 if (properties == null) { 684 Log.e(TAG, "*Error*: GetAdapterProperties returned NULL"); 685 return; 686 } 687 688 for (int i = 0; i < properties.length; i++) { 689 String name = properties[i]; 690 String newValue = null; 691 int len; 692 if (name == null) { 693 Log.e(TAG, "Error:Adapter Property at index" + i + "is null"); 694 continue; 695 } 696 if (name.equals("Devices")) { 697 StringBuilder str = new StringBuilder(); 698 len = Integer.valueOf(properties[++i]); 699 for (int j = 0; j < len; j++) { 700 str.append(properties[++i]); 701 str.append(","); 702 } 703 if (len > 0) { 704 newValue = str.toString(); 705 } 706 } else { 707 newValue = properties[++i]; 708 } 709 mAdapterProperties.put(name, newValue); 710 } 711 712 // Add adapter object path property. 713 String adapterPath = getAdapterPathNative(); 714 if (adapterPath != null) 715 mAdapterProperties.put("ObjectPath", adapterPath + "/dev_"); 716 } 717 setProperty(String name, String value)718 /* package */ synchronized void setProperty(String name, String value) { 719 mAdapterProperties.put(name, value); 720 } 721 setName(String name)722 public synchronized boolean setName(String name) { 723 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 724 "Need BLUETOOTH_ADMIN permission"); 725 if (name == null) { 726 return false; 727 } 728 return setPropertyString("Name", name); 729 } 730 731 //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean 732 // Either have a single property function with Object as the parameter 733 // or have a function for each property and then obfuscate in the JNI layer. 734 // The following looks dirty. setPropertyString(String key, String value)735 private boolean setPropertyString(String key, String value) { 736 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 737 return setAdapterPropertyStringNative(key, value); 738 } 739 setPropertyInteger(String key, int value)740 private boolean setPropertyInteger(String key, int value) { 741 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 742 return setAdapterPropertyIntegerNative(key, value); 743 } 744 setPropertyBoolean(String key, boolean value)745 private boolean setPropertyBoolean(String key, boolean value) { 746 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 747 return setAdapterPropertyBooleanNative(key, value ? 1 : 0); 748 } 749 750 /** 751 * Set the discoverability window for the device. A timeout of zero 752 * makes the device permanently discoverable (if the device is 753 * discoverable). Setting the timeout to a nonzero value does not make 754 * a device discoverable; you need to call setMode() to make the device 755 * explicitly discoverable. 756 * 757 * @param timeout_s The discoverable timeout in seconds. 758 */ setDiscoverableTimeout(int timeout)759 public synchronized boolean setDiscoverableTimeout(int timeout) { 760 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 761 "Need BLUETOOTH_ADMIN permission"); 762 return setPropertyInteger("DiscoverableTimeout", timeout); 763 } 764 setScanMode(int mode, int duration)765 public synchronized boolean setScanMode(int mode, int duration) { 766 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, 767 "Need WRITE_SECURE_SETTINGS permission"); 768 boolean pairable = false; 769 boolean discoverable = false; 770 771 switch (mode) { 772 case BluetoothAdapter.SCAN_MODE_NONE: 773 mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 774 pairable = false; 775 discoverable = false; 776 break; 777 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 778 mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 779 pairable = true; 780 discoverable = false; 781 break; 782 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 783 mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT); 784 pairable = true; 785 discoverable = true; 786 Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT); 787 mHandler.sendMessageDelayed(msg, duration * 1000); 788 if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds"); 789 break; 790 default: 791 Log.w(TAG, "Requested invalid scan mode " + mode); 792 return false; 793 } 794 setPropertyBoolean("Pairable", pairable); 795 setPropertyBoolean("Discoverable", discoverable); 796 797 return true; 798 } 799 getProperty(String name)800 /*package*/ synchronized String getProperty (String name) { 801 if (!mAdapterProperties.isEmpty()) 802 return mAdapterProperties.get(name); 803 getAllProperties(); 804 return mAdapterProperties.get(name); 805 } 806 getAddress()807 public synchronized String getAddress() { 808 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 809 return getProperty("Address"); 810 } 811 getName()812 public synchronized String getName() { 813 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 814 return getProperty("Name"); 815 } 816 817 /** 818 * Returns the user-friendly name of a remote device. This value is 819 * returned from our local cache, which is updated when onPropertyChange 820 * event is received. 821 * Do not expect to retrieve the updated remote name immediately after 822 * changing the name on the remote device. 823 * 824 * @param address Bluetooth address of remote device. 825 * 826 * @return The user-friendly name of the specified remote device. 827 */ getRemoteName(String address)828 public synchronized String getRemoteName(String address) { 829 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 830 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 831 return null; 832 } 833 return getRemoteDeviceProperty(address, "Name"); 834 } 835 836 /** 837 * Get the discoverability window for the device. A timeout of zero 838 * means that the device is permanently discoverable (if the device is 839 * in the discoverable mode). 840 * 841 * @return The discoverability window of the device, in seconds. A negative 842 * value indicates an error. 843 */ getDiscoverableTimeout()844 public synchronized int getDiscoverableTimeout() { 845 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 846 String timeout = getProperty("DiscoverableTimeout"); 847 if (timeout != null) 848 return Integer.valueOf(timeout); 849 else 850 return -1; 851 } 852 getScanMode()853 public synchronized int getScanMode() { 854 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 855 if (!isEnabled()) 856 return BluetoothAdapter.SCAN_MODE_NONE; 857 858 boolean pairable = getProperty("Pairable").equals("true"); 859 boolean discoverable = getProperty("Discoverable").equals("true"); 860 return bluezStringToScanMode (pairable, discoverable); 861 } 862 startDiscovery()863 public synchronized boolean startDiscovery() { 864 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 865 "Need BLUETOOTH_ADMIN permission"); 866 if (!isEnabled()) { 867 return false; 868 } 869 return startDiscoveryNative(); 870 } 871 cancelDiscovery()872 public synchronized boolean cancelDiscovery() { 873 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 874 "Need BLUETOOTH_ADMIN permission"); 875 return stopDiscoveryNative(); 876 } 877 isDiscovering()878 public synchronized boolean isDiscovering() { 879 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 880 return mIsDiscovering; 881 } 882 setIsDiscovering(boolean isDiscovering)883 /* package */ void setIsDiscovering(boolean isDiscovering) { 884 mIsDiscovering = isDiscovering; 885 } 886 createBond(String address)887 public synchronized boolean createBond(String address) { 888 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 889 "Need BLUETOOTH_ADMIN permission"); 890 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 891 return false; 892 } 893 address = address.toUpperCase(); 894 895 if (mBondState.getPendingOutgoingBonding() != null) { 896 log("Ignoring createBond(): another device is bonding"); 897 // a different device is currently bonding, fail 898 return false; 899 } 900 901 // Check for bond state only if we are not performing auto 902 // pairing exponential back-off attempts. 903 if (!mBondState.isAutoPairingAttemptsInProgress(address) && 904 mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) { 905 log("Ignoring createBond(): this device is already bonding or bonded"); 906 return false; 907 } 908 909 if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) { 910 return false; 911 } 912 913 mBondState.setPendingOutgoingBonding(address); 914 mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 915 916 return true; 917 } 918 cancelBondProcess(String address)919 public synchronized boolean cancelBondProcess(String address) { 920 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 921 "Need BLUETOOTH_ADMIN permission"); 922 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 923 return false; 924 } 925 address = address.toUpperCase(); 926 if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) { 927 return false; 928 } 929 930 mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 931 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 932 cancelDeviceCreationNative(address); 933 return true; 934 } 935 removeBond(String address)936 public synchronized boolean removeBond(String address) { 937 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 938 "Need BLUETOOTH_ADMIN permission"); 939 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 940 return false; 941 } 942 return removeDeviceNative(getObjectPathFromAddress(address)); 943 } 944 listBonds()945 public synchronized String[] listBonds() { 946 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 947 return mBondState.listInState(BluetoothDevice.BOND_BONDED); 948 } 949 getBondState(String address)950 public synchronized int getBondState(String address) { 951 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 952 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 953 return BluetoothDevice.ERROR; 954 } 955 return mBondState.getBondState(address.toUpperCase()); 956 } 957 isRemoteDeviceInCache(String address)958 /*package*/ boolean isRemoteDeviceInCache(String address) { 959 return (mDeviceProperties.get(address) != null); 960 } 961 getRemoteDeviceProperties(String address)962 /*package*/ String[] getRemoteDeviceProperties(String address) { 963 String objectPath = getObjectPathFromAddress(address); 964 return (String [])getDevicePropertiesNative(objectPath); 965 } 966 getRemoteDeviceProperty(String address, String property)967 /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) { 968 Map<String, String> properties = mDeviceProperties.get(address); 969 if (properties != null) { 970 return properties.get(property); 971 } else { 972 // Query for remote device properties, again. 973 // We will need to reload the cache when we switch Bluetooth on / off 974 // or if we crash. 975 if (updateRemoteDevicePropertiesCache(address)) 976 return getRemoteDeviceProperty(address, property); 977 } 978 Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address); 979 return null; 980 } 981 updateRemoteDevicePropertiesCache(String address)982 /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) { 983 String[] propValues = getRemoteDeviceProperties(address); 984 if (propValues != null) { 985 addRemoteDeviceProperties(address, propValues); 986 return true; 987 } 988 return false; 989 } 990 addRemoteDeviceProperties(String address, String[] properties)991 /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) { 992 /* 993 * We get a DeviceFound signal every time RSSI changes or name changes. 994 * Don't create a new Map object every time */ 995 Map<String, String> propertyValues = mDeviceProperties.get(address); 996 if (propertyValues == null) { 997 propertyValues = new HashMap<String, String>(); 998 } 999 1000 for (int i = 0; i < properties.length; i++) { 1001 String name = properties[i]; 1002 String newValue = null; 1003 int len; 1004 if (name == null) { 1005 Log.e(TAG, "Error: Remote Device Property at index" + i + "is null"); 1006 continue; 1007 } 1008 if (name.equals("UUIDs") || name.equals("Nodes")) { 1009 StringBuilder str = new StringBuilder(); 1010 len = Integer.valueOf(properties[++i]); 1011 for (int j = 0; j < len; j++) { 1012 str.append(properties[++i]); 1013 str.append(","); 1014 } 1015 if (len > 0) { 1016 newValue = str.toString(); 1017 } 1018 } else { 1019 newValue = properties[++i]; 1020 } 1021 1022 propertyValues.put(name, newValue); 1023 } 1024 mDeviceProperties.put(address, propertyValues); 1025 1026 // We have added a new remote device or updated its properties. 1027 // Also update the serviceChannel cache. 1028 updateDeviceServiceChannelCache(address); 1029 } 1030 removeRemoteDeviceProperties(String address)1031 /* package */ void removeRemoteDeviceProperties(String address) { 1032 mDeviceProperties.remove(address); 1033 } 1034 setRemoteDeviceProperty(String address, String name, String value)1035 /* package */ synchronized void setRemoteDeviceProperty(String address, String name, 1036 String value) { 1037 Map <String, String> propVal = mDeviceProperties.get(address); 1038 if (propVal != null) { 1039 propVal.put(name, value); 1040 mDeviceProperties.put(address, propVal); 1041 } else { 1042 Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); 1043 } 1044 } 1045 1046 /** 1047 * Sets the remote device trust state. 1048 * 1049 * @return boolean to indicate operation success or fail 1050 */ setTrust(String address, boolean value)1051 public synchronized boolean setTrust(String address, boolean value) { 1052 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1053 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1054 "Need BLUETOOTH_ADMIN permission"); 1055 return false; 1056 } 1057 1058 return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted", 1059 value ? 1 : 0); 1060 } 1061 1062 /** 1063 * Gets the remote device trust state as boolean. 1064 * Note: this value may be 1065 * retrieved from cache if we retrieved the data before * 1066 * 1067 * @return boolean to indicate trust or untrust state 1068 */ getTrustState(String address)1069 public synchronized boolean getTrustState(String address) { 1070 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1071 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1072 return false; 1073 } 1074 1075 String val = getRemoteDeviceProperty(address, "Trusted"); 1076 if (val == null) { 1077 return false; 1078 } else { 1079 return val.equals("true") ? true : false; 1080 } 1081 } 1082 1083 /** 1084 * Gets the remote major, minor classes encoded as a 32-bit 1085 * integer. 1086 * 1087 * Note: this value is retrieved from cache, because we get it during 1088 * remote-device discovery. 1089 * 1090 * @return 32-bit integer encoding the remote major, minor, and service 1091 * classes. 1092 */ getRemoteClass(String address)1093 public synchronized int getRemoteClass(String address) { 1094 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1095 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1096 return BluetoothClass.ERROR; 1097 } 1098 String val = getRemoteDeviceProperty(address, "Class"); 1099 if (val == null) 1100 return BluetoothClass.ERROR; 1101 else { 1102 return Integer.valueOf(val); 1103 } 1104 } 1105 1106 1107 /** 1108 * Gets the UUIDs supported by the remote device 1109 * 1110 * @return array of 128bit ParcelUuids 1111 */ getRemoteUuids(String address)1112 public synchronized ParcelUuid[] getRemoteUuids(String address) { 1113 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1114 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1115 return null; 1116 } 1117 return getUuidFromCache(address); 1118 } 1119 getUuidFromCache(String address)1120 private ParcelUuid[] getUuidFromCache(String address) { 1121 String value = getRemoteDeviceProperty(address, "UUIDs"); 1122 if (value == null) return null; 1123 1124 String[] uuidStrings = null; 1125 // The UUIDs are stored as a "," separated string. 1126 uuidStrings = value.split(","); 1127 ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length]; 1128 1129 for (int i = 0; i < uuidStrings.length; i++) { 1130 uuids[i] = ParcelUuid.fromString(uuidStrings[i]); 1131 } 1132 return uuids; 1133 } 1134 1135 /** 1136 * Connect and fetch new UUID's using SDP. 1137 * The UUID's found are broadcast as intents. 1138 * Optionally takes a uuid and callback to fetch the RFCOMM channel for the 1139 * a given uuid. 1140 * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success 1141 * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for 1142 * callback and broadcast intents. 1143 */ fetchRemoteUuids(String address, ParcelUuid uuid, IBluetoothCallback callback)1144 public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid, 1145 IBluetoothCallback callback) { 1146 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1147 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1148 return false; 1149 } 1150 1151 RemoteService service = new RemoteService(address, uuid); 1152 if (uuid != null && mUuidCallbackTracker.get(service) != null) { 1153 // An SDP query for this address & uuid is already in progress 1154 // Do not add this callback for the uuid 1155 return false; 1156 } 1157 1158 if (mUuidIntentTracker.contains(address)) { 1159 // An SDP query for this address is already in progress 1160 // Add this uuid onto the in-progress SDP query 1161 if (uuid != null) { 1162 mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 1163 } 1164 return true; 1165 } 1166 1167 boolean ret; 1168 if (getBondState(address) == BluetoothDevice.BOND_BONDED) { 1169 String path = getObjectPathFromAddress(address); 1170 if (path == null) return false; 1171 1172 // Use an empty string for the UUID pattern 1173 ret = discoverServicesNative(path, ""); 1174 } else { 1175 ret = createDeviceNative(address); 1176 } 1177 1178 mUuidIntentTracker.add(address); 1179 if (uuid != null) { 1180 mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 1181 } 1182 1183 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 1184 message.obj = address; 1185 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 1186 return ret; 1187 } 1188 1189 /** 1190 * Gets the rfcomm channel associated with the UUID. 1191 * Pulls records from the cache only. 1192 * 1193 * @param address Address of the remote device 1194 * @param uuid ParcelUuid of the service attribute 1195 * 1196 * @return rfcomm channel associated with the service attribute 1197 * -1 on error 1198 */ getRemoteServiceChannel(String address, ParcelUuid uuid)1199 public int getRemoteServiceChannel(String address, ParcelUuid uuid) { 1200 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1201 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1202 return BluetoothDevice.ERROR; 1203 } 1204 // Check if we are recovering from a crash. 1205 if (mDeviceProperties.isEmpty()) { 1206 if (!updateRemoteDevicePropertiesCache(address)) 1207 return -1; 1208 } 1209 1210 Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address); 1211 if (value != null && value.containsKey(uuid)) 1212 return value.get(uuid); 1213 return -1; 1214 } 1215 setPin(String address, byte[] pin)1216 public synchronized boolean setPin(String address, byte[] pin) { 1217 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1218 "Need BLUETOOTH_ADMIN permission"); 1219 if (pin == null || pin.length <= 0 || pin.length > 16 || 1220 !BluetoothAdapter.checkBluetoothAddress(address)) { 1221 return false; 1222 } 1223 address = address.toUpperCase(); 1224 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1225 if (data == null) { 1226 Log.w(TAG, "setPin(" + address + ") called but no native data available, " + 1227 "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1228 " or by bluez.\n"); 1229 return false; 1230 } 1231 // bluez API wants pin as a string 1232 String pinString; 1233 try { 1234 pinString = new String(pin, "UTF8"); 1235 } catch (UnsupportedEncodingException uee) { 1236 Log.e(TAG, "UTF8 not supported?!?"); 1237 return false; 1238 } 1239 return setPinNative(address, pinString, data.intValue()); 1240 } 1241 setPasskey(String address, int passkey)1242 public synchronized boolean setPasskey(String address, int passkey) { 1243 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1244 "Need BLUETOOTH_ADMIN permission"); 1245 if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) { 1246 return false; 1247 } 1248 address = address.toUpperCase(); 1249 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1250 if (data == null) { 1251 Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1252 "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1253 " or by bluez.\n"); 1254 return false; 1255 } 1256 return setPasskeyNative(address, passkey, data.intValue()); 1257 } 1258 setPairingConfirmation(String address, boolean confirm)1259 public synchronized boolean setPairingConfirmation(String address, boolean confirm) { 1260 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1261 "Need BLUETOOTH_ADMIN permission"); 1262 address = address.toUpperCase(); 1263 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1264 if (data == null) { 1265 Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1266 "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1267 " or by bluez.\n"); 1268 return false; 1269 } 1270 return setPairingConfirmationNative(address, confirm, data.intValue()); 1271 } 1272 cancelPairingUserInput(String address)1273 public synchronized boolean cancelPairingUserInput(String address) { 1274 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1275 "Need BLUETOOTH_ADMIN permission"); 1276 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1277 return false; 1278 } 1279 mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 1280 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 1281 address = address.toUpperCase(); 1282 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1283 if (data == null) { 1284 Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " + 1285 "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " + 1286 "by the remote or by bluez.\n"); 1287 return false; 1288 } 1289 return cancelPairingUserInputNative(address, data.intValue()); 1290 } 1291 updateDeviceServiceChannelCache(String address)1292 public void updateDeviceServiceChannelCache(String address) { 1293 ParcelUuid[] deviceUuids = getRemoteUuids(address); 1294 // We are storing the rfcomm channel numbers only for the uuids 1295 // we are interested in. 1296 int channel; 1297 if (DBG) log("updateDeviceServiceChannelCache(" + address + ")"); 1298 1299 ArrayList<ParcelUuid> applicationUuids = new ArrayList(); 1300 1301 synchronized (this) { 1302 for (RemoteService service : mUuidCallbackTracker.keySet()) { 1303 if (service.address.equals(address)) { 1304 applicationUuids.add(service.uuid); 1305 } 1306 } 1307 } 1308 1309 Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>(); 1310 1311 // Retrieve RFCOMM channel for default uuids 1312 for (ParcelUuid uuid : RFCOMM_UUIDS) { 1313 if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 1314 channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 1315 uuid.toString(), 0x0004); 1316 if (DBG) log("\tuuid(system): " + uuid + " " + channel); 1317 value.put(uuid, channel); 1318 } 1319 } 1320 // Retrieve RFCOMM channel for application requested uuids 1321 for (ParcelUuid uuid : applicationUuids) { 1322 if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 1323 channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address), 1324 uuid.toString(), 0x0004); 1325 if (DBG) log("\tuuid(application): " + uuid + " " + channel); 1326 value.put(uuid, channel); 1327 } 1328 } 1329 1330 synchronized (this) { 1331 // Make application callbacks 1332 for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 1333 iter.hasNext();) { 1334 RemoteService service = iter.next(); 1335 if (service.address.equals(address)) { 1336 channel = -1; 1337 if (value.get(service.uuid) != null) { 1338 channel = value.get(service.uuid); 1339 } 1340 if (channel != -1) { 1341 if (DBG) log("Making callback for " + service.uuid + " with result " + 1342 channel); 1343 IBluetoothCallback callback = mUuidCallbackTracker.get(service); 1344 if (callback != null) { 1345 try { 1346 callback.onRfcommChannelFound(channel); 1347 } catch (RemoteException e) {Log.e(TAG, "", e);} 1348 } 1349 1350 iter.remove(); 1351 } 1352 } 1353 } 1354 1355 // Update cache 1356 mDeviceServiceChannelCache.put(address, value); 1357 } 1358 } 1359 1360 /** 1361 * b is a handle to a Binder instance, so that this service can be notified 1362 * for Applications that terminate unexpectedly, to clean there service 1363 * records 1364 */ addRfcommServiceRecord(String serviceName, ParcelUuid uuid, int channel, IBinder b)1365 public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid, 1366 int channel, IBinder b) { 1367 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1368 "Need BLUETOOTH permission"); 1369 if (serviceName == null || uuid == null || channel < 1 || 1370 channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) { 1371 return -1; 1372 } 1373 if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) { 1374 Log.w(TAG, "Attempted to register a reserved UUID: " + uuid); 1375 return -1; 1376 } 1377 int handle = addRfcommServiceRecordNative(serviceName, 1378 uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(), 1379 (short)channel); 1380 if (DBG) log("new handle " + Integer.toHexString(handle)); 1381 if (handle == -1) { 1382 return -1; 1383 } 1384 1385 int pid = Binder.getCallingPid(); 1386 mServiceRecordToPid.put(new Integer(handle), new Integer(pid)); 1387 try { 1388 b.linkToDeath(new Reaper(handle, pid), 0); 1389 } catch (RemoteException e) {} 1390 return handle; 1391 } 1392 removeServiceRecord(int handle)1393 public void removeServiceRecord(int handle) { 1394 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1395 "Need BLUETOOTH permission"); 1396 checkAndRemoveRecord(handle, Binder.getCallingPid()); 1397 } 1398 checkAndRemoveRecord(int handle, int pid)1399 private synchronized void checkAndRemoveRecord(int handle, int pid) { 1400 Integer handleInt = new Integer(handle); 1401 Integer owner = mServiceRecordToPid.get(handleInt); 1402 if (owner != null && pid == owner.intValue()) { 1403 if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " + 1404 pid); 1405 mServiceRecordToPid.remove(handleInt); 1406 removeServiceRecordNative(handle); 1407 } 1408 } 1409 1410 private class Reaper implements IBinder.DeathRecipient { 1411 int pid; 1412 int handle; Reaper(int handle, int pid)1413 Reaper(int handle, int pid) { 1414 this.pid = pid; 1415 this.handle = handle; 1416 } binderDied()1417 public void binderDied() { 1418 synchronized (BluetoothService.this) { 1419 if (DBG) log("Tracked app " + pid + " died"); 1420 checkAndRemoveRecord(handle, pid); 1421 } 1422 } 1423 } 1424 1425 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 1426 @Override 1427 public void onReceive(Context context, Intent intent) { 1428 String action = intent.getAction(); 1429 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 1430 ContentResolver resolver = context.getContentResolver(); 1431 // Query the airplane mode from Settings.System just to make sure that 1432 // some random app is not sending this intent and disabling bluetooth 1433 boolean enabled = !isAirplaneModeOn(); 1434 // If bluetooth is currently expected to be on, then enable or disable bluetooth 1435 if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { 1436 if (enabled) { 1437 enable(false); 1438 } else { 1439 disable(false); 1440 } 1441 } 1442 } 1443 } 1444 }; 1445 registerForAirplaneMode()1446 private void registerForAirplaneMode() { 1447 String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(), 1448 Settings.System.AIRPLANE_MODE_RADIOS); 1449 mIsAirplaneSensitive = airplaneModeRadios == null 1450 ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 1451 if (mIsAirplaneSensitive) { 1452 mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 1453 mContext.registerReceiver(mReceiver, mIntentFilter); 1454 } 1455 } 1456 1457 /* Returns true if airplane mode is currently on */ isAirplaneModeOn()1458 private final boolean isAirplaneModeOn() { 1459 return Settings.System.getInt(mContext.getContentResolver(), 1460 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 1461 } 1462 1463 /* Broadcast the Uuid intent */ sendUuidIntent(String address)1464 /*package*/ synchronized void sendUuidIntent(String address) { 1465 ParcelUuid[] uuid = getUuidFromCache(address); 1466 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 1467 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 1468 intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid); 1469 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 1470 1471 if (mUuidIntentTracker.contains(address)) 1472 mUuidIntentTracker.remove(address); 1473 1474 } 1475 makeServiceChannelCallbacks(String address)1476 /*package*/ synchronized void makeServiceChannelCallbacks(String address) { 1477 for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 1478 iter.hasNext();) { 1479 RemoteService service = iter.next(); 1480 if (service.address.equals(address)) { 1481 if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address + 1482 " " + service.uuid); 1483 IBluetoothCallback callback = mUuidCallbackTracker.get(service); 1484 if (callback != null) { 1485 try { 1486 callback.onRfcommChannelFound(-1); 1487 } catch (RemoteException e) {Log.e(TAG, "", e);} 1488 } 1489 1490 iter.remove(); 1491 } 1492 } 1493 } 1494 1495 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1496 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1497 switch(mBluetoothState) { 1498 case BluetoothAdapter.STATE_OFF: 1499 pw.println("Bluetooth OFF\n"); 1500 return; 1501 case BluetoothAdapter.STATE_TURNING_ON: 1502 pw.println("Bluetooth TURNING ON\n"); 1503 return; 1504 case BluetoothAdapter.STATE_TURNING_OFF: 1505 pw.println("Bluetooth TURNING OFF\n"); 1506 return; 1507 case BluetoothAdapter.STATE_ON: 1508 pw.println("Bluetooth ON\n"); 1509 } 1510 1511 pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive); 1512 1513 pw.println("Local address = " + getAddress()); 1514 pw.println("Local name = " + getName()); 1515 pw.println("isDiscovering() = " + isDiscovering()); 1516 1517 BluetoothHeadset headset = new BluetoothHeadset(mContext, null); 1518 1519 pw.println("\n--Known devices--"); 1520 for (String address : mDeviceProperties.keySet()) { 1521 int bondState = mBondState.getBondState(address); 1522 pw.printf("%s %10s (%d) %s\n", address, 1523 toBondStateString(bondState), 1524 mBondState.getAttempt(address), 1525 getRemoteName(address)); 1526 1527 Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address); 1528 if (uuidChannels == null) { 1529 pw.println("\tuuids = null"); 1530 } else { 1531 for (ParcelUuid uuid : uuidChannels.keySet()) { 1532 Integer channel = uuidChannels.get(uuid); 1533 if (channel == null) { 1534 pw.println("\t" + uuid); 1535 } else { 1536 pw.println("\t" + uuid + " RFCOMM channel = " + channel); 1537 } 1538 } 1539 } 1540 for (RemoteService service : mUuidCallbackTracker.keySet()) { 1541 if (service.address.equals(address)) { 1542 pw.println("\tPENDING CALLBACK: " + service.uuid); 1543 } 1544 } 1545 } 1546 1547 String value = getProperty("Devices"); 1548 String[] devicesObjectPath = null; 1549 if (value != null) { 1550 devicesObjectPath = value.split(","); 1551 } 1552 pw.println("\n--ACL connected devices--"); 1553 if (devicesObjectPath != null) { 1554 for (String device : devicesObjectPath) { 1555 pw.println(getAddressFromObjectPath(device)); 1556 } 1557 } 1558 1559 // Rather not do this from here, but no-where else and I need this 1560 // dump 1561 pw.println("\n--Headset Service--"); 1562 switch (headset.getState()) { 1563 case BluetoothHeadset.STATE_DISCONNECTED: 1564 pw.println("getState() = STATE_DISCONNECTED"); 1565 break; 1566 case BluetoothHeadset.STATE_CONNECTING: 1567 pw.println("getState() = STATE_CONNECTING"); 1568 break; 1569 case BluetoothHeadset.STATE_CONNECTED: 1570 pw.println("getState() = STATE_CONNECTED"); 1571 break; 1572 case BluetoothHeadset.STATE_ERROR: 1573 pw.println("getState() = STATE_ERROR"); 1574 break; 1575 } 1576 1577 pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset()); 1578 pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint()); 1579 headset.close(); 1580 pw.println("\n--Application Service Records--"); 1581 for (Integer handle : mServiceRecordToPid.keySet()) { 1582 Integer pid = mServiceRecordToPid.get(handle); 1583 pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle)); 1584 } 1585 } 1586 bluezStringToScanMode(boolean pairable, boolean discoverable)1587 /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) { 1588 if (pairable && discoverable) 1589 return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 1590 else if (pairable && !discoverable) 1591 return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 1592 else 1593 return BluetoothAdapter.SCAN_MODE_NONE; 1594 } 1595 scanModeToBluezString(int mode)1596 /* package */ static String scanModeToBluezString(int mode) { 1597 switch (mode) { 1598 case BluetoothAdapter.SCAN_MODE_NONE: 1599 return "off"; 1600 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 1601 return "connectable"; 1602 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 1603 return "discoverable"; 1604 } 1605 return null; 1606 } 1607 getAddressFromObjectPath(String objectPath)1608 /*package*/ String getAddressFromObjectPath(String objectPath) { 1609 String adapterObjectPath = getProperty("ObjectPath"); 1610 if (adapterObjectPath == null || objectPath == null) { 1611 Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 1612 " or deviceObjectPath:" + objectPath + " is null"); 1613 return null; 1614 } 1615 if (!objectPath.startsWith(adapterObjectPath)) { 1616 Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath + 1617 " is not a prefix of deviceObjectPath:" + objectPath + 1618 "bluetoothd crashed ?"); 1619 return null; 1620 } 1621 String address = objectPath.substring(adapterObjectPath.length()); 1622 if (address != null) return address.replace('_', ':'); 1623 1624 Log.e(TAG, "getAddressFromObjectPath: Address being returned is null"); 1625 return null; 1626 } 1627 getObjectPathFromAddress(String address)1628 /*package*/ String getObjectPathFromAddress(String address) { 1629 String path = getProperty("ObjectPath"); 1630 if (path == null) { 1631 Log.e(TAG, "Error: Object Path is null"); 1632 return null; 1633 } 1634 path = path + address.replace(":", "_"); 1635 return path; 1636 } 1637 log(String msg)1638 private static void log(String msg) { 1639 Log.d(TAG, msg); 1640 } 1641 classInitNative()1642 private native static void classInitNative(); initializeNativeDataNative()1643 private native void initializeNativeDataNative(); setupNativeDataNative()1644 private native boolean setupNativeDataNative(); tearDownNativeDataNative()1645 private native boolean tearDownNativeDataNative(); cleanupNativeDataNative()1646 private native void cleanupNativeDataNative(); getAdapterPathNative()1647 private native String getAdapterPathNative(); 1648 isEnabledNative()1649 private native int isEnabledNative(); enableNative()1650 private native int enableNative(); disableNative()1651 private native int disableNative(); 1652 getAdapterPropertiesNative()1653 private native Object[] getAdapterPropertiesNative(); getDevicePropertiesNative(String objectPath)1654 private native Object[] getDevicePropertiesNative(String objectPath); setAdapterPropertyStringNative(String key, String value)1655 private native boolean setAdapterPropertyStringNative(String key, String value); setAdapterPropertyIntegerNative(String key, int value)1656 private native boolean setAdapterPropertyIntegerNative(String key, int value); setAdapterPropertyBooleanNative(String key, int value)1657 private native boolean setAdapterPropertyBooleanNative(String key, int value); 1658 startDiscoveryNative()1659 private native boolean startDiscoveryNative(); stopDiscoveryNative()1660 private native boolean stopDiscoveryNative(); 1661 createPairedDeviceNative(String address, int timeout_ms)1662 private native boolean createPairedDeviceNative(String address, int timeout_ms); cancelDeviceCreationNative(String address)1663 private native boolean cancelDeviceCreationNative(String address); removeDeviceNative(String objectPath)1664 private native boolean removeDeviceNative(String objectPath); getDeviceServiceChannelNative(String objectPath, String uuid, int attributeId)1665 private native int getDeviceServiceChannelNative(String objectPath, String uuid, 1666 int attributeId); 1667 cancelPairingUserInputNative(String address, int nativeData)1668 private native boolean cancelPairingUserInputNative(String address, int nativeData); setPinNative(String address, String pin, int nativeData)1669 private native boolean setPinNative(String address, String pin, int nativeData); setPasskeyNative(String address, int passkey, int nativeData)1670 private native boolean setPasskeyNative(String address, int passkey, int nativeData); setPairingConfirmationNative(String address, boolean confirm, int nativeData)1671 private native boolean setPairingConfirmationNative(String address, boolean confirm, 1672 int nativeData); setDevicePropertyBooleanNative(String objectPath, String key, int value)1673 private native boolean setDevicePropertyBooleanNative(String objectPath, String key, 1674 int value); createDeviceNative(String address)1675 private native boolean createDeviceNative(String address); discoverServicesNative(String objectPath, String pattern)1676 /*package*/ native boolean discoverServicesNative(String objectPath, String pattern); 1677 addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, short channel)1678 private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, 1679 short channel); removeServiceRecordNative(int handle)1680 private native boolean removeServiceRecordNative(int handle); 1681 } 1682