BluetoothManagerService.java revision bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324
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.Global.getInt(mContentResolver, 163 Settings.Global.BLUETOOTH_ON, 0) ==1; 164 } 165 166 /** 167 * Save the Bluetooth on/off state 168 * 169 */ 170 private void persistBluetoothSetting(boolean setOn) { 171 Settings.Global.putInt(mContext.getContentResolver(), 172 Settings.Global.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 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 222 "Need BLUETOOTH permission"); 223 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 224 msg.obj = callback; 225 mHandler.sendMessage(msg); 226 synchronized(mConnection) { 227 return mBluetooth; 228 } 229 } 230 231 public void unregisterAdapter(IBluetoothManagerCallback callback) { 232 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 233 "Need BLUETOOTH permission"); 234 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 235 msg.obj = callback; 236 mHandler.sendMessage(msg); 237 } 238 239 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 240 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 241 "Need BLUETOOTH permission"); 242 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 243 msg.obj = callback; 244 mHandler.sendMessage(msg); 245 } 246 247 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 248 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 249 "Need BLUETOOTH permission"); 250 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 251 msg.obj = callback; 252 mHandler.sendMessage(msg); 253 } 254 255 public boolean isEnabled() { 256 synchronized(mConnection) { 257 try { 258 return (mBluetooth != null && mBluetooth.isEnabled()); 259 } catch (RemoteException e) { 260 Log.e(TAG, "isEnabled()", e); 261 } 262 } 263 return false; 264 } 265 266 public void getNameAndAddress() { 267 if (DBG) { 268 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 269 " mBinding = " + mBinding); 270 } 271 synchronized(mConnection) { 272 if (mBinding) return; 273 if (mConnection == null) mBinding = true; 274 } 275 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 276 mHandler.sendMessage(msg); 277 } 278 public boolean enableNoAutoConnect() 279 { 280 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 281 "Need BLUETOOTH ADMIN permission"); 282 if (DBG) { 283 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 284 " mBinding = " + mBinding); 285 } 286 if (Binder.getCallingUid() != android.os.Process.NFC_UID) { 287 throw new SecurityException("no permission to enable Bluetooth quietly"); 288 } 289 synchronized(mConnection) { 290 if (mBinding) { 291 Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning.."); 292 return true; 293 } 294 if (mConnection == null) mBinding = true; 295 } 296 297 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 298 msg.arg1=0; //No persist 299 msg.arg2=1; //Quiet mode 300 mHandler.sendMessage(msg); 301 return true; 302 303 } 304 public boolean enable() { 305 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 306 "Need BLUETOOTH ADMIN permission"); 307 if (DBG) { 308 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 309 " mBinding = " + mBinding); 310 } 311 312 synchronized(mConnection) { 313 if (mBinding) { 314 Log.w(TAG,"enable(): binding in progress. Returning.."); 315 return true; 316 } 317 if (mConnection == null) mBinding = true; 318 } 319 320 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 321 msg.arg1=1; //persist 322 msg.arg2=0; //No Quiet Mode 323 mHandler.sendMessage(msg); 324 return true; 325 } 326 327 public boolean disable(boolean persist) { 328 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 329 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 330 if (DBG) { 331 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 332 " mBinding = " + mBinding); 333 } 334 335 synchronized(mConnection) { 336 if (mBluetooth == null) return false; 337 } 338 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE); 339 msg.arg1=(persist?1:0); 340 mHandler.sendMessage(msg); 341 return true; 342 } 343 344 public void unbindAndFinish() { 345 if (DBG) { 346 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 347 " mBinding = " + mBinding); 348 } 349 350 synchronized (mConnection) { 351 if (mUnbinding) return; 352 mUnbinding = true; 353 if (mConnection != null) { 354 if (!mConnection.isGetNameAddressOnly()) { 355 //Unregister callback object 356 try { 357 mBluetooth.unregisterCallback(mBluetoothCallback); 358 } catch (RemoteException re) { 359 Log.e(TAG, "Unable to register BluetoothCallback",re); 360 } 361 } 362 if (DBG) Log.d(TAG, "Sending unbind request."); 363 mBluetooth = null; 364 //Unbind 365 mContext.unbindService(mConnection); 366 mUnbinding = false; 367 } else { 368 mUnbinding=false; 369 } 370 } 371 } 372 373 private void sendBluetoothStateCallback(boolean isUp) { 374 int n = mStateChangeCallbacks.beginBroadcast(); 375 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 376 for (int i=0; i <n;i++) { 377 try { 378 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 379 } catch (RemoteException e) { 380 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 381 } 382 } 383 mStateChangeCallbacks.finishBroadcast(); 384 } 385 386 /** 387 * Inform BluetoothAdapter instances that Adapter service is down 388 */ 389 private void sendBluetoothServiceDownCallback() { 390 if (!mConnection.isGetNameAddressOnly()) { 391 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 392 int n = mCallbacks.beginBroadcast(); 393 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 394 for (int i=0; i <n;i++) { 395 try { 396 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 397 } catch (RemoteException e) { 398 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 399 } 400 } 401 mCallbacks.finishBroadcast(); 402 } 403 } 404 public String getAddress() { 405 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 406 "Need BLUETOOTH ADMIN permission"); 407 synchronized(mConnection) { 408 if (mBluetooth != null) { 409 try { 410 return mBluetooth.getAddress(); 411 } catch (RemoteException e) { 412 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 413 } 414 } 415 } 416 // mAddress is accessed from outside. 417 // It is alright without a lock. Here, bluetooth is off, no other thread is 418 // changing mAddress 419 return mAddress; 420 } 421 422 public String getName() { 423 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 424 "Need BLUETOOTH ADMIN permission"); 425 synchronized(mConnection) { 426 if (mBluetooth != null) { 427 try { 428 return mBluetooth.getName(); 429 } catch (RemoteException e) { 430 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 431 } 432 } 433 } 434 // mName is accessed from outside. 435 // It alright without a lock. Here, bluetooth is off, no other thread is 436 // changing mName 437 return mName; 438 } 439 440 private class BluetoothServiceConnection implements ServiceConnection { 441 442 private boolean mGetNameAddressOnly; 443 444 public void setGetNameAddressOnly(boolean getOnly) { 445 mGetNameAddressOnly = getOnly; 446 } 447 448 public boolean isGetNameAddressOnly() { 449 return mGetNameAddressOnly; 450 } 451 452 public void onServiceConnected(ComponentName className, IBinder service) { 453 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService"); 454 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 455 msg.obj = service; 456 mHandler.sendMessage(msg); 457 } 458 459 public void onServiceDisconnected(ComponentName className) { 460 // Called if we unexpected disconnected. 461 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService"); 462 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 463 mHandler.sendMessage(msg); 464 } 465 } 466 467 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 468 469 private final Handler mHandler = new Handler() { 470 @Override 471 public void handleMessage(Message msg) { 472 if (DBG) Log.d (TAG, "Message: " + msg.what); 473 switch (msg.what) { 474 case MESSAGE_GET_NAME_AND_ADDRESS: { 475 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 476 synchronized(mConnection) { 477 //Start bind request 478 if (mBluetooth == null) { 479 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 480 mConnection.setGetNameAddressOnly(true); 481 //Start bind timeout and bind 482 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 483 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 484 Intent i = new Intent(IBluetooth.class.getName()); 485 if (!mContext.bindService(i, mConnection, 486 Context.BIND_AUTO_CREATE)) { 487 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 488 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName()); 489 } 490 } 491 else { 492 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 493 mHandler.sendMessage(saveMsg); 494 } 495 } 496 break; 497 } 498 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 499 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 500 synchronized(mConnection) { 501 if (mBluetooth != null) { 502 String name = null; 503 String address = null; 504 try { 505 name = mBluetooth.getName(); 506 address = mBluetooth.getAddress(); 507 } catch (RemoteException re) { 508 Log.e(TAG,"",re); 509 } 510 511 if (name != null && address != null) { 512 storeNameAndAddress(name,address); 513 sendBluetoothServiceDownCallback(); 514 unbindAndFinish(); 515 } else { 516 if (msg.arg1 < MAX_SAVE_RETRIES) { 517 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 518 retryMsg.arg1= 1+msg.arg1; 519 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 520 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 521 } else { 522 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 523 sendBluetoothServiceDownCallback(); 524 unbindAndFinish(); 525 } 526 } 527 } 528 } 529 break; 530 } 531 case MESSAGE_ENABLE: 532 if (DBG) { 533 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 534 } 535 536 handleEnable(msg.arg1 == 1, msg.arg2 ==1); 537 break; 538 539 case MESSAGE_DISABLE: 540 handleDisable(msg.arg1 == 1); 541 break; 542 543 case MESSAGE_REGISTER_ADAPTER: 544 { 545 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 546 boolean added = mCallbacks.register(callback); 547 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 548 } 549 break; 550 case MESSAGE_UNREGISTER_ADAPTER: 551 { 552 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 553 boolean removed = mCallbacks.unregister(callback); 554 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 555 break; 556 } 557 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 558 { 559 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 560 mStateChangeCallbacks.register(callback); 561 break; 562 } 563 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 564 { 565 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 566 mStateChangeCallbacks.unregister(callback); 567 break; 568 } 569 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 570 { 571 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); 572 573 //Remove timeout 574 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 575 576 IBinder service = (IBinder) msg.obj; 577 synchronized(mConnection) { 578 mBinding = false; 579 mBluetooth = IBluetooth.Stub.asInterface(service); 580 581 if (mConnection.isGetNameAddressOnly()) { 582 //Request GET NAME AND ADDRESS 583 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 584 mHandler.sendMessage(getMsg); 585 return; 586 } 587 588 //Register callback object 589 try { 590 mBluetooth.registerCallback(mBluetoothCallback); 591 } catch (RemoteException re) { 592 Log.e(TAG, "Unable to register BluetoothCallback",re); 593 } 594 595 //Inform BluetoothAdapter instances that service is up 596 int n = mCallbacks.beginBroadcast(); 597 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 598 for (int i=0; i <n;i++) { 599 try { 600 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 601 } catch (RemoteException e) { 602 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 603 } 604 } 605 mCallbacks.finishBroadcast(); 606 607 //Do enable request 608 try { 609 if (mQuietEnable == false) { 610 if(!mBluetooth.enable()) { 611 Log.e(TAG,"IBluetooth.enable() returned false"); 612 } 613 } 614 else 615 { 616 if(!mBluetooth.enableNoAutoConnect()) { 617 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 618 } 619 } 620 } catch (RemoteException e) { 621 Log.e(TAG,"Unable to call enable()",e); 622 } 623 } 624 break; 625 } 626 case MESSAGE_TIMEOUT_BIND: { 627 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 628 synchronized(mConnection) { 629 mBinding = false; 630 } 631 break; 632 } 633 case MESSAGE_BLUETOOTH_STATE_CHANGE: 634 { 635 int prevState = msg.arg1; 636 int newState = msg.arg2; 637 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 638 if (prevState != newState) { 639 //Notify all proxy objects first of adapter state change 640 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 641 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 642 sendBluetoothStateCallback(isUp); 643 644 //If Bluetooth is off, send service down event to proxy objects, and unbind 645 if (!isUp) { 646 sendBluetoothServiceDownCallback(); 647 unbindAndFinish(); 648 } 649 } 650 651 //Send broadcast message to everyone else 652 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 653 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 654 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 655 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 656 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 657 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 658 BLUETOOTH_PERM); 659 } 660 break; 661 } 662 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 663 { 664 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); 665 sendBluetoothServiceDownCallback(); 666 667 // Send BT state broadcast to update 668 // the BT icon correctly 669 Message stateChangeMsg = mHandler.obtainMessage( 670 MESSAGE_BLUETOOTH_STATE_CHANGE); 671 stateChangeMsg.arg1 = BluetoothAdapter.STATE_ON; 672 stateChangeMsg.arg2 = 673 BluetoothAdapter.STATE_TURNING_OFF; 674 mHandler.sendMessage(stateChangeMsg); 675 synchronized(mConnection) { 676 mBluetooth = null; 677 } 678 // Send a Bluetooth Restart message 679 Message restartMsg = mHandler.obtainMessage( 680 MESSAGE_RESTART_BLUETOOTH_SERVICE); 681 mHandler.sendMessageDelayed(restartMsg, 682 SERVICE_RESTART_TIME_MS); 683 break; 684 } 685 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 686 { 687 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 688 +" Restart IBluetooth service"); 689 /* Enable without persisting the setting as 690 it doesnt change when IBluetooth 691 service restarts */ 692 handleEnable(false, mQuietEnable); 693 break; 694 } 695 696 case MESSAGE_TIMEOUT_UNBIND: 697 { 698 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 699 synchronized(mConnection) { 700 mUnbinding = false; 701 } 702 break; 703 } 704 } 705 } 706 }; 707 708 private void handleEnable(boolean persist, boolean quietMode) { 709 if (persist) { 710 persistBluetoothSetting(true); 711 } 712 713 mQuietEnable = quietMode; 714 715 synchronized(mConnection) { 716 if (mBluetooth == null) { 717 //Start bind timeout and bind 718 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 719 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 720 mConnection.setGetNameAddressOnly(false); 721 Intent i = new Intent(IBluetooth.class.getName()); 722 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) { 723 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 724 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName()); 725 } 726 } else { 727 //Check if name and address is loaded if not get it first. 728 if (!isNameAndAddressSet()) { 729 try { 730 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable."); 731 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress()); 732 } catch (RemoteException e) {Log.e(TAG, "", e);}; 733 } 734 735 //Enable bluetooth 736 try { 737 if (!mQuietEnable) { 738 if(!mBluetooth.enable()) { 739 Log.e(TAG,"IBluetooth.enable() returned false"); 740 } 741 } 742 else { 743 if(!mBluetooth.enableNoAutoConnect()) { 744 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 745 } 746 } 747 } catch (RemoteException e) { 748 Log.e(TAG,"Unable to call enable()",e); 749 } 750 } 751 } 752 } 753 754 private void handleDisable(boolean persist) { 755 synchronized(mConnection) { 756 if (mBluetooth != null ) { 757 if (persist) { 758 persistBluetoothSetting(false); 759 } 760 mConnection.setGetNameAddressOnly(false); 761 if (DBG) Log.d(TAG,"Sending off request."); 762 763 try { 764 if(!mBluetooth.disable()) { 765 Log.e(TAG,"IBluetooth.disable() returned false"); 766 } 767 } catch (RemoteException e) { 768 Log.e(TAG,"Unable to call disable()",e); 769 } 770 } 771 } 772 } 773} 774