BluetoothManagerService.java revision a8c6df0d3a6b929cac3e59abde8309e8a45ea78a
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 ContentResolver mContentResolver; 63 private RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 64 private 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 mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 125 mFilter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 126 registerForAirplaneMode(mFilter); 127 mContext.registerReceiver(mReceiver, mFilter); 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 516 boolean persist = (1==msg.arg1); 517 if (persist) { 518 persistBluetoothSetting(true); 519 } 520 521 if (mBluetooth == null) { 522 //Start bind timeout and bind 523 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 524 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 525 mConnection.setGetNameAddressOnly(false); 526 Intent i = new Intent(IBluetooth.class.getName()); 527 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) { 528 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 529 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName()); 530 } 531 } else { 532 //Check if name and address is loaded if not get it first. 533 if (!isNameAndAddressSet()) { 534 try { 535 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable."); 536 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress()); 537 } catch (RemoteException e) {Log.e(TAG, "", e);}; 538 } 539 540 //Enable bluetooth 541 try { 542 if(!mBluetooth.enable()) { 543 Log.e(TAG,"IBluetooth.enable() returned false"); 544 } 545 } catch (RemoteException e) { 546 Log.e(TAG,"Unable to call enable()",e); 547 } 548 549 } 550 // TODO(BT) what if service failed to start: 551 // [fc] fixed: watch for bind timeout and handle accordingly 552 // TODO(BT) persist the setting depending on argument 553 // [fc]: let AdapterServiceHandle 554 } 555 break; 556 case MESSAGE_AIRPLANE_MODE_ON:; 557 if (DBG) { 558 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth + 559 " isConnected = " + isConnected()); 560 //Fall through to MESSAGE_DISABLE 561 } 562 case MESSAGE_DISABLE: 563 if (mBluetooth != null ) { 564 boolean persist = (1==msg.arg1); 565 if (persist) { 566 persistBluetoothSetting(false); 567 } 568 mConnection.setGetNameAddressOnly(false); 569 if (DBG) Log.d(TAG,"Sending off request."); 570 571 try { 572 if(!mBluetooth.disable()) { 573 Log.e(TAG,"IBluetooth.disable() returned false"); 574 } 575 } catch (RemoteException e) { 576 Log.e(TAG,"Unable to call disable()",e); 577 } 578 } 579 break; 580 case MESSAGE_REGISTER_ADAPTER: 581 { 582 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 583 boolean added = mCallbacks.register(callback); 584 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 585 } 586 break; 587 case MESSAGE_UNREGISTER_ADAPTER: 588 { 589 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 590 boolean removed = mCallbacks.unregister(callback); 591 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 592 } 593 break; 594 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 595 { 596 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 597 mStateChangeCallbacks.register(callback); 598 } 599 break; 600 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 601 { 602 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 603 mStateChangeCallbacks.unregister(callback); 604 } 605 break; 606 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 607 { 608 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); 609 610 //Remove timeout 611 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 612 613 IBinder service = (IBinder) msg.obj; 614 synchronized(mConnection) { 615 mBinding = false; 616 mBluetooth = IBluetooth.Stub.asInterface(service); 617 } 618 619 if (mConnection.isGetNameAddressOnly()) { 620 //Request GET NAME AND ADDRESS 621 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 622 mHandler.sendMessage(getMsg); 623 return; 624 } 625 626 //Register callback object 627 try { 628 mBluetooth.registerCallback(mBluetoothCallback); 629 } catch (RemoteException re) { 630 Log.e(TAG, "Unable to register BluetoothCallback",re); 631 } 632 633 //Inform BluetoothAdapter instances that service is up 634 int n = mCallbacks.beginBroadcast(); 635 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 636 for (int i=0; i <n;i++) { 637 try { 638 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 639 } catch (RemoteException e) { 640 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 641 } 642 } 643 mCallbacks.finishBroadcast(); 644 645 //Do enable request 646 try { 647 if(!mBluetooth.enable()) { 648 Log.e(TAG,"IBluetooth.enable() returned false"); 649 } 650 } catch (RemoteException e) { 651 Log.e(TAG,"Unable to call enable()",e); 652 } 653 } 654 break; 655 case MESSAGE_TIMEOUT_BIND: { 656 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 657 synchronized(mConnection) { 658 mBinding = false; 659 } 660 } 661 break; 662 case MESSAGE_BLUETOOTH_STATE_CHANGE: 663 { 664 int prevState = msg.arg1; 665 int newState = msg.arg2; 666 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 667 if (prevState != newState) { 668 //Notify all proxy objects first of adapter state change 669 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 670 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 671 sendBluetoothStateCallback(isUp); 672 673 //If Bluetooth is off, send service down event to proxy objects, and unbind 674 if (!isUp) { 675 sendBluetoothServiceDownCallback(); 676 unbindAndFinish(); 677 } 678 } 679 680 //Send broadcast message to everyone else 681 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 682 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 683 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 684 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 685 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 686 mContext.sendBroadcast(intent,BLUETOOTH_PERM); 687 } 688 } 689 break; 690 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 691 { 692 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); 693 sendBluetoothServiceDownCallback(); 694 } 695 break; 696 case MESSAGE_TIMEOUT_UNBIND: 697 { 698 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 699 synchronized(mConnection) { 700 mUnbinding = false; 701 } 702 } 703 break; 704 } 705 } 706 }; 707} 708