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