BluetoothManagerService.java revision 40874a096ba6448ebffea4b17486dbfbc957c0df
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5package com.android.server; 6 7import android.app.ActivityManager; 8import android.bluetooth.BluetoothAdapter; 9import android.bluetooth.IBluetooth; 10import android.bluetooth.IBluetoothCallback; 11import android.bluetooth.IBluetoothManager; 12import android.bluetooth.IBluetoothManagerCallback; 13import android.bluetooth.IBluetoothStateChangeCallback; 14import android.content.BroadcastReceiver; 15import android.content.ComponentName; 16import android.content.ContentResolver; 17import android.content.Context; 18import android.content.Intent; 19import android.content.IntentFilter; 20import android.content.ServiceConnection; 21import android.os.Binder; 22import android.os.Handler; 23import android.os.HandlerThread; 24import android.os.IBinder; 25import android.os.Looper; 26import android.os.Message; 27import android.os.Process; 28import android.os.RemoteCallbackList; 29import android.os.RemoteException; 30import android.os.SystemClock; 31import android.os.UserHandle; 32import android.provider.Settings; 33import android.util.Log; 34import java.util.ArrayList; 35import java.util.List; 36class BluetoothManagerService extends IBluetoothManager.Stub { 37 private static final String TAG = "BluetoothManagerService"; 38 private static final boolean DBG = true; 39 40 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 41 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 42 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 43 private static final String EXTRA_ACTION="action"; 44 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; 45 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; 46 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind 47 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save 48 //Maximum msec to wait for service restart 49 private static final int SERVICE_RESTART_TIME_MS = 200; 50 //Maximum msec to delay MESSAGE_USER_SWITCHED 51 private static final int USER_SWITCHED_TIME_MS = 200; 52 53 private static final int MESSAGE_ENABLE = 1; 54 private static final int MESSAGE_DISABLE = 2; 55 private static final int MESSAGE_REGISTER_ADAPTER = 20; 56 private static final int MESSAGE_UNREGISTER_ADAPTER = 21; 57 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; 58 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; 59 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; 60 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; 61 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; 62 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60; 63 private static final int MESSAGE_TIMEOUT_BIND =100; 64 private static final int MESSAGE_TIMEOUT_UNBIND =101; 65 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; 66 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; 67 private static final int MESSAGE_USER_SWITCHED = 300; 68 private static final int MAX_SAVE_RETRIES=3; 69 70 private final Context mContext; 71 72 // Locks are not provided for mName and mAddress. 73 // They are accessed in handler or broadcast receiver, same thread context. 74 private String mAddress; 75 private String mName; 76 private final ContentResolver mContentResolver; 77 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 78 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; 79 private IBluetooth mBluetooth; 80 private boolean mBinding; 81 private boolean mUnbinding; 82 private boolean mQuietEnable = false; 83 private boolean mEnable; 84 private int mState; 85 private HandlerThread mThread; 86 private final BluetoothHandler mHandler; 87 88 private void registerForAirplaneMode(IntentFilter filter) { 89 final ContentResolver resolver = mContext.getContentResolver(); 90 final String airplaneModeRadios = Settings.Global.getString(resolver, 91 Settings.Global.AIRPLANE_MODE_RADIOS); 92 final String toggleableRadios = Settings.Global.getString(resolver, 93 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 94 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true : 95 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH); 96 if (mIsAirplaneSensitive) { 97 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 98 } 99 } 100 101 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { 102 @Override 103 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { 104 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); 105 mHandler.sendMessage(msg); 106 } 107 }; 108 109 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 110 @Override 111 public void onReceive(Context context, Intent intent) { 112 String action = intent.getAction(); 113 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { 114 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); 115 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName); 116 if (newName != null) { 117 storeNameAndAddress(newName, null); 118 } 119 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 120 if (isAirplaneModeOn()) { 121 // disable without persisting the setting 122 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE, 123 0, 0)); 124 } else if (isBluetoothPersistedStateOn()) { 125 // enable without persisting the setting 126 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, 127 0, 0)); 128 } 129 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { 130 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, 131 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 132 } 133 } 134 }; 135 136 BluetoothManagerService(Context context) { 137 mThread = new HandlerThread("BluetoothManager"); 138 mThread.start(); 139 mHandler = new BluetoothHandler(mThread.getLooper()); 140 141 mContext = context; 142 mBluetooth = null; 143 mBinding = false; 144 mUnbinding = false; 145 mEnable = false; 146 mState = BluetoothAdapter.STATE_OFF; 147 mAddress = null; 148 mName = null; 149 mContentResolver = context.getContentResolver(); 150 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); 151 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); 152 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 153 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 154 filter.addAction(Intent.ACTION_USER_SWITCHED); 155 registerForAirplaneMode(filter); 156 mContext.registerReceiver(mReceiver, filter); 157 boolean airplaneModeOn = isAirplaneModeOn(); 158 boolean bluetoothOn = isBluetoothPersistedStateOn(); 159 loadStoredNameAndAddress(); 160 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn); 161 if (bluetoothOn) { 162 //Enable 163 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); 164 enableHelper(); 165 } else if (!isNameAndAddressSet()) { 166 //Sync the Bluetooth name and address from the Bluetooth Adapter 167 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); 168 getNameAndAddress(); 169 } 170 } 171 172 /** 173 * Returns true if airplane mode is currently on 174 */ 175 private final boolean isAirplaneModeOn() { 176 return Settings.Global.getInt(mContext.getContentResolver(), 177 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 178 } 179 180 /** 181 * Returns true if the Bluetooth saved state is "on" 182 */ 183 private final boolean isBluetoothPersistedStateOn() { 184 return Settings.Global.getInt(mContentResolver, 185 Settings.Global.BLUETOOTH_ON, 0) ==1; 186 } 187 188 /** 189 * Save the Bluetooth on/off state 190 * 191 */ 192 private void persistBluetoothSetting(boolean setOn) { 193 Settings.Global.putInt(mContext.getContentResolver(), 194 Settings.Global.BLUETOOTH_ON, 195 setOn ? 1 : 0); 196 } 197 198 /** 199 * Returns true if the Bluetooth Adapter's name and address is 200 * locally cached 201 * @return 202 */ 203 private boolean isNameAndAddressSet() { 204 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; 205 } 206 207 /** 208 * Retrieve the Bluetooth Adapter's name and address and save it in 209 * in the local cache 210 */ 211 private void loadStoredNameAndAddress() { 212 if (DBG) Log.d(TAG, "Loading stored name and address"); 213 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); 214 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); 215 if (mName == null || mAddress == null) { 216 if (DBG) Log.d(TAG, "Name or address not cached..."); 217 } 218 } 219 220 /** 221 * Save the Bluetooth name and address in the persistent store. 222 * Only non-null values will be saved. 223 * @param name 224 * @param address 225 */ 226 private void storeNameAndAddress(String name, String address) { 227 if (name != null) { 228 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); 229 mName = name; 230 if (DBG) Log.d(TAG,"Stored Bluetooth name: " + 231 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); 232 } 233 234 if (address != null) { 235 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); 236 mAddress=address; 237 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " + 238 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); 239 } 240 } 241 242 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ 243 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 244 msg.obj = callback; 245 mHandler.sendMessage(msg); 246 synchronized(mConnection) { 247 return mBluetooth; 248 } 249 } 250 251 public void unregisterAdapter(IBluetoothManagerCallback callback) { 252 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 253 "Need BLUETOOTH permission"); 254 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 255 msg.obj = callback; 256 mHandler.sendMessage(msg); 257 } 258 259 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 260 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 261 "Need BLUETOOTH permission"); 262 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 263 msg.obj = callback; 264 mHandler.sendMessage(msg); 265 } 266 267 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 268 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 269 "Need BLUETOOTH permission"); 270 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 271 msg.obj = callback; 272 mHandler.sendMessage(msg); 273 } 274 275 public boolean isEnabled() { 276 if (!checkIfCallerIsForegroundUser()) { 277 Log.w(TAG,"isEnabled(): not allowed for non-active user"); 278 return false; 279 } 280 281 synchronized(mConnection) { 282 try { 283 return (mBluetooth != null && mBluetooth.isEnabled()); 284 } catch (RemoteException e) { 285 Log.e(TAG, "isEnabled()", e); 286 } 287 } 288 return false; 289 } 290 291 public void getNameAndAddress() { 292 if (DBG) { 293 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 294 " mBinding = " + mBinding); 295 } 296 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 297 mHandler.sendMessage(msg); 298 } 299 public boolean enableNoAutoConnect() 300 { 301 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 302 "Need BLUETOOTH ADMIN permission"); 303 304 if (!checkIfCallerIsForegroundUser()) { 305 Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user"); 306 return false; 307 } 308 309 if (DBG) { 310 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 311 " mBinding = " + mBinding); 312 } 313 if (Binder.getCallingUid() != Process.NFC_UID) { 314 throw new SecurityException("no permission to enable Bluetooth quietly"); 315 } 316 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 317 msg.arg1=0; //No persist 318 msg.arg2=1; //Quiet mode 319 mHandler.sendMessage(msg); 320 return true; 321 322 } 323 public boolean enable() { 324 if (!checkIfCallerIsForegroundUser()) { 325 Log.w(TAG,"enable(): not allowed for non-active user"); 326 return false; 327 } 328 329 return enableHelper(); 330 } 331 332 public boolean disable(boolean persist) { 333 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 334 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 335 336 if (!checkIfCallerIsForegroundUser()) { 337 Log.w(TAG,"disable(): not allowed for non-active user"); 338 return false; 339 } 340 341 if (DBG) { 342 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 343 " mBinding = " + mBinding); 344 } 345 346 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE); 347 msg.arg1=(persist?1:0); 348 mHandler.sendMessage(msg); 349 return true; 350 } 351 352 public void unbindAndFinish() { 353 if (DBG) { 354 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 355 " mBinding = " + mBinding); 356 } 357 358 synchronized (mConnection) { 359 if (mUnbinding) return; 360 mUnbinding = true; 361 if (mBluetooth != null) { 362 if (!mConnection.isGetNameAddressOnly()) { 363 //Unregister callback object 364 try { 365 mBluetooth.unregisterCallback(mBluetoothCallback); 366 } catch (RemoteException re) { 367 Log.e(TAG, "Unable to unregister BluetoothCallback",re); 368 } 369 } 370 if (DBG) Log.d(TAG, "Sending unbind request."); 371 mBluetooth = null; 372 //Unbind 373 mContext.unbindService(mConnection); 374 mUnbinding = false; 375 mBinding = false; 376 } else { 377 mUnbinding=false; 378 } 379 } 380 } 381 382 private void sendBluetoothStateCallback(boolean isUp) { 383 int n = mStateChangeCallbacks.beginBroadcast(); 384 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 385 for (int i=0; i <n;i++) { 386 try { 387 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 388 } catch (RemoteException e) { 389 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 390 } 391 } 392 mStateChangeCallbacks.finishBroadcast(); 393 } 394 395 /** 396 * Inform BluetoothAdapter instances that Adapter service is up 397 */ 398 private void sendBluetoothServiceUpCallback() { 399 if (!mConnection.isGetNameAddressOnly()) { 400 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); 401 int n = mCallbacks.beginBroadcast(); 402 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 403 for (int i=0; i <n;i++) { 404 try { 405 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 406 } catch (RemoteException e) { 407 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 408 } 409 } 410 mCallbacks.finishBroadcast(); 411 } 412 } 413 /** 414 * Inform BluetoothAdapter instances that Adapter service is down 415 */ 416 private void sendBluetoothServiceDownCallback() { 417 if (!mConnection.isGetNameAddressOnly()) { 418 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 419 int n = mCallbacks.beginBroadcast(); 420 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 421 for (int i=0; i <n;i++) { 422 try { 423 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 424 } catch (RemoteException e) { 425 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 426 } 427 } 428 mCallbacks.finishBroadcast(); 429 } 430 } 431 public String getAddress() { 432 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 433 "Need BLUETOOTH ADMIN permission"); 434 435 if (!checkIfCallerIsForegroundUser()) { 436 Log.w(TAG,"getAddress(): not allowed for non-active user"); 437 return mAddress; 438 } 439 440 synchronized(mConnection) { 441 if (mBluetooth != null) { 442 try { 443 return mBluetooth.getAddress(); 444 } catch (RemoteException e) { 445 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 446 } 447 } 448 } 449 // mAddress is accessed from outside. 450 // It is alright without a lock. Here, bluetooth is off, no other thread is 451 // changing mAddress 452 return mAddress; 453 } 454 455 public String getName() { 456 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 457 "Need BLUETOOTH ADMIN permission"); 458 459 if (!checkIfCallerIsForegroundUser()) { 460 Log.w(TAG,"getName(): not allowed for non-active user"); 461 return mName; 462 } 463 464 synchronized(mConnection) { 465 if (mBluetooth != null) { 466 try { 467 return mBluetooth.getName(); 468 } catch (RemoteException e) { 469 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 470 } 471 } 472 } 473 // mName is accessed from outside. 474 // It alright without a lock. Here, bluetooth is off, no other thread is 475 // changing mName 476 return mName; 477 } 478 479 private class BluetoothServiceConnection implements ServiceConnection { 480 481 private boolean mGetNameAddressOnly; 482 483 public void setGetNameAddressOnly(boolean getOnly) { 484 mGetNameAddressOnly = getOnly; 485 } 486 487 public boolean isGetNameAddressOnly() { 488 return mGetNameAddressOnly; 489 } 490 491 public void onServiceConnected(ComponentName className, IBinder service) { 492 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService"); 493 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 494 msg.obj = service; 495 mHandler.sendMessage(msg); 496 } 497 498 public void onServiceDisconnected(ComponentName className) { 499 // Called if we unexpected disconnected. 500 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService"); 501 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 502 mHandler.sendMessage(msg); 503 } 504 } 505 506 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 507 508 private class BluetoothHandler extends Handler { 509 public BluetoothHandler(Looper looper) { 510 super(looper); 511 } 512 513 @Override 514 public void handleMessage(Message msg) { 515 if (DBG) Log.d (TAG, "Message: " + msg.what); 516 switch (msg.what) { 517 case MESSAGE_GET_NAME_AND_ADDRESS: { 518 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 519 synchronized(mConnection) { 520 //Start bind request 521 if ((mBluetooth == null) && (!mBinding)) { 522 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 523 mConnection.setGetNameAddressOnly(true); 524 //Start bind timeout and bind 525 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 526 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 527 Intent i = new Intent(IBluetooth.class.getName()); 528 if (!mContext.bindService(i, mConnection, 529 Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) { 530 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 531 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName()); 532 } else { 533 mBinding = true; 534 } 535 } 536 else { 537 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 538 saveMsg.arg1 = 0; 539 if (mBluetooth != null) { 540 mHandler.sendMessage(saveMsg); 541 } else { 542 // if enable is also called to bind the service 543 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED 544 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); 545 } 546 } 547 } 548 break; 549 } 550 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 551 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 552 synchronized(mConnection) { 553 if (mBluetooth != null) { 554 String name = null; 555 String address = null; 556 try { 557 name = mBluetooth.getName(); 558 address = mBluetooth.getAddress(); 559 } catch (RemoteException re) { 560 Log.e(TAG,"",re); 561 } 562 563 if (name != null && address != null) { 564 storeNameAndAddress(name,address); 565 if (mConnection.isGetNameAddressOnly()) { 566 unbindAndFinish(); 567 } 568 } else { 569 if (msg.arg1 < MAX_SAVE_RETRIES) { 570 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 571 retryMsg.arg1= 1+msg.arg1; 572 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 573 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 574 } else { 575 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 576 if (mConnection.isGetNameAddressOnly()) { 577 unbindAndFinish(); 578 } 579 } 580 } 581 } else { 582 // rebind service by Request GET NAME AND ADDRESS 583 // if service is unbinded by disable or 584 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received 585 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 586 mHandler.sendMessage(getMsg); 587 } 588 } 589 break; 590 } 591 case MESSAGE_ENABLE: 592 if (DBG) { 593 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 594 } 595 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 596 mEnable = true; 597 handleEnable(msg.arg1 == 1, msg.arg2 ==1); 598 break; 599 600 case MESSAGE_DISABLE: 601 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 602 if (mEnable && mBluetooth != null) { 603 waitForOnOff(true, false); 604 mEnable = false; 605 handleDisable(msg.arg1 == 1); 606 waitForOnOff(false, false); 607 } else { 608 mEnable = false; 609 handleDisable(msg.arg1 == 1); 610 } 611 break; 612 613 case MESSAGE_REGISTER_ADAPTER: 614 { 615 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 616 boolean added = mCallbacks.register(callback); 617 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 618 } 619 break; 620 case MESSAGE_UNREGISTER_ADAPTER: 621 { 622 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 623 boolean removed = mCallbacks.unregister(callback); 624 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 625 break; 626 } 627 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 628 { 629 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 630 mStateChangeCallbacks.register(callback); 631 break; 632 } 633 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 634 { 635 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 636 mStateChangeCallbacks.unregister(callback); 637 break; 638 } 639 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 640 { 641 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); 642 643 //Remove timeout 644 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 645 646 IBinder service = (IBinder) msg.obj; 647 synchronized(mConnection) { 648 mBinding = false; 649 mBluetooth = IBluetooth.Stub.asInterface(service); 650 651 if (mConnection.isGetNameAddressOnly()) { 652 //Request GET NAME AND ADDRESS 653 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 654 mHandler.sendMessage(getMsg); 655 if (!mEnable) return; 656 } 657 658 mConnection.setGetNameAddressOnly(false); 659 //Register callback object 660 try { 661 mBluetooth.registerCallback(mBluetoothCallback); 662 } catch (RemoteException re) { 663 Log.e(TAG, "Unable to register BluetoothCallback",re); 664 } 665 //Inform BluetoothAdapter instances that service is up 666 sendBluetoothServiceUpCallback(); 667 668 //Check if name and address is loaded if not get it first. 669 if (!isNameAndAddressSet()) { 670 try { 671 storeNameAndAddress(mBluetooth.getName(), 672 mBluetooth.getAddress()); 673 } catch (RemoteException e) {Log.e(TAG, "", e);}; 674 } 675 676 //Do enable request 677 try { 678 if (mQuietEnable == false) { 679 if(!mBluetooth.enable()) { 680 Log.e(TAG,"IBluetooth.enable() returned false"); 681 } 682 } 683 else 684 { 685 if(!mBluetooth.enableNoAutoConnect()) { 686 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 687 } 688 } 689 } catch (RemoteException e) { 690 Log.e(TAG,"Unable to call enable()",e); 691 } 692 } 693 694 if (!mEnable) { 695 waitForOnOff(true, false); 696 handleDisable(false); 697 waitForOnOff(false, false); 698 } 699 break; 700 } 701 case MESSAGE_TIMEOUT_BIND: { 702 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 703 synchronized(mConnection) { 704 mBinding = false; 705 mEnable = false; 706 } 707 break; 708 } 709 case MESSAGE_BLUETOOTH_STATE_CHANGE: 710 { 711 int prevState = msg.arg1; 712 int newState = msg.arg2; 713 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 714 mState = newState; 715 bluetoothStateChangeHandler(prevState, newState); 716 break; 717 } 718 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 719 { 720 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); 721 synchronized(mConnection) { 722 // if service is unbinded already, do nothing and return 723 if (mBluetooth == null) return; 724 mBluetooth = null; 725 } 726 727 if (mEnable) { 728 mEnable = false; 729 // Send a Bluetooth Restart message 730 Message restartMsg = mHandler.obtainMessage( 731 MESSAGE_RESTART_BLUETOOTH_SERVICE); 732 mHandler.sendMessageDelayed(restartMsg, 733 SERVICE_RESTART_TIME_MS); 734 } 735 736 if (!mConnection.isGetNameAddressOnly()) { 737 sendBluetoothServiceDownCallback(); 738 739 // Send BT state broadcast to update 740 // the BT icon correctly 741 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 742 BluetoothAdapter.STATE_TURNING_OFF); 743 mState = BluetoothAdapter.STATE_OFF; 744 } 745 break; 746 } 747 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 748 { 749 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 750 +" Restart IBluetooth service"); 751 /* Enable without persisting the setting as 752 it doesnt change when IBluetooth 753 service restarts */ 754 mEnable = true; 755 handleEnable(false, mQuietEnable); 756 break; 757 } 758 759 case MESSAGE_TIMEOUT_UNBIND: 760 { 761 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 762 synchronized(mConnection) { 763 mUnbinding = false; 764 } 765 break; 766 } 767 768 case MESSAGE_USER_SWITCHED: 769 { 770 if (DBG) { 771 Log.d(TAG, "MESSAGE_USER_SWITCHED"); 772 } 773 mHandler.removeMessages(MESSAGE_USER_SWITCHED); 774 /* disable and enable BT when detect a user switch */ 775 if (mEnable && mBluetooth != null) { 776 synchronized (mConnection) { 777 if (mBluetooth != null) { 778 //Unregister callback object 779 try { 780 mBluetooth.unregisterCallback(mBluetoothCallback); 781 } catch (RemoteException re) { 782 Log.e(TAG, "Unable to unregister",re); 783 } 784 } 785 } 786 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 787 788 waitForOnOff(true, false); 789 790 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); 791 792 // disable 793 handleDisable(false); 794 795 waitForOnOff(false, true); 796 797 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 798 BluetoothAdapter.STATE_OFF); 799 mState = BluetoothAdapter.STATE_OFF; 800 sendBluetoothServiceDownCallback(); 801 synchronized (mConnection) { 802 if (mBluetooth != null) { 803 mBluetooth = null; 804 //Unbind 805 mContext.unbindService(mConnection); 806 } 807 } 808 SystemClock.sleep(100); 809 810 // enable 811 handleEnable(false, mQuietEnable); 812 } else if (mBinding || mBluetooth != null) { 813 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); 814 userMsg.arg2 = 1 + msg.arg2; 815 // if user is switched when service is being binding 816 // delay sending MESSAGE_USER_SWITCHED 817 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); 818 if (DBG) { 819 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); 820 } 821 } 822 break; 823 } 824 } 825 } 826 } 827 828 private void handleEnable(boolean persist, boolean quietMode) { 829 if (persist) { 830 persistBluetoothSetting(true); 831 } 832 833 mQuietEnable = quietMode; 834 835 synchronized(mConnection) { 836 if ((mBluetooth == null) && (!mBinding)) { 837 //Start bind timeout and bind 838 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 839 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 840 mConnection.setGetNameAddressOnly(false); 841 Intent i = new Intent(IBluetooth.class.getName()); 842 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE, 843 UserHandle.USER_CURRENT)) { 844 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 845 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName()); 846 } else { 847 mBinding = true; 848 } 849 } else if (mBluetooth != null) { 850 if (mConnection.isGetNameAddressOnly()) { 851 // if GetNameAddressOnly is set, we can clear this flag, 852 // so the service won't be unbind 853 // after name and address are saved 854 mConnection.setGetNameAddressOnly(false); 855 //Register callback object 856 try { 857 mBluetooth.registerCallback(mBluetoothCallback); 858 } catch (RemoteException re) { 859 Log.e(TAG, "Unable to register BluetoothCallback",re); 860 } 861 //Inform BluetoothAdapter instances that service is up 862 sendBluetoothServiceUpCallback(); 863 } 864 865 //Check if name and address is loaded if not get it first. 866 if (!isNameAndAddressSet()) { 867 try { 868 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable."); 869 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress()); 870 } catch (RemoteException e) {Log.e(TAG, "", e);}; 871 } 872 873 //Enable bluetooth 874 try { 875 if (!mQuietEnable) { 876 if(!mBluetooth.enable()) { 877 Log.e(TAG,"IBluetooth.enable() returned false"); 878 } 879 } 880 else { 881 if(!mBluetooth.enableNoAutoConnect()) { 882 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 883 } 884 } 885 } catch (RemoteException e) { 886 Log.e(TAG,"Unable to call enable()",e); 887 } 888 } 889 } 890 } 891 892 private void handleDisable(boolean persist) { 893 if (persist) { 894 persistBluetoothSetting(false); 895 } 896 897 synchronized(mConnection) { 898 // don't need to disable if GetNameAddressOnly is set, 899 // service will be unbinded after Name and Address are saved 900 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { 901 if (DBG) Log.d(TAG,"Sending off request."); 902 903 try { 904 if(!mBluetooth.disable()) { 905 Log.e(TAG,"IBluetooth.disable() returned false"); 906 } 907 } catch (RemoteException e) { 908 Log.e(TAG,"Unable to call disable()",e); 909 } 910 } 911 } 912 } 913 914 private boolean checkIfCallerIsForegroundUser() { 915 int foregroundUser; 916 int callingUser = UserHandle.getCallingUserId(); 917 long callingIdentity = Binder.clearCallingIdentity(); 918 boolean valid = false; 919 try { 920 foregroundUser = ActivityManager.getCurrentUser(); 921 valid = (callingUser == foregroundUser); 922 if (DBG) { 923 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid 924 + " callingUser=" + callingUser 925 + " foregroundUser=" + foregroundUser); 926 } 927 } finally { 928 Binder.restoreCallingIdentity(callingIdentity); 929 } 930 return valid; 931 } 932 933 private boolean enableHelper() { 934 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 935 "Need BLUETOOTH ADMIN permission"); 936 if (DBG) { 937 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 938 " mBinding = " + mBinding); 939 } 940 941 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 942 msg.arg1=1; //persist 943 msg.arg2=0; //No Quiet Mode 944 mHandler.sendMessage(msg); 945 return true; 946 } 947 948 private void bluetoothStateChangeHandler(int prevState, int newState) { 949 if (prevState != newState) { 950 //Notify all proxy objects first of adapter state change 951 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 952 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 953 sendBluetoothStateCallback(isUp); 954 955 //If Bluetooth is off, send service down event to proxy objects, and unbind 956 if (!isUp) { 957 //Only unbind with mEnable flag not set 958 //For race condition: disable and enable back-to-back 959 //Avoid unbind right after enable due to callback from disable 960 if ((!mEnable) && (mBluetooth != null)) { 961 sendBluetoothServiceDownCallback(); 962 unbindAndFinish(); 963 } 964 } 965 } 966 967 //Send broadcast message to everyone else 968 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 969 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 970 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 971 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 972 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 973 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 974 BLUETOOTH_PERM); 975 } 976 } 977 978 /** 979 * if on is true, wait for state become ON 980 * if off is true, wait for state become OFF 981 * if both on and off are false, wait for state not ON 982 */ 983 private boolean waitForOnOff(boolean on, boolean off) { 984 int i = 0; 985 while (i < 10) { 986 synchronized(mConnection) { 987 try { 988 if (mBluetooth == null) break; 989 if (on) { 990 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; 991 } else if (off) { 992 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; 993 } else { 994 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; 995 } 996 } catch (RemoteException e) { 997 Log.e(TAG, "getState()", e); 998 break; 999 } 1000 } 1001 if (on || off) { 1002 SystemClock.sleep(300); 1003 } else { 1004 SystemClock.sleep(50); 1005 } 1006 i++; 1007 } 1008 Log.e(TAG,"waitForOnOff time out"); 1009 return false; 1010 } 1011} 1012