AdapterService.java revision 6654f5c903de510a70f9e72cd5ad7837b615d93f
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5/** 6 * @hide 7 */ 8 9package com.android.bluetooth.btservice; 10 11import android.app.Application; 12import android.app.Service; 13import android.bluetooth.BluetoothAdapter; 14import android.bluetooth.BluetoothDevice; 15import android.bluetooth.BluetoothProfile; 16import android.bluetooth.IBluetooth; 17import android.content.BroadcastReceiver; 18import android.content.ContentResolver; 19import android.content.Context; 20import android.content.Intent; 21import android.content.IntentFilter; 22import android.os.Binder; 23import android.os.Handler; 24import android.os.IBinder; 25import android.os.Message; 26import android.os.ParcelFileDescriptor; 27import android.os.ParcelUuid; 28import android.os.RemoteException; 29import android.provider.Settings; 30import android.util.Log; 31import android.util.Pair; 32 33import com.android.bluetooth.a2dp.A2dpService; 34import com.android.bluetooth.hid.HidService; 35import com.android.bluetooth.hfp.HeadsetService; 36import com.android.bluetooth.hdp.HealthService; 37import com.android.bluetooth.pan.PanService; 38import com.android.bluetooth.Utils; 39import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 40 41import java.io.FileDescriptor; 42import java.io.IOException; 43import java.util.HashMap; 44import java.util.Set; 45import java.util.Map; 46import java.util.Iterator; 47import java.util.Map.Entry; 48import android.content.pm.PackageManager; 49 50 51public class AdapterService extends Service { 52 private static final String TAG = "BluetoothAdapterService"; 53 private static final boolean DBG = true; 54 55 /** 56 * List of profile services to support.Comment out to disable a profile 57 * Profiles started in order of appearance 58 */ 59 @SuppressWarnings("rawtypes") 60 private static final Class[] SUPPORTED_PROFILE_SERVICES = { 61 HeadsetService.class, 62 A2dpService.class, 63 HidService.class, 64 HealthService.class, 65 PanService.class 66 }; 67 68 public static final String ACTION_LOAD_ADAPTER_PROPERTIES="com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES"; 69 public static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 70 public static final String EXTRA_ACTION="action"; 71 72 static final String BLUETOOTH_ADMIN_PERM = 73 android.Manifest.permission.BLUETOOTH_ADMIN; 74 static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 75 76 private AdapterProperties mAdapterProperties; 77 private int mAdapterState; 78 private Context mContext; 79 private boolean mIsAirplaneSensitive; 80 private boolean mIsAirplaneToggleable; 81 private static AdapterService sAdapterService; 82 83 private AdapterState mAdapterStateMachine; 84 private BondStateMachine mBondStateMachine; 85 private JniCallbacks mJniCallbacks; 86 private RemoteDevices mRemoteDevices; 87 private boolean mStopPending; 88 private boolean mStartPending; 89 private boolean mProfilesStarted; 90 private boolean mNativeAvailable; 91 private HashMap<String,Integer> mProfileServicesState = new HashMap<String,Integer>(); 92 93 //In case Bluetooth app crashes, we need to reinit JNI 94 private static boolean mIsJniInited; 95 private static synchronized void initJni() { 96 if (!mIsJniInited) { 97 if (DBG) Log.d(TAG,"Initializing JNI Library"); 98 System.loadLibrary("bluetooth_jni"); 99 classInitNative(); 100 mIsJniInited=true; 101 } 102 } 103 104 public static AdapterService getAdapterService(){ 105 return sAdapterService; 106 } 107 108 public void onProfileServiceStateChanged(String serviceName, int state) { 109 if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state); 110 boolean doUpdate=false; 111 synchronized (mProfileServicesState) { 112 Integer prevState = mProfileServicesState.get(serviceName); 113 if (prevState != null && prevState != state) { 114 mProfileServicesState.put(serviceName,state); 115 doUpdate=true; 116 } 117 } 118 if (!doUpdate) { 119 return; 120 } 121 if (mStopPending) { 122 //Process stop or disable pending 123 //Check if all services are stopped if so, do cleanup 124 if (DBG) Log.d(TAG,"Checking if all profiles are stopped..."); 125 synchronized (mProfileServicesState) { 126 Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator(); 127 while (i.hasNext()) { 128 Map.Entry<String,Integer> entry = i.next(); 129 if (BluetoothAdapter.STATE_OFF != entry.getValue()) { 130 //Log.d(TAG, "Profile still running: " entry.getKey()); 131 return; 132 } 133 } 134 } 135 if (DBG) Log.d(TAG, "All profile services stopped..."); 136 Message m = mHandler.obtainMessage(MESSAGE_ONSTOPPED_STOPPENDING); 137 mHandler.sendMessage(m); 138 } else if (mStartPending) { 139 //Process start pending 140 //Check if all services are started if so, update state 141 if (DBG) Log.d(TAG,"Checking if all profiles are running..."); 142 synchronized (mProfileServicesState) { 143 Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator(); 144 while (i.hasNext()) { 145 Map.Entry<String,Integer> entry = i.next(); 146 if (BluetoothAdapter.STATE_ON != entry.getValue()) { 147 //Log.d(TAG, "Profile still not running:" + entry.getKey()); 148 return; 149 } 150 } 151 } 152 if (DBG) Log.d(TAG, "All profile services started."); 153 Message m = mHandler.obtainMessage(MESSAGE_ONSTARTED); 154 mHandler.sendMessage(m); 155 } 156 } 157 158 @Override 159 public void onCreate() { 160 super.onCreate(); 161 if (DBG) Log.d(TAG, "onCreate"); 162 mContext = this; 163 sAdapterService = this; 164 initJni(); //We always check and init JNI in case we crashed and restarted 165 mRemoteDevices = RemoteDevices.getInstance(this, mContext); 166 mRemoteDevices.init(); 167 mAdapterProperties = AdapterProperties.getInstance(this, mContext); 168 mAdapterProperties.init(); 169 mAdapterStateMachine = new AdapterState(this, mContext, mAdapterProperties); 170 mBondStateMachine = new BondStateMachine(this, mContext, mAdapterProperties); 171 mJniCallbacks = JniCallbacks.getInstance(mRemoteDevices, mAdapterProperties, 172 mAdapterStateMachine, mBondStateMachine); 173 initNative(); 174 mNativeAvailable=true; 175 176 //Load the name and address 177 getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR); 178 getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME); 179 } 180 181 @Override 182 public IBinder onBind(Intent intent) { 183 if (DBG) Log.d(TAG, "onBind"); 184 return mBinder; 185 } 186 public boolean onUnbind(Intent intent) { 187 if (DBG) Log.d(TAG,"onUnbind"); 188 return super.onUnbind(intent); 189 } 190 191 public void onDestroy() { 192 if (DBG) Log.d(TAG, "onDestroy()"); 193 super.onDestroy(); 194 if (mBondStateMachine != null) { 195 mBondStateMachine.cleanup(); 196 mBondStateMachine = null; 197 } 198 if (mAdapterStateMachine != null) { 199 mAdapterStateMachine.cleanup(); 200 mAdapterStateMachine = null; 201 } 202 if (mNativeAvailable) { 203 Log.d(TAG, "Cleaning up adapter native...."); 204 cleanupNative(); 205 Log.d(TAG, "Done cleaning up adapter native...."); 206 mNativeAvailable=false; 207 } 208 } 209 210 public int onStartCommand(Intent intent ,int flags, int startId) { 211 if (DBG) Log.d(TAG, "onStartCommand"); 212 if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) { 213 Log.e(TAG, "Permission denied!"); 214 return START_STICKY; 215 } 216 217 String action = intent.getStringExtra(EXTRA_ACTION); 218 if (DBG) Log.d(TAG,"onStartCommand(): action = " + action); 219 if (ACTION_SERVICE_STATE_CHANGED.equals(action)) { 220 int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.ERROR); 221 if (DBG) Log.d(TAG,"onStartCommand(): state = " + Utils.debugGetAdapterStateString(state)); 222 if (state == BluetoothAdapter.STATE_OFF) { 223 stop(); 224 } else if (state == BluetoothAdapter.STATE_ON) { 225 start(); 226 } 227 } 228 return START_STICKY; 229 } 230 231 private void start() { 232 if (DBG) Log.d(TAG,"start() called"); 233 if (mProfilesStarted || mStartPending) return; 234 if (DBG) Log.d(TAG,"starting bluetooth state machine and profiles.."); 235 mStartPending=true; 236 mAdapterStateMachine.start(); 237 mBondStateMachine.start(); 238 //Start profile services 239 for (int i=0; i <SUPPORTED_PROFILE_SERVICES.length;i++) { 240 startProfileService(SUPPORTED_PROFILE_SERVICES[i]); 241 } 242 } 243 244 //Called as part of disable or independently (when just getting address) 245 private void stop() { 246 Log.d(TAG,"stop() called"); 247 if (mStopPending) return; 248 mStopPending=true; 249 if (mProfilesStarted) { 250 //TODO: Start timeout 251 mProfilesStarted = false; 252 253 for (int i=SUPPORTED_PROFILE_SERVICES.length-1; i >=0;i--) { 254 stopProfileService(SUPPORTED_PROFILE_SERVICES[i]); 255 } 256 } else { 257 mStopPending=false; 258 finish(); 259 } 260 } 261 262 private static final int MESSAGE_ONSTARTED=1; 263 private static final int MESSAGE_ONSTOPPED_STOPPENDING =2; 264 private final Handler mHandler = new Handler() { 265 @Override 266 public void handleMessage(Message msg) { 267 if (DBG) Log.d (TAG, "Message: " + msg.what); 268 269 switch (msg.what) { 270 case MESSAGE_ONSTARTED: { 271 Log.d(TAG, "onStarted()"); 272 IntentFilter filter = new IntentFilter(); 273 filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 274 registerForAirplaneMode(filter); 275 registerReceiver(mReceiver, filter); 276 mProfilesStarted = true; 277 mStartPending = false; 278 } 279 break; 280 281 case MESSAGE_ONSTOPPED_STOPPENDING: { 282 Log.d(TAG, "onStopped_StopPending() called"); 283 mStopPending=false; 284 mBondStateMachine.quit(); 285 mAdapterStateMachine.quit(); 286 finish(); 287 } 288 break; 289 } 290 } 291 }; 292 293 /** 294 * Last step in the disable->stop->cleanup sequence 295 */ 296 private void finish() { 297 stopSelf(); 298 } 299 300 @SuppressWarnings("rawtypes") 301 private void startProfileService(Class service) { 302 String serviceName = service.getName(); 303 Integer serviceState = mProfileServicesState.get(serviceName); 304 if(serviceState != null && serviceState != BluetoothAdapter.STATE_OFF) { 305 Log.w(TAG, "Unable to start service "+serviceName+". Invalid state: " + serviceState); 306 return; 307 } 308 309 mProfileServicesState.put(serviceName,BluetoothAdapter.STATE_TURNING_ON); 310 Intent i = new Intent(this,service); 311 i.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED); 312 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON); 313 if (DBG) Log.d(TAG, "Starting profile service "+serviceName); 314 startService(i); 315 } 316 317 @SuppressWarnings("rawtypes") 318 private void stopProfileService(Class service) { 319 String serviceName = service.getName(); 320 Integer serviceState = mProfileServicesState.get(service.getName()); 321 if(serviceState == null || serviceState != BluetoothAdapter.STATE_ON) { 322 Log.w(TAG, "Unable to stop service " + serviceName + ". Invalid state: " + serviceState); 323 return; 324 } 325 mProfileServicesState.put(serviceName, BluetoothAdapter.STATE_TURNING_OFF); 326 Intent i = new Intent(this, service); 327 i.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED); 328 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF); 329 if (DBG) Log.d(TAG, "Stopping profile service "+serviceName); 330 startService(i); 331 } 332 333 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 334 @Override 335 public void onReceive(Context context, Intent intent) { 336 if (intent == null) return; 337 338 String action = intent.getAction(); 339 if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { 340 ContentResolver resolver = context.getContentResolver(); 341 // Query the airplane mode from Settings.System just to make sure that 342 // some random app is not sending this intent and disabling bluetooth 343 if (isAirplaneModeOn()) { 344 mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_ON); 345 } else { 346 mAdapterStateMachine.sendMessage(AdapterState.AIRPLANE_MODE_OFF); 347 } 348 } 349 } 350 }; 351 352 private void registerForAirplaneMode(IntentFilter filter) { 353 final ContentResolver resolver = mContext.getContentResolver(); 354 final String airplaneModeRadios = Settings.System.getString(resolver, 355 Settings.System.AIRPLANE_MODE_RADIOS); 356 final String toggleableRadios = Settings.System.getString(resolver, 357 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 358 359 mIsAirplaneSensitive = airplaneModeRadios == null ? true : 360 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 361 mIsAirplaneToggleable = toggleableRadios == null ? false : 362 toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH); 363 364 if (mIsAirplaneSensitive) { 365 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 366 } 367 } 368 369 /* Returns true if airplane mode is currently on */ 370 private final boolean isAirplaneModeOn() { 371 return Settings.System.getInt(mContext.getContentResolver(), 372 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 373 } 374 private boolean mPersistDisable; 375 376 /** 377 * Handlers for incoming service calls 378 */ 379 private final IBluetooth.Stub mBinder = new IBluetooth.Stub() { 380 public boolean isEnabled() { 381 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 382 return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON; 383 } 384 385 public int getState() { 386 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 387 return mAdapterProperties.getState(); 388 } 389 390 public boolean enable() { 391 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 392 "Need BLUETOOTH ADMIN permission"); 393 Log.d(TAG,"enable() called..."); 394 Message m = 395 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON); 396 m.arg1 = 1; //persist state 397 mAdapterStateMachine.sendMessage(m); 398 return true; 399 } 400 401 public boolean disable(boolean persist) { 402 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 403 "Need BLUETOOTH ADMIN permission"); 404 unregisterReceiver(mReceiver); 405 int val = (persist ? 1 : 0); 406 Message m = 407 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF); 408 m.arg1 = val; 409 mAdapterStateMachine.sendMessage(m); 410 return true; 411 } 412 413 public String getAddress() { 414 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 415 String addrString = null; 416 byte[] address = mAdapterProperties.getAddress(); 417 return Utils.getAddressStringFromByte(address); 418 } 419 420 public ParcelUuid[] getUuids() { 421 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 422 return mAdapterProperties.getUuids(); 423 } 424 425 public String getName() { 426 enforceCallingOrSelfPermission(BLUETOOTH_PERM, 427 "Need BLUETOOTH permission"); 428 return mAdapterProperties.getName(); 429 } 430 431 public boolean setName(String name) { 432 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 433 "Need BLUETOOTH ADMIN permission"); 434 return mAdapterProperties.setName(name); 435 } 436 437 public int getScanMode() { 438 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 439 return mAdapterProperties.getScanMode(); 440 } 441 442 public boolean setScanMode(int mode, int duration) { 443 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 444 setDiscoverableTimeout(duration); 445 446 int newMode = convertScanModeToHal(mode); 447 return mAdapterProperties.setScanMode(newMode); 448 } 449 450 public int getDiscoverableTimeout() { 451 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 452 return mAdapterProperties.getDiscoverableTimeout(); 453 } 454 455 public boolean setDiscoverableTimeout(int timeout) { 456 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 457 return mAdapterProperties.setDiscoverableTimeout(timeout); 458 } 459 460 public boolean startDiscovery() { 461 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 462 "Need BLUETOOTH ADMIN permission"); 463 return startDiscoveryNative(); 464 } 465 466 public boolean cancelDiscovery() { 467 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 468 "Need BLUETOOTH ADMIN permission"); 469 return cancelDiscoveryNative(); 470 } 471 472 public boolean isDiscovering() { 473 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 474 return mAdapterProperties.isDiscovering(); 475 } 476 477 public BluetoothDevice[] getBondedDevices() { 478 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 479 debugLog("Get Bonded Devices being called"); 480 return mAdapterProperties.getBondedDevices(); 481 } 482 483 public int getAdapterConnectionState() { 484 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 485 return mAdapterProperties.getConnectionState(); 486 } 487 488 public int getProfileConnectionState(int profile) { 489 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 490 return mAdapterProperties.getProfileConnectionState(profile); 491 } 492 493 public boolean createBond(BluetoothDevice device) { 494 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 495 "Need BLUETOOTH ADMIN permission"); 496 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 497 if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) { 498 return false; 499 } 500 501 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND); 502 msg.obj = device; 503 mBondStateMachine.sendMessage(msg); 504 return true; 505 } 506 507 public boolean cancelBondProcess(BluetoothDevice device) { 508 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 509 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 510 return cancelBondNative(addr); 511 } 512 513 public boolean removeBond(BluetoothDevice device) { 514 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 515 "Need BLUETOOTH ADMIN permission"); 516 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 517 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) { 518 return false; 519 } 520 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND); 521 msg.obj = device; 522 mBondStateMachine.sendMessage(msg); 523 return true; 524 } 525 526 public int getBondState(BluetoothDevice device) { 527 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 528 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 529 if (deviceProp == null) { 530 return BluetoothDevice.BOND_NONE; 531 } 532 return deviceProp.getBondState(); 533 } 534 535 public String getRemoteName(BluetoothDevice device) { 536 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 537 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 538 if (deviceProp == null) return null; 539 return deviceProp.getName(); 540 } 541 542 public String getRemoteAlias(BluetoothDevice device) { 543 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 544 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 545 if (deviceProp == null) return null; 546 return deviceProp.getAlias(); 547 } 548 549 public boolean setRemoteAlias(BluetoothDevice device, String name) { 550 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 551 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 552 if (deviceProp == null) return false; 553 deviceProp.setAlias(name); 554 return true; 555 } 556 557 public int getRemoteClass(BluetoothDevice device) { 558 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 559 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 560 if (deviceProp == null) return 0; 561 562 return deviceProp.getBluetoothClass(); 563 } 564 565 public ParcelUuid[] getRemoteUuids(BluetoothDevice device) { 566 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 567 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 568 if (deviceProp == null) return null; 569 return deviceProp.getUuids(); 570 } 571 572 public boolean fetchRemoteUuids(BluetoothDevice device) { 573 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 574 mRemoteDevices.fetchUuids(device); 575 return true; 576 } 577 578 public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) { 579 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 580 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 581 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 582 return false; 583 } 584 585 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 586 return pinReplyNative(addr, accept, len, pinCode); 587 } 588 589 public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) { 590 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 591 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 592 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 593 return false; 594 } 595 596 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 597 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept, 598 Utils.byteArrayToInt(passkey)); 599 } 600 601 public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) { 602 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 603 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 604 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 605 return false; 606 } 607 608 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 609 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION, 610 accept, 0); 611 } 612 613 public void sendConnectionStateChange(BluetoothDevice 614 device, int profile, int state, int prevState) { 615 // TODO(BT) permission check? 616 // Since this is a binder call check if Bluetooth is on still 617 if (getState() == BluetoothAdapter.STATE_OFF) return; 618 619 mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState); 620 621 } 622 623 public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type, 624 ParcelUuid uuid, int port, int flag) { 625 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 626 int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()), 627 type, Utils.uuidToByteArray(uuid), port, flag); 628 if (fd < 0) { 629 errorLog("Failed to connect socket"); 630 return null; 631 } 632 return ParcelFileDescriptor.adoptFd(fd); 633 } 634 635 public ParcelFileDescriptor createSocketChannel(int type, String serviceName, 636 ParcelUuid uuid, int port, int flag) { 637 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 638 int fd = createSocketChannelNative(type, serviceName, 639 Utils.uuidToByteArray(uuid), port, flag); 640 if (fd < 0) { 641 errorLog("Failed to create socket channel"); 642 return null; 643 } 644 return ParcelFileDescriptor.adoptFd(fd); 645 } 646 }; 647 648 private int convertScanModeToHal(int mode) { 649 switch (mode) { 650 case BluetoothAdapter.SCAN_MODE_NONE: 651 return AbstractionLayer.BT_SCAN_MODE_NONE; 652 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 653 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE; 654 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 655 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE; 656 } 657 errorLog("Incorrect scan mode in convertScanModeToHal"); 658 return -1; 659 } 660 661 int convertScanModeFromHal(int mode) { 662 switch (mode) { 663 case AbstractionLayer.BT_SCAN_MODE_NONE: 664 return BluetoothAdapter.SCAN_MODE_NONE; 665 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE: 666 return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 667 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE: 668 return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 669 } 670 errorLog("Incorrect scan mode in convertScanModeFromHal"); 671 return -1; 672 } 673 674 private static void debugLog(String msg) { 675 Log.d(TAG, msg); 676 } 677 678 private static void errorLog(String msg) { 679 Log.e(TAG, msg); 680 } 681 682 void persistBluetoothSetting(boolean setOn) { 683 long origCallerIdentityToken = Binder.clearCallingIdentity(); 684 Settings.Secure.putInt(mContext.getContentResolver(), 685 Settings.Secure.BLUETOOTH_ON, 686 setOn ? 1 : 0); 687 Binder.restoreCallingIdentity(origCallerIdentityToken); 688 } 689 690 boolean getBluetoothPersistedSetting() { 691 ContentResolver contentResolver = mContext.getContentResolver(); 692 return (Settings.Secure.getInt(contentResolver, 693 Settings.Secure.BLUETOOTH_ON, 0) > 0); 694 } 695 696 private native static void classInitNative(); 697 private native boolean initNative(); 698 private native void cleanupNative(); 699 /*package*/ native boolean enableNative(); 700 /*package*/ native boolean disableNative(); 701 /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val); 702 /*package*/ native boolean getAdapterPropertiesNative(); 703 /*package*/ native boolean getAdapterPropertyNative(int type); 704 /*package*/ native boolean setAdapterPropertyNative(int type); 705 /*package*/ native boolean 706 setDevicePropertyNative(byte[] address, int type, byte[] val); 707 /*package*/ native boolean getDevicePropertyNative(byte[] address, int type); 708 709 /*package*/ native boolean createBondNative(byte[] address); 710 /*package*/ native boolean removeBondNative(byte[] address); 711 /*package*/ native boolean cancelBondNative(byte[] address); 712 713 private native boolean startDiscoveryNative(); 714 private native boolean cancelDiscoveryNative(); 715 716 private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin); 717 private native boolean sspReplyNative(byte[] address, int type, boolean 718 accept, int passkey); 719 720 /*package*/ native boolean getRemoteServicesNative(byte[] address); 721 722 // TODO(BT) move this to ../btsock dir 723 private native int connectSocketNative(byte[] address, int type, 724 byte[] uuid, int port, int flag); 725 private native int createSocketChannelNative(int type, String serviceName, 726 byte[] uuid, int port, int flag); 727} 728