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