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