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