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