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