BluetoothManagerService.java revision 55db646c4e43fd24386bf522aef13c0b3075593c
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import android.app.ActivityManager; 20import android.bluetooth.BluetoothAdapter; 21import android.bluetooth.IBluetooth; 22import android.bluetooth.IBluetoothGatt; 23import android.bluetooth.IBluetoothCallback; 24import android.bluetooth.IBluetoothManager; 25import android.bluetooth.IBluetoothManagerCallback; 26import android.bluetooth.IBluetoothStateChangeCallback; 27import android.content.BroadcastReceiver; 28import android.content.ComponentName; 29import android.content.ContentResolver; 30import android.content.Context; 31import android.content.Intent; 32import android.content.IntentFilter; 33import android.content.ServiceConnection; 34import android.content.pm.PackageManager; 35import android.os.Binder; 36import android.os.Handler; 37import android.os.IBinder; 38import android.os.Looper; 39import android.os.Message; 40import android.os.Process; 41import android.os.RemoteCallbackList; 42import android.os.RemoteException; 43import android.os.SystemClock; 44import android.os.UserHandle; 45import android.provider.Settings; 46import android.util.Log; 47class BluetoothManagerService extends IBluetoothManager.Stub { 48 private static final String TAG = "BluetoothManagerService"; 49 private static final boolean DBG = true; 50 51 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 52 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 53 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 54 private static final String EXTRA_ACTION="action"; 55 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid"; 56 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; 57 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; 58 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind 59 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save 60 //Maximum msec to wait for service restart 61 private static final int SERVICE_RESTART_TIME_MS = 200; 62 //Maximum msec to wait for restart due to error 63 private static final int ERROR_RESTART_TIME_MS = 3000; 64 //Maximum msec to delay MESSAGE_USER_SWITCHED 65 private static final int USER_SWITCHED_TIME_MS = 200; 66 67 private static final int MESSAGE_ENABLE = 1; 68 private static final int MESSAGE_DISABLE = 2; 69 private static final int MESSAGE_REGISTER_ADAPTER = 20; 70 private static final int MESSAGE_UNREGISTER_ADAPTER = 21; 71 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; 72 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; 73 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; 74 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; 75 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; 76 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60; 77 private static final int MESSAGE_TIMEOUT_BIND =100; 78 private static final int MESSAGE_TIMEOUT_UNBIND =101; 79 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; 80 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; 81 private static final int MESSAGE_USER_SWITCHED = 300; 82 private static final int MAX_SAVE_RETRIES=3; 83 private static final int MAX_ERROR_RESTART_RETRIES=6; 84 85 // Bluetooth persisted setting is off 86 private static final int BLUETOOTH_OFF=0; 87 // Bluetooth persisted setting is on 88 // and Airplane mode won't affect Bluetooth state at start up 89 private static final int BLUETOOTH_ON_BLUETOOTH=1; 90 // Bluetooth persisted setting is on 91 // but Airplane mode will affect Bluetooth state at start up 92 // and Airplane mode will have higher priority. 93 private static final int BLUETOOTH_ON_AIRPLANE=2; 94 95 private static final int SERVICE_IBLUETOOTH = 1; 96 private static final int SERVICE_IBLUETOOTHGATT = 2; 97 98 private final Context mContext; 99 100 // Locks are not provided for mName and mAddress. 101 // They are accessed in handler or broadcast receiver, same thread context. 102 private String mAddress; 103 private String mName; 104 private final ContentResolver mContentResolver; 105 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 106 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; 107 private IBluetooth mBluetooth; 108 private IBluetoothGatt mBluetoothGatt; 109 private boolean mBinding; 110 private boolean mUnbinding; 111 // used inside handler thread 112 private boolean mQuietEnable = false; 113 // configuarion from external IBinder call which is used to 114 // synchronize with broadcast receiver. 115 private boolean mQuietEnableExternal; 116 // configuarion from external IBinder call which is used to 117 // synchronize with broadcast receiver. 118 private boolean mEnableExternal; 119 // used inside handler thread 120 private boolean mEnable; 121 private int mState; 122 private final BluetoothHandler mHandler; 123 private int mErrorRecoveryRetryCounter; 124 125 private void registerForAirplaneMode(IntentFilter filter) { 126 final ContentResolver resolver = mContext.getContentResolver(); 127 final String airplaneModeRadios = Settings.Global.getString(resolver, 128 Settings.Global.AIRPLANE_MODE_RADIOS); 129 final String toggleableRadios = Settings.Global.getString(resolver, 130 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 131 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true : 132 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH); 133 if (mIsAirplaneSensitive) { 134 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 135 } 136 } 137 138 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { 139 @Override 140 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { 141 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); 142 mHandler.sendMessage(msg); 143 } 144 }; 145 146 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 147 @Override 148 public void onReceive(Context context, Intent intent) { 149 String action = intent.getAction(); 150 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { 151 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); 152 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName); 153 if (newName != null) { 154 storeNameAndAddress(newName, null); 155 } 156 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 157 synchronized(mReceiver) { 158 if (isBluetoothPersistedStateOn()) { 159 if (isAirplaneModeOn()) { 160 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); 161 } else { 162 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 163 } 164 } 165 if (isAirplaneModeOn()) { 166 // disable without persisting the setting 167 sendDisableMsg(); 168 } else if (mEnableExternal) { 169 // enable without persisting the setting 170 sendEnableMsg(mQuietEnableExternal); 171 } 172 } 173 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { 174 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, 175 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 176 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 177 synchronized(mReceiver) { 178 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) { 179 //Enable 180 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); 181 sendEnableMsg(mQuietEnableExternal); 182 } 183 } 184 185 if (!isNameAndAddressSet()) { 186 //Sync the Bluetooth name and address from the Bluetooth Adapter 187 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); 188 getNameAndAddress(); 189 } 190 } 191 } 192 }; 193 194 BluetoothManagerService(Context context) { 195 mHandler = new BluetoothHandler(IoThread.get().getLooper()); 196 197 mContext = context; 198 mBluetooth = null; 199 mBinding = false; 200 mUnbinding = false; 201 mEnable = false; 202 mState = BluetoothAdapter.STATE_OFF; 203 mQuietEnableExternal = false; 204 mEnableExternal = false; 205 mAddress = null; 206 mName = null; 207 mErrorRecoveryRetryCounter = 0; 208 mContentResolver = context.getContentResolver(); 209 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); 210 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); 211 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 212 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 213 filter.addAction(Intent.ACTION_USER_SWITCHED); 214 registerForAirplaneMode(filter); 215 mContext.registerReceiver(mReceiver, filter); 216 loadStoredNameAndAddress(); 217 if (isBluetoothPersistedStateOn()) { 218 mEnableExternal = true; 219 } 220 } 221 222 /** 223 * Returns true if airplane mode is currently on 224 */ 225 private final boolean isAirplaneModeOn() { 226 return Settings.Global.getInt(mContext.getContentResolver(), 227 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 228 } 229 230 /** 231 * Returns true if the Bluetooth saved state is "on" 232 */ 233 private final boolean isBluetoothPersistedStateOn() { 234 return Settings.Global.getInt(mContentResolver, 235 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF; 236 } 237 238 /** 239 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH 240 */ 241 private final boolean isBluetoothPersistedStateOnBluetooth() { 242 return Settings.Global.getInt(mContentResolver, 243 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH; 244 } 245 246 /** 247 * Save the Bluetooth on/off state 248 * 249 */ 250 private void persistBluetoothSetting(int value) { 251 Settings.Global.putInt(mContext.getContentResolver(), 252 Settings.Global.BLUETOOTH_ON, 253 value); 254 } 255 256 /** 257 * Returns true if the Bluetooth Adapter's name and address is 258 * locally cached 259 * @return 260 */ 261 private boolean isNameAndAddressSet() { 262 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; 263 } 264 265 /** 266 * Retrieve the Bluetooth Adapter's name and address and save it in 267 * in the local cache 268 */ 269 private void loadStoredNameAndAddress() { 270 if (DBG) Log.d(TAG, "Loading stored name and address"); 271 if (mContext.getResources().getBoolean 272 (com.android.internal.R.bool.config_bluetooth_address_validation) && 273 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) { 274 // if the valid flag is not set, don't load the address and name 275 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored"); 276 return; 277 } 278 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); 279 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); 280 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); 281 } 282 283 /** 284 * Save the Bluetooth name and address in the persistent store. 285 * Only non-null values will be saved. 286 * @param name 287 * @param address 288 */ 289 private void storeNameAndAddress(String name, String address) { 290 if (name != null) { 291 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); 292 mName = name; 293 if (DBG) Log.d(TAG,"Stored Bluetooth name: " + 294 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); 295 } 296 297 if (address != null) { 298 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); 299 mAddress=address; 300 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " + 301 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); 302 } 303 304 if ((name != null) && (address != null)) { 305 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1); 306 } 307 } 308 309 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ 310 if (callback == null) { 311 Log.w(TAG, "Callback is null in registerAdapter"); 312 return null; 313 } 314 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 315 msg.obj = callback; 316 mHandler.sendMessage(msg); 317 synchronized(mConnection) { 318 return mBluetooth; 319 } 320 } 321 322 public void unregisterAdapter(IBluetoothManagerCallback callback) { 323 if (callback == null) { 324 Log.w(TAG, "Callback is null in unregisterAdapter"); 325 return; 326 } 327 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 328 "Need BLUETOOTH permission"); 329 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 330 msg.obj = callback; 331 mHandler.sendMessage(msg); 332 } 333 334 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 335 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 336 "Need BLUETOOTH permission"); 337 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 338 msg.obj = callback; 339 mHandler.sendMessage(msg); 340 } 341 342 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 343 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 344 "Need BLUETOOTH permission"); 345 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 346 msg.obj = callback; 347 mHandler.sendMessage(msg); 348 } 349 350 public boolean isEnabled() { 351 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 352 (!checkIfCallerIsForegroundUser())) { 353 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user"); 354 return false; 355 } 356 357 synchronized(mConnection) { 358 try { 359 return (mBluetooth != null && mBluetooth.isEnabled()); 360 } catch (RemoteException e) { 361 Log.e(TAG, "isEnabled()", e); 362 } 363 } 364 return false; 365 } 366 367 public void getNameAndAddress() { 368 if (DBG) { 369 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 370 " mBinding = " + mBinding); 371 } 372 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 373 mHandler.sendMessage(msg); 374 } 375 public boolean enableNoAutoConnect() 376 { 377 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 378 "Need BLUETOOTH ADMIN permission"); 379 380 if (DBG) { 381 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 382 " mBinding = " + mBinding); 383 } 384 int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); 385 386 if (callingAppId != Process.NFC_UID) { 387 throw new SecurityException("no permission to enable Bluetooth quietly"); 388 } 389 390 synchronized(mReceiver) { 391 mQuietEnableExternal = true; 392 mEnableExternal = true; 393 sendEnableMsg(true); 394 } 395 return true; 396 397 } 398 public boolean enable() { 399 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 400 (!checkIfCallerIsForegroundUser())) { 401 Log.w(TAG,"enable(): not allowed for non-active and non system user"); 402 return false; 403 } 404 405 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 406 "Need BLUETOOTH ADMIN permission"); 407 if (DBG) { 408 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 409 " mBinding = " + mBinding); 410 } 411 412 synchronized(mReceiver) { 413 mQuietEnableExternal = false; 414 mEnableExternal = true; 415 // waive WRITE_SECURE_SETTINGS permission check 416 long callingIdentity = Binder.clearCallingIdentity(); 417 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 418 Binder.restoreCallingIdentity(callingIdentity); 419 sendEnableMsg(false); 420 } 421 return true; 422 } 423 424 public boolean disable(boolean persist) { 425 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 426 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 427 428 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 429 (!checkIfCallerIsForegroundUser())) { 430 Log.w(TAG,"disable(): not allowed for non-active and non system user"); 431 return false; 432 } 433 434 if (DBG) { 435 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 436 " mBinding = " + mBinding); 437 } 438 439 synchronized(mReceiver) { 440 if (persist) { 441 // waive WRITE_SECURE_SETTINGS permission check 442 long callingIdentity = Binder.clearCallingIdentity(); 443 persistBluetoothSetting(BLUETOOTH_OFF); 444 Binder.restoreCallingIdentity(callingIdentity); 445 } 446 mEnableExternal = false; 447 sendDisableMsg(); 448 } 449 return true; 450 } 451 452 public void unbindAndFinish() { 453 if (DBG) { 454 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 455 " mBinding = " + mBinding); 456 } 457 458 synchronized (mConnection) { 459 if (mUnbinding) return; 460 mUnbinding = true; 461 if (mBluetooth != null) { 462 if (!mConnection.isGetNameAddressOnly()) { 463 //Unregister callback object 464 try { 465 mBluetooth.unregisterCallback(mBluetoothCallback); 466 } catch (RemoteException re) { 467 Log.e(TAG, "Unable to unregister BluetoothCallback",re); 468 } 469 } 470 if (DBG) Log.d(TAG, "Sending unbind request."); 471 mBluetooth = null; 472 //Unbind 473 mContext.unbindService(mConnection); 474 mUnbinding = false; 475 mBinding = false; 476 } else { 477 mUnbinding=false; 478 } 479 } 480 } 481 482 public IBluetoothGatt getBluetoothGatt() { 483 // sync protection 484 return mBluetoothGatt; 485 } 486 487 private void sendBluetoothStateCallback(boolean isUp) { 488 int n = mStateChangeCallbacks.beginBroadcast(); 489 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 490 for (int i=0; i <n;i++) { 491 try { 492 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 493 } catch (RemoteException e) { 494 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 495 } 496 } 497 mStateChangeCallbacks.finishBroadcast(); 498 } 499 500 /** 501 * Inform BluetoothAdapter instances that Adapter service is up 502 */ 503 private void sendBluetoothServiceUpCallback() { 504 if (!mConnection.isGetNameAddressOnly()) { 505 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); 506 int n = mCallbacks.beginBroadcast(); 507 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 508 for (int i=0; i <n;i++) { 509 try { 510 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 511 } catch (RemoteException e) { 512 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 513 } 514 } 515 mCallbacks.finishBroadcast(); 516 } 517 } 518 /** 519 * Inform BluetoothAdapter instances that Adapter service is down 520 */ 521 private void sendBluetoothServiceDownCallback() { 522 if (!mConnection.isGetNameAddressOnly()) { 523 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 524 int n = mCallbacks.beginBroadcast(); 525 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 526 for (int i=0; i <n;i++) { 527 try { 528 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 529 } catch (RemoteException e) { 530 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 531 } 532 } 533 mCallbacks.finishBroadcast(); 534 } 535 } 536 public String getAddress() { 537 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 538 "Need BLUETOOTH permission"); 539 540 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 541 (!checkIfCallerIsForegroundUser())) { 542 Log.w(TAG,"getAddress(): not allowed for non-active and non system user"); 543 return null; 544 } 545 546 synchronized(mConnection) { 547 if (mBluetooth != null) { 548 try { 549 return mBluetooth.getAddress(); 550 } catch (RemoteException e) { 551 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 552 } 553 } 554 } 555 // mAddress is accessed from outside. 556 // It is alright without a lock. Here, bluetooth is off, no other thread is 557 // changing mAddress 558 return mAddress; 559 } 560 561 public String getName() { 562 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 563 "Need BLUETOOTH permission"); 564 565 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 566 (!checkIfCallerIsForegroundUser())) { 567 Log.w(TAG,"getName(): not allowed for non-active and non system user"); 568 return null; 569 } 570 571 synchronized(mConnection) { 572 if (mBluetooth != null) { 573 try { 574 return mBluetooth.getName(); 575 } catch (RemoteException e) { 576 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 577 } 578 } 579 } 580 // mName is accessed from outside. 581 // It alright without a lock. Here, bluetooth is off, no other thread is 582 // changing mName 583 return mName; 584 } 585 586 private class BluetoothServiceConnection implements ServiceConnection { 587 588 private boolean mGetNameAddressOnly; 589 590 public void setGetNameAddressOnly(boolean getOnly) { 591 mGetNameAddressOnly = getOnly; 592 } 593 594 public boolean isGetNameAddressOnly() { 595 return mGetNameAddressOnly; 596 } 597 598 public void onServiceConnected(ComponentName className, IBinder service) { 599 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName()); 600 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 601 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) { 602 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 603 msg.arg1 = SERVICE_IBLUETOOTH; 604 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) { 605 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 606 msg.arg1 = SERVICE_IBLUETOOTHGATT; 607 } else { 608 Log.e(TAG, "Unknown service connected: " + className.getClassName()); 609 return; 610 } 611 msg.obj = service; 612 mHandler.sendMessage(msg); 613 } 614 615 public void onServiceDisconnected(ComponentName className) { 616 // Called if we unexpected disconnected. 617 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " + 618 className.getClassName()); 619 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 620 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 621 msg.arg1 = SERVICE_IBLUETOOTH; 622 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 623 msg.arg1 = SERVICE_IBLUETOOTHGATT; 624 } else { 625 Log.e(TAG, "Unknown service disconnected: " + className.getClassName()); 626 return; 627 } 628 mHandler.sendMessage(msg); 629 } 630 } 631 632 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 633 634 private class BluetoothHandler extends Handler { 635 public BluetoothHandler(Looper looper) { 636 super(looper); 637 } 638 639 @Override 640 public void handleMessage(Message msg) { 641 if (DBG) Log.d (TAG, "Message: " + msg.what); 642 switch (msg.what) { 643 case MESSAGE_GET_NAME_AND_ADDRESS: { 644 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 645 synchronized(mConnection) { 646 //Start bind request 647 if ((mBluetooth == null) && (!mBinding)) { 648 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 649 mConnection.setGetNameAddressOnly(true); 650 //Start bind timeout and bind 651 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 652 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 653 Intent i = new Intent(IBluetooth.class.getName()); 654 if (!doBind(i, mConnection, 655 Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) { 656 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 657 } else { 658 mBinding = true; 659 } 660 } 661 else { 662 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 663 saveMsg.arg1 = 0; 664 if (mBluetooth != null) { 665 mHandler.sendMessage(saveMsg); 666 } else { 667 // if enable is also called to bind the service 668 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED 669 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); 670 } 671 } 672 } 673 break; 674 } 675 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 676 boolean unbind = false; 677 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 678 synchronized(mConnection) { 679 if (!mEnable && mBluetooth != null) { 680 try { 681 mBluetooth.enable(); 682 } catch (RemoteException e) { 683 Log.e(TAG,"Unable to call enable()",e); 684 } 685 } 686 } 687 if (mBluetooth != null) waitForOnOff(true, false); 688 synchronized(mConnection) { 689 if (mBluetooth != null) { 690 String name = null; 691 String address = null; 692 try { 693 name = mBluetooth.getName(); 694 address = mBluetooth.getAddress(); 695 } catch (RemoteException re) { 696 Log.e(TAG,"",re); 697 } 698 699 if (name != null && address != null) { 700 storeNameAndAddress(name,address); 701 if (mConnection.isGetNameAddressOnly()) { 702 unbind = true; 703 } 704 } else { 705 if (msg.arg1 < MAX_SAVE_RETRIES) { 706 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 707 retryMsg.arg1= 1+msg.arg1; 708 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 709 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 710 } else { 711 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 712 if (mConnection.isGetNameAddressOnly()) { 713 unbind = true; 714 } 715 } 716 } 717 if (!mEnable) { 718 try { 719 mBluetooth.disable(); 720 } catch (RemoteException e) { 721 Log.e(TAG,"Unable to call disable()",e); 722 } 723 } 724 } else { 725 // rebind service by Request GET NAME AND ADDRESS 726 // if service is unbinded by disable or 727 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received 728 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 729 mHandler.sendMessage(getMsg); 730 } 731 } 732 if (!mEnable && mBluetooth != null) waitForOnOff(false, true); 733 if (unbind) { 734 unbindAndFinish(); 735 } 736 break; 737 } 738 case MESSAGE_ENABLE: 739 if (DBG) { 740 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 741 } 742 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 743 mEnable = true; 744 handleEnable(msg.arg1 == 1); 745 break; 746 747 case MESSAGE_DISABLE: 748 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 749 if (mEnable && mBluetooth != null) { 750 waitForOnOff(true, false); 751 mEnable = false; 752 handleDisable(); 753 waitForOnOff(false, false); 754 } else { 755 mEnable = false; 756 handleDisable(); 757 } 758 break; 759 760 case MESSAGE_REGISTER_ADAPTER: 761 { 762 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 763 boolean added = mCallbacks.register(callback); 764 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 765 } 766 break; 767 case MESSAGE_UNREGISTER_ADAPTER: 768 { 769 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 770 boolean removed = mCallbacks.unregister(callback); 771 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 772 break; 773 } 774 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 775 { 776 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 777 if (callback != null) { 778 mStateChangeCallbacks.register(callback); 779 } 780 break; 781 } 782 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 783 { 784 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 785 if (callback != null) { 786 mStateChangeCallbacks.unregister(callback); 787 } 788 break; 789 } 790 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 791 { 792 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); 793 794 IBinder service = (IBinder) msg.obj; 795 synchronized(mConnection) { 796 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 797 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service); 798 break; 799 } // else must be SERVICE_IBLUETOOTH 800 801 //Remove timeout 802 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 803 804 mBinding = false; 805 mBluetooth = IBluetooth.Stub.asInterface(service); 806 807 try { 808 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver, 809 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1); 810 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) { 811 Log.e(TAG,"IBluetooth.configHciSnoopLog return false"); 812 } 813 } catch (RemoteException e) { 814 Log.e(TAG,"Unable to call configHciSnoopLog", e); 815 } 816 817 if (mConnection.isGetNameAddressOnly()) { 818 //Request GET NAME AND ADDRESS 819 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 820 mHandler.sendMessage(getMsg); 821 if (!mEnable) return; 822 } 823 824 mConnection.setGetNameAddressOnly(false); 825 //Register callback object 826 try { 827 mBluetooth.registerCallback(mBluetoothCallback); 828 } catch (RemoteException re) { 829 Log.e(TAG, "Unable to register BluetoothCallback",re); 830 } 831 //Inform BluetoothAdapter instances that service is up 832 sendBluetoothServiceUpCallback(); 833 834 //Do enable request 835 try { 836 if (mQuietEnable == false) { 837 if(!mBluetooth.enable()) { 838 Log.e(TAG,"IBluetooth.enable() returned false"); 839 } 840 } 841 else 842 { 843 if(!mBluetooth.enableNoAutoConnect()) { 844 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 845 } 846 } 847 } catch (RemoteException e) { 848 Log.e(TAG,"Unable to call enable()",e); 849 } 850 } 851 852 if (!mEnable) { 853 waitForOnOff(true, false); 854 handleDisable(); 855 waitForOnOff(false, false); 856 } 857 break; 858 } 859 case MESSAGE_TIMEOUT_BIND: { 860 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 861 synchronized(mConnection) { 862 mBinding = false; 863 } 864 break; 865 } 866 case MESSAGE_BLUETOOTH_STATE_CHANGE: 867 { 868 int prevState = msg.arg1; 869 int newState = msg.arg2; 870 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 871 mState = newState; 872 bluetoothStateChangeHandler(prevState, newState); 873 // handle error state transition case from TURNING_ON to OFF 874 // unbind and rebind bluetooth service and enable bluetooth 875 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && 876 (newState == BluetoothAdapter.STATE_OFF) && 877 (mBluetooth != null) && mEnable) { 878 recoverBluetoothServiceFromError(); 879 } 880 if (newState == BluetoothAdapter.STATE_ON) { 881 // bluetooth is working, reset the counter 882 if (mErrorRecoveryRetryCounter != 0) { 883 Log.w(TAG, "bluetooth is recovered from error"); 884 mErrorRecoveryRetryCounter = 0; 885 } 886 } 887 break; 888 } 889 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 890 { 891 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1); 892 synchronized(mConnection) { 893 if (msg.arg1 == SERVICE_IBLUETOOTH) { 894 // if service is unbinded already, do nothing and return 895 if (mBluetooth == null) break; 896 mBluetooth = null; 897 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 898 mBluetoothGatt = null; 899 break; 900 } else { 901 Log.e(TAG, "Bad msg.arg1: " + msg.arg1); 902 break; 903 } 904 } 905 906 if (mEnable) { 907 mEnable = false; 908 // Send a Bluetooth Restart message 909 Message restartMsg = mHandler.obtainMessage( 910 MESSAGE_RESTART_BLUETOOTH_SERVICE); 911 mHandler.sendMessageDelayed(restartMsg, 912 SERVICE_RESTART_TIME_MS); 913 } 914 915 if (!mConnection.isGetNameAddressOnly()) { 916 sendBluetoothServiceDownCallback(); 917 918 // Send BT state broadcast to update 919 // the BT icon correctly 920 if ((mState == BluetoothAdapter.STATE_TURNING_ON) || 921 (mState == BluetoothAdapter.STATE_ON)) { 922 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 923 BluetoothAdapter.STATE_TURNING_OFF); 924 mState = BluetoothAdapter.STATE_TURNING_OFF; 925 } 926 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 927 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 928 BluetoothAdapter.STATE_OFF); 929 } 930 931 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 932 mState = BluetoothAdapter.STATE_OFF; 933 } 934 break; 935 } 936 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 937 { 938 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 939 +" Restart IBluetooth service"); 940 /* Enable without persisting the setting as 941 it doesnt change when IBluetooth 942 service restarts */ 943 mEnable = true; 944 handleEnable(mQuietEnable); 945 break; 946 } 947 948 case MESSAGE_TIMEOUT_UNBIND: 949 { 950 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 951 synchronized(mConnection) { 952 mUnbinding = false; 953 } 954 break; 955 } 956 957 case MESSAGE_USER_SWITCHED: 958 { 959 if (DBG) { 960 Log.d(TAG, "MESSAGE_USER_SWITCHED"); 961 } 962 mHandler.removeMessages(MESSAGE_USER_SWITCHED); 963 /* disable and enable BT when detect a user switch */ 964 if (mEnable && mBluetooth != null) { 965 synchronized (mConnection) { 966 if (mBluetooth != null) { 967 //Unregister callback object 968 try { 969 mBluetooth.unregisterCallback(mBluetoothCallback); 970 } catch (RemoteException re) { 971 Log.e(TAG, "Unable to unregister",re); 972 } 973 } 974 } 975 976 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 977 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE 978 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF); 979 mState = BluetoothAdapter.STATE_OFF; 980 } 981 if (mState == BluetoothAdapter.STATE_OFF) { 982 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON); 983 mState = BluetoothAdapter.STATE_TURNING_ON; 984 } 985 986 waitForOnOff(true, false); 987 988 if (mState == BluetoothAdapter.STATE_TURNING_ON) { 989 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); 990 } 991 992 // disable 993 handleDisable(); 994 // Pbap service need receive STATE_TURNING_OFF intent to close 995 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 996 BluetoothAdapter.STATE_TURNING_OFF); 997 998 waitForOnOff(false, true); 999 1000 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 1001 BluetoothAdapter.STATE_OFF); 1002 sendBluetoothServiceDownCallback(); 1003 synchronized (mConnection) { 1004 if (mBluetooth != null) { 1005 mBluetooth = null; 1006 //Unbind 1007 mContext.unbindService(mConnection); 1008 } 1009 } 1010 SystemClock.sleep(100); 1011 1012 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1013 mState = BluetoothAdapter.STATE_OFF; 1014 // enable 1015 handleEnable(mQuietEnable); 1016 } else if (mBinding || mBluetooth != null) { 1017 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); 1018 userMsg.arg2 = 1 + msg.arg2; 1019 // if user is switched when service is being binding 1020 // delay sending MESSAGE_USER_SWITCHED 1021 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); 1022 if (DBG) { 1023 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); 1024 } 1025 } 1026 break; 1027 } 1028 } 1029 } 1030 } 1031 1032 private void handleEnable(boolean quietMode) { 1033 mQuietEnable = quietMode; 1034 1035 synchronized(mConnection) { 1036 if ((mBluetooth == null) && (!mBinding)) { 1037 //Start bind timeout and bind 1038 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 1039 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 1040 mConnection.setGetNameAddressOnly(false); 1041 Intent i = new Intent(IBluetooth.class.getName()); 1042 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) { 1043 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1044 } else { 1045 mBinding = true; 1046 } 1047 } else if (mBluetooth != null) { 1048 if (mConnection.isGetNameAddressOnly()) { 1049 // if GetNameAddressOnly is set, we can clear this flag, 1050 // so the service won't be unbind 1051 // after name and address are saved 1052 mConnection.setGetNameAddressOnly(false); 1053 //Register callback object 1054 try { 1055 mBluetooth.registerCallback(mBluetoothCallback); 1056 } catch (RemoteException re) { 1057 Log.e(TAG, "Unable to register BluetoothCallback",re); 1058 } 1059 //Inform BluetoothAdapter instances that service is up 1060 sendBluetoothServiceUpCallback(); 1061 } 1062 1063 //Enable bluetooth 1064 try { 1065 if (!mQuietEnable) { 1066 if(!mBluetooth.enable()) { 1067 Log.e(TAG,"IBluetooth.enable() returned false"); 1068 } 1069 } 1070 else { 1071 if(!mBluetooth.enableNoAutoConnect()) { 1072 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 1073 } 1074 } 1075 } catch (RemoteException e) { 1076 Log.e(TAG,"Unable to call enable()",e); 1077 } 1078 } 1079 } 1080 } 1081 1082 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) { 1083 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); 1084 intent.setComponent(comp); 1085 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) { 1086 Log.e(TAG, "Fail to bind to: " + intent); 1087 return false; 1088 } 1089 return true; 1090 } 1091 1092 private void handleDisable() { 1093 synchronized(mConnection) { 1094 // don't need to disable if GetNameAddressOnly is set, 1095 // service will be unbinded after Name and Address are saved 1096 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { 1097 if (DBG) Log.d(TAG,"Sending off request."); 1098 1099 try { 1100 if(!mBluetooth.disable()) { 1101 Log.e(TAG,"IBluetooth.disable() returned false"); 1102 } 1103 } catch (RemoteException e) { 1104 Log.e(TAG,"Unable to call disable()",e); 1105 } 1106 } 1107 } 1108 } 1109 1110 private boolean checkIfCallerIsForegroundUser() { 1111 int foregroundUser; 1112 int callingUser = UserHandle.getCallingUserId(); 1113 int callingUid = Binder.getCallingUid(); 1114 long callingIdentity = Binder.clearCallingIdentity(); 1115 int callingAppId = UserHandle.getAppId(callingUid); 1116 boolean valid = false; 1117 try { 1118 foregroundUser = ActivityManager.getCurrentUser(); 1119 valid = (callingUser == foregroundUser) || 1120 callingAppId == Process.NFC_UID; 1121 if (DBG) { 1122 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid 1123 + " callingUser=" + callingUser 1124 + " foregroundUser=" + foregroundUser); 1125 } 1126 } finally { 1127 Binder.restoreCallingIdentity(callingIdentity); 1128 } 1129 return valid; 1130 } 1131 1132 private void bluetoothStateChangeHandler(int prevState, int newState) { 1133 if (prevState != newState) { 1134 //Notify all proxy objects first of adapter state change 1135 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 1136 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 1137 sendBluetoothStateCallback(isUp); 1138 1139 if (isUp) { 1140 // connect to GattService 1141 if (mContext.getPackageManager().hasSystemFeature( 1142 PackageManager.FEATURE_BLUETOOTH_LE)) { 1143 Intent i = new Intent(IBluetoothGatt.class.getName()); 1144 doBind(i, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT); 1145 } 1146 } else { 1147 //If Bluetooth is off, send service down event to proxy objects, and unbind 1148 if (!isUp && canUnbindBluetoothService()) { 1149 sendBluetoothServiceDownCallback(); 1150 unbindAndFinish(); 1151 } 1152 } 1153 } 1154 1155 //Send broadcast message to everyone else 1156 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 1157 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 1158 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 1159 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1160 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 1161 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 1162 BLUETOOTH_PERM); 1163 } 1164 } 1165 1166 /** 1167 * if on is true, wait for state become ON 1168 * if off is true, wait for state become OFF 1169 * if both on and off are false, wait for state not ON 1170 */ 1171 private boolean waitForOnOff(boolean on, boolean off) { 1172 int i = 0; 1173 while (i < 10) { 1174 synchronized(mConnection) { 1175 try { 1176 if (mBluetooth == null) break; 1177 if (on) { 1178 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; 1179 } else if (off) { 1180 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; 1181 } else { 1182 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; 1183 } 1184 } catch (RemoteException e) { 1185 Log.e(TAG, "getState()", e); 1186 break; 1187 } 1188 } 1189 if (on || off) { 1190 SystemClock.sleep(300); 1191 } else { 1192 SystemClock.sleep(50); 1193 } 1194 i++; 1195 } 1196 Log.e(TAG,"waitForOnOff time out"); 1197 return false; 1198 } 1199 1200 private void sendDisableMsg() { 1201 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); 1202 } 1203 1204 private void sendEnableMsg(boolean quietMode) { 1205 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, 1206 quietMode ? 1 : 0, 0)); 1207 } 1208 1209 private boolean canUnbindBluetoothService() { 1210 synchronized(mConnection) { 1211 //Only unbind with mEnable flag not set 1212 //For race condition: disable and enable back-to-back 1213 //Avoid unbind right after enable due to callback from disable 1214 //Only unbind with Bluetooth at OFF state 1215 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message 1216 try { 1217 if (mEnable || (mBluetooth == null)) return false; 1218 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false; 1219 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF); 1220 } catch (RemoteException e) { 1221 Log.e(TAG, "getState()", e); 1222 } 1223 } 1224 return false; 1225 } 1226 1227 private void recoverBluetoothServiceFromError() { 1228 Log.e(TAG,"recoverBluetoothServiceFromError"); 1229 synchronized (mConnection) { 1230 if (mBluetooth != null) { 1231 //Unregister callback object 1232 try { 1233 mBluetooth.unregisterCallback(mBluetoothCallback); 1234 } catch (RemoteException re) { 1235 Log.e(TAG, "Unable to unregister",re); 1236 } 1237 } 1238 } 1239 1240 SystemClock.sleep(500); 1241 1242 // disable 1243 handleDisable(); 1244 1245 waitForOnOff(false, true); 1246 1247 sendBluetoothServiceDownCallback(); 1248 synchronized (mConnection) { 1249 if (mBluetooth != null) { 1250 mBluetooth = null; 1251 //Unbind 1252 mContext.unbindService(mConnection); 1253 } 1254 } 1255 1256 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1257 mState = BluetoothAdapter.STATE_OFF; 1258 1259 mEnable = false; 1260 1261 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) { 1262 // Send a Bluetooth Restart message to reenable bluetooth 1263 Message restartMsg = mHandler.obtainMessage( 1264 MESSAGE_RESTART_BLUETOOTH_SERVICE); 1265 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS); 1266 } else { 1267 // todo: notify user to power down and power up phone to make bluetooth work. 1268 } 1269 } 1270} 1271