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