BluetoothManagerService.java revision fffa86ba834d37684238c83c0dd081133324984d
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5package com.android.server; 6 7import android.bluetooth.BluetoothAdapter; 8import android.bluetooth.IBluetooth; 9import android.bluetooth.IBluetoothCallback; 10import android.bluetooth.IBluetoothManager; 11import android.bluetooth.IBluetoothManagerCallback; 12import android.bluetooth.IBluetoothStateChangeCallback; 13import android.content.BroadcastReceiver; 14import android.content.ComponentName; 15import android.content.ContentResolver; 16import android.content.Context; 17import android.content.Intent; 18import android.content.IntentFilter; 19import android.content.ServiceConnection; 20import android.os.Handler; 21import android.os.IBinder; 22import android.os.Message; 23import android.os.RemoteCallbackList; 24import android.os.RemoteException; 25import android.os.Binder; 26import android.provider.Settings; 27import android.util.Log; 28import java.util.List; 29import java.util.ArrayList; 30class BluetoothManagerService extends IBluetoothManager.Stub { 31 private static final String TAG = "BluetoothManagerService"; 32 private static final boolean DBG = true; 33 34 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 35 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 36 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 37 private static final String EXTRA_ACTION="action"; 38 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; 39 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; 40 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind 41 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save 42 43 private static final int MESSAGE_ENABLE = 1; 44 private static final int MESSAGE_DISABLE = 2; 45 private static final int MESSAGE_REGISTER_ADAPTER = 20; 46 private static final int MESSAGE_UNREGISTER_ADAPTER = 21; 47 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; 48 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; 49 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; 50 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; 51 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60; 52 private static final int MESSAGE_TIMEOUT_BIND =100; 53 private static final int MESSAGE_TIMEOUT_UNBIND =101; 54 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; 55 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; 56 private static final int MAX_SAVE_RETRIES=3; 57 58 private final Context mContext; 59 60 // Locks are not provided for mName and mAddress. 61 // They are accessed in handler or broadcast receiver, same thread context. 62 private String mAddress; 63 private String mName; 64 private final ContentResolver mContentResolver; 65 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 66 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; 67 private IBluetooth mBluetooth; 68 private boolean mBinding; 69 private boolean mUnbinding; 70 private boolean mQuietEnable = false; 71 72 private void registerForAirplaneMode(IntentFilter filter) { 73 final ContentResolver resolver = mContext.getContentResolver(); 74 final String airplaneModeRadios = Settings.System.getString(resolver, 75 Settings.System.AIRPLANE_MODE_RADIOS); 76 final String toggleableRadios = Settings.System.getString(resolver, 77 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 78 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true : 79 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH); 80 if (mIsAirplaneSensitive) { 81 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 82 } 83 } 84 85 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { 86 @Override 87 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { 88 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); 89 mHandler.sendMessage(msg); 90 } 91 }; 92 93 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 94 @Override 95 public void onReceive(Context context, Intent intent) { 96 String action = intent.getAction(); 97 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { 98 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); 99 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName); 100 if (newName != null) { 101 storeNameAndAddress(newName, null); 102 } 103 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 104 if (isAirplaneModeOn()) { 105 // disable without persisting the setting 106 handleDisable(false); 107 } else { 108 if (isBluetoothPersistedStateOn()) { 109 // enable without persisting the setting 110 handleEnable(false, false); 111 } 112 } 113 } 114 } 115 }; 116 117 BluetoothManagerService(Context context) { 118 mContext = context; 119 mBluetooth = null; 120 mBinding = false; 121 mUnbinding = false; 122 mAddress = null; 123 mName = null; 124 mContentResolver = context.getContentResolver(); 125 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); 126 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); 127 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 128 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 129 registerForAirplaneMode(filter); 130 mContext.registerReceiver(mReceiver, filter); 131 boolean airplaneModeOn = isAirplaneModeOn(); 132 boolean bluetoothOn = isBluetoothPersistedStateOn(); 133 loadStoredNameAndAddress(); 134 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn); 135 if (bluetoothOn) { 136 //Enable 137 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); 138 enable(); 139 } else if (!isNameAndAddressSet()) { 140 //Sync the Bluetooth name and address from the Bluetooth Adapter 141 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); 142 getNameAndAddress(); 143 } 144 } 145 146 /** 147 * Returns true if airplane mode is currently on 148 */ 149 private final boolean isAirplaneModeOn() { 150 return Settings.System.getInt(mContext.getContentResolver(), 151 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 152 } 153 154 /** 155 * Returns true if the Bluetooth saved state is "on" 156 */ 157 private final boolean isBluetoothPersistedStateOn() { 158 return Settings.Secure.getInt(mContentResolver, 159 Settings.Secure.BLUETOOTH_ON, 0) ==1; 160 } 161 162 /** 163 * Save the Bluetooth on/off state 164 * 165 */ 166 private void persistBluetoothSetting(boolean setOn) { 167 Settings.Secure.putInt(mContext.getContentResolver(), 168 Settings.Secure.BLUETOOTH_ON, 169 setOn ? 1 : 0); 170 } 171 172 /** 173 * Returns true if the Bluetooth Adapter's name and address is 174 * locally cached 175 * @return 176 */ 177 private boolean isNameAndAddressSet() { 178 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; 179 } 180 181 /** 182 * Retrieve the Bluetooth Adapter's name and address and save it in 183 * in the local cache 184 */ 185 private void loadStoredNameAndAddress() { 186 if (DBG) Log.d(TAG, "Loading stored name and address"); 187 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); 188 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); 189 if (mName == null || mAddress == null) { 190 if (DBG) Log.d(TAG, "Name or address not cached..."); 191 } 192 } 193 194 /** 195 * Save the Bluetooth name and address in the persistent store. 196 * Only non-null values will be saved. 197 * @param name 198 * @param address 199 */ 200 private void storeNameAndAddress(String name, String address) { 201 if (name != null) { 202 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); 203 mName = name; 204 if (DBG) Log.d(TAG,"Stored Bluetooth name: " + 205 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); 206 } 207 208 if (address != null) { 209 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); 210 mAddress=address; 211 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " + 212 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); 213 } 214 } 215 216 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ 217 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 218 "Need BLUETOOTH permission"); 219 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 220 msg.obj = callback; 221 mHandler.sendMessage(msg); 222 synchronized(mConnection) { 223 return mBluetooth; 224 } 225 } 226 227 public void unregisterAdapter(IBluetoothManagerCallback callback) { 228 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 229 "Need BLUETOOTH permission"); 230 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 231 msg.obj = callback; 232 mHandler.sendMessage(msg); 233 } 234 235 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 236 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 237 "Need BLUETOOTH permission"); 238 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 239 msg.obj = callback; 240 mHandler.sendMessage(msg); 241 } 242 243 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 244 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 245 "Need BLUETOOTH permission"); 246 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 247 msg.obj = callback; 248 mHandler.sendMessage(msg); 249 } 250 251 public boolean isEnabled() { 252 synchronized(mConnection) { 253 try { 254 return (mBluetooth != null && mBluetooth.isEnabled()); 255 } catch (RemoteException e) { 256 Log.e(TAG, "isEnabled()", e); 257 } 258 } 259 return false; 260 } 261 262 public void getNameAndAddress() { 263 if (DBG) { 264 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 265 " mBinding = " + mBinding); 266 } 267 synchronized(mConnection) { 268 if (mBinding) return; 269 if (mConnection == null) mBinding = true; 270 } 271 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 272 mHandler.sendMessage(msg); 273 } 274 public boolean enableNoAutoConnect() 275 { 276 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 277 "Need BLUETOOTH ADMIN permission"); 278 if (DBG) { 279 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 280 " mBinding = " + mBinding); 281 } 282 if (Binder.getCallingUid() != android.os.Process.NFC_UID) { 283 throw new SecurityException("no permission to enable Bluetooth quietly"); 284 } 285 synchronized(mConnection) { 286 if (mBinding) { 287 Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning.."); 288 return true; 289 } 290 if (mConnection == null) mBinding = true; 291 } 292 293 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 294 msg.arg1=0; //No persist 295 msg.arg2=1; //Quiet mode 296 mHandler.sendMessage(msg); 297 return true; 298 299 } 300 public boolean enable() { 301 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 302 "Need BLUETOOTH ADMIN permission"); 303 if (DBG) { 304 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 305 " mBinding = " + mBinding); 306 } 307 308 synchronized(mConnection) { 309 if (mBinding) { 310 Log.w(TAG,"enable(): binding in progress. Returning.."); 311 return true; 312 } 313 if (mConnection == null) mBinding = true; 314 } 315 316 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 317 msg.arg1=1; //persist 318 msg.arg2=0; //No Quiet Mode 319 mHandler.sendMessage(msg); 320 return true; 321 } 322 323 public boolean disable(boolean persist) { 324 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 325 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 326 if (DBG) { 327 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 328 " mBinding = " + mBinding); 329 } 330 331 synchronized(mConnection) { 332 if (mBluetooth == null) return false; 333 } 334 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE); 335 msg.arg1=(persist?1:0); 336 mHandler.sendMessage(msg); 337 return true; 338 } 339 340 public void unbindAndFinish() { 341 if (DBG) { 342 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 343 " mBinding = " + mBinding); 344 } 345 346 synchronized (mConnection) { 347 if (mUnbinding) return; 348 mUnbinding = true; 349 if (mConnection != null) { 350 if (!mConnection.isGetNameAddressOnly()) { 351 //Unregister callback object 352 try { 353 mBluetooth.unregisterCallback(mBluetoothCallback); 354 } catch (RemoteException re) { 355 Log.e(TAG, "Unable to register BluetoothCallback",re); 356 } 357 } 358 if (DBG) Log.d(TAG, "Sending unbind request."); 359 mBluetooth = null; 360 //Unbind 361 mContext.unbindService(mConnection); 362 mUnbinding = false; 363 } else { 364 mUnbinding=false; 365 } 366 } 367 } 368 369 private void sendBluetoothStateCallback(boolean isUp) { 370 int n = mStateChangeCallbacks.beginBroadcast(); 371 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 372 for (int i=0; i <n;i++) { 373 try { 374 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 375 } catch (RemoteException e) { 376 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 377 } 378 } 379 mStateChangeCallbacks.finishBroadcast(); 380 } 381 382 /** 383 * Inform BluetoothAdapter instances that Adapter service is down 384 */ 385 private void sendBluetoothServiceDownCallback() { 386 if (!mConnection.isGetNameAddressOnly()) { 387 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 388 int n = mCallbacks.beginBroadcast(); 389 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 390 for (int i=0; i <n;i++) { 391 try { 392 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 393 } catch (RemoteException e) { 394 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 395 } 396 } 397 mCallbacks.finishBroadcast(); 398 } 399 } 400 public String getAddress() { 401 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 402 "Need BLUETOOTH ADMIN permission"); 403 synchronized(mConnection) { 404 if (mBluetooth != null) { 405 try { 406 return mBluetooth.getAddress(); 407 } catch (RemoteException e) { 408 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 409 } 410 } 411 } 412 // mAddress is accessed from outside. 413 // It is alright without a lock. Here, bluetooth is off, no other thread is 414 // changing mAddress 415 return mAddress; 416 } 417 418 public String getName() { 419 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 420 "Need BLUETOOTH ADMIN permission"); 421 synchronized(mConnection) { 422 if (mBluetooth != null) { 423 try { 424 return mBluetooth.getName(); 425 } catch (RemoteException e) { 426 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 427 } 428 } 429 } 430 // mName is accessed from outside. 431 // It alright without a lock. Here, bluetooth is off, no other thread is 432 // changing mName 433 return mName; 434 } 435 436 private class BluetoothServiceConnection implements ServiceConnection { 437 438 private boolean mGetNameAddressOnly; 439 440 public void setGetNameAddressOnly(boolean getOnly) { 441 mGetNameAddressOnly = getOnly; 442 } 443 444 public boolean isGetNameAddressOnly() { 445 return mGetNameAddressOnly; 446 } 447 448 public void onServiceConnected(ComponentName className, IBinder service) { 449 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService"); 450 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 451 msg.obj = service; 452 mHandler.sendMessage(msg); 453 } 454 455 public void onServiceDisconnected(ComponentName className) { 456 // Called if we unexpected disconnected. 457 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService"); 458 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 459 mHandler.sendMessage(msg); 460 } 461 } 462 463 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 464 465 private final Handler mHandler = new Handler() { 466 @Override 467 public void handleMessage(Message msg) { 468 if (DBG) Log.d (TAG, "Message: " + msg.what); 469 switch (msg.what) { 470 case MESSAGE_GET_NAME_AND_ADDRESS: { 471 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 472 synchronized(mConnection) { 473 //Start bind request 474 if (mBluetooth == null) { 475 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 476 mConnection.setGetNameAddressOnly(true); 477 //Start bind timeout and bind 478 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 479 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 480 Intent i = new Intent(IBluetooth.class.getName()); 481 if (!mContext.bindService(i, mConnection, 482 Context.BIND_AUTO_CREATE)) { 483 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 484 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName()); 485 } 486 } 487 else { 488 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 489 mHandler.sendMessage(saveMsg); 490 } 491 } 492 break; 493 } 494 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 495 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 496 synchronized(mConnection) { 497 if (mBluetooth != null) { 498 String name = null; 499 String address = null; 500 try { 501 name = mBluetooth.getName(); 502 address = mBluetooth.getAddress(); 503 } catch (RemoteException re) { 504 Log.e(TAG,"",re); 505 } 506 507 if (name != null && address != null) { 508 storeNameAndAddress(name,address); 509 sendBluetoothServiceDownCallback(); 510 unbindAndFinish(); 511 } else { 512 if (msg.arg1 < MAX_SAVE_RETRIES) { 513 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 514 retryMsg.arg1= 1+msg.arg1; 515 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 516 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 517 } else { 518 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 519 sendBluetoothServiceDownCallback(); 520 unbindAndFinish(); 521 } 522 } 523 } 524 } 525 break; 526 } 527 case MESSAGE_ENABLE: 528 if (DBG) { 529 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 530 } 531 532 handleEnable(msg.arg1 == 1, msg.arg2 ==1); 533 break; 534 535 case MESSAGE_DISABLE: 536 handleDisable(msg.arg1 == 1); 537 break; 538 539 case MESSAGE_REGISTER_ADAPTER: 540 { 541 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 542 boolean added = mCallbacks.register(callback); 543 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 544 } 545 break; 546 case MESSAGE_UNREGISTER_ADAPTER: 547 { 548 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 549 boolean removed = mCallbacks.unregister(callback); 550 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 551 break; 552 } 553 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 554 { 555 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 556 mStateChangeCallbacks.register(callback); 557 break; 558 } 559 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 560 { 561 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 562 mStateChangeCallbacks.unregister(callback); 563 break; 564 } 565 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 566 { 567 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); 568 569 //Remove timeout 570 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 571 572 IBinder service = (IBinder) msg.obj; 573 synchronized(mConnection) { 574 mBinding = false; 575 mBluetooth = IBluetooth.Stub.asInterface(service); 576 577 if (mConnection.isGetNameAddressOnly()) { 578 //Request GET NAME AND ADDRESS 579 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 580 mHandler.sendMessage(getMsg); 581 return; 582 } 583 584 //Register callback object 585 try { 586 mBluetooth.registerCallback(mBluetoothCallback); 587 } catch (RemoteException re) { 588 Log.e(TAG, "Unable to register BluetoothCallback",re); 589 } 590 591 //Inform BluetoothAdapter instances that service is up 592 int n = mCallbacks.beginBroadcast(); 593 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 594 for (int i=0; i <n;i++) { 595 try { 596 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 597 } catch (RemoteException e) { 598 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 599 } 600 } 601 mCallbacks.finishBroadcast(); 602 603 //Do enable request 604 try { 605 if (mQuietEnable == false) { 606 if(!mBluetooth.enable()) { 607 Log.e(TAG,"IBluetooth.enable() returned false"); 608 } 609 } 610 else 611 { 612 if(!mBluetooth.enableNoAutoConnect()) { 613 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 614 } 615 } 616 } catch (RemoteException e) { 617 Log.e(TAG,"Unable to call enable()",e); 618 } 619 } 620 break; 621 } 622 case MESSAGE_TIMEOUT_BIND: { 623 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 624 synchronized(mConnection) { 625 mBinding = false; 626 } 627 break; 628 } 629 case MESSAGE_BLUETOOTH_STATE_CHANGE: 630 { 631 int prevState = msg.arg1; 632 int newState = msg.arg2; 633 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 634 if (prevState != newState) { 635 //Notify all proxy objects first of adapter state change 636 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 637 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 638 sendBluetoothStateCallback(isUp); 639 640 //If Bluetooth is off, send service down event to proxy objects, and unbind 641 if (!isUp) { 642 sendBluetoothServiceDownCallback(); 643 unbindAndFinish(); 644 } 645 } 646 647 //Send broadcast message to everyone else 648 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 649 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 650 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 651 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 652 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 653 mContext.sendBroadcast(intent,BLUETOOTH_PERM); 654 } 655 break; 656 } 657 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 658 { 659 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); 660 sendBluetoothServiceDownCallback(); 661 break; 662 } 663 case MESSAGE_TIMEOUT_UNBIND: 664 { 665 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 666 synchronized(mConnection) { 667 mUnbinding = false; 668 } 669 break; 670 } 671 } 672 } 673 }; 674 675 private void handleEnable(boolean persist, boolean quietMode) { 676 if (persist) { 677 persistBluetoothSetting(true); 678 } 679 680 mQuietEnable = quietMode; 681 682 synchronized(mConnection) { 683 if (mBluetooth == null) { 684 //Start bind timeout and bind 685 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 686 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 687 mConnection.setGetNameAddressOnly(false); 688 Intent i = new Intent(IBluetooth.class.getName()); 689 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) { 690 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 691 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName()); 692 } 693 } else { 694 //Check if name and address is loaded if not get it first. 695 if (!isNameAndAddressSet()) { 696 try { 697 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable."); 698 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress()); 699 } catch (RemoteException e) {Log.e(TAG, "", e);}; 700 } 701 702 //Enable bluetooth 703 try { 704 if (!mQuietEnable) { 705 if(!mBluetooth.enable()) { 706 Log.e(TAG,"IBluetooth.enable() returned false"); 707 } 708 } 709 else { 710 if(!mBluetooth.enableNoAutoConnect()) { 711 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 712 } 713 } 714 } catch (RemoteException e) { 715 Log.e(TAG,"Unable to call enable()",e); 716 } 717 } 718 } 719 } 720 721 private void handleDisable(boolean persist) { 722 synchronized(mConnection) { 723 if (mBluetooth != null ) { 724 if (persist) { 725 persistBluetoothSetting(false); 726 } 727 mConnection.setGetNameAddressOnly(false); 728 if (DBG) Log.d(TAG,"Sending off request."); 729 730 try { 731 if(!mBluetooth.disable()) { 732 Log.e(TAG,"IBluetooth.disable() returned false"); 733 } 734 } catch (RemoteException e) { 735 Log.e(TAG,"Unable to call disable()",e); 736 } 737 } 738 } 739 } 740} 741