AdapterService.java revision 1c03c84f90991f6c9c740d72d91716d4b6a933e4
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.IBluetoothCallback; 18import android.bluetooth.IBluetoothManager; 19import android.bluetooth.IBluetoothManagerCallback; 20import android.content.BroadcastReceiver; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.os.Binder; 26import android.os.Bundle; 27import android.os.Handler; 28import android.os.IBinder; 29import android.os.Message; 30import android.os.ParcelFileDescriptor; 31import android.os.ParcelUuid; 32import android.os.RemoteCallbackList; 33import android.os.RemoteException; 34import android.provider.Settings; 35import android.util.Log; 36import android.util.Pair; 37import com.android.bluetooth.a2dp.A2dpService; 38import com.android.bluetooth.hid.HidService; 39import com.android.bluetooth.hfp.HeadsetService; 40import com.android.bluetooth.hdp.HealthService; 41import com.android.bluetooth.pan.PanService; 42import com.android.bluetooth.R; 43import com.android.bluetooth.Utils; 44import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 45import java.io.FileDescriptor; 46import java.io.IOException; 47import java.util.ArrayList; 48import java.util.HashMap; 49import java.util.Set; 50import java.util.Map; 51import java.util.Iterator; 52import java.util.Map.Entry; 53import java.util.List; 54import android.content.pm.PackageManager; 55import android.os.ServiceManager; 56 57public class AdapterService extends Service { 58 private static final String TAG = "BluetoothAdapterService"; 59 private static final boolean DBG = true; 60 private static final boolean TRACE_REF = true; 61 //For Debugging only 62 private static int sRefCount=0; 63 64 public static final String ACTION_LOAD_ADAPTER_PROPERTIES="com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES"; 65 public static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 66 public static final String EXTRA_ACTION="action"; 67 public static final int PROFILE_CONN_CONNECTED = 1; 68 public static final int PROFILE_CONN_REJECTED = 2; 69 70 static final String BLUETOOTH_ADMIN_PERM = 71 android.Manifest.permission.BLUETOOTH_ADMIN; 72 static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 73 74 private static final int ADAPTER_SERVICE_TYPE=Service.START_STICKY; 75 76 static { 77 classInitNative(); 78 } 79 80 private static AdapterService sAdapterService; 81 public static synchronized AdapterService getAdapterService(){ 82 if (sAdapterService != null && !sAdapterService.mCleaningUp) { 83 if (DBG) Log.d(TAG, "getAdapterService(): returning " + sAdapterService); 84 return sAdapterService; 85 } 86 if (DBG) { 87 if (sAdapterService == null) { 88 Log.d(TAG, "getAdapterService(): service not available"); 89 } else if (sAdapterService.mCleaningUp) { 90 Log.d(TAG,"getAdapterService(): service is cleaning up"); 91 } 92 } 93 return null; 94 } 95 96 private static synchronized void setAdapterService(AdapterService instance) { 97 if (instance != null && !instance.mCleaningUp) { 98 if (DBG) Log.d(TAG, "setAdapterService(): set to: " + sAdapterService); 99 sAdapterService = instance; 100 } else { 101 if (DBG) { 102 if (sAdapterService == null) { 103 Log.d(TAG, "setAdapterService(): service not available"); 104 } else if (sAdapterService.mCleaningUp) { 105 Log.d(TAG,"setAdapterService(): service is cleaning up"); 106 } 107 } 108 } 109 } 110 111 private static synchronized void clearAdapterService() { 112 sAdapterService = null; 113 } 114 115 private AdapterProperties mAdapterProperties; 116 private AdapterState mAdapterStateMachine; 117 private BondStateMachine mBondStateMachine; 118 private JniCallbacks mJniCallbacks; 119 private RemoteDevices mRemoteDevices; 120 private boolean mProfilesStarted; 121 private boolean mNativeAvailable; 122 private boolean mCleaningUp; 123 private HashMap<String,Integer> mProfileServicesState = new HashMap<String,Integer>(); 124 private RemoteCallbackList<IBluetoothCallback> mCallbacks;//Only BluetoothManagerService should be registered 125 private int mCurrentRequestId; 126 private boolean mQuietmode = false; 127 128 public AdapterService() { 129 super(); 130 if (TRACE_REF) { 131 synchronized (AdapterService.class) { 132 sRefCount++; 133 Log.d(TAG, "REFCOUNT: CREATED. INSTANCE_COUNT" + sRefCount); 134 } 135 } 136 } 137 138 public void onProfileConnectionStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) { 139 Message m = mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED); 140 m.obj = device; 141 m.arg1 = profileId; 142 m.arg2 = newState; 143 Bundle b = new Bundle(1); 144 b.putInt("prevState", prevState); 145 m.setData(b); 146 mHandler.sendMessage(m); 147 } 148 149 private void processProfileStateChanged(BluetoothDevice device, int profileId, int newState, int prevState) { 150 if (((profileId == BluetoothProfile.A2DP) ||(profileId == BluetoothProfile.HEADSET)) && 151 (newState == BluetoothProfile.STATE_CONNECTED)){ 152 if (DBG) debugLog( "Profile connected. Schedule missing profile connection if any"); 153 connectOtherProfile(device, PROFILE_CONN_CONNECTED); 154 setProfileAutoConnectionPriority(device, profileId); 155 } 156 IBluetooth.Stub binder = mBinder; 157 if (binder != null) { 158 try { 159 binder.sendConnectionStateChange(device, profileId, newState,prevState); 160 } catch (RemoteException re) { 161 Log.e(TAG, "",re); 162 } 163 } 164 } 165 166 public void onProfileServiceStateChanged(String serviceName, int state) { 167 Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED); 168 m.obj=serviceName; 169 m.arg1 = state; 170 mHandler.sendMessage(m); 171 } 172 173 private void processProfileServiceStateChanged(String serviceName, int state) { 174 boolean doUpdate=false; 175 boolean isTurningOn; 176 boolean isTurningOff; 177 178 synchronized (mProfileServicesState) { 179 Integer prevState = mProfileServicesState.get(serviceName); 180 if (prevState != null && prevState != state) { 181 mProfileServicesState.put(serviceName,state); 182 doUpdate=true; 183 } 184 } 185 if (DBG) Log.d(TAG,"onProfileServiceStateChange: serviceName=" + serviceName + ", state = " + state +", doUpdate = " + doUpdate); 186 187 if (!doUpdate) { 188 return; 189 } 190 191 synchronized (mAdapterStateMachine) { 192 isTurningOff = mAdapterStateMachine.isTurningOff(); 193 isTurningOn = mAdapterStateMachine.isTurningOn(); 194 } 195 196 if (isTurningOff) { 197 //Process stop or disable pending 198 //Check if all services are stopped if so, do cleanup 199 //if (DBG) Log.d(TAG,"Checking if all profiles are stopped..."); 200 synchronized (mProfileServicesState) { 201 Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator(); 202 while (i.hasNext()) { 203 Map.Entry<String,Integer> entry = i.next(); 204 if (BluetoothAdapter.STATE_OFF != entry.getValue()) { 205 Log.d(TAG, "Profile still running: " + entry.getKey()); 206 return; 207 } 208 } 209 } 210 if (DBG) Log.d(TAG, "All profile services stopped..."); 211 //Send message to state machine 212 mProfilesStarted=false; 213 mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STOPPED)); 214 } else if (isTurningOn) { 215 //Process start pending 216 //Check if all services are started if so, update state 217 //if (DBG) Log.d(TAG,"Checking if all profiles are running..."); 218 synchronized (mProfileServicesState) { 219 Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator(); 220 while (i.hasNext()) { 221 Map.Entry<String,Integer> entry = i.next(); 222 if (BluetoothAdapter.STATE_ON != entry.getValue()) { 223 Log.d(TAG, "Profile still not running:" + entry.getKey()); 224 return; 225 } 226 } 227 } 228 if (DBG) Log.d(TAG, "All profile services started."); 229 mProfilesStarted=true; 230 //Send message to state machine 231 mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED)); 232 } 233 } 234 235 @Override 236 public void onCreate() { 237 super.onCreate(); 238 if (DBG) debugLog("onCreate"); 239 mBinder = new AdapterServiceBinder(this); 240 mAdapterProperties = new AdapterProperties(this); 241 mAdapterStateMachine = new AdapterState(this, mAdapterProperties); 242 mJniCallbacks = new JniCallbacks(mAdapterStateMachine, mAdapterProperties); 243 initNative(); 244 mNativeAvailable=true; 245 mAdapterStateMachine.start(); 246 mCallbacks = new RemoteCallbackList<IBluetoothCallback>(); 247 //Load the name and address 248 getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR); 249 getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME); 250 251 } 252 253 @Override 254 public IBinder onBind(Intent intent) { 255 if (DBG) debugLog("onBind"); 256 return mBinder; 257 } 258 public boolean onUnbind(Intent intent) { 259 if (DBG) debugLog("onUnbind, calling cleanup"); 260 cleanup(); 261 return super.onUnbind(intent); 262 } 263 264 public void onDestroy() { 265 debugLog("****onDestroy()********"); 266 } 267 268 void processStart() { 269 if (DBG) debugLog("processStart()"); 270 Class[] supportedProfileServices = Config.getSupportedProfiles(); 271 //Initialize data objects 272 for (int i=0; i < supportedProfileServices.length;i++) { 273 mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF); 274 } 275 mRemoteDevices = new RemoteDevices(this); 276 mBondStateMachine = new BondStateMachine(this, mAdapterProperties, mRemoteDevices); 277 mAdapterProperties.init(mRemoteDevices); 278 mJniCallbacks.init(mBondStateMachine,mRemoteDevices); 279 280 //Start Bond State Machine 281 if (DBG) {debugLog("processStart(): Starting Bond State Machine");} 282 mBondStateMachine.start(); 283 284 //FIXME: Set static instance here??? 285 setAdapterService(this); 286 287 //Start profile services 288 if (!mProfilesStarted && supportedProfileServices.length >0) { 289 //Startup all profile services 290 setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON); 291 }else { 292 if (DBG) {debugLog("processStart(): Profile Services alreay started");} 293 mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED)); 294 } 295 } 296 297 void startBluetoothDisable() { 298 mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BEGIN_DISABLE)); 299 } 300 301 boolean stopProfileServices() { 302 Class[] supportedProfileServices = Config.getSupportedProfiles(); 303 if (mProfilesStarted && supportedProfileServices.length>0) { 304 setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_OFF); 305 return true; 306 } else { 307 if (DBG) {debugLog("stopProfileServices(): No profiles services to stop or already stopped.");} 308 return false; 309 } 310 } 311 312 void updateAdapterState(int prevState, int newState){ 313 if (mCallbacks !=null) { 314 int n=mCallbacks.beginBroadcast(); 315 Log.d(TAG,"Broadcasting updateAdapterState() to " + n + " receivers."); 316 for (int i=0; i <n;i++) { 317 try { 318 mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState,newState); 319 } catch (RemoteException e) { 320 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e); 321 } 322 } 323 mCallbacks.finishBroadcast(); 324 } 325 } 326 327 void cleanup () { 328 if (DBG)debugLog("cleanup()"); 329 if (mCleaningUp) { 330 Log.w(TAG,"*************service already starting to cleanup... Ignoring cleanup request........."); 331 return; 332 } 333 334 mCleaningUp = true; 335 336 if (mAdapterStateMachine != null) { 337 mAdapterStateMachine.doQuit(); 338 mAdapterStateMachine.cleanup(); 339 } 340 341 if (mBondStateMachine != null) { 342 mBondStateMachine.doQuit(); 343 mBondStateMachine.cleanup(); 344 } 345 346 if (mRemoteDevices != null) { 347 mRemoteDevices.cleanup(); 348 } 349 350 if (mNativeAvailable) { 351 Log.d(TAG, "Cleaning up adapter native...."); 352 cleanupNative(); 353 Log.d(TAG, "Done cleaning up adapter native...."); 354 mNativeAvailable=false; 355 } 356 357 if (mAdapterProperties != null) { 358 mAdapterProperties.cleanup(); 359 } 360 361 if (mJniCallbacks != null) { 362 mJniCallbacks.cleanup(); 363 } 364 365 if (mProfileServicesState != null) { 366 mProfileServicesState.clear(); 367 } 368 369 clearAdapterService(); 370 371 if (mBinder != null) { 372 mBinder.cleanup(); 373 mBinder = null; //Do not remove. Otherwise Binder leak! 374 } 375 376 if (mCallbacks !=null) { 377 mCallbacks.kill(); 378 } 379 380 if (DBG)debugLog("cleanup() done"); 381 } 382 383 private static final int MESSAGE_PROFILE_SERVICE_STATE_CHANGED =1; 384 private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED=20; 385 private static final int MESSAGE_CONNECT_OTHER_PROFILES = 30; 386 private static final int CONNECT_OTHER_PROFILES_TIMEOUT= 6000; 387 388 private final Handler mHandler = new Handler() { 389 @Override 390 public void handleMessage(Message msg) { 391 if (DBG) debugLog("Message: " + msg.what); 392 393 switch (msg.what) { 394 case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: { 395 if(DBG) debugLog("MESSAGE_PROFILE_SERVICE_STATE_CHANGED"); 396 processProfileServiceStateChanged((String) msg.obj, msg.arg1); 397 } 398 break; 399 case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: { 400 if (DBG) debugLog( "MESSAGE_PROFILE_CONNECTION_STATE_CHANGED"); 401 processProfileStateChanged((BluetoothDevice) msg.obj, msg.arg1,msg.arg2, msg.getData().getInt("prevState",BluetoothAdapter.ERROR)); 402 } 403 break; 404 case MESSAGE_CONNECT_OTHER_PROFILES: { 405 if (DBG) debugLog( "MESSAGE_CONNECT_OTHER_PROFILES"); 406 processConnectOtherProfiles((BluetoothDevice) msg.obj,msg.arg1); 407 } 408 break; 409 } 410 } 411 }; 412 413 @SuppressWarnings("rawtypes") 414 private void setProfileServiceState(Class[] services, int state) { 415 if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { 416 Log.w(TAG,"setProfileServiceState(): invalid state...Leaving..."); 417 return; 418 } 419 420 int expectedCurrentState= BluetoothAdapter.STATE_OFF; 421 int pendingState = BluetoothAdapter.STATE_TURNING_ON; 422 if (state == BluetoothAdapter.STATE_OFF) { 423 expectedCurrentState= BluetoothAdapter.STATE_ON; 424 pendingState = BluetoothAdapter.STATE_TURNING_OFF; 425 } 426 427 for (int i=0; i <services.length;i++) { 428 String serviceName = services[i].getName(); 429 Integer serviceState = mProfileServicesState.get(serviceName); 430 if(serviceState != null && serviceState != expectedCurrentState) { 431 Log.w(TAG, "Unable to " + (state == BluetoothAdapter.STATE_OFF? "start" : "stop" ) +" service " + 432 serviceName+". Invalid state: " + serviceState); 433 continue; 434 } 435 436 if (DBG) { 437 Log.w(TAG, (state == BluetoothAdapter.STATE_OFF? "Stopping" : "Starting" ) +" service " + 438 serviceName); 439 } 440 441 mProfileServicesState.put(serviceName,pendingState); 442 Intent intent = new Intent(this,services[i]); 443 intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED); 444 intent.putExtra(BluetoothAdapter.EXTRA_STATE,state); 445 startService(intent); 446 } 447 } 448 449 private boolean isAvailable() { 450 return !mCleaningUp; 451 } 452 453 /** 454 * Handlers for incoming service calls 455 */ 456 private AdapterServiceBinder mBinder; 457 458 /** 459 * The Binder implementation must be declared to be a static class, with 460 * the AdapterService instance passed in the constructor. Furthermore, 461 * when the AdapterService shuts down, the reference to the AdapterService 462 * must be explicitly removed. 463 * 464 * Otherwise, a memory leak can occur from repeated starting/stopping the 465 * service...Please refer to android.os.Binder for further details on 466 * why an inner instance class should be avoided. 467 * 468 */ 469 private static class AdapterServiceBinder extends IBluetooth.Stub { 470 private AdapterService mService; 471 472 public AdapterServiceBinder(AdapterService svc) { 473 mService = svc; 474 } 475 public boolean cleanup() { 476 mService = null; 477 return true; 478 } 479 480 public AdapterService getService() { 481 if (mService != null && mService.isAvailable()) { 482 return mService; 483 } 484 return null; 485 } 486 public boolean isEnabled() { 487 AdapterService service = getService(); 488 if (service == null) return false; 489 return service.isEnabled(); 490 } 491 492 public int getState() { 493 AdapterService service = getService(); 494 if (service == null) return BluetoothAdapter.STATE_OFF; 495 return service.getState(); 496 } 497 498 public boolean enable() { 499 AdapterService service = getService(); 500 if (service == null) return false; 501 return service.enable(); 502 } 503 504 public boolean enableNoAutoConnect() { 505 AdapterService service = getService(); 506 if (service == null) return false; 507 return service.enableNoAutoConnect(); 508 } 509 510 public boolean disable() { 511 AdapterService service = getService(); 512 if (service == null) return false; 513 return service.disable(); 514 } 515 516 public String getAddress() { 517 AdapterService service = getService(); 518 if (service == null) return null; 519 return service.getAddress(); 520 } 521 522 public ParcelUuid[] getUuids() { 523 AdapterService service = getService(); 524 if (service == null) return new ParcelUuid[0]; 525 return service.getUuids(); 526 } 527 528 public String getName() { 529 AdapterService service = getService(); 530 if (service == null) return null; 531 return service.getName(); 532 } 533 534 public boolean setName(String name) { 535 AdapterService service = getService(); 536 if (service == null) return false; 537 return service.setName(name); 538 } 539 540 public int getScanMode() { 541 AdapterService service = getService(); 542 if (service == null) return BluetoothAdapter.SCAN_MODE_NONE; 543 return service.getScanMode(); 544 } 545 546 public boolean setScanMode(int mode, int duration) { 547 AdapterService service = getService(); 548 if (service == null) return false; 549 return service.setScanMode(mode,duration); 550 } 551 552 public int getDiscoverableTimeout() { 553 AdapterService service = getService(); 554 if (service == null) return 0; 555 return service.getDiscoverableTimeout(); 556 } 557 558 public boolean setDiscoverableTimeout(int timeout) { 559 AdapterService service = getService(); 560 if (service == null) return false; 561 return service.setDiscoverableTimeout(timeout); 562 } 563 564 public boolean startDiscovery() { 565 AdapterService service = getService(); 566 if (service == null) return false; 567 return service.startDiscovery(); 568 } 569 570 public boolean cancelDiscovery() { 571 AdapterService service = getService(); 572 if (service == null) return false; 573 return service.cancelDiscovery(); 574 } 575 public boolean isDiscovering() { 576 AdapterService service = getService(); 577 if (service == null) return false; 578 return service.isDiscovering(); 579 } 580 581 public BluetoothDevice[] getBondedDevices() { 582 AdapterService service = getService(); 583 if (service == null) return new BluetoothDevice[0]; 584 return service.getBondedDevices(); 585 } 586 587 public int getAdapterConnectionState() { 588 AdapterService service = getService(); 589 if (service == null) return BluetoothAdapter.STATE_DISCONNECTED; 590 return service.getAdapterConnectionState(); 591 } 592 593 public int getProfileConnectionState(int profile) { 594 AdapterService service = getService(); 595 if (service == null) return BluetoothProfile.STATE_DISCONNECTED; 596 return service.getProfileConnectionState(profile); 597 } 598 599 public boolean createBond(BluetoothDevice device) { 600 AdapterService service = getService(); 601 if (service == null) return false; 602 return service.createBond(device); 603 } 604 605 public boolean cancelBondProcess(BluetoothDevice device) { 606 AdapterService service = getService(); 607 if (service == null) return false; 608 return service.cancelBondProcess(device); 609 } 610 611 public boolean removeBond(BluetoothDevice device) { 612 AdapterService service = getService(); 613 if (service == null) return false; 614 return service.removeBond(device); 615 } 616 617 public int getBondState(BluetoothDevice device) { 618 AdapterService service = getService(); 619 if (service == null) return BluetoothDevice.BOND_NONE; 620 return service.getBondState(device); 621 } 622 623 public String getRemoteName(BluetoothDevice device) { 624 AdapterService service = getService(); 625 if (service == null) return null; 626 return service.getRemoteName(device); 627 } 628 629 public String getRemoteAlias(BluetoothDevice device) { 630 AdapterService service = getService(); 631 if (service == null) return null; 632 return service.getRemoteAlias(device); 633 } 634 635 public boolean setRemoteAlias(BluetoothDevice device, String name) { 636 AdapterService service = getService(); 637 if (service == null) return false; 638 return service.setRemoteAlias(device, name); 639 } 640 641 public int getRemoteClass(BluetoothDevice device) { 642 AdapterService service = getService(); 643 if (service == null) return 0; 644 return service.getRemoteClass(device); 645 } 646 647 public ParcelUuid[] getRemoteUuids(BluetoothDevice device) { 648 AdapterService service = getService(); 649 if (service == null) return null; 650 return service.getRemoteUuids(device); 651 } 652 653 public boolean fetchRemoteUuids(BluetoothDevice device) { 654 AdapterService service = getService(); 655 if (service == null) return false; 656 return service.fetchRemoteUuids(device); 657 } 658 659 public boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) { 660 AdapterService service = getService(); 661 if (service == null) return false; 662 return service.setPin(device, accept, len, pinCode); 663 } 664 665 public boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) { 666 AdapterService service = getService(); 667 if (service == null) return false; 668 return service.setPasskey(device, accept, len, passkey); 669 } 670 671 public boolean setPairingConfirmation(BluetoothDevice device, boolean accept) { 672 AdapterService service = getService(); 673 if (service == null) return false; 674 return service.setPairingConfirmation(device, accept); 675 } 676 677 public void sendConnectionStateChange(BluetoothDevice 678 device, int profile, int state, int prevState) { 679 AdapterService service = getService(); 680 if (service == null) return; 681 service.sendConnectionStateChange(device, profile, state, prevState); 682 } 683 684 public ParcelFileDescriptor connectSocket(BluetoothDevice device, int type, 685 ParcelUuid uuid, int port, int flag) { 686 AdapterService service = getService(); 687 if (service == null) return null; 688 return service.connectSocket(device, type, uuid, port, flag); 689 } 690 691 public ParcelFileDescriptor createSocketChannel(int type, String serviceName, 692 ParcelUuid uuid, int port, int flag) { 693 AdapterService service = getService(); 694 if (service == null) return null; 695 return service.createSocketChannel(type, serviceName, uuid, port, flag); 696 } 697 698 public void registerCallback(IBluetoothCallback cb) { 699 AdapterService service = getService(); 700 if (service == null) return ; 701 service.registerCallback(cb); 702 } 703 704 public void unregisterCallback(IBluetoothCallback cb) { 705 AdapterService service = getService(); 706 if (service == null) return ; 707 service.unregisterCallback(cb); 708 } 709 }; 710 711 712 //----API Methods-------- 713 boolean isEnabled() { 714 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 715 return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON; 716 } 717 718 int getState() { 719 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 720 if (mAdapterProperties == null){ 721 return BluetoothAdapter.STATE_OFF; 722 } 723 else { 724 debugLog("getState(): mAdapterProperties: " + mAdapterProperties); 725 return mAdapterProperties.getState(); 726 } 727 } 728 729 boolean enable() { 730 return enable (false); 731 } 732 733 public boolean enableNoAutoConnect() { 734 return enable (true); 735 } 736 737 public synchronized boolean enable(boolean quietMode) { 738 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 739 "Need BLUETOOTH ADMIN permission"); 740 if (DBG)debugLog("Enable called with quiet mode status = " + mQuietmode); 741 mQuietmode = quietMode; 742 Message m = 743 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON); 744 mAdapterStateMachine.sendMessage(m); 745 return true; 746 } 747 748 boolean disable() { 749 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 750 "Need BLUETOOTH ADMIN permission"); 751 if (DBG) debugLog("disable() called..."); 752 Message m = 753 mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF); 754 mAdapterStateMachine.sendMessage(m); 755 return true; 756 } 757 758 String getAddress() { 759 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 760 String addrString = null; 761 byte[] address = mAdapterProperties.getAddress(); 762 return Utils.getAddressStringFromByte(address); 763 } 764 765 ParcelUuid[] getUuids() { 766 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 767 return mAdapterProperties.getUuids(); 768 } 769 770 String getName() { 771 enforceCallingOrSelfPermission(BLUETOOTH_PERM, 772 "Need BLUETOOTH permission"); 773 try { 774 return mAdapterProperties.getName(); 775 } catch (Throwable t) { 776 Log.d(TAG, "Unexpected exception while calling getName()",t); 777 } 778 return null; 779 } 780 781 boolean setName(String name) { 782 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 783 "Need BLUETOOTH ADMIN permission"); 784 return mAdapterProperties.setName(name); 785 } 786 787 int getScanMode() { 788 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 789 return mAdapterProperties.getScanMode(); 790 } 791 792 boolean setScanMode(int mode, int duration) { 793 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 794 setDiscoverableTimeout(duration); 795 796 int newMode = convertScanModeToHal(mode); 797 return mAdapterProperties.setScanMode(newMode); 798 } 799 800 int getDiscoverableTimeout() { 801 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 802 return mAdapterProperties.getDiscoverableTimeout(); 803 } 804 805 boolean setDiscoverableTimeout(int timeout) { 806 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 807 return mAdapterProperties.setDiscoverableTimeout(timeout); 808 } 809 810 boolean startDiscovery() { 811 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 812 "Need BLUETOOTH ADMIN permission"); 813 return startDiscoveryNative(); 814 } 815 816 boolean cancelDiscovery() { 817 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 818 "Need BLUETOOTH ADMIN permission"); 819 return cancelDiscoveryNative(); 820 } 821 822 boolean isDiscovering() { 823 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 824 return mAdapterProperties.isDiscovering(); 825 } 826 827 BluetoothDevice[] getBondedDevices() { 828 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 829 debugLog("Get Bonded Devices being called"); 830 return mAdapterProperties.getBondedDevices(); 831 } 832 833 int getAdapterConnectionState() { 834 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 835 return mAdapterProperties.getConnectionState(); 836 } 837 838 int getProfileConnectionState(int profile) { 839 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 840 return mAdapterProperties.getProfileConnectionState(profile); 841 } 842 843 boolean createBond(BluetoothDevice device) { 844 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 845 "Need BLUETOOTH ADMIN permission"); 846 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 847 if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) { 848 return false; 849 } 850 851 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND); 852 msg.obj = device; 853 mBondStateMachine.sendMessage(msg); 854 return true; 855 } 856 857 public boolean isQuietModeEnabled() { 858 if (DBG) debugLog("Quiet mode Enabled = " + mQuietmode); 859 return mQuietmode; 860 } 861 862 public void autoConnect(){ 863 if (getState() != BluetoothAdapter.STATE_ON){ 864 errorLog("BT is not ON. Exiting autoConnect"); 865 return; 866 } 867 if (isQuietModeEnabled() == false) { 868 if (DBG) debugLog( "Initiate auto connection on BT on..."); 869 autoConnectHeadset(); 870 autoConnectA2dp(); 871 } 872 else { 873 if (DBG) debugLog( "BT is in Quiet mode. Not initiating auto connections"); 874 } 875 } 876 877 private void autoConnectHeadset(){ 878 HeadsetService hsService = HeadsetService.getHeadsetService(); 879 880 BluetoothDevice bondedDevices[] = getBondedDevices(); 881 if ((bondedDevices == null) ||(hsService == null)) { 882 return; 883 } 884 for (BluetoothDevice device : bondedDevices) { 885 if (hsService.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){ 886 Log.d(TAG,"Auto Connecting Headset Profile with device " + device.toString()); 887 hsService.connect(device); 888 } 889 } 890 } 891 892 private void autoConnectA2dp(){ 893 A2dpService a2dpSservice = A2dpService.getA2dpService(); 894 BluetoothDevice bondedDevices[] = getBondedDevices(); 895 if ((bondedDevices == null) ||(a2dpSservice == null)) { 896 return; 897 } 898 for (BluetoothDevice device : bondedDevices) { 899 if (a2dpSservice.getPriority(device) == BluetoothProfile.PRIORITY_AUTO_CONNECT ){ 900 Log.d(TAG,"Auto Connecting A2DP Profile with device " + device.toString()); 901 a2dpSservice.connect(device); 902 } 903 } 904 } 905 906 public void connectOtherProfile(BluetoothDevice device, int firstProfileStatus){ 907 if ((mHandler.hasMessages(MESSAGE_CONNECT_OTHER_PROFILES) == false) && 908 (isQuietModeEnabled()== false)){ 909 Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES); 910 m.obj = device; 911 m.arg1 = (int)firstProfileStatus; 912 mHandler.sendMessageDelayed(m,CONNECT_OTHER_PROFILES_TIMEOUT); 913 } 914 } 915 916 private void processConnectOtherProfiles (BluetoothDevice device, int firstProfileStatus){ 917 if (getState()!= BluetoothAdapter.STATE_ON){ 918 return; 919 } 920 HeadsetService hsService = HeadsetService.getHeadsetService(); 921 A2dpService a2dpService = A2dpService.getA2dpService(); 922 // if any of the profile service is null, second profile connection not required 923 if ((hsService == null) ||(a2dpService == null )){ 924 return; 925 } 926 List<BluetoothDevice> a2dpConnDevList= a2dpService.getConnectedDevices(); 927 List<BluetoothDevice> hfConnDevList= hsService.getConnectedDevices(); 928 // Check if the device is in disconnected state and if so return 929 // We ned to connect other profile only if one of the profile is still in connected state 930 // This is required to avoide a race condition in which profiles would 931 // automaticlly connect if the disconnection is initiated within 6 seconds of connection 932 //First profile connection being rejected is an exception 933 if((hfConnDevList.isEmpty() && a2dpConnDevList.isEmpty())&& 934 (PROFILE_CONN_CONNECTED == firstProfileStatus)){ 935 return; 936 } 937 if((hfConnDevList.isEmpty()) && 938 (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){ 939 hsService.connect(device); 940 } 941 else if((a2dpConnDevList.isEmpty()) && 942 (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)){ 943 a2dpService.connect(device); 944 } 945 } 946 947 private void adjustOtherHeadsetPriorities(HeadsetService hsService, 948 BluetoothDevice connectedDevice) { 949 for (BluetoothDevice device : getBondedDevices()) { 950 if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT && 951 !device.equals(connectedDevice)) { 952 hsService.setPriority(device, BluetoothProfile.PRIORITY_ON); 953 } 954 } 955 } 956 957 private void adjustOtherSinkPriorities(A2dpService a2dpService, 958 BluetoothDevice connectedDevice) { 959 for (BluetoothDevice device : getBondedDevices()) { 960 if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT && 961 !device.equals(connectedDevice)) { 962 a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON); 963 } 964 } 965 } 966 967 void setProfileAutoConnectionPriority (BluetoothDevice device, int profileId){ 968 if (profileId == BluetoothProfile.HEADSET) { 969 HeadsetService hsService = HeadsetService.getHeadsetService(); 970 if ((hsService != null) && 971 (BluetoothProfile.PRIORITY_AUTO_CONNECT != hsService.getPriority(device))){ 972 adjustOtherHeadsetPriorities(hsService, device); 973 hsService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT); 974 } 975 } 976 else if (profileId == BluetoothProfile.A2DP) { 977 A2dpService a2dpService = A2dpService.getA2dpService(); 978 if ((a2dpService != null) && 979 (BluetoothProfile.PRIORITY_AUTO_CONNECT != a2dpService.getPriority(device))){ 980 adjustOtherSinkPriorities(a2dpService, device); 981 a2dpService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT); 982 } 983 } 984 } 985 986 boolean cancelBondProcess(BluetoothDevice device) { 987 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 988 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 989 return cancelBondNative(addr); 990 } 991 992 boolean removeBond(BluetoothDevice device) { 993 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 994 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 995 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDED) { 996 return false; 997 } 998 Message msg = mBondStateMachine.obtainMessage(BondStateMachine.REMOVE_BOND); 999 msg.obj = device; 1000 mBondStateMachine.sendMessage(msg); 1001 return true; 1002 } 1003 1004 int getBondState(BluetoothDevice device) { 1005 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1006 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1007 if (deviceProp == null) { 1008 return BluetoothDevice.BOND_NONE; 1009 } 1010 return deviceProp.getBondState(); 1011 } 1012 1013 String getRemoteName(BluetoothDevice device) { 1014 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1015 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1016 if (deviceProp == null) return null; 1017 return deviceProp.getName(); 1018 } 1019 1020 String getRemoteAlias(BluetoothDevice device) { 1021 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1022 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1023 if (deviceProp == null) return null; 1024 return deviceProp.getAlias(); 1025 } 1026 1027 boolean setRemoteAlias(BluetoothDevice device, String name) { 1028 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1029 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1030 if (deviceProp == null) return false; 1031 deviceProp.setAlias(name); 1032 return true; 1033 } 1034 1035 int getRemoteClass(BluetoothDevice device) { 1036 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1037 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1038 if (deviceProp == null) return 0; 1039 1040 return deviceProp.getBluetoothClass(); 1041 } 1042 1043 ParcelUuid[] getRemoteUuids(BluetoothDevice device) { 1044 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1045 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1046 if (deviceProp == null) return null; 1047 return deviceProp.getUuids(); 1048 } 1049 1050 boolean fetchRemoteUuids(BluetoothDevice device) { 1051 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1052 mRemoteDevices.fetchUuids(device); 1053 return true; 1054 } 1055 1056 boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) { 1057 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1058 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1059 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 1060 return false; 1061 } 1062 1063 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 1064 return pinReplyNative(addr, accept, len, pinCode); 1065 } 1066 1067 boolean setPasskey(BluetoothDevice device, boolean accept, int len, byte[] passkey) { 1068 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1069 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1070 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 1071 return false; 1072 } 1073 1074 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 1075 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY, accept, 1076 Utils.byteArrayToInt(passkey)); 1077 } 1078 1079 boolean setPairingConfirmation(BluetoothDevice device, boolean accept) { 1080 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1081 DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device); 1082 if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) { 1083 return false; 1084 } 1085 1086 byte[] addr = Utils.getBytesFromAddress(device.getAddress()); 1087 return sspReplyNative(addr, AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION, 1088 accept, 0); 1089 } 1090 1091 void sendConnectionStateChange(BluetoothDevice 1092 device, int profile, int state, int prevState) { 1093 // TODO(BT) permission check? 1094 // Since this is a binder call check if Bluetooth is on still 1095 if (getState() == BluetoothAdapter.STATE_OFF) return; 1096 1097 mAdapterProperties.sendConnectionStateChange(device, profile, state, prevState); 1098 1099 } 1100 1101 ParcelFileDescriptor connectSocket(BluetoothDevice device, int type, 1102 ParcelUuid uuid, int port, int flag) { 1103 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1104 int fd = connectSocketNative(Utils.getBytesFromAddress(device.getAddress()), 1105 type, Utils.uuidToByteArray(uuid), port, flag); 1106 if (fd < 0) { 1107 errorLog("Failed to connect socket"); 1108 return null; 1109 } 1110 return ParcelFileDescriptor.adoptFd(fd); 1111 } 1112 1113 ParcelFileDescriptor createSocketChannel(int type, String serviceName, 1114 ParcelUuid uuid, int port, int flag) { 1115 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1116 int fd = createSocketChannelNative(type, serviceName, 1117 Utils.uuidToByteArray(uuid), port, flag); 1118 if (fd < 0) { 1119 errorLog("Failed to create socket channel"); 1120 return null; 1121 } 1122 return ParcelFileDescriptor.adoptFd(fd); 1123 } 1124 1125 void registerCallback(IBluetoothCallback cb) { 1126 mCallbacks.register(cb); 1127 } 1128 1129 void unregisterCallback(IBluetoothCallback cb) { 1130 mCallbacks.unregister(cb); 1131 } 1132 1133 private static int convertScanModeToHal(int mode) { 1134 switch (mode) { 1135 case BluetoothAdapter.SCAN_MODE_NONE: 1136 return AbstractionLayer.BT_SCAN_MODE_NONE; 1137 case BluetoothAdapter.SCAN_MODE_CONNECTABLE: 1138 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE; 1139 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: 1140 return AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE; 1141 } 1142 // errorLog("Incorrect scan mode in convertScanModeToHal"); 1143 return -1; 1144 } 1145 1146 static int convertScanModeFromHal(int mode) { 1147 switch (mode) { 1148 case AbstractionLayer.BT_SCAN_MODE_NONE: 1149 return BluetoothAdapter.SCAN_MODE_NONE; 1150 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE: 1151 return BluetoothAdapter.SCAN_MODE_CONNECTABLE; 1152 case AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE: 1153 return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE; 1154 } 1155 //errorLog("Incorrect scan mode in convertScanModeFromHal"); 1156 return -1; 1157 } 1158 1159 private void debugLog(String msg) { 1160 Log.d(TAG +"(" +hashCode()+")", msg); 1161 } 1162 1163 private void errorLog(String msg) { 1164 Log.e(TAG +"(" +hashCode()+")", msg); 1165 } 1166 1167 private native static void classInitNative(); 1168 private native boolean initNative(); 1169 private native void cleanupNative(); 1170 /*package*/ native boolean enableNative(); 1171 /*package*/ native boolean disableNative(); 1172 /*package*/ native boolean setAdapterPropertyNative(int type, byte[] val); 1173 /*package*/ native boolean getAdapterPropertiesNative(); 1174 /*package*/ native boolean getAdapterPropertyNative(int type); 1175 /*package*/ native boolean setAdapterPropertyNative(int type); 1176 /*package*/ native boolean 1177 setDevicePropertyNative(byte[] address, int type, byte[] val); 1178 /*package*/ native boolean getDevicePropertyNative(byte[] address, int type); 1179 1180 /*package*/ native boolean createBondNative(byte[] address); 1181 /*package*/ native boolean removeBondNative(byte[] address); 1182 /*package*/ native boolean cancelBondNative(byte[] address); 1183 1184 private native boolean startDiscoveryNative(); 1185 private native boolean cancelDiscoveryNative(); 1186 1187 private native boolean pinReplyNative(byte[] address, boolean accept, int len, byte[] pin); 1188 private native boolean sspReplyNative(byte[] address, int type, boolean 1189 accept, int passkey); 1190 1191 /*package*/ native boolean getRemoteServicesNative(byte[] address); 1192 1193 // TODO(BT) move this to ../btsock dir 1194 private native int connectSocketNative(byte[] address, int type, 1195 byte[] uuid, int port, int flag); 1196 private native int createSocketChannelNative(int type, String serviceName, 1197 byte[] uuid, int port, int flag); 1198 1199 protected void finalize() { 1200 cleanup(); 1201 if (TRACE_REF) { 1202 synchronized (AdapterService.class) { 1203 sRefCount--; 1204 Log.d(TAG, "REFCOUNT: FINALIZED. INSTANCE_COUNT= " + sRefCount); 1205 } 1206 } 1207 } 1208} 1209