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.BluetoothDeviceProfileState; 31 import android.bluetooth.BluetoothHeadset; 32 import android.bluetooth.BluetoothHealthAppConfiguration; 33 import android.bluetooth.BluetoothInputDevice; 34 import android.bluetooth.BluetoothPan; 35 import android.bluetooth.BluetoothProfile; 36 import android.bluetooth.BluetoothProfileState; 37 import android.bluetooth.BluetoothSocket; 38 import android.bluetooth.BluetoothUuid; 39 import android.bluetooth.IBluetooth; 40 import android.bluetooth.IBluetoothCallback; 41 import android.bluetooth.IBluetoothHealthCallback; 42 import android.bluetooth.IBluetoothStateChangeCallback; 43 import android.content.BroadcastReceiver; 44 import android.content.ContentResolver; 45 import android.content.Context; 46 import android.content.Intent; 47 import android.content.IntentFilter; 48 import android.content.SharedPreferences; 49 import android.os.Binder; 50 import android.os.Handler; 51 import android.os.IBinder; 52 import android.os.Message; 53 import android.os.ParcelFileDescriptor; 54 import android.os.ParcelUuid; 55 import android.os.RemoteException; 56 import android.os.ServiceManager; 57 import android.provider.Settings; 58 import android.util.Log; 59 import android.util.Pair; 60 61 import com.android.internal.app.IBatteryStats; 62 63 import java.io.BufferedInputStream; 64 import java.io.BufferedReader; 65 import java.io.BufferedWriter; 66 import java.io.DataInputStream; 67 import java.io.File; 68 import java.io.FileDescriptor; 69 import java.io.FileInputStream; 70 import java.io.FileNotFoundException; 71 import java.io.FileWriter; 72 import java.io.IOException; 73 import java.io.InputStreamReader; 74 import java.io.PrintWriter; 75 import java.io.RandomAccessFile; 76 import java.io.UnsupportedEncodingException; 77 import java.util.ArrayList; 78 import java.util.Arrays; 79 import java.util.Collection; 80 import java.util.Collections; 81 import java.util.HashMap; 82 import java.util.Iterator; 83 import java.util.List; 84 import java.util.Map; 85 86 public class BluetoothService extends IBluetooth.Stub { 87 private static final String TAG = "BluetoothService"; 88 private static final boolean DBG = true; 89 90 private int mNativeData; 91 private BluetoothEventLoop mEventLoop; 92 private BluetoothHeadset mBluetoothHeadset; 93 private BluetoothInputDevice mInputDevice; 94 private BluetoothPan mPan; 95 private boolean mIsAirplaneSensitive; 96 private boolean mIsAirplaneToggleable; 97 private BluetoothAdapterStateMachine mBluetoothState; 98 private int[] mAdapterSdpHandles; 99 private ParcelUuid[] mAdapterUuids; 100 101 private BluetoothAdapter mAdapter; // constant after init() 102 private final BluetoothBondState mBondState; // local cache of bondings 103 private final IBatteryStats mBatteryStats; 104 private final Context mContext; 105 private Map<Integer, IBluetoothStateChangeCallback> mStateChangeTracker = 106 Collections.synchronizedMap(new HashMap<Integer, IBluetoothStateChangeCallback>()); 107 108 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 109 static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 110 111 private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr"; 112 private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin"; 113 114 private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address"; 115 private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings"; 116 117 private static final int MESSAGE_UUID_INTENT = 1; 118 private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2; 119 private static final int MESSAGE_REMOVE_SERVICE_RECORD = 3; 120 121 private static final int RFCOMM_RECORD_REAPER = 10; 122 private static final int STATE_CHANGE_REAPER = 11; 123 124 // The time (in millisecs) to delay the pairing attempt after the first 125 // auto pairing attempt fails. We use an exponential delay with 126 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and 127 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value. 128 private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000; 129 private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000; 130 131 // The timeout used to sent the UUIDs Intent 132 // This timeout should be greater than the page timeout 133 private static final int UUID_INTENT_DELAY = 6000; 134 135 /** Always retrieve RFCOMM channel for these SDP UUIDs */ 136 private static final ParcelUuid[] RFCOMM_UUIDS = { 137 BluetoothUuid.Handsfree, 138 BluetoothUuid.HSP, 139 BluetoothUuid.ObexObjectPush }; 140 141 private final BluetoothAdapterProperties mAdapterProperties; 142 private final BluetoothDeviceProperties mDeviceProperties; 143 144 private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache; 145 private final ArrayList<String> mUuidIntentTracker; 146 private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker; 147 148 private final HashMap<Integer, Pair<Integer, IBinder>> mServiceRecordToPid; 149 150 private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState; 151 private final BluetoothProfileState mA2dpProfileState; 152 private final BluetoothProfileState mHfpProfileState; 153 154 private BluetoothA2dpService mA2dpService; 155 private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData; 156 157 private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0; 158 159 private static String mDockAddress; 160 private String mDockPin; 161 162 private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED; 163 private BluetoothPanProfileHandler mBluetoothPanProfileHandler; 164 private BluetoothInputProfileHandler mBluetoothInputProfileHandler; 165 private BluetoothHealthProfileHandler mBluetoothHealthProfileHandler; 166 private static final String INCOMING_CONNECTION_FILE = 167 "/data/misc/bluetooth/incoming_connection.conf"; 168 private HashMap<String, Pair<Integer, String>> mIncomingConnections; 169 private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState; 170 171 private static class RemoteService { 172 public String address; 173 public ParcelUuid uuid; 174 public RemoteService(String address, ParcelUuid uuid) { 175 this.address = address; 176 this.uuid = uuid; 177 } 178 @Override 179 public boolean equals(Object o) { 180 if (o instanceof RemoteService) { 181 RemoteService service = (RemoteService)o; 182 return address.equals(service.address) && uuid.equals(service.uuid); 183 } 184 return false; 185 } 186 187 @Override 188 public int hashCode() { 189 int hash = 1; 190 hash = hash * 31 + (address == null ? 0 : address.hashCode()); 191 hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode()); 192 return hash; 193 } 194 } 195 196 static { 197 classInitNative(); 198 } 199 200 public BluetoothService(Context context) { 201 mContext = context; 202 203 // Need to do this in place of: 204 // mBatteryStats = BatteryStatsService.getService(); 205 // Since we can not import BatteryStatsService from here. This class really needs to be 206 // moved to java/services/com/android/server/ 207 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 208 209 initializeNativeDataNative(); 210 211 if (isEnabledNative() == 1) { 212 Log.w(TAG, "Bluetooth daemons already running - runtime restart? "); 213 disableNative(); 214 } 215 216 mBondState = new BluetoothBondState(context, this); 217 mAdapterProperties = new BluetoothAdapterProperties(context, this); 218 mDeviceProperties = new BluetoothDeviceProperties(this); 219 220 mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>(); 221 mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>(); 222 mUuidIntentTracker = new ArrayList<String>(); 223 mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); 224 mServiceRecordToPid = new HashMap<Integer, Pair<Integer, IBinder>>(); 225 mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>(); 226 mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP); 227 mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP); 228 229 mHfpProfileState.start(); 230 mA2dpProfileState.start(); 231 232 IntentFilter filter = new IntentFilter(); 233 registerForAirplaneMode(filter); 234 235 filter.addAction(Intent.ACTION_DOCK_EVENT); 236 mContext.registerReceiver(mReceiver, filter); 237 mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, this); 238 mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this); 239 mBluetoothHealthProfileHandler = BluetoothHealthProfileHandler.getInstance(mContext, this); 240 mIncomingConnections = new HashMap<String, Pair<Integer, String>>(); 241 mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>(); 242 } 243 244 public static synchronized String readDockBluetoothAddress() { 245 if (mDockAddress != null) return mDockAddress; 246 247 BufferedInputStream file = null; 248 String dockAddress; 249 try { 250 file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH)); 251 byte[] address = new byte[17]; 252 file.read(address); 253 dockAddress = new String(address); 254 dockAddress = dockAddress.toUpperCase(); 255 if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) { 256 mDockAddress = dockAddress; 257 return mDockAddress; 258 } else { 259 Log.e(TAG, "CheckBluetoothAddress failed for car dock address: " 260 + dockAddress); 261 } 262 } catch (FileNotFoundException e) { 263 Log.e(TAG, "FileNotFoundException while trying to read dock address"); 264 } catch (IOException e) { 265 Log.e(TAG, "IOException while trying to read dock address"); 266 } finally { 267 if (file != null) { 268 try { 269 file.close(); 270 } catch (IOException e) { 271 // Ignore 272 } 273 } 274 } 275 mDockAddress = null; 276 return null; 277 } 278 279 private synchronized boolean writeDockPin() { 280 BufferedWriter out = null; 281 try { 282 out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH)); 283 284 // Generate a random 4 digit pin between 0000 and 9999 285 // This is not truly random but good enough for our purposes. 286 int pin = (int) Math.floor(Math.random() * 10000); 287 288 mDockPin = String.format("%04d", pin); 289 out.write(mDockPin); 290 return true; 291 } catch (FileNotFoundException e) { 292 Log.e(TAG, "FileNotFoundException while trying to write dock pairing pin"); 293 } catch (IOException e) { 294 Log.e(TAG, "IOException while while trying to write dock pairing pin"); 295 } finally { 296 if (out != null) { 297 try { 298 out.close(); 299 } catch (IOException e) { 300 // Ignore 301 } 302 } 303 } 304 mDockPin = null; 305 return false; 306 } 307 308 /*package*/ synchronized String getDockPin() { 309 return mDockPin; 310 } 311 312 public synchronized void initAfterRegistration() { 313 mAdapter = BluetoothAdapter.getDefaultAdapter(); 314 mBluetoothState = new BluetoothAdapterStateMachine(mContext, this, mAdapter); 315 mBluetoothState.start(); 316 if (mContext.getResources().getBoolean 317 (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { 318 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT); 319 } 320 mEventLoop = mBluetoothState.getBluetoothEventLoop(); 321 } 322 323 public synchronized void initAfterA2dpRegistration() { 324 mEventLoop.getProfileProxy(); 325 } 326 327 @Override 328 protected void finalize() throws Throwable { 329 mContext.unregisterReceiver(mReceiver); 330 try { 331 cleanupNativeDataNative(); 332 } finally { 333 super.finalize(); 334 } 335 } 336 337 public boolean isEnabled() { 338 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 339 return isEnabledInternal(); 340 } 341 342 private boolean isEnabledInternal() { 343 return (getBluetoothStateInternal() == BluetoothAdapter.STATE_ON); 344 } 345 346 public int getBluetoothState() { 347 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 348 return getBluetoothStateInternal(); 349 } 350 351 int getBluetoothStateInternal() { 352 return mBluetoothState.getBluetoothAdapterState(); 353 } 354 355 /** 356 * Bring down bluetooth and disable BT in settings. Returns true on success. 357 */ 358 public boolean disable() { 359 return disable(true); 360 } 361 362 /** 363 * Bring down bluetooth. Returns true on success. 364 * 365 * @param saveSetting If true, persist the new setting 366 */ 367 public synchronized boolean disable(boolean saveSetting) { 368 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 369 370 int adapterState = getBluetoothStateInternal(); 371 372 switch (adapterState) { 373 case BluetoothAdapter.STATE_OFF: 374 return true; 375 case BluetoothAdapter.STATE_ON: 376 break; 377 default: 378 return false; 379 } 380 381 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_OFF, saveSetting); 382 return true; 383 } 384 385 synchronized void disconnectDevices() { 386 // Disconnect devices handled by BluetoothService. 387 for (BluetoothDevice device: getConnectedInputDevices()) { 388 disconnectInputDevice(device); 389 } 390 391 for (BluetoothDevice device: getConnectedPanDevices()) { 392 disconnectPanDevice(device); 393 } 394 } 395 396 /** 397 * The Bluetooth has been turned off, but hot. Do bonding, profile cleanup 398 */ 399 synchronized void finishDisable() { 400 // mark in progress bondings as cancelled 401 for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) { 402 mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 403 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 404 } 405 406 // Stop the profile state machine for bonded devices. 407 for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDED)) { 408 removeProfileState(address); 409 } 410 411 // update mode 412 Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 413 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE); 414 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 415 } 416 417 /** 418 * Local clean up after broadcasting STATE_OFF intent 419 */ 420 synchronized void cleanupAfterFinishDisable() { 421 mAdapterProperties.clear(); 422 423 for (Integer srHandle : mServiceRecordToPid.keySet()) { 424 removeServiceRecordNative(srHandle); 425 } 426 mServiceRecordToPid.clear(); 427 428 mProfilesConnected = 0; 429 mProfilesConnecting = 0; 430 mProfilesDisconnecting = 0; 431 mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED; 432 mAdapterUuids = null; 433 mAdapterSdpHandles = null; 434 435 // Log bluetooth off to battery stats. 436 long ident = Binder.clearCallingIdentity(); 437 try { 438 mBatteryStats.noteBluetoothOff(); 439 } catch (RemoteException e) { 440 } finally { 441 Binder.restoreCallingIdentity(ident); 442 } 443 } 444 445 /** 446 * power off Bluetooth 447 */ 448 synchronized void shutoffBluetooth() { 449 if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles); 450 setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE, 451 BluetoothPanProfileHandler.NAP_BRIDGE); 452 tearDownNativeDataNative(); 453 } 454 455 /** 456 * Data clean up after Bluetooth shutoff 457 */ 458 synchronized void cleanNativeAfterShutoffBluetooth() { 459 // Ths method is called after shutdown of event loop in the Bluetooth shut down 460 // procedure 461 462 // the adapter property could be changed before event loop is stoped, clear it again 463 mAdapterProperties.clear(); 464 disableNative(); 465 } 466 467 /** Bring up BT and persist BT on in settings */ 468 public boolean enable() { 469 return enable(true); 470 } 471 472 /** 473 * Enable this Bluetooth device, asynchronously. 474 * This turns on/off the underlying hardware. 475 * 476 * @param saveSetting If true, persist the new state of BT in settings 477 * @return True on success (so far) 478 */ 479 public synchronized boolean enable(boolean saveSetting) { 480 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 481 "Need BLUETOOTH_ADMIN permission"); 482 483 // Airplane mode can prevent Bluetooth radio from being turned on. 484 if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { 485 return false; 486 } 487 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting); 488 return true; 489 } 490 491 /** 492 * Turn on Bluetooth Module, Load firmware, and do all the preparation 493 * needed to get the Bluetooth Module ready but keep it not discoverable 494 * and not connectable. 495 */ 496 /* package */ synchronized boolean prepareBluetooth() { 497 if (!setupNativeDataNative()) { 498 return false; 499 } 500 switchConnectable(false); 501 updateSdpRecords(); 502 return true; 503 } 504 505 private final Handler mHandler = new Handler() { 506 @Override 507 public void handleMessage(Message msg) { 508 switch (msg.what) { 509 case MESSAGE_UUID_INTENT: 510 String address = (String)msg.obj; 511 if (address != null) { 512 sendUuidIntent(address); 513 makeServiceChannelCallbacks(address); 514 } 515 break; 516 case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY: 517 address = (String)msg.obj; 518 if (address == null) return; 519 int attempt = mBondState.getAttempt(address); 520 521 // Try only if attemps are in progress and cap it 2 attempts 522 // The 2 attempts cap is a fail safe if the stack returns 523 // an incorrect error code for bonding failures and if the pin 524 // is entered wrongly twice we should abort. 525 if (attempt > 0 && attempt <= 2) { 526 mBondState.attempt(address); 527 createBond(address); 528 return; 529 } 530 if (attempt > 0) mBondState.clearPinAttempts(address); 531 break; 532 case MESSAGE_REMOVE_SERVICE_RECORD: 533 Pair<Integer, Integer> pair = (Pair<Integer, Integer>) msg.obj; 534 checkAndRemoveRecord(pair.first, pair.second); 535 break; 536 } 537 } 538 }; 539 540 private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) { 541 //Register SDP records. 542 int[] svcIdentifiers = new int[uuids.size()]; 543 for (int i = 0; i < uuids.size(); i++) { 544 svcIdentifiers[i] = BluetoothUuid.getServiceIdentifierFromParcelUuid(uuids.get(i)); 545 } 546 mAdapterSdpHandles = addReservedServiceRecordsNative(svcIdentifiers); 547 } 548 549 private synchronized void updateSdpRecords() { 550 ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>(); 551 552 // Add the default records 553 uuids.add(BluetoothUuid.HSP_AG); 554 uuids.add(BluetoothUuid.ObexObjectPush); 555 556 if (mContext.getResources(). 557 getBoolean(com.android.internal.R.bool.config_voice_capable)) { 558 uuids.add(BluetoothUuid.Handsfree_AG); 559 uuids.add(BluetoothUuid.PBAP_PSE); 560 } 561 562 // Add SDP records for profiles maintained by Android userspace 563 addReservedSdpRecords(uuids); 564 565 // Enable profiles maintained by Bluez userspace. 566 setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE, 567 BluetoothPanProfileHandler.NAP_BRIDGE); 568 569 // Add SDP records for profiles maintained by Bluez userspace 570 uuids.add(BluetoothUuid.AudioSource); 571 uuids.add(BluetoothUuid.AvrcpTarget); 572 uuids.add(BluetoothUuid.NAP); 573 574 // Cannot cast uuids.toArray directly since ParcelUuid is parcelable 575 mAdapterUuids = new ParcelUuid[uuids.size()]; 576 for (int i = 0; i < uuids.size(); i++) { 577 mAdapterUuids[i] = uuids.get(i); 578 } 579 } 580 581 /** 582 * This function is called from Bluetooth Event Loop when onPropertyChanged 583 * for adapter comes in with UUID property. 584 * @param uuidsThe uuids of adapter as reported by Bluez. 585 */ 586 /*package*/ synchronized void updateBluetoothState(String uuids) { 587 ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids); 588 589 if (mAdapterUuids != null && 590 BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) { 591 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED); 592 } 593 } 594 595 /** 596 * This method is called immediately before Bluetooth module is turned on after 597 * the adapter became pariable. 598 * It inits bond state and profile state before STATE_ON intent is broadcasted. 599 */ 600 /*package*/ void initBluetoothAfterTurningOn() { 601 String discoverable = getProperty("Discoverable", false); 602 String timeout = getProperty("DiscoverableTimeout", false); 603 if (discoverable.equals("true") && Integer.valueOf(timeout) != 0) { 604 setAdapterPropertyBooleanNative("Discoverable", 0); 605 } 606 mBondState.initBondState(); 607 initProfileState(); 608 } 609 610 /** 611 * This method is called immediately after Bluetooth module is turned on. 612 * It starts auto-connection and places bluetooth on sign onto the battery 613 * stats 614 */ 615 /*package*/ void runBluetooth() { 616 autoConnect(); 617 618 // Log bluetooth on to battery stats. 619 long ident = Binder.clearCallingIdentity(); 620 try { 621 mBatteryStats.noteBluetoothOn(); 622 } catch (RemoteException e) { 623 Log.e(TAG, "", e); 624 } finally { 625 Binder.restoreCallingIdentity(ident); 626 } 627 } 628 629 /*package*/ synchronized boolean attemptAutoPair(String address) { 630 if (!mBondState.hasAutoPairingFailed(address) && 631 !mBondState.isAutoPairingBlacklisted(address)) { 632 mBondState.attempt(address); 633 setPin(address, BluetoothDevice.convertPinToBytes("0000")); 634 return true; 635 } 636 return false; 637 } 638 639 /*package*/ synchronized boolean isFixedPinZerosAutoPairKeyboard(String address) { 640 // Check for keyboards which have fixed PIN 0000 as the pairing pin 641 return mBondState.isFixedPinZerosAutoPairKeyboard(address); 642 } 643 644 /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) { 645 if (result == BluetoothDevice.BOND_SUCCESS) { 646 setBondState(address, BluetoothDevice.BOND_BONDED); 647 if (mBondState.isAutoPairingAttemptsInProgress(address)) { 648 mBondState.clearPinAttempts(address); 649 } 650 } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED && 651 mBondState.getAttempt(address) == 1) { 652 mBondState.addAutoPairingFailure(address); 653 pairingAttempt(address, result); 654 } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN && 655 mBondState.isAutoPairingAttemptsInProgress(address)) { 656 pairingAttempt(address, result); 657 } else { 658 setBondState(address, BluetoothDevice.BOND_NONE, result); 659 if (mBondState.isAutoPairingAttemptsInProgress(address)) { 660 mBondState.clearPinAttempts(address); 661 } 662 } 663 } 664 665 /*package*/ synchronized String getPendingOutgoingBonding() { 666 return mBondState.getPendingOutgoingBonding(); 667 } 668 669 private void pairingAttempt(String address, int result) { 670 // This happens when our initial guess of "0000" as the pass key 671 // fails. Try to create the bond again and display the pin dialog 672 // to the user. Use back-off while posting the delayed 673 // message. The initial value is 674 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is 675 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is 676 // reached, display an error to the user. 677 int attempt = mBondState.getAttempt(address); 678 if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY > 679 MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) { 680 mBondState.clearPinAttempts(address); 681 setBondState(address, BluetoothDevice.BOND_NONE, result); 682 return; 683 } 684 685 Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 686 message.obj = address; 687 boolean postResult = mHandler.sendMessageDelayed(message, 688 attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 689 if (!postResult) { 690 mBondState.clearPinAttempts(address); 691 setBondState(address, 692 BluetoothDevice.BOND_NONE, result); 693 return; 694 } 695 } 696 697 /*package*/ BluetoothDevice getRemoteDevice(String address) { 698 return mAdapter.getRemoteDevice(address); 699 } 700 701 private static String toBondStateString(int bondState) { 702 switch (bondState) { 703 case BluetoothDevice.BOND_NONE: 704 return "not bonded"; 705 case BluetoothDevice.BOND_BONDING: 706 return "bonding"; 707 case BluetoothDevice.BOND_BONDED: 708 return "bonded"; 709 default: 710 return "??????"; 711 } 712 } 713 714 public synchronized boolean setName(String name) { 715 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 716 "Need BLUETOOTH_ADMIN permission"); 717 if (name == null) { 718 return false; 719 } 720 return setPropertyString("Name", name); 721 } 722 723 //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean 724 // Either have a single property function with Object as the parameter 725 // or have a function for each property and then obfuscate in the JNI layer. 726 // The following looks dirty. 727 private boolean setPropertyString(String key, String value) { 728 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 729 if (!isEnabledInternal()) return false; 730 return setAdapterPropertyStringNative(key, value); 731 } 732 733 private boolean setPropertyInteger(String key, int value) { 734 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 735 if (!isEnabledInternal()) return false; 736 return setAdapterPropertyIntegerNative(key, value); 737 } 738 739 private boolean setPropertyBoolean(String key, boolean value) { 740 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 741 if (!isEnabledInternal()) return false; 742 return setAdapterPropertyBooleanNative(key, value ? 1 : 0); 743 } 744 745 /** 746 * Set the discoverability window for the device. A timeout of zero 747 * makes the device permanently discoverable (if the device is 748 * discoverable). Setting the timeout to a nonzero value does not make 749 * a device discoverable; you need to call setMode() to make the device 750 * explicitly discoverable. 751 * 752 * @param timeout The discoverable timeout in seconds. 753 */ 754 public synchronized boolean setDiscoverableTimeout(int timeout) { 755 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 756 "Need BLUETOOTH_ADMIN permission"); 757 return setPropertyInteger("DiscoverableTimeout", timeout); 758 } 759 760 public synchronized boolean setScanMode(int mode, int duration) { 761 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, 762 "Need WRITE_SECURE_SETTINGS permission"); 763 boolean pairable; 764 boolean discoverable; 765 766 switch (mode) { 767 case BluetoothAdapter.SCAN_MODE_NONE: 768 pairable = false; 769 discoverable = false; 770 break; 771 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 772 pairable = true; 773 discoverable = false; 774 break; 775 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 776 pairable = true; 777 discoverable = true; 778 if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds"); 779 break; 780 default: 781 Log.w(TAG, "Requested invalid scan mode " + mode); 782 return false; 783 } 784 785 setPropertyBoolean("Discoverable", discoverable); 786 setPropertyBoolean("Pairable", pairable); 787 return true; 788 } 789 790 /** 791 * @param on true set the local Bluetooth module to be connectable 792 * The dicoverability is recovered to what it was before 793 * switchConnectable(false) call 794 * false set the local Bluetooth module to be not connectable 795 * and not dicoverable 796 */ 797 /*package*/ synchronized void switchConnectable(boolean on) { 798 setAdapterPropertyBooleanNative("Powered", on ? 1 : 0); 799 } 800 801 /*package*/ synchronized void setPairable() { 802 String pairableString = getProperty("Pairable", false); 803 if (pairableString == null) { 804 Log.e(TAG, "null pairableString"); 805 return; 806 } 807 if (pairableString.equals("false")) { 808 setAdapterPropertyBooleanNative("Pairable", 1); 809 } 810 } 811 812 /*package*/ synchronized String getProperty(String name, boolean checkState) { 813 // If checkState is false, check if the event loop is running. 814 // before making the call to Bluez 815 if (checkState) { 816 if (!isEnabledInternal()) return null; 817 } else if (!mEventLoop.isEventLoopRunning()) { 818 return null; 819 } 820 821 return mAdapterProperties.getProperty(name); 822 } 823 824 BluetoothAdapterProperties getAdapterProperties() { 825 return mAdapterProperties; 826 } 827 828 BluetoothDeviceProperties getDeviceProperties() { 829 return mDeviceProperties; 830 } 831 832 boolean isRemoteDeviceInCache(String address) { 833 return mDeviceProperties.isInCache(address); 834 } 835 836 void setRemoteDeviceProperty(String address, String name, String value) { 837 mDeviceProperties.setProperty(address, name, value); 838 } 839 840 void updateRemoteDevicePropertiesCache(String address) { 841 mDeviceProperties.updateCache(address); 842 } 843 844 public synchronized String getAddress() { 845 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 846 // Don't check state since we want to provide address, even if BT is off 847 return getProperty("Address", false); 848 } 849 850 public synchronized String getName() { 851 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 852 // Don't check state since we want to provide name, even if BT is off 853 return getProperty("Name", false); 854 } 855 856 public synchronized ParcelUuid[] getUuids() { 857 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 858 String value = getProperty("UUIDs", true); 859 if (value == null) return null; 860 return convertStringToParcelUuid(value); 861 } 862 863 private synchronized ParcelUuid[] convertStringToParcelUuid(String value) { 864 String[] uuidStrings = null; 865 // The UUIDs are stored as a "," separated string. 866 uuidStrings = value.split(","); 867 ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length]; 868 869 for (int i = 0; i < uuidStrings.length; i++) { 870 uuids[i] = ParcelUuid.fromString(uuidStrings[i]); 871 } 872 return uuids; 873 } 874 875 /** 876 * Returns the user-friendly name of a remote device. This value is 877 * returned from our local cache, which is updated when onPropertyChange 878 * event is received. 879 * Do not expect to retrieve the updated remote name immediately after 880 * changing the name on the remote device. 881 * 882 * @param address Bluetooth address of remote device. 883 * 884 * @return The user-friendly name of the specified remote device. 885 */ 886 public synchronized String getRemoteName(String address) { 887 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 888 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 889 return null; 890 } 891 return mDeviceProperties.getProperty(address, "Name"); 892 } 893 894 /** 895 * Returns alias of a remote device. This value is returned from our 896 * local cache, which is updated when onPropertyChange event is received. 897 * 898 * @param address Bluetooth address of remote device. 899 * 900 * @return The alias of the specified remote device. 901 */ 902 public synchronized String getRemoteAlias(String address) { 903 904 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 905 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 906 return null; 907 } 908 return mDeviceProperties.getProperty(address, "Alias"); 909 } 910 911 /** 912 * Set the alias of a remote device. 913 * 914 * @param address Bluetooth address of remote device. 915 * @param alias new alias to change to 916 * @return true on success, false on error 917 */ 918 public synchronized boolean setRemoteAlias(String address, String alias) { 919 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 920 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 921 return false; 922 } 923 924 return setDevicePropertyStringNative(getObjectPathFromAddress(address), 925 "Alias", alias); 926 } 927 928 /** 929 * Get the discoverability window for the device. A timeout of zero 930 * means that the device is permanently discoverable (if the device is 931 * in the discoverable mode). 932 * 933 * @return The discoverability window of the device, in seconds. A negative 934 * value indicates an error. 935 */ 936 public synchronized int getDiscoverableTimeout() { 937 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 938 String timeout = getProperty("DiscoverableTimeout", true); 939 if (timeout != null) 940 return Integer.valueOf(timeout); 941 else 942 return -1; 943 } 944 945 public synchronized int getScanMode() { 946 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 947 if (!isEnabledInternal()) 948 return BluetoothAdapter.SCAN_MODE_NONE; 949 950 boolean pairable = getProperty("Pairable", true).equals("true"); 951 boolean discoverable = getProperty("Discoverable", true).equals("true"); 952 return bluezStringToScanMode (pairable, discoverable); 953 } 954 955 public synchronized boolean startDiscovery() { 956 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 957 "Need BLUETOOTH_ADMIN permission"); 958 if (!isEnabledInternal()) return false; 959 960 return startDiscoveryNative(); 961 } 962 963 public synchronized boolean cancelDiscovery() { 964 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 965 "Need BLUETOOTH_ADMIN permission"); 966 if (!isEnabledInternal()) return false; 967 968 return stopDiscoveryNative(); 969 } 970 971 public synchronized boolean isDiscovering() { 972 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 973 974 String discoveringProperty = getProperty("Discovering", false); 975 if (discoveringProperty == null) { 976 return false; 977 } 978 979 return discoveringProperty.equals("true"); 980 } 981 982 private boolean isBondingFeasible(String address) { 983 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 984 "Need BLUETOOTH_ADMIN permission"); 985 if (!isEnabledInternal()) return false; 986 987 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 988 return false; 989 } 990 address = address.toUpperCase(); 991 992 if (mBondState.getPendingOutgoingBonding() != null) { 993 Log.d(TAG, "Ignoring createBond(): another device is bonding"); 994 // a different device is currently bonding, fail 995 return false; 996 } 997 998 // Check for bond state only if we are not performing auto 999 // pairing exponential back-off attempts. 1000 if (!mBondState.isAutoPairingAttemptsInProgress(address) && 1001 mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) { 1002 Log.d(TAG, "Ignoring createBond(): this device is already bonding or bonded"); 1003 return false; 1004 } 1005 1006 if (address.equals(mDockAddress)) { 1007 if (!writeDockPin()) { 1008 Log.e(TAG, "Error while writing Pin for the dock"); 1009 return false; 1010 } 1011 } 1012 return true; 1013 } 1014 1015 public synchronized boolean createBond(String address) { 1016 if (!isBondingFeasible(address)) return false; 1017 1018 if (!createPairedDeviceNative(address, 60000 /*1 minute*/ )) { 1019 return false; 1020 } 1021 1022 mBondState.setPendingOutgoingBonding(address); 1023 mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 1024 1025 return true; 1026 } 1027 1028 public synchronized boolean createBondOutOfBand(String address, byte[] hash, 1029 byte[] randomizer) { 1030 if (!isBondingFeasible(address)) return false; 1031 1032 if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) { 1033 return false; 1034 } 1035 1036 setDeviceOutOfBandData(address, hash, randomizer); 1037 mBondState.setPendingOutgoingBonding(address); 1038 mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); 1039 1040 return true; 1041 } 1042 1043 public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash, 1044 byte[] randomizer) { 1045 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1046 "Need BLUETOOTH_ADMIN permission"); 1047 if (!isEnabledInternal()) return false; 1048 1049 Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer); 1050 1051 if (DBG) { 1052 Log.d(TAG, "Setting out of band data for: " + address + ":" + 1053 Arrays.toString(hash) + ":" + Arrays.toString(randomizer)); 1054 } 1055 1056 mDeviceOobData.put(address, value); 1057 return true; 1058 } 1059 1060 Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) { 1061 return mDeviceOobData.get(device.getAddress()); 1062 } 1063 1064 1065 public synchronized byte[] readOutOfBandData() { 1066 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1067 "Need BLUETOOTH permission"); 1068 if (!isEnabledInternal()) return null; 1069 1070 return readAdapterOutOfBandDataNative(); 1071 } 1072 1073 public synchronized boolean cancelBondProcess(String address) { 1074 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1075 "Need BLUETOOTH_ADMIN permission"); 1076 if (!isEnabledInternal()) return false; 1077 1078 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1079 return false; 1080 } 1081 address = address.toUpperCase(); 1082 if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) { 1083 return false; 1084 } 1085 1086 mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 1087 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 1088 cancelDeviceCreationNative(address); 1089 return true; 1090 } 1091 1092 public synchronized boolean removeBond(String address) { 1093 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1094 "Need BLUETOOTH_ADMIN permission"); 1095 if (!isEnabledInternal()) return false; 1096 1097 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1098 return false; 1099 } 1100 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 1101 if (state != null) { 1102 state.sendMessage(BluetoothDeviceProfileState.UNPAIR); 1103 return true; 1104 } else { 1105 return false; 1106 } 1107 } 1108 1109 public synchronized boolean removeBondInternal(String address) { 1110 // Unset the trusted device state and then unpair 1111 setTrust(address, false); 1112 return removeDeviceNative(getObjectPathFromAddress(address)); 1113 } 1114 1115 public synchronized String[] listBonds() { 1116 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1117 return mBondState.listInState(BluetoothDevice.BOND_BONDED); 1118 } 1119 1120 /*package*/ synchronized String[] listInState(int state) { 1121 return mBondState.listInState(state); 1122 } 1123 1124 public synchronized int getBondState(String address) { 1125 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1126 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1127 return BluetoothDevice.ERROR; 1128 } 1129 return mBondState.getBondState(address.toUpperCase()); 1130 } 1131 1132 /*package*/ synchronized boolean setBondState(String address, int state) { 1133 return setBondState(address, state, 0); 1134 } 1135 1136 /*package*/ synchronized boolean setBondState(String address, int state, int reason) { 1137 mBondState.setBondState(address.toUpperCase(), state, reason); 1138 return true; 1139 } 1140 1141 public synchronized boolean isBluetoothDock(String address) { 1142 SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 1143 Context.MODE_PRIVATE); 1144 1145 return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address); 1146 } 1147 1148 /*package*/ String[] getRemoteDeviceProperties(String address) { 1149 if (!isEnabledInternal()) return null; 1150 1151 String objectPath = getObjectPathFromAddress(address); 1152 return (String [])getDevicePropertiesNative(objectPath); 1153 } 1154 1155 /** 1156 * Sets the remote device trust state. 1157 * 1158 * @return boolean to indicate operation success or fail 1159 */ 1160 public synchronized boolean setTrust(String address, boolean value) { 1161 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1162 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1163 "Need BLUETOOTH_ADMIN permission"); 1164 return false; 1165 } 1166 1167 if (!isEnabledInternal()) return false; 1168 1169 return setDevicePropertyBooleanNative( 1170 getObjectPathFromAddress(address), "Trusted", value ? 1 : 0); 1171 } 1172 1173 /** 1174 * Gets the remote device trust state as boolean. 1175 * Note: this value may be 1176 * retrieved from cache if we retrieved the data before * 1177 * 1178 * @return boolean to indicate trusted or untrusted state 1179 */ 1180 public synchronized boolean getTrustState(String address) { 1181 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1182 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1183 return false; 1184 } 1185 1186 String val = mDeviceProperties.getProperty(address, "Trusted"); 1187 if (val == null) { 1188 return false; 1189 } else { 1190 return val.equals("true"); 1191 } 1192 } 1193 1194 /** 1195 * Gets the remote major, minor classes encoded as a 32-bit 1196 * integer. 1197 * 1198 * Note: this value is retrieved from cache, because we get it during 1199 * remote-device discovery. 1200 * 1201 * @return 32-bit integer encoding the remote major, minor, and service 1202 * classes. 1203 */ 1204 public synchronized int getRemoteClass(String address) { 1205 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1206 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1207 return BluetoothClass.ERROR; 1208 } 1209 String val = mDeviceProperties.getProperty(address, "Class"); 1210 if (val == null) 1211 return BluetoothClass.ERROR; 1212 else { 1213 return Integer.valueOf(val); 1214 } 1215 } 1216 1217 1218 /** 1219 * Gets the UUIDs supported by the remote device 1220 * 1221 * @return array of 128bit ParcelUuids 1222 */ 1223 public synchronized ParcelUuid[] getRemoteUuids(String address) { 1224 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1225 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1226 return null; 1227 } 1228 return getUuidFromCache(address); 1229 } 1230 1231 ParcelUuid[] getUuidFromCache(String address) { 1232 String value = mDeviceProperties.getProperty(address, "UUIDs"); 1233 if (value == null) return null; 1234 1235 String[] uuidStrings = null; 1236 // The UUIDs are stored as a "," separated string. 1237 uuidStrings = value.split(","); 1238 ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length]; 1239 1240 for (int i = 0; i < uuidStrings.length; i++) { 1241 uuids[i] = ParcelUuid.fromString(uuidStrings[i]); 1242 } 1243 return uuids; 1244 } 1245 1246 /** 1247 * Connect and fetch new UUID's using SDP. 1248 * The UUID's found are broadcast as intents. 1249 * Optionally takes a uuid and callback to fetch the RFCOMM channel for the 1250 * a given uuid. 1251 * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success 1252 * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for 1253 * callback and broadcast intents. 1254 */ 1255 public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid, 1256 IBluetoothCallback callback) { 1257 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1258 if (!isEnabledInternal()) return false; 1259 1260 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1261 return false; 1262 } 1263 1264 RemoteService service = new RemoteService(address, uuid); 1265 if (uuid != null && mUuidCallbackTracker.get(service) != null) { 1266 // An SDP query for this address & uuid is already in progress 1267 // Do not add this callback for the uuid 1268 return false; 1269 } 1270 1271 if (mUuidIntentTracker.contains(address)) { 1272 // An SDP query for this address is already in progress 1273 // Add this uuid onto the in-progress SDP query 1274 if (uuid != null) { 1275 mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 1276 } 1277 return true; 1278 } 1279 1280 // If the device is already created, we will 1281 // do the SDP on the callback of createDeviceNative. 1282 boolean ret= createDeviceNative(address); 1283 1284 mUuidIntentTracker.add(address); 1285 if (uuid != null) { 1286 mUuidCallbackTracker.put(new RemoteService(address, uuid), callback); 1287 } 1288 1289 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 1290 message.obj = address; 1291 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 1292 return ret; 1293 } 1294 1295 /** 1296 * Gets the rfcomm channel associated with the UUID. 1297 * Pulls records from the cache only. 1298 * 1299 * @param address Address of the remote device 1300 * @param uuid ParcelUuid of the service attribute 1301 * 1302 * @return rfcomm channel associated with the service attribute 1303 * -1 on error 1304 */ 1305 public int getRemoteServiceChannel(String address, ParcelUuid uuid) { 1306 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1307 if (!isEnabledInternal()) return -1; 1308 1309 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1310 return BluetoothDevice.ERROR; 1311 } 1312 // Check if we are recovering from a crash. 1313 if (mDeviceProperties.isEmpty()) { 1314 if (mDeviceProperties.updateCache(address) == null) 1315 return -1; 1316 } 1317 1318 Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address); 1319 if (value != null && value.containsKey(uuid)) 1320 return value.get(uuid); 1321 return -1; 1322 } 1323 1324 public synchronized boolean setPin(String address, byte[] pin) { 1325 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1326 "Need BLUETOOTH_ADMIN permission"); 1327 if (!isEnabledInternal()) return false; 1328 1329 if (pin == null || pin.length <= 0 || pin.length > 16 || 1330 !BluetoothAdapter.checkBluetoothAddress(address)) { 1331 return false; 1332 } 1333 address = address.toUpperCase(); 1334 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1335 if (data == null) { 1336 Log.w(TAG, "setPin(" + address + ") called but no native data available, " + 1337 "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1338 " or by bluez.\n"); 1339 return false; 1340 } 1341 // bluez API wants pin as a string 1342 String pinString; 1343 try { 1344 pinString = new String(pin, "UTF8"); 1345 } catch (UnsupportedEncodingException uee) { 1346 Log.e(TAG, "UTF8 not supported?!?"); 1347 return false; 1348 } 1349 return setPinNative(address, pinString, data.intValue()); 1350 } 1351 1352 public synchronized boolean setPasskey(String address, int passkey) { 1353 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1354 "Need BLUETOOTH_ADMIN permission"); 1355 if (!isEnabledInternal()) return false; 1356 1357 if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) { 1358 return false; 1359 } 1360 address = address.toUpperCase(); 1361 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1362 if (data == null) { 1363 Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1364 "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1365 " or by bluez.\n"); 1366 return false; 1367 } 1368 return setPasskeyNative(address, passkey, data.intValue()); 1369 } 1370 1371 public synchronized boolean setPairingConfirmation(String address, boolean confirm) { 1372 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1373 "Need BLUETOOTH_ADMIN permission"); 1374 if (!isEnabledInternal()) return false; 1375 1376 address = address.toUpperCase(); 1377 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1378 if (data == null) { 1379 Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " + 1380 "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1381 " or by bluez.\n"); 1382 return false; 1383 } 1384 return setPairingConfirmationNative(address, confirm, data.intValue()); 1385 } 1386 1387 public synchronized boolean setRemoteOutOfBandData(String address) { 1388 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1389 "Need BLUETOOTH_ADMIN permission"); 1390 if (!isEnabledInternal()) return false; 1391 address = address.toUpperCase(); 1392 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1393 if (data == null) { 1394 Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " + 1395 "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + 1396 " or by bluez.\n"); 1397 return false; 1398 } 1399 1400 Pair<byte[], byte[]> val = mDeviceOobData.get(address); 1401 byte[] hash, randomizer; 1402 if (val == null) { 1403 // TODO: check what should be passed in this case. 1404 hash = new byte[16]; 1405 randomizer = new byte[16]; 1406 } else { 1407 hash = val.first; 1408 randomizer = val.second; 1409 } 1410 return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue()); 1411 } 1412 1413 public synchronized boolean cancelPairingUserInput(String address) { 1414 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 1415 "Need BLUETOOTH_ADMIN permission"); 1416 if (!isEnabledInternal()) return false; 1417 1418 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1419 return false; 1420 } 1421 mBondState.setBondState(address, BluetoothDevice.BOND_NONE, 1422 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); 1423 address = address.toUpperCase(); 1424 Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); 1425 if (data == null) { 1426 Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " + 1427 "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " + 1428 "by the remote or by bluez.\n"); 1429 return false; 1430 } 1431 return cancelPairingUserInputNative(address, data.intValue()); 1432 } 1433 1434 /*package*/ void updateDeviceServiceChannelCache(String address) { 1435 if (DBG) Log.d(TAG, "updateDeviceServiceChannelCache(" + address + ")"); 1436 1437 // We are storing the rfcomm channel numbers only for the uuids 1438 // we are interested in. 1439 ParcelUuid[] deviceUuids = getRemoteUuids(address); 1440 1441 ArrayList<ParcelUuid> applicationUuids = new ArrayList<ParcelUuid>(); 1442 1443 synchronized (this) { 1444 for (RemoteService service : mUuidCallbackTracker.keySet()) { 1445 if (service.address.equals(address)) { 1446 applicationUuids.add(service.uuid); 1447 } 1448 } 1449 } 1450 1451 Map <ParcelUuid, Integer> uuidToChannelMap = new HashMap<ParcelUuid, Integer>(); 1452 1453 // Retrieve RFCOMM channel for default uuids 1454 for (ParcelUuid uuid : RFCOMM_UUIDS) { 1455 if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 1456 int channel = getDeviceServiceChannelForUuid(address, uuid); 1457 uuidToChannelMap.put(uuid, channel); 1458 if (DBG) Log.d(TAG, "\tuuid(system): " + uuid + " " + channel); 1459 } 1460 } 1461 // Retrieve RFCOMM channel for application requested uuids 1462 for (ParcelUuid uuid : applicationUuids) { 1463 if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { 1464 int channel = getDeviceServiceChannelForUuid(address, uuid); 1465 uuidToChannelMap.put(uuid, channel); 1466 if (DBG) Log.d(TAG, "\tuuid(application): " + uuid + " " + channel); 1467 } 1468 } 1469 1470 synchronized (this) { 1471 // Make application callbacks 1472 for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 1473 iter.hasNext();) { 1474 RemoteService service = iter.next(); 1475 if (service.address.equals(address)) { 1476 if (uuidToChannelMap.containsKey(service.uuid)) { 1477 int channel = uuidToChannelMap.get(service.uuid); 1478 1479 if (DBG) Log.d(TAG, "Making callback for " + service.uuid + 1480 " with result " + channel); 1481 IBluetoothCallback callback = mUuidCallbackTracker.get(service); 1482 if (callback != null) { 1483 try { 1484 callback.onRfcommChannelFound(channel); 1485 } catch (RemoteException e) {Log.e(TAG, "", e);} 1486 } 1487 1488 iter.remove(); 1489 } 1490 } 1491 } 1492 1493 // Update cache 1494 mDeviceServiceChannelCache.put(address, uuidToChannelMap); 1495 } 1496 } 1497 1498 private int getDeviceServiceChannelForUuid(String address, 1499 ParcelUuid uuid) { 1500 return getDeviceServiceChannelNative(getObjectPathFromAddress(address), 1501 uuid.toString(), 0x0004); 1502 } 1503 1504 /** 1505 * b is a handle to a Binder instance, so that this service can be notified 1506 * for Applications that terminate unexpectedly, to clean there service 1507 * records 1508 */ 1509 public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid, 1510 int channel, IBinder b) { 1511 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1512 if (!isEnabledInternal()) return -1; 1513 1514 if (serviceName == null || uuid == null || channel < 1 || 1515 channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) { 1516 return -1; 1517 } 1518 if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) { 1519 Log.w(TAG, "Attempted to register a reserved UUID: " + uuid); 1520 return -1; 1521 } 1522 int handle = addRfcommServiceRecordNative(serviceName, 1523 uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(), 1524 (short)channel); 1525 if (DBG) Log.d(TAG, "new handle " + Integer.toHexString(handle)); 1526 if (handle == -1) { 1527 return -1; 1528 } 1529 1530 int pid = Binder.getCallingPid(); 1531 mServiceRecordToPid.put(new Integer(handle), new Pair<Integer, IBinder>(pid, b)); 1532 try { 1533 b.linkToDeath(new Reaper(handle, pid, RFCOMM_RECORD_REAPER), 0); 1534 } catch (RemoteException e) {Log.e(TAG, "", e);} 1535 return handle; 1536 } 1537 1538 public void removeServiceRecord(int handle) { 1539 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1540 "Need BLUETOOTH permission"); 1541 // Since this is a binder call check if Bluetooth is off 1542 if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return; 1543 Message message = mHandler.obtainMessage(MESSAGE_REMOVE_SERVICE_RECORD); 1544 message.obj = new Pair<Integer, Integer>(handle, Binder.getCallingPid()); 1545 mHandler.sendMessage(message); 1546 } 1547 1548 private synchronized void checkAndRemoveRecord(int handle, int pid) { 1549 Pair<Integer, IBinder> pidPair = mServiceRecordToPid.get(handle); 1550 if (pidPair != null && pid == pidPair.first) { 1551 if (DBG) Log.d(TAG, "Removing service record " + 1552 Integer.toHexString(handle) + " for pid " + pid); 1553 mServiceRecordToPid.remove(handle); 1554 removeServiceRecordNative(handle); 1555 } 1556 } 1557 1558 private class Reaper implements IBinder.DeathRecipient { 1559 int mPid; 1560 int mHandle; 1561 int mType; 1562 1563 Reaper(int handle, int pid, int type) { 1564 mPid = pid; 1565 mHandle = handle; 1566 mType = type; 1567 } 1568 1569 Reaper(int pid, int type) { 1570 mPid = pid; 1571 mType = type; 1572 } 1573 1574 @Override 1575 public void binderDied() { 1576 synchronized (BluetoothService.this) { 1577 if (DBG) Log.d(TAG, "Tracked app " + mPid + " died" + "Type:" + mType); 1578 if (mType == RFCOMM_RECORD_REAPER) { 1579 checkAndRemoveRecord(mHandle, mPid); 1580 } else if (mType == STATE_CHANGE_REAPER) { 1581 mStateChangeTracker.remove(mPid); 1582 } 1583 } 1584 } 1585 } 1586 1587 1588 @Override 1589 public boolean changeApplicationBluetoothState(boolean on, 1590 IBluetoothStateChangeCallback callback, IBinder binder) { 1591 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1592 1593 int pid = Binder.getCallingPid(); 1594 //mStateChangeTracker is a synchronized map 1595 if (!mStateChangeTracker.containsKey(pid)) { 1596 if (on) { 1597 mStateChangeTracker.put(pid, callback); 1598 } else { 1599 return false; 1600 } 1601 } else if (!on) { 1602 mStateChangeTracker.remove(pid); 1603 } 1604 1605 if (binder != null) { 1606 try { 1607 binder.linkToDeath(new Reaper(pid, STATE_CHANGE_REAPER), 0); 1608 } catch (RemoteException e) { 1609 Log.e(TAG, "", e); 1610 return false; 1611 } 1612 } 1613 1614 int type; 1615 if (on) { 1616 type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_ON; 1617 } else { 1618 type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_OFF; 1619 } 1620 1621 mBluetoothState.sendMessage(type, callback); 1622 return true; 1623 } 1624 1625 boolean isApplicationStateChangeTrackerEmpty() { 1626 return mStateChangeTracker.isEmpty(); 1627 } 1628 1629 void clearApplicationStateChangeTracker() { 1630 mStateChangeTracker.clear(); 1631 } 1632 1633 Collection<IBluetoothStateChangeCallback> getApplicationStateChangeCallbacks() { 1634 return mStateChangeTracker.values(); 1635 } 1636 1637 int getNumberOfApplicationStateChangeTrackers() { 1638 return mStateChangeTracker.size(); 1639 } 1640 1641 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 1642 @Override 1643 public void onReceive(Context context, Intent intent) { 1644 if (intent == null) return; 1645 1646 String action = intent.getAction(); 1647 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 1648 ContentResolver resolver = context.getContentResolver(); 1649 // Query the airplane mode from Settings.System just to make sure that 1650 // some random app is not sending this intent and disabling bluetooth 1651 if (isAirplaneModeOn()) { 1652 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_ON); 1653 } else { 1654 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_OFF); 1655 } 1656 } else if (Intent.ACTION_DOCK_EVENT.equals(action)) { 1657 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 1658 Intent.EXTRA_DOCK_STATE_UNDOCKED); 1659 if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state); 1660 if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) { 1661 mDockAddress = null; 1662 mDockPin = null; 1663 } else { 1664 SharedPreferences.Editor editor = 1665 mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, 1666 mContext.MODE_PRIVATE).edit(); 1667 editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true); 1668 editor.apply(); 1669 } 1670 } 1671 } 1672 }; 1673 1674 private void registerForAirplaneMode(IntentFilter filter) { 1675 final ContentResolver resolver = mContext.getContentResolver(); 1676 final String airplaneModeRadios = Settings.System.getString(resolver, 1677 Settings.System.AIRPLANE_MODE_RADIOS); 1678 final String toggleableRadios = Settings.System.getString(resolver, 1679 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 1680 1681 mIsAirplaneSensitive = airplaneModeRadios == null ? true : 1682 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 1683 mIsAirplaneToggleable = toggleableRadios == null ? false : 1684 toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 1685 1686 if (mIsAirplaneSensitive) { 1687 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 1688 } 1689 } 1690 1691 /* Returns true if airplane mode is currently on */ 1692 private final boolean isAirplaneModeOn() { 1693 return Settings.System.getInt(mContext.getContentResolver(), 1694 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 1695 } 1696 1697 /* Broadcast the Uuid intent */ 1698 /*package*/ synchronized void sendUuidIntent(String address) { 1699 ParcelUuid[] uuid = getUuidFromCache(address); 1700 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 1701 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 1702 intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid); 1703 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 1704 mUuidIntentTracker.remove(address); 1705 } 1706 1707 /*package*/ synchronized void makeServiceChannelCallbacks(String address) { 1708 for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator(); 1709 iter.hasNext();) { 1710 RemoteService service = iter.next(); 1711 if (service.address.equals(address)) { 1712 if (DBG) Log.d(TAG, "Cleaning up failed UUID channel lookup: " 1713 + service.address + " " + service.uuid); 1714 IBluetoothCallback callback = mUuidCallbackTracker.get(service); 1715 if (callback != null) { 1716 try { 1717 callback.onRfcommChannelFound(-1); 1718 } catch (RemoteException e) {Log.e(TAG, "", e);} 1719 } 1720 1721 iter.remove(); 1722 } 1723 } 1724 } 1725 1726 @Override 1727 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1728 if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) { 1729 return; 1730 } 1731 1732 pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive); 1733 pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable); 1734 1735 pw.println("Local address = " + getAddress()); 1736 pw.println("Local name = " + getName()); 1737 pw.println("isDiscovering() = " + isDiscovering()); 1738 1739 mAdapter.getProfileProxy(mContext, 1740 mBluetoothProfileServiceListener, BluetoothProfile.HEADSET); 1741 mAdapter.getProfileProxy(mContext, 1742 mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE); 1743 mAdapter.getProfileProxy(mContext, 1744 mBluetoothProfileServiceListener, BluetoothProfile.PAN); 1745 1746 dumpKnownDevices(pw); 1747 dumpAclConnectedDevices(pw); 1748 dumpHeadsetService(pw); 1749 dumpInputDeviceProfile(pw); 1750 dumpPanProfile(pw); 1751 dumpApplicationServiceRecords(pw); 1752 dumpProfileState(pw); 1753 } 1754 1755 private void dumpProfileState(PrintWriter pw) { 1756 pw.println("\n--Profile State dump--"); 1757 pw.println("\n Headset profile state:" + 1758 mAdapter.getProfileConnectionState(BluetoothProfile.HEADSET)); 1759 pw.println("\n A2dp profile state:" + 1760 mAdapter.getProfileConnectionState(BluetoothProfile.A2DP)); 1761 pw.println("\n HID profile state:" + 1762 mAdapter.getProfileConnectionState(BluetoothProfile.INPUT_DEVICE)); 1763 pw.println("\n PAN profile state:" + 1764 mAdapter.getProfileConnectionState(BluetoothProfile.PAN)); 1765 } 1766 1767 private void dumpHeadsetService(PrintWriter pw) { 1768 pw.println("\n--Headset Service--"); 1769 if (mBluetoothHeadset != null) { 1770 List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); 1771 if (deviceList.size() == 0) { 1772 pw.println("No headsets connected"); 1773 } else { 1774 BluetoothDevice device = deviceList.get(0); 1775 pw.println("\ngetConnectedDevices[0] = " + device); 1776 dumpHeadsetConnectionState(pw, device); 1777 pw.println("getBatteryUsageHint() = " + 1778 mBluetoothHeadset.getBatteryUsageHint(device)); 1779 } 1780 1781 deviceList.clear(); 1782 deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] { 1783 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); 1784 pw.println("--Connected and Disconnected Headsets"); 1785 for (BluetoothDevice device: deviceList) { 1786 pw.println(device); 1787 if (mBluetoothHeadset.isAudioConnected(device)) { 1788 pw.println("SCO audio connected to device:" + device); 1789 } 1790 } 1791 } 1792 mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset); 1793 } 1794 1795 private void dumpInputDeviceProfile(PrintWriter pw) { 1796 pw.println("\n--Bluetooth Service- Input Device Profile"); 1797 if (mInputDevice != null) { 1798 List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices(); 1799 if (deviceList.size() == 0) { 1800 pw.println("No input devices connected"); 1801 } else { 1802 pw.println("Number of connected devices:" + deviceList.size()); 1803 BluetoothDevice device = deviceList.get(0); 1804 pw.println("getConnectedDevices[0] = " + device); 1805 pw.println("Priority of Connected device = " + mInputDevice.getPriority(device)); 1806 1807 switch (mInputDevice.getConnectionState(device)) { 1808 case BluetoothInputDevice.STATE_CONNECTING: 1809 pw.println("getConnectionState() = STATE_CONNECTING"); 1810 break; 1811 case BluetoothInputDevice.STATE_CONNECTED: 1812 pw.println("getConnectionState() = STATE_CONNECTED"); 1813 break; 1814 case BluetoothInputDevice.STATE_DISCONNECTING: 1815 pw.println("getConnectionState() = STATE_DISCONNECTING"); 1816 break; 1817 } 1818 } 1819 deviceList.clear(); 1820 deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] { 1821 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); 1822 pw.println("--Connected and Disconnected input devices"); 1823 for (BluetoothDevice device: deviceList) { 1824 pw.println(device); 1825 } 1826 } 1827 mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset); 1828 } 1829 1830 private void dumpPanProfile(PrintWriter pw) { 1831 pw.println("\n--Bluetooth Service- Pan Profile"); 1832 if (mPan != null) { 1833 List<BluetoothDevice> deviceList = mPan.getConnectedDevices(); 1834 if (deviceList.size() == 0) { 1835 pw.println("No Pan devices connected"); 1836 } else { 1837 pw.println("Number of connected devices:" + deviceList.size()); 1838 BluetoothDevice device = deviceList.get(0); 1839 pw.println("getConnectedDevices[0] = " + device); 1840 1841 switch (mPan.getConnectionState(device)) { 1842 case BluetoothInputDevice.STATE_CONNECTING: 1843 pw.println("getConnectionState() = STATE_CONNECTING"); 1844 break; 1845 case BluetoothInputDevice.STATE_CONNECTED: 1846 pw.println("getConnectionState() = STATE_CONNECTED"); 1847 break; 1848 case BluetoothInputDevice.STATE_DISCONNECTING: 1849 pw.println("getConnectionState() = STATE_DISCONNECTING"); 1850 break; 1851 } 1852 } 1853 deviceList.clear(); 1854 deviceList = mPan.getDevicesMatchingConnectionStates(new int[] { 1855 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); 1856 pw.println("--Connected and Disconnected Pan devices"); 1857 for (BluetoothDevice device: deviceList) { 1858 pw.println(device); 1859 } 1860 } 1861 } 1862 1863 private void dumpHeadsetConnectionState(PrintWriter pw, 1864 BluetoothDevice device) { 1865 switch (mBluetoothHeadset.getConnectionState(device)) { 1866 case BluetoothHeadset.STATE_CONNECTING: 1867 pw.println("getConnectionState() = STATE_CONNECTING"); 1868 break; 1869 case BluetoothHeadset.STATE_CONNECTED: 1870 pw.println("getConnectionState() = STATE_CONNECTED"); 1871 break; 1872 case BluetoothHeadset.STATE_DISCONNECTING: 1873 pw.println("getConnectionState() = STATE_DISCONNECTING"); 1874 break; 1875 case BluetoothHeadset.STATE_AUDIO_CONNECTED: 1876 pw.println("getConnectionState() = STATE_AUDIO_CONNECTED"); 1877 break; 1878 } 1879 } 1880 1881 private void dumpApplicationServiceRecords(PrintWriter pw) { 1882 pw.println("\n--Application Service Records--"); 1883 for (Integer handle : mServiceRecordToPid.keySet()) { 1884 Integer pid = mServiceRecordToPid.get(handle).first; 1885 pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle)); 1886 } 1887 mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset); 1888 } 1889 1890 private void dumpAclConnectedDevices(PrintWriter pw) { 1891 String[] devicesObjectPath = getKnownDevices(); 1892 pw.println("\n--ACL connected devices--"); 1893 if (devicesObjectPath != null) { 1894 for (String device : devicesObjectPath) { 1895 pw.println(getAddressFromObjectPath(device)); 1896 } 1897 } 1898 } 1899 1900 private void dumpKnownDevices(PrintWriter pw) { 1901 pw.println("\n--Known devices--"); 1902 for (String address : mDeviceProperties.keySet()) { 1903 int bondState = mBondState.getBondState(address); 1904 pw.printf("%s %10s (%d) %s\n", address, 1905 toBondStateString(bondState), 1906 mBondState.getAttempt(address), 1907 getRemoteName(address)); 1908 1909 Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address); 1910 if (uuidChannels == null) { 1911 pw.println("\tuuids = null"); 1912 } else { 1913 for (ParcelUuid uuid : uuidChannels.keySet()) { 1914 Integer channel = uuidChannels.get(uuid); 1915 if (channel == null) { 1916 pw.println("\t" + uuid); 1917 } else { 1918 pw.println("\t" + uuid + " RFCOMM channel = " + channel); 1919 } 1920 } 1921 } 1922 for (RemoteService service : mUuidCallbackTracker.keySet()) { 1923 if (service.address.equals(address)) { 1924 pw.println("\tPENDING CALLBACK: " + service.uuid); 1925 } 1926 } 1927 } 1928 } 1929 1930 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 1931 new BluetoothProfile.ServiceListener() { 1932 public void onServiceConnected(int profile, BluetoothProfile proxy) { 1933 if (profile == BluetoothProfile.HEADSET) { 1934 mBluetoothHeadset = (BluetoothHeadset) proxy; 1935 } else if (profile == BluetoothProfile.INPUT_DEVICE) { 1936 mInputDevice = (BluetoothInputDevice) proxy; 1937 } else if (profile == BluetoothProfile.PAN) { 1938 mPan = (BluetoothPan) proxy; 1939 } 1940 } 1941 public void onServiceDisconnected(int profile) { 1942 if (profile == BluetoothProfile.HEADSET) { 1943 mBluetoothHeadset = null; 1944 } else if (profile == BluetoothProfile.INPUT_DEVICE) { 1945 mInputDevice = null; 1946 } else if (profile == BluetoothProfile.PAN) { 1947 mPan = null; 1948 } 1949 } 1950 }; 1951 1952 /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) { 1953 if (pairable && discoverable) 1954 return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 1955 else if (pairable && !discoverable) 1956 return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 1957 else 1958 return BluetoothAdapter.SCAN_MODE_NONE; 1959 } 1960 1961 /* package */ static String scanModeToBluezString(int mode) { 1962 switch (mode) { 1963 case BluetoothAdapter.SCAN_MODE_NONE: 1964 return "off"; 1965 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 1966 return "connectable"; 1967 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 1968 return "discoverable"; 1969 } 1970 return null; 1971 } 1972 1973 /*package*/ String getAddressFromObjectPath(String objectPath) { 1974 String adapterObjectPath = mAdapterProperties.getObjectPath(); 1975 if (adapterObjectPath == null || objectPath == null) { 1976 Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath + 1977 " or deviceObjectPath:" + objectPath + " is null"); 1978 return null; 1979 } 1980 if (!objectPath.startsWith(adapterObjectPath)) { 1981 Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath + 1982 " is not a prefix of deviceObjectPath:" + objectPath + 1983 "bluetoothd crashed ?"); 1984 return null; 1985 } 1986 String address = objectPath.substring(adapterObjectPath.length()); 1987 if (address != null) return address.replace('_', ':'); 1988 1989 Log.e(TAG, "getAddressFromObjectPath: Address being returned is null"); 1990 return null; 1991 } 1992 1993 /*package*/ String getObjectPathFromAddress(String address) { 1994 String path = mAdapterProperties.getObjectPath(); 1995 if (path == null) { 1996 Log.e(TAG, "Error: Object Path is null"); 1997 return null; 1998 } 1999 path = path + address.replace(":", "_"); 2000 return path; 2001 } 2002 2003 /*package */ void setLinkTimeout(String address, int num_slots) { 2004 String path = getObjectPathFromAddress(address); 2005 boolean result = setLinkTimeoutNative(path, num_slots); 2006 2007 if (!result) Log.d(TAG, "Set Link Timeout to " + num_slots + " slots failed"); 2008 } 2009 2010 /**** Handlers for PAN Profile ****/ 2011 // TODO: This needs to be converted to a state machine. 2012 2013 public boolean isTetheringOn() { 2014 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2015 synchronized (mBluetoothPanProfileHandler) { 2016 return mBluetoothPanProfileHandler.isTetheringOn(); 2017 } 2018 } 2019 2020 /*package*/boolean allowIncomingTethering() { 2021 synchronized (mBluetoothPanProfileHandler) { 2022 return mBluetoothPanProfileHandler.allowIncomingTethering(); 2023 } 2024 } 2025 2026 public void setBluetoothTethering(boolean value) { 2027 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2028 synchronized (mBluetoothPanProfileHandler) { 2029 mBluetoothPanProfileHandler.setBluetoothTethering(value); 2030 } 2031 } 2032 2033 public int getPanDeviceConnectionState(BluetoothDevice device) { 2034 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2035 synchronized (mBluetoothPanProfileHandler) { 2036 return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device); 2037 } 2038 } 2039 2040 public boolean connectPanDevice(BluetoothDevice device) { 2041 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2042 "Need BLUETOOTH_ADMIN permission"); 2043 synchronized (mBluetoothPanProfileHandler) { 2044 return mBluetoothPanProfileHandler.connectPanDevice(device); 2045 } 2046 } 2047 2048 public List<BluetoothDevice> getConnectedPanDevices() { 2049 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2050 synchronized (mBluetoothPanProfileHandler) { 2051 return mBluetoothPanProfileHandler.getConnectedPanDevices(); 2052 } 2053 } 2054 2055 public List<BluetoothDevice> getPanDevicesMatchingConnectionStates( 2056 int[] states) { 2057 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2058 synchronized (mBluetoothPanProfileHandler) { 2059 return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states); 2060 } 2061 } 2062 2063 public boolean disconnectPanDevice(BluetoothDevice device) { 2064 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2065 "Need BLUETOOTH_ADMIN permission"); 2066 synchronized (mBluetoothPanProfileHandler) { 2067 return mBluetoothPanProfileHandler.disconnectPanDevice(device); 2068 } 2069 } 2070 2071 /*package*/void handlePanDeviceStateChange(BluetoothDevice device, 2072 String iface, 2073 int state, 2074 int role) { 2075 synchronized (mBluetoothPanProfileHandler) { 2076 mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role); 2077 } 2078 } 2079 2080 /*package*/void handlePanDeviceStateChange(BluetoothDevice device, 2081 int state, int role) { 2082 synchronized (mBluetoothPanProfileHandler) { 2083 mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role); 2084 } 2085 } 2086 2087 /**** Handlers for Input Device Profile ****/ 2088 // This needs to be converted to state machine 2089 2090 public boolean connectInputDevice(BluetoothDevice device) { 2091 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2092 "Need BLUETOOTH_ADMIN permission"); 2093 BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress()); 2094 synchronized (mBluetoothInputProfileHandler) { 2095 return mBluetoothInputProfileHandler.connectInputDevice(device, state); 2096 } 2097 } 2098 2099 public boolean connectInputDeviceInternal(BluetoothDevice device) { 2100 synchronized (mBluetoothInputProfileHandler) { 2101 return mBluetoothInputProfileHandler.connectInputDeviceInternal(device); 2102 } 2103 } 2104 2105 public boolean disconnectInputDevice(BluetoothDevice device) { 2106 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2107 "Need BLUETOOTH_ADMIN permission"); 2108 BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress()); 2109 synchronized (mBluetoothInputProfileHandler) { 2110 return mBluetoothInputProfileHandler.disconnectInputDevice(device, state); 2111 } 2112 } 2113 2114 public boolean disconnectInputDeviceInternal(BluetoothDevice device) { 2115 synchronized (mBluetoothInputProfileHandler) { 2116 return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device); 2117 } 2118 } 2119 2120 public int getInputDeviceConnectionState(BluetoothDevice device) { 2121 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2122 synchronized (mBluetoothInputProfileHandler) { 2123 return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device); 2124 } 2125 } 2126 2127 public List<BluetoothDevice> getConnectedInputDevices() { 2128 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2129 synchronized (mBluetoothInputProfileHandler) { 2130 return mBluetoothInputProfileHandler.getConnectedInputDevices(); 2131 } 2132 } 2133 2134 public List<BluetoothDevice> getInputDevicesMatchingConnectionStates( 2135 int[] states) { 2136 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2137 synchronized (mBluetoothInputProfileHandler) { 2138 return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states); 2139 } 2140 } 2141 2142 2143 public int getInputDevicePriority(BluetoothDevice device) { 2144 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2145 synchronized (mBluetoothInputProfileHandler) { 2146 return mBluetoothInputProfileHandler.getInputDevicePriority(device); 2147 } 2148 } 2149 2150 public boolean setInputDevicePriority(BluetoothDevice device, int priority) { 2151 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2152 "Need BLUETOOTH_ADMIN permission"); 2153 synchronized (mBluetoothInputProfileHandler) { 2154 return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority); 2155 } 2156 } 2157 2158 /** 2159 * Handle incoming profile acceptance for profiles handled by Bluetooth Service, 2160 * currently PAN and HID. This also is the catch all for all rejections for profiles 2161 * that is not supported. 2162 * 2163 * @param device - Bluetooth Device 2164 * @param allow - true / false 2165 * @return 2166 */ 2167 public boolean allowIncomingProfileConnect(BluetoothDevice device, boolean allow) { 2168 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 2169 "Need BLUETOOTH_ADMIN permission"); 2170 String address = device.getAddress(); 2171 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 2172 return false; 2173 } 2174 2175 Integer data = getAuthorizationAgentRequestData(address); 2176 if (data == null) { 2177 Log.w(TAG, "allowIncomingProfileConnect(" + device + 2178 ") called but no native data available"); 2179 return false; 2180 } 2181 if (DBG) log("allowIncomingProfileConnect: " + device + " : " + allow + " : " + data); 2182 return setAuthorizationNative(address, allow, data.intValue()); 2183 } 2184 2185 /*package*/List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) { 2186 synchronized (mBluetoothInputProfileHandler) { 2187 return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states); 2188 } 2189 } 2190 2191 /*package*/void handleInputDevicePropertyChange(String address, boolean connected) { 2192 synchronized (mBluetoothInputProfileHandler) { 2193 mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected); 2194 } 2195 } 2196 2197 /**** Handlers for Health Device Profile ****/ 2198 // TODO: All these need to be converted to a state machine. 2199 2200 public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config, 2201 IBluetoothHealthCallback callback) { 2202 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2203 "Need BLUETOOTH permission"); 2204 synchronized (mBluetoothHealthProfileHandler) { 2205 return mBluetoothHealthProfileHandler.registerAppConfiguration(config, callback); 2206 } 2207 } 2208 2209 public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { 2210 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2211 "Need BLUETOOTH permission"); 2212 synchronized (mBluetoothHealthProfileHandler) { 2213 return mBluetoothHealthProfileHandler.unregisterAppConfiguration(config); 2214 } 2215 } 2216 2217 2218 public boolean connectChannelToSource(BluetoothDevice device, 2219 BluetoothHealthAppConfiguration config) { 2220 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2221 "Need BLUETOOTH permission"); 2222 synchronized (mBluetoothHealthProfileHandler) { 2223 return mBluetoothHealthProfileHandler.connectChannelToSource(device, 2224 config); 2225 } 2226 } 2227 2228 public boolean connectChannelToSink(BluetoothDevice device, 2229 BluetoothHealthAppConfiguration config, int channelType) { 2230 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2231 "Need BLUETOOTH permission"); 2232 synchronized (mBluetoothHealthProfileHandler) { 2233 return mBluetoothHealthProfileHandler.connectChannel(device, config, 2234 channelType); 2235 } 2236 } 2237 2238 public boolean disconnectChannel(BluetoothDevice device, 2239 BluetoothHealthAppConfiguration config, int id) { 2240 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2241 "Need BLUETOOTH permission"); 2242 synchronized (mBluetoothHealthProfileHandler) { 2243 return mBluetoothHealthProfileHandler.disconnectChannel(device, config, id); 2244 } 2245 } 2246 2247 public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, 2248 BluetoothHealthAppConfiguration config) { 2249 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2250 "Need BLUETOOTH permission"); 2251 synchronized (mBluetoothHealthProfileHandler) { 2252 return mBluetoothHealthProfileHandler.getMainChannelFd(device, config); 2253 } 2254 } 2255 2256 /*package*/ void onHealthDevicePropertyChanged(String devicePath, 2257 String channelPath) { 2258 synchronized (mBluetoothHealthProfileHandler) { 2259 mBluetoothHealthProfileHandler.onHealthDevicePropertyChanged(devicePath, 2260 channelPath); 2261 } 2262 } 2263 2264 /*package*/ void onHealthDeviceChannelChanged(String devicePath, 2265 String channelPath, boolean exists) { 2266 synchronized(mBluetoothHealthProfileHandler) { 2267 mBluetoothHealthProfileHandler.onHealthDeviceChannelChanged(devicePath, 2268 channelPath, exists); 2269 } 2270 } 2271 2272 /*package*/ void onHealthDeviceChannelConnectionError(int channelCode, 2273 int newState) { 2274 synchronized(mBluetoothHealthProfileHandler) { 2275 mBluetoothHealthProfileHandler.onHealthDeviceChannelConnectionError(channelCode, 2276 newState); 2277 } 2278 } 2279 2280 public int getHealthDeviceConnectionState(BluetoothDevice device) { 2281 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2282 "Need BLUETOOTH permission"); 2283 synchronized (mBluetoothHealthProfileHandler) { 2284 return mBluetoothHealthProfileHandler.getHealthDeviceConnectionState(device); 2285 } 2286 } 2287 2288 public List<BluetoothDevice> getConnectedHealthDevices() { 2289 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2290 "Need BLUETOOTH permission"); 2291 synchronized (mBluetoothHealthProfileHandler) { 2292 return mBluetoothHealthProfileHandler.getConnectedHealthDevices(); 2293 } 2294 } 2295 2296 public List<BluetoothDevice> getHealthDevicesMatchingConnectionStates( 2297 int[] states) { 2298 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 2299 "Need BLUETOOTH permission"); 2300 synchronized (mBluetoothHealthProfileHandler) { 2301 return mBluetoothHealthProfileHandler. 2302 getHealthDevicesMatchingConnectionStates(states); 2303 } 2304 } 2305 2306 /*package*/boolean notifyIncomingHidConnection(String address) { 2307 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 2308 if (state == null) { 2309 return false; 2310 } 2311 Message msg = new Message(); 2312 msg.what = BluetoothDeviceProfileState.CONNECT_HID_INCOMING; 2313 state.sendMessage(msg); 2314 return true; 2315 } 2316 2317 public boolean connectHeadset(String address) { 2318 if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 2319 2320 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 2321 if (state != null) { 2322 Message msg = new Message(); 2323 msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING; 2324 msg.obj = state; 2325 mHfpProfileState.sendMessage(msg); 2326 return true; 2327 } 2328 return false; 2329 } 2330 2331 public boolean disconnectHeadset(String address) { 2332 if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 2333 2334 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 2335 if (state != null) { 2336 Message msg = new Message(); 2337 msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING; 2338 msg.obj = state; 2339 mHfpProfileState.sendMessage(msg); 2340 return true; 2341 } 2342 return false; 2343 } 2344 2345 public boolean connectSink(String address) { 2346 if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 2347 2348 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 2349 if (state != null) { 2350 Message msg = new Message(); 2351 msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING; 2352 msg.obj = state; 2353 mA2dpProfileState.sendMessage(msg); 2354 return true; 2355 } 2356 return false; 2357 } 2358 2359 public boolean disconnectSink(String address) { 2360 if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false; 2361 2362 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 2363 if (state != null) { 2364 Message msg = new Message(); 2365 msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING; 2366 msg.obj = state; 2367 mA2dpProfileState.sendMessage(msg); 2368 return true; 2369 } 2370 return false; 2371 } 2372 2373 BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) { 2374 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 2375 if (state != null) return state; 2376 2377 state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust); 2378 mDeviceProfileState.put(address, state); 2379 state.start(); 2380 return state; 2381 } 2382 2383 void removeProfileState(String address) { 2384 mDeviceProfileState.remove(address); 2385 } 2386 2387 synchronized String[] getKnownDevices() { 2388 String[] bonds = null; 2389 String val = getProperty("Devices", true); 2390 if (val != null) { 2391 bonds = val.split(","); 2392 } 2393 return bonds; 2394 } 2395 2396 private void initProfileState() { 2397 String[] bonds = null; 2398 String val = getProperty("Devices", false); 2399 if (val != null) { 2400 bonds = val.split(","); 2401 } 2402 if (bonds == null) { 2403 return; 2404 } 2405 for (String path : bonds) { 2406 String address = getAddressFromObjectPath(path); 2407 BluetoothDeviceProfileState state = addProfileState(address, false); 2408 } 2409 } 2410 2411 private void autoConnect() { 2412 String[] bonds = getKnownDevices(); 2413 if (bonds == null) { 2414 return; 2415 } 2416 for (String path : bonds) { 2417 String address = getAddressFromObjectPath(path); 2418 BluetoothDeviceProfileState state = mDeviceProfileState.get(address); 2419 if (state != null) { 2420 Message msg = new Message(); 2421 msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES; 2422 state.sendMessage(msg); 2423 } 2424 } 2425 } 2426 2427 public boolean notifyIncomingConnection(String address) { 2428 BluetoothDeviceProfileState state = 2429 mDeviceProfileState.get(address); 2430 if (state != null) { 2431 Message msg = new Message(); 2432 msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING; 2433 state.sendMessage(msg); 2434 return true; 2435 } 2436 return false; 2437 } 2438 2439 /*package*/ boolean notifyIncomingA2dpConnection(String address) { 2440 BluetoothDeviceProfileState state = 2441 mDeviceProfileState.get(address); 2442 if (state != null) { 2443 Message msg = new Message(); 2444 msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING; 2445 state.sendMessage(msg); 2446 return true; 2447 } 2448 return false; 2449 } 2450 2451 /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) { 2452 mA2dpService = a2dpService; 2453 } 2454 2455 /*package*/ Integer getAuthorizationAgentRequestData(String address) { 2456 Integer data = mEventLoop.getAuthorizationAgentRequestData().remove(address); 2457 return data; 2458 } 2459 2460 public void sendProfileStateMessage(int profile, int cmd) { 2461 Message msg = new Message(); 2462 msg.what = cmd; 2463 if (profile == BluetoothProfileState.HFP) { 2464 mHfpProfileState.sendMessage(msg); 2465 } else if (profile == BluetoothProfileState.A2DP) { 2466 mA2dpProfileState.sendMessage(msg); 2467 } 2468 } 2469 2470 public int getAdapterConnectionState() { 2471 return mAdapterConnectionState; 2472 } 2473 2474 public int getProfileConnectionState(int profile) { 2475 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2476 2477 Pair<Integer, Integer> state = mProfileConnectionState.get(profile); 2478 if (state == null) return BluetoothProfile.STATE_DISCONNECTED; 2479 2480 return state.first; 2481 } 2482 2483 private void updateProfileConnectionState(int profile, int newState, int oldState) { 2484 // mProfileConnectionState is a hashmap - 2485 // <Integer, Pair<Integer, Integer>> 2486 // The key is the profile, the value is a pair. first element 2487 // is the state and the second element is the number of devices 2488 // in that state. 2489 int numDev = 1; 2490 int newHashState = newState; 2491 boolean update = true; 2492 2493 // The following conditions are considered in this function: 2494 // 1. If there is no record of profile and state - update 2495 // 2. If a new device's state is current hash state - increment 2496 // number of devices in the state. 2497 // 3. If a state change has happened to Connected or Connecting 2498 // (if current state is not connected), update. 2499 // 4. If numDevices is 1 and that device state is being updated, update 2500 // 5. If numDevices is > 1 and one of the devices is changing state, 2501 // decrement numDevices but maintain oldState if it is Connected or 2502 // Connecting 2503 Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile); 2504 if (stateNumDev != null) { 2505 int currHashState = stateNumDev.first; 2506 numDev = stateNumDev.second; 2507 2508 if (newState == currHashState) { 2509 numDev ++; 2510 } else if (newState == BluetoothProfile.STATE_CONNECTED || 2511 (newState == BluetoothProfile.STATE_CONNECTING && 2512 currHashState != BluetoothProfile.STATE_CONNECTED)) { 2513 numDev = 1; 2514 } else if (numDev == 1 && oldState == currHashState) { 2515 update = true; 2516 } else if (numDev > 1 && oldState == currHashState) { 2517 numDev --; 2518 2519 if (currHashState == BluetoothProfile.STATE_CONNECTED || 2520 currHashState == BluetoothProfile.STATE_CONNECTING) { 2521 newHashState = currHashState; 2522 } 2523 } else { 2524 update = false; 2525 } 2526 } 2527 2528 if (update) { 2529 mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState, 2530 numDev)); 2531 } 2532 } 2533 2534 public synchronized void sendConnectionStateChange(BluetoothDevice 2535 device, int profile, int state, int prevState) { 2536 // Since this is a binder call check if Bluetooth is on still 2537 if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return; 2538 2539 if (!validateProfileConnectionState(state) || 2540 !validateProfileConnectionState(prevState)) { 2541 // Previously, an invalid state was broadcast anyway, 2542 // with the invalid state converted to -1 in the intent. 2543 // Better to log an error and not send an intent with 2544 // invalid contents or set mAdapterConnectionState to -1. 2545 Log.e(TAG, "Error in sendConnectionStateChange: " 2546 + "prevState " + prevState + " state " + state); 2547 return; 2548 } 2549 2550 updateProfileConnectionState(profile, state, prevState); 2551 2552 if (updateCountersAndCheckForConnectionStateChange(state, prevState)) { 2553 mAdapterConnectionState = state; 2554 2555 if (state == BluetoothProfile.STATE_DISCONNECTED) { 2556 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.ALL_DEVICES_DISCONNECTED); 2557 } 2558 2559 Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 2560 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 2561 intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 2562 convertToAdapterState(state)); 2563 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, 2564 convertToAdapterState(prevState)); 2565 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2566 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 2567 Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": " 2568 + prevState + " -> " + state); 2569 } 2570 } 2571 2572 private boolean validateProfileConnectionState(int state) { 2573 return (state == BluetoothProfile.STATE_DISCONNECTED || 2574 state == BluetoothProfile.STATE_CONNECTING || 2575 state == BluetoothProfile.STATE_CONNECTED || 2576 state == BluetoothProfile.STATE_DISCONNECTING); 2577 } 2578 2579 private int convertToAdapterState(int state) { 2580 switch (state) { 2581 case BluetoothProfile.STATE_DISCONNECTED: 2582 return BluetoothAdapter.STATE_DISCONNECTED; 2583 case BluetoothProfile.STATE_DISCONNECTING: 2584 return BluetoothAdapter.STATE_DISCONNECTING; 2585 case BluetoothProfile.STATE_CONNECTED: 2586 return BluetoothAdapter.STATE_CONNECTED; 2587 case BluetoothProfile.STATE_CONNECTING: 2588 return BluetoothAdapter.STATE_CONNECTING; 2589 } 2590 Log.e(TAG, "Error in convertToAdapterState"); 2591 return -1; 2592 } 2593 2594 private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) { 2595 switch (prevState) { 2596 case BluetoothProfile.STATE_CONNECTING: 2597 mProfilesConnecting--; 2598 break; 2599 2600 case BluetoothProfile.STATE_CONNECTED: 2601 mProfilesConnected--; 2602 break; 2603 2604 case BluetoothProfile.STATE_DISCONNECTING: 2605 mProfilesDisconnecting--; 2606 break; 2607 } 2608 2609 switch (state) { 2610 case BluetoothProfile.STATE_CONNECTING: 2611 mProfilesConnecting++; 2612 return (mProfilesConnected == 0 && mProfilesConnecting == 1); 2613 2614 case BluetoothProfile.STATE_CONNECTED: 2615 mProfilesConnected++; 2616 return (mProfilesConnected == 1); 2617 2618 case BluetoothProfile.STATE_DISCONNECTING: 2619 mProfilesDisconnecting++; 2620 return (mProfilesConnected == 0 && mProfilesDisconnecting == 1); 2621 2622 case BluetoothProfile.STATE_DISCONNECTED: 2623 return (mProfilesConnected == 0 && mProfilesConnecting == 0); 2624 2625 default: 2626 return true; 2627 } 2628 } 2629 2630 private void createIncomingConnectionStateFile() { 2631 File f = new File(INCOMING_CONNECTION_FILE); 2632 if (!f.exists()) { 2633 try { 2634 f.createNewFile(); 2635 } catch (IOException e) { 2636 Log.e(TAG, "IOException: cannot create file"); 2637 } 2638 } 2639 } 2640 2641 /** @hide */ 2642 public Pair<Integer, String> getIncomingState(String address) { 2643 if (mIncomingConnections.isEmpty()) { 2644 createIncomingConnectionStateFile(); 2645 readIncomingConnectionState(); 2646 } 2647 return mIncomingConnections.get(address); 2648 } 2649 2650 private void readIncomingConnectionState() { 2651 synchronized(mIncomingConnections) { 2652 FileInputStream fstream = null; 2653 try { 2654 fstream = new FileInputStream(INCOMING_CONNECTION_FILE); 2655 DataInputStream in = new DataInputStream(fstream); 2656 BufferedReader file = new BufferedReader(new InputStreamReader(in)); 2657 String line; 2658 while((line = file.readLine()) != null) { 2659 line = line.trim(); 2660 if (line.length() == 0) continue; 2661 String[] value = line.split(","); 2662 if (value != null && value.length == 3) { 2663 Integer val1 = Integer.parseInt(value[1]); 2664 Pair<Integer, String> val = new Pair(val1, value[2]); 2665 mIncomingConnections.put(value[0], val); 2666 } 2667 } 2668 } catch (FileNotFoundException e) { 2669 log("FileNotFoundException: readIncomingConnectionState" + e.toString()); 2670 } catch (IOException e) { 2671 log("IOException: readIncomingConnectionState" + e.toString()); 2672 } finally { 2673 if (fstream != null) { 2674 try { 2675 fstream.close(); 2676 } catch (IOException e) { 2677 // Ignore 2678 } 2679 } 2680 } 2681 } 2682 } 2683 2684 private void truncateIncomingConnectionFile() { 2685 RandomAccessFile r = null; 2686 try { 2687 r = new RandomAccessFile(INCOMING_CONNECTION_FILE, "rw"); 2688 r.setLength(0); 2689 } catch (FileNotFoundException e) { 2690 log("FileNotFoundException: truncateIncomingConnectionState" + e.toString()); 2691 } catch (IOException e) { 2692 log("IOException: truncateIncomingConnectionState" + e.toString()); 2693 } finally { 2694 if (r != null) { 2695 try { 2696 r.close(); 2697 } catch (IOException e) { 2698 // ignore 2699 } 2700 } 2701 } 2702 } 2703 2704 /** @hide */ 2705 public void writeIncomingConnectionState(String address, Pair<Integer, String> data) { 2706 synchronized(mIncomingConnections) { 2707 mIncomingConnections.put(address, data); 2708 2709 truncateIncomingConnectionFile(); 2710 BufferedWriter out = null; 2711 StringBuilder value = new StringBuilder(); 2712 try { 2713 out = new BufferedWriter(new FileWriter(INCOMING_CONNECTION_FILE, true)); 2714 for (String devAddress: mIncomingConnections.keySet()) { 2715 Pair<Integer, String> val = mIncomingConnections.get(devAddress); 2716 value.append(devAddress); 2717 value.append(","); 2718 value.append(val.first.toString()); 2719 value.append(","); 2720 value.append(val.second); 2721 value.append("\n"); 2722 } 2723 out.write(value.toString()); 2724 } catch (FileNotFoundException e) { 2725 log("FileNotFoundException: writeIncomingConnectionState" + e.toString()); 2726 } catch (IOException e) { 2727 log("IOException: writeIncomingConnectionState" + e.toString()); 2728 } finally { 2729 if (out != null) { 2730 try { 2731 out.close(); 2732 } catch (IOException e) { 2733 // Ignore 2734 } 2735 } 2736 } 2737 } 2738 } 2739 2740 private static void log(String msg) { 2741 Log.d(TAG, msg); 2742 } 2743 2744 private native static void classInitNative(); 2745 private native void initializeNativeDataNative(); 2746 private native boolean setupNativeDataNative(); 2747 private native boolean tearDownNativeDataNative(); 2748 private native void cleanupNativeDataNative(); 2749 /*package*/ native String getAdapterPathNative(); 2750 2751 private native int isEnabledNative(); 2752 /*package*/ native int enableNative(); 2753 /*package*/ native int disableNative(); 2754 2755 /*package*/ native Object[] getAdapterPropertiesNative(); 2756 private native Object[] getDevicePropertiesNative(String objectPath); 2757 private native boolean setAdapterPropertyStringNative(String key, String value); 2758 private native boolean setAdapterPropertyIntegerNative(String key, int value); 2759 private native boolean setAdapterPropertyBooleanNative(String key, int value); 2760 2761 private native boolean startDiscoveryNative(); 2762 private native boolean stopDiscoveryNative(); 2763 2764 private native boolean createPairedDeviceNative(String address, int timeout_ms); 2765 private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms); 2766 private native byte[] readAdapterOutOfBandDataNative(); 2767 2768 private native boolean cancelDeviceCreationNative(String address); 2769 private native boolean removeDeviceNative(String objectPath); 2770 private native int getDeviceServiceChannelNative(String objectPath, String uuid, 2771 int attributeId); 2772 2773 private native boolean cancelPairingUserInputNative(String address, int nativeData); 2774 private native boolean setPinNative(String address, String pin, int nativeData); 2775 private native boolean setPasskeyNative(String address, int passkey, int nativeData); 2776 private native boolean setPairingConfirmationNative(String address, boolean confirm, 2777 int nativeData); 2778 private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash, 2779 byte[] randomizer, int nativeData); 2780 2781 private native boolean setDevicePropertyBooleanNative(String objectPath, String key, 2782 int value); 2783 private native boolean setDevicePropertyStringNative(String objectPath, String key, 2784 String value); 2785 private native boolean createDeviceNative(String address); 2786 /*package*/ native boolean discoverServicesNative(String objectPath, String pattern); 2787 2788 private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb, 2789 short channel); 2790 private native boolean removeServiceRecordNative(int handle); 2791 private native boolean setLinkTimeoutNative(String path, int num_slots); 2792 2793 native boolean connectInputDeviceNative(String path); 2794 native boolean disconnectInputDeviceNative(String path); 2795 2796 native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge); 2797 native boolean connectPanDeviceNative(String path, String dstRole); 2798 native boolean disconnectPanDeviceNative(String path); 2799 native boolean disconnectPanServerDeviceNative(String path, 2800 String address, String iface); 2801 2802 private native int[] addReservedServiceRecordsNative(int[] uuuids); 2803 private native boolean removeReservedServiceRecordsNative(int[] handles); 2804 2805 // Health API 2806 native String registerHealthApplicationNative(int dataType, String role, String name, 2807 String channelType); 2808 native String registerHealthApplicationNative(int dataType, String role, String name); 2809 native boolean unregisterHealthApplicationNative(String path); 2810 native boolean createChannelNative(String devicePath, String appPath, String channelType, 2811 int code); 2812 native boolean destroyChannelNative(String devicePath, String channelpath, int code); 2813 native String getMainChannelNative(String path); 2814 native String getChannelApplicationNative(String channelPath); 2815 native ParcelFileDescriptor getChannelFdNative(String channelPath); 2816 native boolean releaseChannelFdNative(String channelPath); 2817 native boolean setAuthorizationNative(String address, boolean value, int data); 2818 } 2819