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