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