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.Manifest; 20 import android.app.ActivityManager; 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.BluetoothProfile; 24 import android.bluetooth.IBluetooth; 25 import android.bluetooth.IBluetoothCallback; 26 import android.bluetooth.IBluetoothGatt; 27 import android.bluetooth.IBluetoothHeadset; 28 import android.bluetooth.IBluetoothManager; 29 import android.bluetooth.IBluetoothManagerCallback; 30 import android.bluetooth.IBluetoothProfileServiceConnection; 31 import android.bluetooth.IBluetoothStateChangeCallback; 32 import android.content.BroadcastReceiver; 33 import android.content.ComponentName; 34 import android.content.ContentResolver; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.content.ServiceConnection; 39 import android.content.pm.PackageManager; 40 import android.content.pm.UserInfo; 41 import android.database.ContentObserver; 42 import android.os.Binder; 43 import android.os.Handler; 44 import android.os.IBinder; 45 import android.os.Looper; 46 import android.os.Message; 47 import android.os.ParcelFileDescriptor; 48 import android.os.Process; 49 import android.os.RemoteCallbackList; 50 import android.os.RemoteException; 51 import android.os.SystemClock; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 import android.provider.Settings; 55 import android.provider.Settings.SettingNotFoundException; 56 import android.util.Log; 57 58 import java.io.FileDescriptor; 59 import java.io.IOException; 60 import java.io.PrintWriter; 61 import java.util.HashMap; 62 import java.util.Map; 63 64 class BluetoothManagerService extends IBluetoothManager.Stub { 65 private static final String TAG = "BluetoothManagerService"; 66 private static final boolean DBG = false; 67 68 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 69 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 70 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 71 private static final String EXTRA_ACTION="action"; 72 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid"; 73 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; 74 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; 75 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind 76 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save 77 //Maximum msec to wait for service restart 78 private static final int SERVICE_RESTART_TIME_MS = 200; 79 //Maximum msec to wait for restart due to error 80 private static final int ERROR_RESTART_TIME_MS = 3000; 81 //Maximum msec to delay MESSAGE_USER_SWITCHED 82 private static final int USER_SWITCHED_TIME_MS = 200; 83 // Delay for the addProxy function in msec 84 private static final int ADD_PROXY_DELAY_MS = 100; 85 86 private static final int MESSAGE_ENABLE = 1; 87 private static final int MESSAGE_DISABLE = 2; 88 private static final int MESSAGE_REGISTER_ADAPTER = 20; 89 private static final int MESSAGE_UNREGISTER_ADAPTER = 21; 90 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; 91 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; 92 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; 93 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; 94 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; 95 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60; 96 private static final int MESSAGE_TIMEOUT_BIND =100; 97 private static final int MESSAGE_TIMEOUT_UNBIND =101; 98 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; 99 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; 100 private static final int MESSAGE_USER_SWITCHED = 300; 101 private static final int MESSAGE_ADD_PROXY_DELAYED = 400; 102 private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; 103 private static final int MAX_SAVE_RETRIES=3; 104 private static final int MAX_ERROR_RESTART_RETRIES=6; 105 106 // Bluetooth persisted setting is off 107 private static final int BLUETOOTH_OFF=0; 108 // Bluetooth persisted setting is on 109 // and Airplane mode won't affect Bluetooth state at start up 110 private static final int BLUETOOTH_ON_BLUETOOTH=1; 111 // Bluetooth persisted setting is on 112 // but Airplane mode will affect Bluetooth state at start up 113 // and Airplane mode will have higher priority. 114 private static final int BLUETOOTH_ON_AIRPLANE=2; 115 116 private static final int SERVICE_IBLUETOOTH = 1; 117 private static final int SERVICE_IBLUETOOTHGATT = 2; 118 119 private static final String[] DEVICE_TYPE_NAMES = new String[] { 120 "???", 121 "BR/EDR", 122 "LE", 123 "DUAL" 124 }; 125 126 private final Context mContext; 127 private static int mBleAppCount = 0; 128 129 // Locks are not provided for mName and mAddress. 130 // They are accessed in handler or broadcast receiver, same thread context. 131 private String mAddress; 132 private String mName; 133 private final ContentResolver mContentResolver; 134 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 135 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; 136 private IBluetooth mBluetooth; 137 private IBluetoothGatt mBluetoothGatt; 138 private boolean mBinding; 139 private boolean mUnbinding; 140 // used inside handler thread 141 private boolean mQuietEnable = false; 142 // configuarion from external IBinder call which is used to 143 // synchronize with broadcast receiver. 144 private boolean mQuietEnableExternal; 145 // configuarion from external IBinder call which is used to 146 // synchronize with broadcast receiver. 147 private boolean mEnableExternal; 148 // used inside handler thread 149 private boolean mEnable; 150 private int mState; 151 private final BluetoothHandler mHandler; 152 private int mErrorRecoveryRetryCounter; 153 private final int mSystemUiUid; 154 155 // Save a ProfileServiceConnections object for each of the bound 156 // bluetooth profile services 157 private final Map <Integer, ProfileServiceConnections> mProfileServices = 158 new HashMap <Integer, ProfileServiceConnections>(); 159 160 private void registerForAirplaneMode(IntentFilter filter) { 161 final ContentResolver resolver = mContext.getContentResolver(); 162 final String airplaneModeRadios = Settings.Global.getString(resolver, 163 Settings.Global.AIRPLANE_MODE_RADIOS); 164 final String toggleableRadios = Settings.Global.getString(resolver, 165 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 166 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true : 167 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH); 168 if (mIsAirplaneSensitive) { 169 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 170 } 171 } 172 173 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { 174 @Override 175 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { 176 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); 177 mHandler.sendMessage(msg); 178 } 179 }; 180 181 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 182 @Override 183 public void onReceive(Context context, Intent intent) { 184 String action = intent.getAction(); 185 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { 186 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); 187 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName); 188 if (newName != null) { 189 storeNameAndAddress(newName, null); 190 } 191 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 192 synchronized(mReceiver) { 193 if (isBluetoothPersistedStateOn()) { 194 if (isAirplaneModeOn()) { 195 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE); 196 } else { 197 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 198 } 199 } 200 201 int st = BluetoothAdapter.STATE_OFF; 202 if (mBluetooth != null) { 203 try { 204 st = mBluetooth.getState(); 205 } catch (RemoteException e) { 206 Log.e(TAG,"Unable to call getState", e); 207 } 208 } 209 Log.d(TAG, "state" + st); 210 211 if (isAirplaneModeOn()) { 212 // Clear registered LE apps to force shut-off 213 synchronized (this) { 214 mBleAppCount = 0; 215 mBleApps.clear(); 216 } 217 if (st == BluetoothAdapter.STATE_BLE_ON) { 218 //if state is BLE_ON make sure you trigger disableBLE part 219 try { 220 if (mBluetooth != null) { 221 mBluetooth.onBrEdrDown(); 222 mEnableExternal = false; 223 } 224 } catch(RemoteException e) { 225 Log.e(TAG,"Unable to call onBrEdrDown", e); 226 } 227 } else if (st == BluetoothAdapter.STATE_ON){ 228 // disable without persisting the setting 229 Log.d(TAG, "Calling disable"); 230 sendDisableMsg(); 231 } 232 } else if (mEnableExternal) { 233 // enable without persisting the setting 234 Log.d(TAG, "Calling enable"); 235 sendEnableMsg(mQuietEnableExternal); 236 } 237 } 238 } 239 } 240 }; 241 242 BluetoothManagerService(Context context) { 243 mHandler = new BluetoothHandler(IoThread.get().getLooper()); 244 245 mContext = context; 246 mBluetooth = null; 247 mBluetoothGatt = null; 248 mBinding = false; 249 mUnbinding = false; 250 mEnable = false; 251 mState = BluetoothAdapter.STATE_OFF; 252 mQuietEnableExternal = false; 253 mEnableExternal = false; 254 mAddress = null; 255 mName = null; 256 mErrorRecoveryRetryCounter = 0; 257 mContentResolver = context.getContentResolver(); 258 // Observe BLE scan only mode settings change. 259 registerForBleScanModeChange(); 260 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); 261 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); 262 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 263 registerForAirplaneMode(filter); 264 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 265 mContext.registerReceiver(mReceiver, filter); 266 loadStoredNameAndAddress(); 267 if (isBluetoothPersistedStateOn()) { 268 mEnableExternal = true; 269 } 270 271 int sysUiUid = -1; 272 try { 273 sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui", 274 UserHandle.USER_OWNER); 275 } catch (PackageManager.NameNotFoundException e) { 276 Log.wtf(TAG, "Unable to resolve SystemUI's UID.", e); 277 } 278 mSystemUiUid = sysUiUid; 279 } 280 281 /** 282 * Returns true if airplane mode is currently on 283 */ 284 private final boolean isAirplaneModeOn() { 285 return Settings.Global.getInt(mContext.getContentResolver(), 286 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 287 } 288 289 /** 290 * Returns true if the Bluetooth saved state is "on" 291 */ 292 private final boolean isBluetoothPersistedStateOn() { 293 return Settings.Global.getInt(mContentResolver, 294 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF; 295 } 296 297 /** 298 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH 299 */ 300 private final boolean isBluetoothPersistedStateOnBluetooth() { 301 return Settings.Global.getInt(mContentResolver, 302 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH; 303 } 304 305 /** 306 * Save the Bluetooth on/off state 307 * 308 */ 309 private void persistBluetoothSetting(int value) { 310 Settings.Global.putInt(mContext.getContentResolver(), 311 Settings.Global.BLUETOOTH_ON, 312 value); 313 } 314 315 /** 316 * Returns true if the Bluetooth Adapter's name and address is 317 * locally cached 318 * @return 319 */ 320 private boolean isNameAndAddressSet() { 321 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; 322 } 323 324 /** 325 * Retrieve the Bluetooth Adapter's name and address and save it in 326 * in the local cache 327 */ 328 private void loadStoredNameAndAddress() { 329 if (DBG) Log.d(TAG, "Loading stored name and address"); 330 if (mContext.getResources().getBoolean 331 (com.android.internal.R.bool.config_bluetooth_address_validation) && 332 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) { 333 // if the valid flag is not set, don't load the address and name 334 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored"); 335 return; 336 } 337 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); 338 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); 339 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); 340 } 341 342 /** 343 * Save the Bluetooth name and address in the persistent store. 344 * Only non-null values will be saved. 345 * @param name 346 * @param address 347 */ 348 private void storeNameAndAddress(String name, String address) { 349 if (name != null) { 350 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); 351 mName = name; 352 if (DBG) Log.d(TAG,"Stored Bluetooth name: " + 353 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); 354 } 355 356 if (address != null) { 357 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); 358 mAddress=address; 359 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " + 360 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); 361 } 362 363 if ((name != null) && (address != null)) { 364 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1); 365 } 366 } 367 368 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ 369 if (callback == null) { 370 Log.w(TAG, "Callback is null in registerAdapter"); 371 return null; 372 } 373 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 374 msg.obj = callback; 375 mHandler.sendMessage(msg); 376 synchronized(mConnection) { 377 return mBluetooth; 378 } 379 } 380 381 public void unregisterAdapter(IBluetoothManagerCallback callback) { 382 if (callback == null) { 383 Log.w(TAG, "Callback is null in unregisterAdapter"); 384 return; 385 } 386 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 387 "Need BLUETOOTH permission"); 388 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 389 msg.obj = callback; 390 mHandler.sendMessage(msg); 391 } 392 393 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 394 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 395 "Need BLUETOOTH permission"); 396 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 397 msg.obj = callback; 398 mHandler.sendMessage(msg); 399 } 400 401 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 402 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 403 "Need BLUETOOTH permission"); 404 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 405 msg.obj = callback; 406 mHandler.sendMessage(msg); 407 } 408 409 public boolean isEnabled() { 410 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 411 (!checkIfCallerIsForegroundUser())) { 412 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user"); 413 return false; 414 } 415 416 synchronized(mConnection) { 417 try { 418 return (mBluetooth != null && mBluetooth.isEnabled()); 419 } catch (RemoteException e) { 420 Log.e(TAG, "isEnabled()", e); 421 } 422 } 423 return false; 424 } 425 426 class ClientDeathRecipient implements IBinder.DeathRecipient { 427 public void binderDied() { 428 if (DBG) Log.d(TAG, "Binder is dead - unregister Ble App"); 429 if (mBleAppCount > 0) --mBleAppCount; 430 431 if (mBleAppCount == 0) { 432 if (DBG) Log.d(TAG, "Disabling LE only mode after application crash"); 433 try { 434 if (mBluetooth != null) { 435 mBluetooth.onBrEdrDown(); 436 } 437 } catch(RemoteException e) { 438 Log.e(TAG,"Unable to call onBrEdrDown", e); 439 } 440 } 441 } 442 } 443 444 /** Internal death rec list */ 445 Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>(); 446 447 @Override 448 public boolean isBleScanAlwaysAvailable() { 449 try { 450 return (Settings.Global.getInt(mContentResolver, 451 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0; 452 } catch (SettingNotFoundException e) { 453 } 454 return false; 455 } 456 457 // Monitor change of BLE scan only mode settings. 458 private void registerForBleScanModeChange() { 459 ContentObserver contentObserver = new ContentObserver(null) { 460 @Override 461 public void onChange(boolean selfChange) { 462 if (!isBleScanAlwaysAvailable()) { 463 disableBleScanMode(); 464 clearBleApps(); 465 try { 466 if (mBluetooth != null) mBluetooth.onBrEdrDown(); 467 } catch (RemoteException e) { 468 Log.e(TAG, "error when disabling bluetooth", e); 469 } 470 } 471 } 472 }; 473 474 mContentResolver.registerContentObserver( 475 Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), 476 false, contentObserver); 477 } 478 479 // Disable ble scan only mode. 480 private void disableBleScanMode() { 481 try { 482 if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) { 483 if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable"); 484 mEnable = false; 485 } 486 } catch (RemoteException e) { 487 Log.e(TAG, "getState()", e); 488 } 489 } 490 491 public int updateBleAppCount(IBinder token, boolean enable) { 492 if (enable) { 493 ClientDeathRecipient r = mBleApps.get(token); 494 if (r == null) { 495 ClientDeathRecipient deathRec = new ClientDeathRecipient(); 496 try { 497 token.linkToDeath(deathRec, 0); 498 } catch (RemoteException ex) { 499 throw new IllegalArgumentException("Wake lock is already dead."); 500 } 501 mBleApps.put(token, deathRec); 502 synchronized (this) { 503 ++mBleAppCount; 504 } 505 if (DBG) Log.d(TAG, "Registered for death Notification"); 506 } 507 508 } else { 509 ClientDeathRecipient r = mBleApps.get(token); 510 if (r != null) { 511 // Unregister death recipient as the app goes away. 512 token.unlinkToDeath(r, 0); 513 mBleApps.remove(token); 514 synchronized (this) { 515 if (mBleAppCount > 0) --mBleAppCount; 516 } 517 if (DBG) Log.d(TAG, "Unregistered for death Notification"); 518 } 519 } 520 if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount); 521 if (mBleAppCount == 0 && mEnable) { 522 disableBleScanMode(); 523 } 524 return mBleAppCount; 525 } 526 527 // Clear all apps using BLE scan only mode. 528 private void clearBleApps() { 529 synchronized (this) { 530 mBleApps.clear(); 531 mBleAppCount = 0; 532 } 533 } 534 535 /** @hide*/ 536 public boolean isBleAppPresent() { 537 if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount); 538 return (mBleAppCount > 0); 539 } 540 541 /** 542 * Action taken when GattService is turned off 543 */ 544 private void onBluetoothGattServiceUp() { 545 if (DBG) Log.d(TAG,"BluetoothGatt Service is Up"); 546 try{ 547 if (isBleAppPresent() == false && mBluetooth != null 548 && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) { 549 mBluetooth.onLeServiceUp(); 550 551 // waive WRITE_SECURE_SETTINGS permission check 552 long callingIdentity = Binder.clearCallingIdentity(); 553 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH); 554 Binder.restoreCallingIdentity(callingIdentity); 555 } 556 } catch(RemoteException e) { 557 Log.e(TAG,"Unable to call onServiceUp", e); 558 } 559 } 560 561 /** 562 * Inform BluetoothAdapter instances that BREDR part is down 563 * and turn off all service and stack if no LE app needs it 564 */ 565 private void sendBrEdrDownCallback() { 566 if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks"); 567 568 if(mBluetooth == null) { 569 Log.w(TAG, "Bluetooth handle is null"); 570 return; 571 } 572 573 if (isBleAppPresent() == false) { 574 try { 575 mBluetooth.onBrEdrDown(); 576 } catch(RemoteException e) { 577 Log.e(TAG, "Call to onBrEdrDown() failed.", e); 578 } 579 } else { 580 // Need to stay at BLE ON. Disconnect all Gatt connections 581 try{ 582 mBluetoothGatt.unregAll(); 583 } catch(RemoteException e) { 584 Log.e(TAG, "Unable to disconnect all apps.", e); 585 } 586 } 587 } 588 589 /** @hide*/ 590 public void getNameAndAddress() { 591 if (DBG) { 592 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 593 " mBinding = " + mBinding); 594 } 595 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 596 mHandler.sendMessage(msg); 597 } 598 public boolean enableNoAutoConnect() 599 { 600 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 601 "Need BLUETOOTH ADMIN permission"); 602 603 if (DBG) { 604 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 605 " mBinding = " + mBinding); 606 } 607 int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); 608 609 if (callingAppId != Process.NFC_UID) { 610 throw new SecurityException("no permission to enable Bluetooth quietly"); 611 } 612 613 synchronized(mReceiver) { 614 mQuietEnableExternal = true; 615 mEnableExternal = true; 616 sendEnableMsg(true); 617 } 618 return true; 619 620 } 621 public boolean enable() { 622 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 623 (!checkIfCallerIsForegroundUser())) { 624 Log.w(TAG,"enable(): not allowed for non-active and non system user"); 625 return false; 626 } 627 628 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 629 "Need BLUETOOTH ADMIN permission"); 630 if (DBG) { 631 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 632 " mBinding = " + mBinding); 633 } 634 635 synchronized(mReceiver) { 636 mQuietEnableExternal = false; 637 mEnableExternal = true; 638 // waive WRITE_SECURE_SETTINGS permission check 639 sendEnableMsg(false); 640 } 641 if (DBG) Log.d(TAG, "enable returning"); 642 return true; 643 } 644 645 public boolean disable(boolean persist) { 646 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 647 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 648 649 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 650 (!checkIfCallerIsForegroundUser())) { 651 Log.w(TAG,"disable(): not allowed for non-active and non system user"); 652 return false; 653 } 654 655 if (DBG) { 656 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 657 " mBinding = " + mBinding); 658 } 659 660 synchronized(mReceiver) { 661 if (persist) { 662 // waive WRITE_SECURE_SETTINGS permission check 663 long callingIdentity = Binder.clearCallingIdentity(); 664 persistBluetoothSetting(BLUETOOTH_OFF); 665 Binder.restoreCallingIdentity(callingIdentity); 666 } 667 mEnableExternal = false; 668 sendDisableMsg(); 669 } 670 return true; 671 } 672 673 public void unbindAndFinish() { 674 if (DBG) { 675 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 676 " mBinding = " + mBinding); 677 } 678 679 synchronized (mConnection) { 680 if (mUnbinding) return; 681 mUnbinding = true; 682 if (mBluetooth != null) { 683 if (!mConnection.isGetNameAddressOnly()) { 684 //Unregister callback object 685 try { 686 mBluetooth.unregisterCallback(mBluetoothCallback); 687 } catch (RemoteException re) { 688 Log.e(TAG, "Unable to unregister BluetoothCallback",re); 689 } 690 } 691 if (DBG) Log.d(TAG, "Sending unbind request."); 692 mBluetooth = null; 693 //Unbind 694 mContext.unbindService(mConnection); 695 mUnbinding = false; 696 mBinding = false; 697 } else { 698 mUnbinding=false; 699 } 700 mBluetoothGatt = null; 701 } 702 } 703 704 public IBluetoothGatt getBluetoothGatt() { 705 // sync protection 706 return mBluetoothGatt; 707 } 708 709 @Override 710 public boolean bindBluetoothProfileService(int bluetoothProfile, 711 IBluetoothProfileServiceConnection proxy) { 712 if (!mEnable) { 713 if (DBG) { 714 Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile + 715 ", while Bluetooth was disabled"); 716 } 717 return false; 718 } 719 synchronized (mProfileServices) { 720 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); 721 if (psc == null) { 722 if (DBG) { 723 Log.d(TAG, "Creating new ProfileServiceConnections object for" 724 + " profile: " + bluetoothProfile); 725 } 726 727 if (bluetoothProfile != BluetoothProfile.HEADSET) return false; 728 729 Intent intent = new Intent(IBluetoothHeadset.class.getName()); 730 psc = new ProfileServiceConnections(intent); 731 if (!psc.bindService()) return false; 732 733 mProfileServices.put(new Integer(bluetoothProfile), psc); 734 } 735 } 736 737 // Introducing a delay to give the client app time to prepare 738 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); 739 addProxyMsg.arg1 = bluetoothProfile; 740 addProxyMsg.obj = proxy; 741 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); 742 return true; 743 } 744 745 @Override 746 public void unbindBluetoothProfileService(int bluetoothProfile, 747 IBluetoothProfileServiceConnection proxy) { 748 synchronized (mProfileServices) { 749 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); 750 if (psc == null) { 751 return; 752 } 753 psc.removeProxy(proxy); 754 } 755 } 756 757 private void unbindAllBluetoothProfileServices() { 758 synchronized (mProfileServices) { 759 for (Integer i : mProfileServices.keySet()) { 760 ProfileServiceConnections psc = mProfileServices.get(i); 761 try { 762 mContext.unbindService(psc); 763 } catch (IllegalArgumentException e) { 764 Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); 765 } 766 psc.removeAllProxies(); 767 } 768 mProfileServices.clear(); 769 } 770 } 771 772 /** 773 * Send enable message and set adapter name and address. Called when the boot phase becomes 774 * PHASE_SYSTEM_SERVICES_READY. 775 */ 776 public void handleOnBootPhase() { 777 if (DBG) Log.d(TAG, "Bluetooth boot completed"); 778 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) { 779 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); 780 sendEnableMsg(mQuietEnableExternal); 781 } 782 if (!isNameAndAddressSet()) { 783 // Sync the Bluetooth name and address from the Bluetooth Adapter 784 if (DBG) Log.d(TAG, "Retrieving Bluetooth Adapter name and address..."); 785 getNameAndAddress(); 786 } 787 } 788 789 /** 790 * Called when switching to a different foreground user. 791 */ 792 public void handleOnSwitchUser(int userHandle) { 793 if (DBG) Log.d(TAG, "Bluetooth user switched"); 794 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0)); 795 } 796 797 /** 798 * This class manages the clients connected to a given ProfileService 799 * and maintains the connection with that service. 800 */ 801 final private class ProfileServiceConnections implements ServiceConnection, 802 IBinder.DeathRecipient { 803 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = 804 new RemoteCallbackList <IBluetoothProfileServiceConnection>(); 805 IBinder mService; 806 ComponentName mClassName; 807 Intent mIntent; 808 boolean mInvokingProxyCallbacks = false; 809 810 ProfileServiceConnections(Intent intent) { 811 mService = null; 812 mClassName = null; 813 mIntent = intent; 814 } 815 816 private boolean bindService() { 817 if (mIntent != null && mService == null && 818 doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { 819 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 820 msg.obj = this; 821 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); 822 return true; 823 } 824 Log.w(TAG, "Unable to bind with intent: " + mIntent); 825 return false; 826 } 827 828 private void addProxy(IBluetoothProfileServiceConnection proxy) { 829 mProxies.register(proxy); 830 if (mService != null) { 831 try{ 832 proxy.onServiceConnected(mClassName, mService); 833 } catch (RemoteException e) { 834 Log.e(TAG, "Unable to connect to proxy", e); 835 } 836 } else { 837 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { 838 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 839 msg.obj = this; 840 mHandler.sendMessage(msg); 841 } 842 } 843 } 844 845 private void removeProxy(IBluetoothProfileServiceConnection proxy) { 846 if (proxy != null) { 847 if (mProxies.unregister(proxy)) { 848 try { 849 proxy.onServiceDisconnected(mClassName); 850 } catch (RemoteException e) { 851 Log.e(TAG, "Unable to disconnect proxy", e); 852 } 853 } 854 } else { 855 Log.w(TAG, "Trying to remove a null proxy"); 856 } 857 } 858 859 private void removeAllProxies() { 860 onServiceDisconnected(mClassName); 861 mProxies.kill(); 862 } 863 864 @Override 865 public void onServiceConnected(ComponentName className, IBinder service) { 866 // remove timeout message 867 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); 868 mService = service; 869 mClassName = className; 870 try { 871 mService.linkToDeath(this, 0); 872 } catch (RemoteException e) { 873 Log.e(TAG, "Unable to linkToDeath", e); 874 } 875 876 if (mInvokingProxyCallbacks) { 877 Log.e(TAG, "Proxy callbacks already in progress."); 878 return; 879 } 880 mInvokingProxyCallbacks = true; 881 882 final int n = mProxies.beginBroadcast(); 883 try { 884 for (int i = 0; i < n; i++) { 885 try { 886 mProxies.getBroadcastItem(i).onServiceConnected(className, service); 887 } catch (RemoteException e) { 888 Log.e(TAG, "Unable to connect to proxy", e); 889 } 890 } 891 } finally { 892 mProxies.finishBroadcast(); 893 mInvokingProxyCallbacks = false; 894 } 895 } 896 897 @Override 898 public void onServiceDisconnected(ComponentName className) { 899 if (mService == null) return; 900 mService.unlinkToDeath(this, 0); 901 mService = null; 902 mClassName = null; 903 904 if (mInvokingProxyCallbacks) { 905 Log.e(TAG, "Proxy callbacks already in progress."); 906 return; 907 } 908 mInvokingProxyCallbacks = true; 909 910 final int n = mProxies.beginBroadcast(); 911 try { 912 for (int i = 0; i < n; i++) { 913 try { 914 mProxies.getBroadcastItem(i).onServiceDisconnected(className); 915 } catch (RemoteException e) { 916 Log.e(TAG, "Unable to disconnect from proxy", e); 917 } 918 } 919 } finally { 920 mProxies.finishBroadcast(); 921 mInvokingProxyCallbacks = false; 922 } 923 } 924 925 @Override 926 public void binderDied() { 927 if (DBG) { 928 Log.w(TAG, "Profile service for profile: " + mClassName 929 + " died."); 930 } 931 onServiceDisconnected(mClassName); 932 // Trigger rebind 933 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); 934 msg.obj = this; 935 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); 936 } 937 } 938 939 private void sendBluetoothStateCallback(boolean isUp) { 940 try { 941 int n = mStateChangeCallbacks.beginBroadcast(); 942 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 943 for (int i=0; i <n;i++) { 944 try { 945 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 946 } catch (RemoteException e) { 947 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 948 } 949 } 950 } finally { 951 mStateChangeCallbacks.finishBroadcast(); 952 } 953 } 954 955 /** 956 * Inform BluetoothAdapter instances that Adapter service is up 957 */ 958 private void sendBluetoothServiceUpCallback() { 959 if (!mConnection.isGetNameAddressOnly()) { 960 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); 961 try { 962 int n = mCallbacks.beginBroadcast(); 963 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 964 for (int i=0; i <n;i++) { 965 try { 966 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 967 } catch (RemoteException e) { 968 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 969 } 970 } 971 } finally { 972 mCallbacks.finishBroadcast(); 973 } 974 } 975 } 976 /** 977 * Inform BluetoothAdapter instances that Adapter service is down 978 */ 979 private void sendBluetoothServiceDownCallback() { 980 if (!mConnection.isGetNameAddressOnly()) { 981 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 982 try { 983 int n = mCallbacks.beginBroadcast(); 984 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 985 for (int i=0; i <n;i++) { 986 try { 987 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 988 } catch (RemoteException e) { 989 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 990 } 991 } 992 } finally { 993 mCallbacks.finishBroadcast(); 994 } 995 } 996 } 997 998 public String getAddress() { 999 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1000 "Need BLUETOOTH permission"); 1001 1002 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 1003 (!checkIfCallerIsForegroundUser())) { 1004 Log.w(TAG,"getAddress(): not allowed for non-active and non system user"); 1005 return null; 1006 } 1007 1008 if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS) 1009 != PackageManager.PERMISSION_GRANTED) { 1010 return BluetoothAdapter.DEFAULT_MAC_ADDRESS; 1011 } 1012 1013 synchronized(mConnection) { 1014 if (mBluetooth != null) { 1015 try { 1016 return mBluetooth.getAddress(); 1017 } catch (RemoteException e) { 1018 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 1019 } 1020 } 1021 } 1022 // mAddress is accessed from outside. 1023 // It is alright without a lock. Here, bluetooth is off, no other thread is 1024 // changing mAddress 1025 return mAddress; 1026 } 1027 1028 public String getName() { 1029 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 1030 "Need BLUETOOTH permission"); 1031 1032 if ((Binder.getCallingUid() != Process.SYSTEM_UID) && 1033 (!checkIfCallerIsForegroundUser())) { 1034 Log.w(TAG,"getName(): not allowed for non-active and non system user"); 1035 return null; 1036 } 1037 1038 synchronized(mConnection) { 1039 if (mBluetooth != null) { 1040 try { 1041 return mBluetooth.getName(); 1042 } catch (RemoteException e) { 1043 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 1044 } 1045 } 1046 } 1047 // mName is accessed from outside. 1048 // It alright without a lock. Here, bluetooth is off, no other thread is 1049 // changing mName 1050 return mName; 1051 } 1052 1053 private class BluetoothServiceConnection implements ServiceConnection { 1054 1055 private boolean mGetNameAddressOnly; 1056 1057 public void setGetNameAddressOnly(boolean getOnly) { 1058 mGetNameAddressOnly = getOnly; 1059 } 1060 1061 public boolean isGetNameAddressOnly() { 1062 return mGetNameAddressOnly; 1063 } 1064 1065 public void onServiceConnected(ComponentName className, IBinder service) { 1066 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName()); 1067 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 1068 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) { 1069 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 1070 msg.arg1 = SERVICE_IBLUETOOTH; 1071 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) { 1072 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 1073 msg.arg1 = SERVICE_IBLUETOOTHGATT; 1074 } else { 1075 Log.e(TAG, "Unknown service connected: " + className.getClassName()); 1076 return; 1077 } 1078 msg.obj = service; 1079 mHandler.sendMessage(msg); 1080 } 1081 1082 public void onServiceDisconnected(ComponentName className) { 1083 // Called if we unexpected disconnected. 1084 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " + 1085 className.getClassName()); 1086 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 1087 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) { 1088 msg.arg1 = SERVICE_IBLUETOOTH; 1089 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) { 1090 msg.arg1 = SERVICE_IBLUETOOTHGATT; 1091 } else { 1092 Log.e(TAG, "Unknown service disconnected: " + className.getClassName()); 1093 return; 1094 } 1095 mHandler.sendMessage(msg); 1096 } 1097 } 1098 1099 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 1100 1101 private class BluetoothHandler extends Handler { 1102 public BluetoothHandler(Looper looper) { 1103 super(looper); 1104 } 1105 1106 @Override 1107 public void handleMessage(Message msg) { 1108 if (DBG) Log.d (TAG, "Message: " + msg.what); 1109 switch (msg.what) { 1110 case MESSAGE_GET_NAME_AND_ADDRESS: { 1111 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 1112 synchronized(mConnection) { 1113 //Start bind request 1114 if ((mBluetooth == null) && (!mBinding)) { 1115 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 1116 mConnection.setGetNameAddressOnly(true); 1117 //Start bind timeout and bind 1118 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 1119 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 1120 Intent i = new Intent(IBluetooth.class.getName()); 1121 if (!doBind(i, mConnection, 1122 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 1123 UserHandle.CURRENT)) { 1124 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1125 } else { 1126 mBinding = true; 1127 } 1128 } 1129 else { 1130 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 1131 saveMsg.arg1 = 0; 1132 if (mBluetooth != null) { 1133 mHandler.sendMessage(saveMsg); 1134 } else { 1135 // if enable is also called to bind the service 1136 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED 1137 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); 1138 } 1139 } 1140 } 1141 break; 1142 } 1143 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 1144 boolean unbind = false; 1145 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 1146 synchronized(mConnection) { 1147 if (!mEnable && mBluetooth != null && !mConnection.isGetNameAddressOnly()) { 1148 try { 1149 mBluetooth.enable(); 1150 } catch (RemoteException e) { 1151 Log.e(TAG,"Unable to call enable()",e); 1152 } 1153 } 1154 } 1155 if (mBluetooth != null && !mConnection.isGetNameAddressOnly()) waitForOnOff(true, false); 1156 synchronized(mConnection) { 1157 if (mBluetooth != null) { 1158 String name = null; 1159 String address = null; 1160 try { 1161 name = mBluetooth.getName(); 1162 address = mBluetooth.getAddress(); 1163 } catch (RemoteException re) { 1164 Log.e(TAG,"",re); 1165 } 1166 1167 if (name != null && address != null) { 1168 storeNameAndAddress(name,address); 1169 if (mConnection.isGetNameAddressOnly()) { 1170 unbind = true; 1171 } 1172 } else { 1173 if (msg.arg1 < MAX_SAVE_RETRIES) { 1174 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 1175 retryMsg.arg1= 1+msg.arg1; 1176 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 1177 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 1178 } else { 1179 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 1180 if (mConnection.isGetNameAddressOnly()) { 1181 unbind = true; 1182 } 1183 } 1184 } 1185 if (!mEnable && !mConnection.isGetNameAddressOnly()) { 1186 try { 1187 mBluetooth.disable(); 1188 } catch (RemoteException e) { 1189 Log.e(TAG,"Unable to call disable()",e); 1190 } 1191 } 1192 } else { 1193 // rebind service by Request GET NAME AND ADDRESS 1194 // if service is unbinded by disable or 1195 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received 1196 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 1197 mHandler.sendMessage(getMsg); 1198 } 1199 } 1200 if (!mEnable && mBluetooth != null && !mConnection.isGetNameAddressOnly()) { 1201 waitForOnOff(false, true); 1202 } 1203 if (unbind) { 1204 unbindAndFinish(); 1205 } 1206 break; 1207 } 1208 case MESSAGE_ENABLE: 1209 if (DBG) { 1210 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 1211 } 1212 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 1213 mEnable = true; 1214 handleEnable(msg.arg1 == 1); 1215 break; 1216 1217 case MESSAGE_DISABLE: 1218 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 1219 if (mEnable && mBluetooth != null) { 1220 waitForOnOff(true, false); 1221 mEnable = false; 1222 handleDisable(); 1223 waitForOnOff(false, false); 1224 } else { 1225 mEnable = false; 1226 handleDisable(); 1227 } 1228 break; 1229 1230 case MESSAGE_REGISTER_ADAPTER: 1231 { 1232 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 1233 boolean added = mCallbacks.register(callback); 1234 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 1235 } 1236 break; 1237 case MESSAGE_UNREGISTER_ADAPTER: 1238 { 1239 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 1240 boolean removed = mCallbacks.unregister(callback); 1241 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 1242 break; 1243 } 1244 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 1245 { 1246 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 1247 if (callback != null) { 1248 mStateChangeCallbacks.register(callback); 1249 } 1250 break; 1251 } 1252 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 1253 { 1254 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 1255 if (callback != null) { 1256 mStateChangeCallbacks.unregister(callback); 1257 } 1258 break; 1259 } 1260 case MESSAGE_ADD_PROXY_DELAYED: 1261 { 1262 ProfileServiceConnections psc = mProfileServices.get( 1263 new Integer(msg.arg1)); 1264 if (psc == null) { 1265 break; 1266 } 1267 IBluetoothProfileServiceConnection proxy = 1268 (IBluetoothProfileServiceConnection) msg.obj; 1269 psc.addProxy(proxy); 1270 break; 1271 } 1272 case MESSAGE_BIND_PROFILE_SERVICE: 1273 { 1274 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; 1275 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); 1276 if (psc == null) { 1277 break; 1278 } 1279 psc.bindService(); 1280 break; 1281 } 1282 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 1283 { 1284 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); 1285 1286 IBinder service = (IBinder) msg.obj; 1287 synchronized(mConnection) { 1288 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 1289 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service); 1290 onBluetoothGattServiceUp(); 1291 break; 1292 } // else must be SERVICE_IBLUETOOTH 1293 1294 //Remove timeout 1295 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1296 1297 mBinding = false; 1298 mBluetooth = IBluetooth.Stub.asInterface(service); 1299 1300 try { 1301 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver, 1302 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1); 1303 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) { 1304 Log.e(TAG,"IBluetooth.configHciSnoopLog return false"); 1305 } 1306 } catch (RemoteException e) { 1307 Log.e(TAG,"Unable to call configHciSnoopLog", e); 1308 } 1309 1310 if (mConnection.isGetNameAddressOnly()) { 1311 //Request GET NAME AND ADDRESS 1312 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 1313 mHandler.sendMessage(getMsg); 1314 if (!mEnable) return; 1315 } 1316 1317 mConnection.setGetNameAddressOnly(false); 1318 //Register callback object 1319 try { 1320 mBluetooth.registerCallback(mBluetoothCallback); 1321 } catch (RemoteException re) { 1322 Log.e(TAG, "Unable to register BluetoothCallback",re); 1323 } 1324 //Inform BluetoothAdapter instances that service is up 1325 sendBluetoothServiceUpCallback(); 1326 1327 //Do enable request 1328 try { 1329 if (mQuietEnable == false) { 1330 if(!mBluetooth.enable()) { 1331 Log.e(TAG,"IBluetooth.enable() returned false"); 1332 } 1333 } 1334 else 1335 { 1336 if(!mBluetooth.enableNoAutoConnect()) { 1337 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 1338 } 1339 } 1340 } catch (RemoteException e) { 1341 Log.e(TAG,"Unable to call enable()",e); 1342 } 1343 } 1344 1345 if (!mEnable) { 1346 waitForOnOff(true, false); 1347 handleDisable(); 1348 waitForOnOff(false, false); 1349 } 1350 break; 1351 } 1352 case MESSAGE_TIMEOUT_BIND: { 1353 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 1354 synchronized(mConnection) { 1355 mBinding = false; 1356 } 1357 break; 1358 } 1359 case MESSAGE_BLUETOOTH_STATE_CHANGE: 1360 { 1361 int prevState = msg.arg1; 1362 int newState = msg.arg2; 1363 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 1364 mState = newState; 1365 bluetoothStateChangeHandler(prevState, newState); 1366 // handle error state transition case from TURNING_ON to OFF 1367 // unbind and rebind bluetooth service and enable bluetooth 1368 if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && 1369 (newState == BluetoothAdapter.STATE_OFF) && 1370 (mBluetooth != null) && mEnable) { 1371 recoverBluetoothServiceFromError(); 1372 } 1373 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && 1374 (newState == BluetoothAdapter.STATE_BLE_ON) && 1375 (mBluetooth != null) && mEnable) { 1376 recoverBluetoothServiceFromError(); 1377 } 1378 if (newState == BluetoothAdapter.STATE_ON || 1379 newState == BluetoothAdapter.STATE_BLE_ON) { 1380 // bluetooth is working, reset the counter 1381 if (mErrorRecoveryRetryCounter != 0) { 1382 Log.w(TAG, "bluetooth is recovered from error"); 1383 mErrorRecoveryRetryCounter = 0; 1384 } 1385 } 1386 break; 1387 } 1388 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 1389 { 1390 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1); 1391 synchronized(mConnection) { 1392 if (msg.arg1 == SERVICE_IBLUETOOTH) { 1393 // if service is unbinded already, do nothing and return 1394 if (mBluetooth == null) break; 1395 mBluetooth = null; 1396 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) { 1397 mBluetoothGatt = null; 1398 break; 1399 } else { 1400 Log.e(TAG, "Bad msg.arg1: " + msg.arg1); 1401 break; 1402 } 1403 } 1404 1405 if (mEnable) { 1406 mEnable = false; 1407 // Send a Bluetooth Restart message 1408 Message restartMsg = mHandler.obtainMessage( 1409 MESSAGE_RESTART_BLUETOOTH_SERVICE); 1410 mHandler.sendMessageDelayed(restartMsg, 1411 SERVICE_RESTART_TIME_MS); 1412 } 1413 1414 if (!mConnection.isGetNameAddressOnly()) { 1415 sendBluetoothServiceDownCallback(); 1416 1417 // Send BT state broadcast to update 1418 // the BT icon correctly 1419 if ((mState == BluetoothAdapter.STATE_TURNING_ON) || 1420 (mState == BluetoothAdapter.STATE_ON)) { 1421 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 1422 BluetoothAdapter.STATE_TURNING_OFF); 1423 mState = BluetoothAdapter.STATE_TURNING_OFF; 1424 } 1425 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 1426 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 1427 BluetoothAdapter.STATE_OFF); 1428 } 1429 1430 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1431 mState = BluetoothAdapter.STATE_OFF; 1432 } 1433 break; 1434 } 1435 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 1436 { 1437 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 1438 +" Restart IBluetooth service"); 1439 /* Enable without persisting the setting as 1440 it doesnt change when IBluetooth 1441 service restarts */ 1442 mEnable = true; 1443 handleEnable(mQuietEnable); 1444 break; 1445 } 1446 1447 case MESSAGE_TIMEOUT_UNBIND: 1448 { 1449 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 1450 synchronized(mConnection) { 1451 mUnbinding = false; 1452 } 1453 break; 1454 } 1455 1456 case MESSAGE_USER_SWITCHED: 1457 { 1458 if (DBG) { 1459 Log.d(TAG, "MESSAGE_USER_SWITCHED"); 1460 } 1461 mHandler.removeMessages(MESSAGE_USER_SWITCHED); 1462 /* disable and enable BT when detect a user switch */ 1463 if (mEnable && mBluetooth != null) { 1464 synchronized (mConnection) { 1465 if (mBluetooth != null) { 1466 //Unregister callback object 1467 try { 1468 mBluetooth.unregisterCallback(mBluetoothCallback); 1469 } catch (RemoteException re) { 1470 Log.e(TAG, "Unable to unregister",re); 1471 } 1472 } 1473 } 1474 1475 if (mState == BluetoothAdapter.STATE_TURNING_OFF) { 1476 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE 1477 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF); 1478 mState = BluetoothAdapter.STATE_OFF; 1479 } 1480 if (mState == BluetoothAdapter.STATE_OFF) { 1481 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON); 1482 mState = BluetoothAdapter.STATE_TURNING_ON; 1483 } 1484 1485 waitForOnOff(true, false); 1486 1487 if (mState == BluetoothAdapter.STATE_TURNING_ON) { 1488 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); 1489 } 1490 1491 unbindAllBluetoothProfileServices(); 1492 // disable 1493 handleDisable(); 1494 // Pbap service need receive STATE_TURNING_OFF intent to close 1495 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 1496 BluetoothAdapter.STATE_TURNING_OFF); 1497 1498 waitForOnOff(false, true); 1499 1500 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, 1501 BluetoothAdapter.STATE_OFF); 1502 sendBluetoothServiceDownCallback(); 1503 synchronized (mConnection) { 1504 if (mBluetooth != null) { 1505 mBluetooth = null; 1506 //Unbind 1507 mContext.unbindService(mConnection); 1508 } 1509 mBluetoothGatt = null; 1510 } 1511 SystemClock.sleep(100); 1512 1513 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1514 mState = BluetoothAdapter.STATE_OFF; 1515 // enable 1516 handleEnable(mQuietEnable); 1517 } else if (mBinding || mBluetooth != null) { 1518 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); 1519 userMsg.arg2 = 1 + msg.arg2; 1520 // if user is switched when service is being binding 1521 // delay sending MESSAGE_USER_SWITCHED 1522 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); 1523 if (DBG) { 1524 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); 1525 } 1526 } 1527 break; 1528 } 1529 } 1530 } 1531 } 1532 1533 private void handleEnable(boolean quietMode) { 1534 mQuietEnable = quietMode; 1535 1536 synchronized(mConnection) { 1537 if ((mBluetooth == null) && (!mBinding)) { 1538 //Start bind timeout and bind 1539 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 1540 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 1541 mConnection.setGetNameAddressOnly(false); 1542 Intent i = new Intent(IBluetooth.class.getName()); 1543 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, 1544 UserHandle.CURRENT)) { 1545 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 1546 } else { 1547 mBinding = true; 1548 } 1549 } else if (mBluetooth != null) { 1550 if (mConnection.isGetNameAddressOnly()) { 1551 // if GetNameAddressOnly is set, we can clear this flag, 1552 // so the service won't be unbind 1553 // after name and address are saved 1554 mConnection.setGetNameAddressOnly(false); 1555 //Register callback object 1556 try { 1557 mBluetooth.registerCallback(mBluetoothCallback); 1558 } catch (RemoteException re) { 1559 Log.e(TAG, "Unable to register BluetoothCallback",re); 1560 } 1561 //Inform BluetoothAdapter instances that service is up 1562 sendBluetoothServiceUpCallback(); 1563 } 1564 1565 //Enable bluetooth 1566 try { 1567 if (!mQuietEnable) { 1568 if(!mBluetooth.enable()) { 1569 Log.e(TAG,"IBluetooth.enable() returned false"); 1570 } 1571 } 1572 else { 1573 if(!mBluetooth.enableNoAutoConnect()) { 1574 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 1575 } 1576 } 1577 } catch (RemoteException e) { 1578 Log.e(TAG,"Unable to call enable()",e); 1579 } 1580 } 1581 } 1582 } 1583 1584 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) { 1585 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); 1586 intent.setComponent(comp); 1587 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) { 1588 Log.e(TAG, "Fail to bind to: " + intent); 1589 return false; 1590 } 1591 return true; 1592 } 1593 1594 private void handleDisable() { 1595 synchronized(mConnection) { 1596 // don't need to disable if GetNameAddressOnly is set, 1597 // service will be unbinded after Name and Address are saved 1598 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { 1599 if (DBG) Log.d(TAG,"Sending off request."); 1600 1601 try { 1602 if(!mBluetooth.disable()) { 1603 Log.e(TAG,"IBluetooth.disable() returned false"); 1604 } 1605 } catch (RemoteException e) { 1606 Log.e(TAG,"Unable to call disable()",e); 1607 } 1608 } 1609 } 1610 } 1611 1612 private boolean checkIfCallerIsForegroundUser() { 1613 int foregroundUser; 1614 int callingUser = UserHandle.getCallingUserId(); 1615 int callingUid = Binder.getCallingUid(); 1616 long callingIdentity = Binder.clearCallingIdentity(); 1617 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1618 UserInfo ui = um.getProfileParent(callingUser); 1619 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; 1620 int callingAppId = UserHandle.getAppId(callingUid); 1621 boolean valid = false; 1622 try { 1623 foregroundUser = ActivityManager.getCurrentUser(); 1624 valid = (callingUser == foregroundUser) || 1625 parentUser == foregroundUser || 1626 callingAppId == Process.NFC_UID || 1627 callingAppId == mSystemUiUid; 1628 if (DBG) { 1629 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid 1630 + " callingUser=" + callingUser 1631 + " parentUser=" + parentUser 1632 + " foregroundUser=" + foregroundUser); 1633 } 1634 } finally { 1635 Binder.restoreCallingIdentity(callingIdentity); 1636 } 1637 return valid; 1638 } 1639 1640 private void sendBleStateChanged(int prevState, int newState) { 1641 if (DBG) Log.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState); 1642 // Send broadcast message to everyone else 1643 Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); 1644 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 1645 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 1646 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1647 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM); 1648 } 1649 1650 private void bluetoothStateChangeHandler(int prevState, int newState) { 1651 boolean isStandardBroadcast = true; 1652 if (prevState != newState) { 1653 //Notify all proxy objects first of adapter state change 1654 if (newState == BluetoothAdapter.STATE_BLE_ON 1655 || newState == BluetoothAdapter.STATE_OFF) { 1656 boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF 1657 && newState == BluetoothAdapter.STATE_BLE_ON); 1658 1659 if (newState == BluetoothAdapter.STATE_OFF) { 1660 // If Bluetooth is off, send service down event to proxy objects, and unbind 1661 if (DBG) Log.d(TAG, "Bluetooth is complete turn off"); 1662 if (canUnbindBluetoothService()) { 1663 if (DBG) Log.d(TAG, "Good to unbind!"); 1664 sendBluetoothServiceDownCallback(); 1665 unbindAndFinish(); 1666 sendBleStateChanged(prevState, newState); 1667 // Don't broadcast as it has already been broadcast before 1668 isStandardBroadcast = false; 1669 } 1670 1671 } else if (!intermediate_off) { 1672 // connect to GattService 1673 if (DBG) Log.d(TAG, "Bluetooth is in LE only mode"); 1674 if (mBluetoothGatt != null) { 1675 if (DBG) Log.d(TAG, "Calling BluetoothGattServiceUp"); 1676 onBluetoothGattServiceUp(); 1677 } else { 1678 if (DBG) Log.d(TAG, "Binding Bluetooth GATT service"); 1679 if (mContext.getPackageManager().hasSystemFeature( 1680 PackageManager.FEATURE_BLUETOOTH_LE)) { 1681 Intent i = new Intent(IBluetoothGatt.class.getName()); 1682 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT); 1683 } 1684 } 1685 sendBleStateChanged(prevState, newState); 1686 //Don't broadcase this as std intent 1687 isStandardBroadcast = false; 1688 1689 } else if (intermediate_off){ 1690 if (DBG) Log.d(TAG, "Intermediate off, back to LE only mode"); 1691 // For LE only mode, broadcast as is 1692 sendBleStateChanged(prevState, newState); 1693 sendBluetoothStateCallback(false); // BT is OFF for general users 1694 // Broadcast as STATE_OFF 1695 newState = BluetoothAdapter.STATE_OFF; 1696 sendBrEdrDownCallback(); 1697 } 1698 } else if (newState == BluetoothAdapter.STATE_ON) { 1699 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 1700 sendBluetoothStateCallback(isUp); 1701 sendBleStateChanged(prevState, newState); 1702 1703 } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON 1704 || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) { 1705 sendBleStateChanged(prevState, newState); 1706 isStandardBroadcast = false; 1707 1708 } else if (newState == BluetoothAdapter.STATE_TURNING_ON 1709 || newState == BluetoothAdapter.STATE_TURNING_OFF) { 1710 sendBleStateChanged(prevState, newState); 1711 } 1712 1713 if (isStandardBroadcast) { 1714 if (prevState == BluetoothAdapter.STATE_BLE_ON) { 1715 // Show prevState of BLE_ON as OFF to standard users 1716 prevState = BluetoothAdapter.STATE_OFF; 1717 } 1718 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 1719 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 1720 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 1721 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1722 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM); 1723 } 1724 } 1725 } 1726 1727 /** 1728 * if on is true, wait for state become ON 1729 * if off is true, wait for state become OFF 1730 * if both on and off are false, wait for state not ON 1731 */ 1732 private boolean waitForOnOff(boolean on, boolean off) { 1733 int i = 0; 1734 while (i < 10) { 1735 synchronized(mConnection) { 1736 try { 1737 if (mBluetooth == null) break; 1738 if (on) { 1739 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; 1740 } else if (off) { 1741 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; 1742 } else { 1743 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; 1744 } 1745 } catch (RemoteException e) { 1746 Log.e(TAG, "getState()", e); 1747 break; 1748 } 1749 } 1750 if (on || off) { 1751 SystemClock.sleep(300); 1752 } else { 1753 SystemClock.sleep(50); 1754 } 1755 i++; 1756 } 1757 Log.e(TAG,"waitForOnOff time out"); 1758 return false; 1759 } 1760 1761 private void sendDisableMsg() { 1762 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE)); 1763 } 1764 1765 private void sendEnableMsg(boolean quietMode) { 1766 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, 1767 quietMode ? 1 : 0, 0)); 1768 } 1769 1770 private boolean canUnbindBluetoothService() { 1771 synchronized(mConnection) { 1772 //Only unbind with mEnable flag not set 1773 //For race condition: disable and enable back-to-back 1774 //Avoid unbind right after enable due to callback from disable 1775 //Only unbind with Bluetooth at OFF state 1776 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message 1777 try { 1778 if (mEnable || (mBluetooth == null)) return false; 1779 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false; 1780 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF); 1781 } catch (RemoteException e) { 1782 Log.e(TAG, "getState()", e); 1783 } 1784 } 1785 return false; 1786 } 1787 1788 private void recoverBluetoothServiceFromError() { 1789 Log.e(TAG,"recoverBluetoothServiceFromError"); 1790 synchronized (mConnection) { 1791 if (mBluetooth != null) { 1792 //Unregister callback object 1793 try { 1794 mBluetooth.unregisterCallback(mBluetoothCallback); 1795 } catch (RemoteException re) { 1796 Log.e(TAG, "Unable to unregister",re); 1797 } 1798 } 1799 } 1800 1801 SystemClock.sleep(500); 1802 1803 // disable 1804 handleDisable(); 1805 1806 waitForOnOff(false, true); 1807 1808 sendBluetoothServiceDownCallback(); 1809 synchronized (mConnection) { 1810 if (mBluetooth != null) { 1811 mBluetooth = null; 1812 //Unbind 1813 mContext.unbindService(mConnection); 1814 } 1815 mBluetoothGatt = null; 1816 } 1817 1818 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 1819 mState = BluetoothAdapter.STATE_OFF; 1820 1821 mEnable = false; 1822 1823 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) { 1824 // Send a Bluetooth Restart message to reenable bluetooth 1825 Message restartMsg = mHandler.obtainMessage( 1826 MESSAGE_RESTART_BLUETOOTH_SERVICE); 1827 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS); 1828 } else { 1829 // todo: notify user to power down and power up phone to make bluetooth work. 1830 } 1831 } 1832 1833 @Override 1834 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1835 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 1836 1837 writer.println("Bluetooth Status"); 1838 writer.println(" enabled: " + mEnable); 1839 writer.println(" state: " + mState); 1840 writer.println(" address: " + mAddress); 1841 writer.println(" name: " + mName + "\n"); 1842 writer.flush(); 1843 1844 if (mBluetooth == null) { 1845 writer.println("Bluetooth Service not connected"); 1846 } else { 1847 ParcelFileDescriptor pfd = null; 1848 try { 1849 writer.println("Bonded devices:"); 1850 for (BluetoothDevice device : mBluetooth.getBondedDevices()) { 1851 writer.println(" " + device.getAddress() + 1852 " [" + DEVICE_TYPE_NAMES[device.getType()] + "] " + 1853 device.getName()); 1854 } 1855 writer.flush(); 1856 1857 pfd = ParcelFileDescriptor.dup(fd); 1858 mBluetooth.dump(pfd); 1859 } catch (RemoteException re) { 1860 writer.println("RemoteException while calling Bluetooth Service"); 1861 } catch (IOException ioe) { 1862 writer.println("IOException attempting to dup() fd"); 1863 } finally { 1864 if (pfd != null) { 1865 try { 1866 pfd.close(); 1867 } catch (IOException ioe) { 1868 writer.println("IOException attempting to close() fd"); 1869 } 1870 } 1871 } 1872 } 1873 } 1874 } 1875