BluetoothManagerService.java revision fa0fd39a4bf296d254aa398c1b19ec960efa641d
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.IBluetoothCallback; 23import android.bluetooth.IBluetoothManager; 24import android.bluetooth.IBluetoothManagerCallback; 25import android.bluetooth.IBluetoothStateChangeCallback; 26import android.content.BroadcastReceiver; 27import android.content.ComponentName; 28import android.content.ContentResolver; 29import android.content.Context; 30import android.content.Intent; 31import android.content.IntentFilter; 32import android.content.ServiceConnection; 33import android.os.Binder; 34import android.os.Handler; 35import android.os.HandlerThread; 36import android.os.IBinder; 37import android.os.Looper; 38import android.os.Message; 39import android.os.Process; 40import android.os.RemoteCallbackList; 41import android.os.RemoteException; 42import android.os.SystemClock; 43import android.os.UserHandle; 44import android.provider.Settings; 45import android.util.Log; 46import java.util.ArrayList; 47import java.util.List; 48class BluetoothManagerService extends IBluetoothManager.Stub { 49 private static final String TAG = "BluetoothManagerService"; 50 private static final boolean DBG = true; 51 52 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 53 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 54 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED"; 55 private static final String EXTRA_ACTION="action"; 56 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address"; 57 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name"; 58 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind 59 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save 60 //Maximum msec to wait for service restart 61 private static final int SERVICE_RESTART_TIME_MS = 200; 62 //Maximum msec to delay MESSAGE_USER_SWITCHED 63 private static final int USER_SWITCHED_TIME_MS = 200; 64 65 private static final int MESSAGE_ENABLE = 1; 66 private static final int MESSAGE_DISABLE = 2; 67 private static final int MESSAGE_REGISTER_ADAPTER = 20; 68 private static final int MESSAGE_UNREGISTER_ADAPTER = 21; 69 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; 70 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; 71 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; 72 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41; 73 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42; 74 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60; 75 private static final int MESSAGE_TIMEOUT_BIND =100; 76 private static final int MESSAGE_TIMEOUT_UNBIND =101; 77 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200; 78 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201; 79 private static final int MESSAGE_USER_SWITCHED = 300; 80 private static final int MAX_SAVE_RETRIES=3; 81 82 private final Context mContext; 83 84 // Locks are not provided for mName and mAddress. 85 // They are accessed in handler or broadcast receiver, same thread context. 86 private String mAddress; 87 private String mName; 88 private final ContentResolver mContentResolver; 89 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; 90 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; 91 private IBluetooth mBluetooth; 92 private boolean mBinding; 93 private boolean mUnbinding; 94 private boolean mQuietEnable = false; 95 private boolean mEnable; 96 private int mState; 97 private HandlerThread mThread; 98 private final BluetoothHandler mHandler; 99 100 private void registerForAirplaneMode(IntentFilter filter) { 101 final ContentResolver resolver = mContext.getContentResolver(); 102 final String airplaneModeRadios = Settings.Global.getString(resolver, 103 Settings.Global.AIRPLANE_MODE_RADIOS); 104 final String toggleableRadios = Settings.Global.getString(resolver, 105 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 106 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true : 107 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH); 108 if (mIsAirplaneSensitive) { 109 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); 110 } 111 } 112 113 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { 114 @Override 115 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { 116 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState); 117 mHandler.sendMessage(msg); 118 } 119 }; 120 121 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 122 @Override 123 public void onReceive(Context context, Intent intent) { 124 String action = intent.getAction(); 125 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) { 126 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME); 127 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName); 128 if (newName != null) { 129 storeNameAndAddress(newName, null); 130 } 131 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { 132 if (isAirplaneModeOn()) { 133 // disable without persisting the setting 134 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE, 135 0, 0)); 136 } else if (isBluetoothPersistedStateOn()) { 137 // enable without persisting the setting 138 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, 139 0, 0)); 140 } 141 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { 142 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED, 143 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); 144 } 145 } 146 }; 147 148 BluetoothManagerService(Context context) { 149 mThread = new HandlerThread("BluetoothManager"); 150 mThread.start(); 151 mHandler = new BluetoothHandler(mThread.getLooper()); 152 153 mContext = context; 154 mBluetooth = null; 155 mBinding = false; 156 mUnbinding = false; 157 mEnable = false; 158 mState = BluetoothAdapter.STATE_OFF; 159 mAddress = null; 160 mName = null; 161 mContentResolver = context.getContentResolver(); 162 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); 163 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); 164 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 165 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 166 filter.addAction(Intent.ACTION_USER_SWITCHED); 167 registerForAirplaneMode(filter); 168 mContext.registerReceiver(mReceiver, filter); 169 boolean airplaneModeOn = isAirplaneModeOn(); 170 boolean bluetoothOn = isBluetoothPersistedStateOn(); 171 loadStoredNameAndAddress(); 172 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn); 173 if (bluetoothOn) { 174 //Enable 175 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth."); 176 enableHelper(); 177 } else if (!isNameAndAddressSet()) { 178 //Sync the Bluetooth name and address from the Bluetooth Adapter 179 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); 180 getNameAndAddress(); 181 } 182 } 183 184 /** 185 * Returns true if airplane mode is currently on 186 */ 187 private final boolean isAirplaneModeOn() { 188 return Settings.Global.getInt(mContext.getContentResolver(), 189 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 190 } 191 192 /** 193 * Returns true if the Bluetooth saved state is "on" 194 */ 195 private final boolean isBluetoothPersistedStateOn() { 196 return Settings.Global.getInt(mContentResolver, 197 Settings.Global.BLUETOOTH_ON, 0) ==1; 198 } 199 200 /** 201 * Save the Bluetooth on/off state 202 * 203 */ 204 private void persistBluetoothSetting(boolean setOn) { 205 Settings.Global.putInt(mContext.getContentResolver(), 206 Settings.Global.BLUETOOTH_ON, 207 setOn ? 1 : 0); 208 } 209 210 /** 211 * Returns true if the Bluetooth Adapter's name and address is 212 * locally cached 213 * @return 214 */ 215 private boolean isNameAndAddressSet() { 216 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0; 217 } 218 219 /** 220 * Retrieve the Bluetooth Adapter's name and address and save it in 221 * in the local cache 222 */ 223 private void loadStoredNameAndAddress() { 224 if (DBG) Log.d(TAG, "Loading stored name and address"); 225 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); 226 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); 227 if (mName == null || mAddress == null) { 228 if (DBG) Log.d(TAG, "Name or address not cached..."); 229 } 230 } 231 232 /** 233 * Save the Bluetooth name and address in the persistent store. 234 * Only non-null values will be saved. 235 * @param name 236 * @param address 237 */ 238 private void storeNameAndAddress(String name, String address) { 239 if (name != null) { 240 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); 241 mName = name; 242 if (DBG) Log.d(TAG,"Stored Bluetooth name: " + 243 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME)); 244 } 245 246 if (address != null) { 247 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); 248 mAddress=address; 249 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " + 250 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS)); 251 } 252 } 253 254 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ 255 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); 256 msg.obj = callback; 257 mHandler.sendMessage(msg); 258 synchronized(mConnection) { 259 return mBluetooth; 260 } 261 } 262 263 public void unregisterAdapter(IBluetoothManagerCallback callback) { 264 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 265 "Need BLUETOOTH permission"); 266 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); 267 msg.obj = callback; 268 mHandler.sendMessage(msg); 269 } 270 271 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { 272 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 273 "Need BLUETOOTH permission"); 274 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK); 275 msg.obj = callback; 276 mHandler.sendMessage(msg); 277 } 278 279 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) { 280 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, 281 "Need BLUETOOTH permission"); 282 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK); 283 msg.obj = callback; 284 mHandler.sendMessage(msg); 285 } 286 287 public boolean isEnabled() { 288 if (!checkIfCallerIsForegroundUser()) { 289 Log.w(TAG,"isEnabled(): not allowed for non-active user"); 290 return false; 291 } 292 293 synchronized(mConnection) { 294 try { 295 return (mBluetooth != null && mBluetooth.isEnabled()); 296 } catch (RemoteException e) { 297 Log.e(TAG, "isEnabled()", e); 298 } 299 } 300 return false; 301 } 302 303 public void getNameAndAddress() { 304 if (DBG) { 305 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth + 306 " mBinding = " + mBinding); 307 } 308 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 309 mHandler.sendMessage(msg); 310 } 311 public boolean enableNoAutoConnect() 312 { 313 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 314 "Need BLUETOOTH ADMIN permission"); 315 316 if (!checkIfCallerIsForegroundUser()) { 317 Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user"); 318 return false; 319 } 320 321 if (DBG) { 322 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth + 323 " mBinding = " + mBinding); 324 } 325 if (Binder.getCallingUid() != Process.NFC_UID) { 326 throw new SecurityException("no permission to enable Bluetooth quietly"); 327 } 328 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 329 msg.arg1=0; //No persist 330 msg.arg2=1; //Quiet mode 331 mHandler.sendMessage(msg); 332 return true; 333 334 } 335 public boolean enable() { 336 if (!checkIfCallerIsForegroundUser()) { 337 Log.w(TAG,"enable(): not allowed for non-active user"); 338 return false; 339 } 340 341 return enableHelper(); 342 } 343 344 public boolean disable(boolean persist) { 345 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 346 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); 347 348 if (!checkIfCallerIsForegroundUser()) { 349 Log.w(TAG,"disable(): not allowed for non-active user"); 350 return false; 351 } 352 353 if (DBG) { 354 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth + 355 " mBinding = " + mBinding); 356 } 357 358 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE); 359 msg.arg1=(persist?1:0); 360 mHandler.sendMessage(msg); 361 return true; 362 } 363 364 public void unbindAndFinish() { 365 if (DBG) { 366 Log.d(TAG,"unbindAndFinish(): " + mBluetooth + 367 " mBinding = " + mBinding); 368 } 369 370 synchronized (mConnection) { 371 if (mUnbinding) return; 372 mUnbinding = true; 373 if (mBluetooth != null) { 374 if (!mConnection.isGetNameAddressOnly()) { 375 //Unregister callback object 376 try { 377 mBluetooth.unregisterCallback(mBluetoothCallback); 378 } catch (RemoteException re) { 379 Log.e(TAG, "Unable to unregister BluetoothCallback",re); 380 } 381 } 382 if (DBG) Log.d(TAG, "Sending unbind request."); 383 mBluetooth = null; 384 //Unbind 385 mContext.unbindService(mConnection); 386 mUnbinding = false; 387 mBinding = false; 388 } else { 389 mUnbinding=false; 390 } 391 } 392 } 393 394 private void sendBluetoothStateCallback(boolean isUp) { 395 int n = mStateChangeCallbacks.beginBroadcast(); 396 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers."); 397 for (int i=0; i <n;i++) { 398 try { 399 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp); 400 } catch (RemoteException e) { 401 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e); 402 } 403 } 404 mStateChangeCallbacks.finishBroadcast(); 405 } 406 407 /** 408 * Inform BluetoothAdapter instances that Adapter service is up 409 */ 410 private void sendBluetoothServiceUpCallback() { 411 if (!mConnection.isGetNameAddressOnly()) { 412 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks"); 413 int n = mCallbacks.beginBroadcast(); 414 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers."); 415 for (int i=0; i <n;i++) { 416 try { 417 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); 418 } catch (RemoteException e) { 419 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); 420 } 421 } 422 mCallbacks.finishBroadcast(); 423 } 424 } 425 /** 426 * Inform BluetoothAdapter instances that Adapter service is down 427 */ 428 private void sendBluetoothServiceDownCallback() { 429 if (!mConnection.isGetNameAddressOnly()) { 430 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks"); 431 int n = mCallbacks.beginBroadcast(); 432 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers."); 433 for (int i=0; i <n;i++) { 434 try { 435 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); 436 } catch (RemoteException e) { 437 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); 438 } 439 } 440 mCallbacks.finishBroadcast(); 441 } 442 } 443 public String getAddress() { 444 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 445 "Need BLUETOOTH ADMIN permission"); 446 447 if (!checkIfCallerIsForegroundUser()) { 448 Log.w(TAG,"getAddress(): not allowed for non-active user"); 449 return mAddress; 450 } 451 452 synchronized(mConnection) { 453 if (mBluetooth != null) { 454 try { 455 return mBluetooth.getAddress(); 456 } catch (RemoteException e) { 457 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e); 458 } 459 } 460 } 461 // mAddress is accessed from outside. 462 // It is alright without a lock. Here, bluetooth is off, no other thread is 463 // changing mAddress 464 return mAddress; 465 } 466 467 public String getName() { 468 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 469 "Need BLUETOOTH ADMIN permission"); 470 471 if (!checkIfCallerIsForegroundUser()) { 472 Log.w(TAG,"getName(): not allowed for non-active user"); 473 return mName; 474 } 475 476 synchronized(mConnection) { 477 if (mBluetooth != null) { 478 try { 479 return mBluetooth.getName(); 480 } catch (RemoteException e) { 481 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e); 482 } 483 } 484 } 485 // mName is accessed from outside. 486 // It alright without a lock. Here, bluetooth is off, no other thread is 487 // changing mName 488 return mName; 489 } 490 491 private class BluetoothServiceConnection implements ServiceConnection { 492 493 private boolean mGetNameAddressOnly; 494 495 public void setGetNameAddressOnly(boolean getOnly) { 496 mGetNameAddressOnly = getOnly; 497 } 498 499 public boolean isGetNameAddressOnly() { 500 return mGetNameAddressOnly; 501 } 502 503 public void onServiceConnected(ComponentName className, IBinder service) { 504 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService"); 505 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); 506 msg.obj = service; 507 mHandler.sendMessage(msg); 508 } 509 510 public void onServiceDisconnected(ComponentName className) { 511 // Called if we unexpected disconnected. 512 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService"); 513 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); 514 mHandler.sendMessage(msg); 515 } 516 } 517 518 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection(); 519 520 private class BluetoothHandler extends Handler { 521 public BluetoothHandler(Looper looper) { 522 super(looper); 523 } 524 525 @Override 526 public void handleMessage(Message msg) { 527 if (DBG) Log.d (TAG, "Message: " + msg.what); 528 switch (msg.what) { 529 case MESSAGE_GET_NAME_AND_ADDRESS: { 530 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS"); 531 synchronized(mConnection) { 532 //Start bind request 533 if ((mBluetooth == null) && (!mBinding)) { 534 if (DBG) Log.d(TAG, "Binding to service to get name and address"); 535 mConnection.setGetNameAddressOnly(true); 536 //Start bind timeout and bind 537 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 538 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 539 Intent i = new Intent(IBluetooth.class.getName()); 540 if (!mContext.bindService(i, mConnection, 541 Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) { 542 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 543 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName()); 544 } else { 545 mBinding = true; 546 } 547 } 548 else { 549 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 550 saveMsg.arg1 = 0; 551 if (mBluetooth != null) { 552 mHandler.sendMessage(saveMsg); 553 } else { 554 // if enable is also called to bind the service 555 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED 556 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS); 557 } 558 } 559 } 560 break; 561 } 562 case MESSAGE_SAVE_NAME_AND_ADDRESS: { 563 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS"); 564 synchronized(mConnection) { 565 if (mBluetooth != null) { 566 String name = null; 567 String address = null; 568 try { 569 name = mBluetooth.getName(); 570 address = mBluetooth.getAddress(); 571 } catch (RemoteException re) { 572 Log.e(TAG,"",re); 573 } 574 575 if (name != null && address != null) { 576 storeNameAndAddress(name,address); 577 if (mConnection.isGetNameAddressOnly()) { 578 unbindAndFinish(); 579 } 580 } else { 581 if (msg.arg1 < MAX_SAVE_RETRIES) { 582 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS); 583 retryMsg.arg1= 1+msg.arg1; 584 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1); 585 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS); 586 } else { 587 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded"); 588 if (mConnection.isGetNameAddressOnly()) { 589 unbindAndFinish(); 590 } 591 } 592 } 593 } else { 594 // rebind service by Request GET NAME AND ADDRESS 595 // if service is unbinded by disable or 596 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received 597 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 598 mHandler.sendMessage(getMsg); 599 } 600 } 601 break; 602 } 603 case MESSAGE_ENABLE: 604 if (DBG) { 605 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth); 606 } 607 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 608 mEnable = true; 609 handleEnable(msg.arg1 == 1, msg.arg2 ==1); 610 break; 611 612 case MESSAGE_DISABLE: 613 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); 614 if (mEnable && mBluetooth != null) { 615 waitForOnOff(true, false); 616 mEnable = false; 617 handleDisable(msg.arg1 == 1); 618 waitForOnOff(false, false); 619 } else { 620 mEnable = false; 621 handleDisable(msg.arg1 == 1); 622 } 623 break; 624 625 case MESSAGE_REGISTER_ADAPTER: 626 { 627 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 628 boolean added = mCallbacks.register(callback); 629 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added ); 630 } 631 break; 632 case MESSAGE_UNREGISTER_ADAPTER: 633 { 634 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; 635 boolean removed = mCallbacks.unregister(callback); 636 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed); 637 break; 638 } 639 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: 640 { 641 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 642 mStateChangeCallbacks.register(callback); 643 break; 644 } 645 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: 646 { 647 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; 648 mStateChangeCallbacks.unregister(callback); 649 break; 650 } 651 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: 652 { 653 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED"); 654 655 //Remove timeout 656 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 657 658 IBinder service = (IBinder) msg.obj; 659 synchronized(mConnection) { 660 mBinding = false; 661 mBluetooth = IBluetooth.Stub.asInterface(service); 662 663 if (mConnection.isGetNameAddressOnly()) { 664 //Request GET NAME AND ADDRESS 665 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); 666 mHandler.sendMessage(getMsg); 667 if (!mEnable) return; 668 } 669 670 mConnection.setGetNameAddressOnly(false); 671 //Register callback object 672 try { 673 mBluetooth.registerCallback(mBluetoothCallback); 674 } catch (RemoteException re) { 675 Log.e(TAG, "Unable to register BluetoothCallback",re); 676 } 677 //Inform BluetoothAdapter instances that service is up 678 sendBluetoothServiceUpCallback(); 679 680 //Check if name and address is loaded if not get it first. 681 if (!isNameAndAddressSet()) { 682 try { 683 storeNameAndAddress(mBluetooth.getName(), 684 mBluetooth.getAddress()); 685 } catch (RemoteException e) {Log.e(TAG, "", e);}; 686 } 687 688 //Do enable request 689 try { 690 if (mQuietEnable == false) { 691 if(!mBluetooth.enable()) { 692 Log.e(TAG,"IBluetooth.enable() returned false"); 693 } 694 } 695 else 696 { 697 if(!mBluetooth.enableNoAutoConnect()) { 698 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 699 } 700 } 701 } catch (RemoteException e) { 702 Log.e(TAG,"Unable to call enable()",e); 703 } 704 } 705 706 if (!mEnable) { 707 waitForOnOff(true, false); 708 handleDisable(false); 709 waitForOnOff(false, false); 710 } 711 break; 712 } 713 case MESSAGE_TIMEOUT_BIND: { 714 Log.e(TAG, "MESSAGE_TIMEOUT_BIND"); 715 synchronized(mConnection) { 716 mBinding = false; 717 } 718 break; 719 } 720 case MESSAGE_BLUETOOTH_STATE_CHANGE: 721 { 722 int prevState = msg.arg1; 723 int newState = msg.arg2; 724 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState); 725 mState = newState; 726 bluetoothStateChangeHandler(prevState, newState); 727 break; 728 } 729 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: 730 { 731 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED"); 732 synchronized(mConnection) { 733 // if service is unbinded already, do nothing and return 734 if (mBluetooth == null) return; 735 mBluetooth = null; 736 } 737 738 if (mEnable) { 739 mEnable = false; 740 // Send a Bluetooth Restart message 741 Message restartMsg = mHandler.obtainMessage( 742 MESSAGE_RESTART_BLUETOOTH_SERVICE); 743 mHandler.sendMessageDelayed(restartMsg, 744 SERVICE_RESTART_TIME_MS); 745 } 746 747 if (!mConnection.isGetNameAddressOnly()) { 748 sendBluetoothServiceDownCallback(); 749 750 // Send BT state broadcast to update 751 // the BT icon correctly 752 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 753 BluetoothAdapter.STATE_TURNING_OFF); 754 mState = BluetoothAdapter.STATE_OFF; 755 } 756 break; 757 } 758 case MESSAGE_RESTART_BLUETOOTH_SERVICE: 759 { 760 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:" 761 +" Restart IBluetooth service"); 762 /* Enable without persisting the setting as 763 it doesnt change when IBluetooth 764 service restarts */ 765 mEnable = true; 766 handleEnable(false, mQuietEnable); 767 break; 768 } 769 770 case MESSAGE_TIMEOUT_UNBIND: 771 { 772 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND"); 773 synchronized(mConnection) { 774 mUnbinding = false; 775 } 776 break; 777 } 778 779 case MESSAGE_USER_SWITCHED: 780 { 781 if (DBG) { 782 Log.d(TAG, "MESSAGE_USER_SWITCHED"); 783 } 784 mHandler.removeMessages(MESSAGE_USER_SWITCHED); 785 /* disable and enable BT when detect a user switch */ 786 if (mEnable && mBluetooth != null) { 787 synchronized (mConnection) { 788 if (mBluetooth != null) { 789 //Unregister callback object 790 try { 791 mBluetooth.unregisterCallback(mBluetoothCallback); 792 } catch (RemoteException re) { 793 Log.e(TAG, "Unable to unregister",re); 794 } 795 } 796 } 797 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE); 798 799 waitForOnOff(true, false); 800 801 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); 802 803 // disable 804 handleDisable(false); 805 806 waitForOnOff(false, true); 807 808 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, 809 BluetoothAdapter.STATE_OFF); 810 mState = BluetoothAdapter.STATE_OFF; 811 sendBluetoothServiceDownCallback(); 812 synchronized (mConnection) { 813 if (mBluetooth != null) { 814 mBluetooth = null; 815 //Unbind 816 mContext.unbindService(mConnection); 817 } 818 } 819 SystemClock.sleep(100); 820 821 // enable 822 handleEnable(false, mQuietEnable); 823 } else if (mBinding || mBluetooth != null) { 824 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); 825 userMsg.arg2 = 1 + msg.arg2; 826 // if user is switched when service is being binding 827 // delay sending MESSAGE_USER_SWITCHED 828 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS); 829 if (DBG) { 830 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2); 831 } 832 } 833 break; 834 } 835 } 836 } 837 } 838 839 private void handleEnable(boolean persist, boolean quietMode) { 840 if (persist) { 841 persistBluetoothSetting(true); 842 } 843 844 mQuietEnable = quietMode; 845 846 synchronized(mConnection) { 847 if ((mBluetooth == null) && (!mBinding)) { 848 //Start bind timeout and bind 849 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); 850 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS); 851 mConnection.setGetNameAddressOnly(false); 852 Intent i = new Intent(IBluetooth.class.getName()); 853 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE, 854 UserHandle.USER_CURRENT)) { 855 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); 856 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName()); 857 } else { 858 mBinding = true; 859 } 860 } else if (mBluetooth != null) { 861 if (mConnection.isGetNameAddressOnly()) { 862 // if GetNameAddressOnly is set, we can clear this flag, 863 // so the service won't be unbind 864 // after name and address are saved 865 mConnection.setGetNameAddressOnly(false); 866 //Register callback object 867 try { 868 mBluetooth.registerCallback(mBluetoothCallback); 869 } catch (RemoteException re) { 870 Log.e(TAG, "Unable to register BluetoothCallback",re); 871 } 872 //Inform BluetoothAdapter instances that service is up 873 sendBluetoothServiceUpCallback(); 874 } 875 876 //Check if name and address is loaded if not get it first. 877 if (!isNameAndAddressSet()) { 878 try { 879 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable."); 880 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress()); 881 } catch (RemoteException e) {Log.e(TAG, "", e);}; 882 } 883 884 //Enable bluetooth 885 try { 886 if (!mQuietEnable) { 887 if(!mBluetooth.enable()) { 888 Log.e(TAG,"IBluetooth.enable() returned false"); 889 } 890 } 891 else { 892 if(!mBluetooth.enableNoAutoConnect()) { 893 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); 894 } 895 } 896 } catch (RemoteException e) { 897 Log.e(TAG,"Unable to call enable()",e); 898 } 899 } 900 } 901 } 902 903 private void handleDisable(boolean persist) { 904 if (persist) { 905 persistBluetoothSetting(false); 906 } 907 908 synchronized(mConnection) { 909 // don't need to disable if GetNameAddressOnly is set, 910 // service will be unbinded after Name and Address are saved 911 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) { 912 if (DBG) Log.d(TAG,"Sending off request."); 913 914 try { 915 if(!mBluetooth.disable()) { 916 Log.e(TAG,"IBluetooth.disable() returned false"); 917 } 918 } catch (RemoteException e) { 919 Log.e(TAG,"Unable to call disable()",e); 920 } 921 } 922 } 923 } 924 925 private boolean checkIfCallerIsForegroundUser() { 926 int foregroundUser; 927 int callingUser = UserHandle.getCallingUserId(); 928 long callingIdentity = Binder.clearCallingIdentity(); 929 boolean valid = false; 930 try { 931 foregroundUser = ActivityManager.getCurrentUser(); 932 valid = (callingUser == foregroundUser); 933 if (DBG) { 934 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid 935 + " callingUser=" + callingUser 936 + " foregroundUser=" + foregroundUser); 937 } 938 } finally { 939 Binder.restoreCallingIdentity(callingIdentity); 940 } 941 return valid; 942 } 943 944 private boolean enableHelper() { 945 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 946 "Need BLUETOOTH ADMIN permission"); 947 if (DBG) { 948 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth + 949 " mBinding = " + mBinding); 950 } 951 952 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE); 953 msg.arg1=1; //persist 954 msg.arg2=0; //No Quiet Mode 955 mHandler.sendMessage(msg); 956 return true; 957 } 958 959 private void bluetoothStateChangeHandler(int prevState, int newState) { 960 if (prevState != newState) { 961 //Notify all proxy objects first of adapter state change 962 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) { 963 boolean isUp = (newState==BluetoothAdapter.STATE_ON); 964 sendBluetoothStateCallback(isUp); 965 966 //If Bluetooth is off, send service down event to proxy objects, and unbind 967 if (!isUp) { 968 //Only unbind with mEnable flag not set 969 //For race condition: disable and enable back-to-back 970 //Avoid unbind right after enable due to callback from disable 971 if ((!mEnable) && (mBluetooth != null)) { 972 sendBluetoothServiceDownCallback(); 973 unbindAndFinish(); 974 } 975 } 976 } 977 978 //Send broadcast message to everyone else 979 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 980 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); 981 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); 982 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 983 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState); 984 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 985 BLUETOOTH_PERM); 986 } 987 } 988 989 /** 990 * if on is true, wait for state become ON 991 * if off is true, wait for state become OFF 992 * if both on and off are false, wait for state not ON 993 */ 994 private boolean waitForOnOff(boolean on, boolean off) { 995 int i = 0; 996 while (i < 10) { 997 synchronized(mConnection) { 998 try { 999 if (mBluetooth == null) break; 1000 if (on) { 1001 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true; 1002 } else if (off) { 1003 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true; 1004 } else { 1005 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true; 1006 } 1007 } catch (RemoteException e) { 1008 Log.e(TAG, "getState()", e); 1009 break; 1010 } 1011 } 1012 if (on || off) { 1013 SystemClock.sleep(300); 1014 } else { 1015 SystemClock.sleep(50); 1016 } 1017 i++; 1018 } 1019 Log.e(TAG,"waitForOnOff time out"); 1020 return false; 1021 } 1022} 1023