DockService.java revision ae3311e5bd7b146eb4e1bc6310cbaba051776fb4
1/* 2 * Copyright (C) 2009 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.settings.bluetooth; 18 19import com.android.settings.R; 20import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile; 21 22import android.app.AlertDialog; 23import android.app.Notification; 24import android.app.Service; 25import android.bluetooth.BluetoothA2dp; 26import android.bluetooth.BluetoothAdapter; 27import android.bluetooth.BluetoothDevice; 28import android.bluetooth.BluetoothHeadset; 29import android.content.Context; 30import android.content.DialogInterface; 31import android.content.Intent; 32import android.content.IntentFilter; 33import android.content.SharedPreferences; 34import android.os.Handler; 35import android.os.HandlerThread; 36import android.os.IBinder; 37import android.os.Looper; 38import android.os.Message; 39import android.util.Log; 40import android.view.LayoutInflater; 41import android.view.View; 42import android.view.WindowManager; 43import android.widget.CheckBox; 44import android.widget.CompoundButton; 45 46import java.util.List; 47import java.util.Set; 48 49public class DockService extends Service implements AlertDialog.OnMultiChoiceClickListener, 50 DialogInterface.OnClickListener, DialogInterface.OnDismissListener, 51 CompoundButton.OnCheckedChangeListener { 52 53 private static final String TAG = "DockService"; 54 55 static final boolean DEBUG = false; 56 57 // Time allowed for the device to be undocked and redocked without severing 58 // the bluetooth connection 59 private static final long UNDOCKED_GRACE_PERIOD = 1000; 60 61 // Time allowed for the device to be undocked and redocked without turning 62 // off Bluetooth 63 private static final long DISABLE_BT_GRACE_PERIOD = 2000; 64 65 // Msg for user wanting the UI to setup the dock 66 private static final int MSG_TYPE_SHOW_UI = 111; 67 68 // Msg for device docked event 69 private static final int MSG_TYPE_DOCKED = 222; 70 71 // Msg for device undocked event 72 private static final int MSG_TYPE_UNDOCKED_TEMPORARY = 333; 73 74 // Msg for undocked command to be process after UNDOCKED_GRACE_PERIOD millis 75 // since MSG_TYPE_UNDOCKED_TEMPORARY 76 private static final int MSG_TYPE_UNDOCKED_PERMANENT = 444; 77 78 // Msg for disabling bt after DISABLE_BT_GRACE_PERIOD millis since 79 // MSG_TYPE_UNDOCKED_PERMANENT 80 private static final int MSG_TYPE_DISABLE_BT = 555; 81 82 private static final String SHARED_PREFERENCES_NAME = "dock_settings"; 83 84 private static final String SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED = 85 "disable_bt_when_undock"; 86 87 private static final String SHARED_PREFERENCES_KEY_DISABLE_BT = 88 "disable_bt"; 89 90 private static final int INVALID_STARTID = -100; 91 92 // Created in OnCreate() 93 private volatile Looper mServiceLooper; 94 private volatile ServiceHandler mServiceHandler; 95 private DockService mContext; 96 private LocalBluetoothManager mBtManager; 97 98 // Normally set after getting a docked event and unset when the connection 99 // is severed. One exception is that mDevice could be null if the service 100 // was started after the docked event. 101 private BluetoothDevice mDevice; 102 103 // Created and used for the duration of the dialog 104 private AlertDialog mDialog; 105 private Profile[] mProfiles; 106 private boolean[] mCheckedItems; 107 private int mStartIdAssociatedWithDialog; 108 109 // Set while BT is being enabled. 110 private BluetoothDevice mPendingDevice; 111 private int mPendingStartId; 112 private int mPendingTurnOnStartId = INVALID_STARTID; 113 private int mPendingTurnOffStartId = INVALID_STARTID; 114 115 @Override 116 public void onCreate() { 117 if (DEBUG) Log.d(TAG, "onCreate"); 118 119 mBtManager = LocalBluetoothManager.getInstance(this); 120 mContext = this; 121 122 HandlerThread thread = new HandlerThread("DockService"); 123 thread.start(); 124 125 mServiceLooper = thread.getLooper(); 126 mServiceHandler = new ServiceHandler(mServiceLooper); 127 } 128 129 @Override 130 public void onDestroy() { 131 if (DEBUG) Log.d(TAG, "onDestroy"); 132 if (mDialog != null) { 133 mDialog.dismiss(); 134 mDialog = null; 135 } 136 mServiceLooper.quit(); 137 } 138 139 @Override 140 public IBinder onBind(Intent intent) { 141 // not supported 142 return null; 143 } 144 145 @Override 146 public int onStartCommand(Intent intent, int flags, int startId) { 147 if (DEBUG) Log.d(TAG, "onStartCommand startId:" + startId + " flags: " + flags); 148 149 if (intent == null) { 150 // Nothing to process, stop. 151 if (DEBUG) Log.d(TAG, "START_NOT_STICKY - intent is null."); 152 153 // NOTE: We MUST not call stopSelf() directly, since we need to 154 // make sure the wake lock acquired by the Receiver is released. 155 DockEventReceiver.finishStartingService(this, startId); 156 return START_NOT_STICKY; 157 } 158 159 if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) { 160 handleBtStateChange(intent, startId); 161 return START_NOT_STICKY; 162 } 163 164 Message msg = parseIntent(intent); 165 if (msg == null) { 166 // Bad intent 167 if (DEBUG) Log.d(TAG, "START_NOT_STICKY - Bad intent."); 168 DockEventReceiver.finishStartingService(this, startId); 169 return START_NOT_STICKY; 170 } 171 172 msg.arg2 = startId; 173 processMessage(msg); 174 175 return START_NOT_STICKY; 176 } 177 178 private final class ServiceHandler extends Handler { 179 public ServiceHandler(Looper looper) { 180 super(looper); 181 } 182 183 @Override 184 public void handleMessage(Message msg) { 185 processMessage(msg); 186 } 187 } 188 189 // This method gets messages from both onStartCommand and mServiceHandler/mServiceLooper 190 private synchronized void processMessage(Message msg) { 191 int msgType = msg.what; 192 int state = msg.arg1; 193 int startId = msg.arg2; 194 boolean deferFinishCall = false; 195 BluetoothDevice device = null; 196 if (msg.obj != null) { 197 device = (BluetoothDevice) msg.obj; 198 } 199 200 if(DEBUG) Log.d(TAG, "processMessage: " + msgType + " state: " + state + " device = " 201 + (device == null ? "null" : device.toString())); 202 203 switch (msgType) { 204 case MSG_TYPE_SHOW_UI: 205 if (mDialog != null) { 206 // Shouldn't normally happen 207 mDialog.dismiss(); 208 mDialog = null; 209 } 210 mDevice = device; 211 createDialog(mContext, mDevice, state, startId); 212 break; 213 214 case MSG_TYPE_DOCKED: 215 if (DEBUG) { 216 // TODO figure out why hasMsg always returns false if device 217 // is supplied 218 Log.d(TAG, "1 Has undock perm msg = " 219 + mServiceHandler.hasMessages(MSG_TYPE_UNDOCKED_PERMANENT, mDevice)); 220 Log.d(TAG, "2 Has undock perm msg = " 221 + mServiceHandler.hasMessages(MSG_TYPE_UNDOCKED_PERMANENT, device)); 222 } 223 224 mServiceHandler.removeMessages(MSG_TYPE_UNDOCKED_PERMANENT); 225 mServiceHandler.removeMessages(MSG_TYPE_DISABLE_BT); 226 removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT); 227 228 if (!device.equals(mDevice)) { 229 if (mDevice != null) { 230 // Not expected. Cleanup/undock existing 231 handleUndocked(mContext, mBtManager, mDevice); 232 } 233 234 mDevice = device; 235 if (mBtManager.getDockAutoConnectSetting(device.getAddress())) { 236 // Setting == auto connect 237 initBtSettings(mContext, device, state, false); 238 applyBtSettings(mDevice, startId); 239 } else { 240 createDialog(mContext, mDevice, state, startId); 241 } 242 } 243 break; 244 245 case MSG_TYPE_UNDOCKED_PERMANENT: 246 // Grace period passed. Disconnect. 247 handleUndocked(mContext, mBtManager, device); 248 249 if (DEBUG) { 250 Log.d(TAG, "DISABLE_BT_WHEN_UNDOCKED = " 251 + getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)); 252 } 253 254 if (getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)) { 255 // BT was disabled when we first docked 256 if (!hasOtherConnectedDevices(device)) { 257 if(DEBUG) Log.d(TAG, "QUEUED BT DISABLE"); 258 // Queue a delayed msg to disable BT 259 Message newMsg = mServiceHandler.obtainMessage(MSG_TYPE_DISABLE_BT, 0, 260 startId, null); 261 mServiceHandler.sendMessageDelayed(newMsg, DISABLE_BT_GRACE_PERIOD); 262 deferFinishCall = true; 263 } else { 264 // Don't disable BT if something is connected 265 removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED); 266 } 267 } 268 break; 269 270 case MSG_TYPE_UNDOCKED_TEMPORARY: 271 // Undocked event received. Queue a delayed msg to sever connection 272 Message newMsg = mServiceHandler.obtainMessage(MSG_TYPE_UNDOCKED_PERMANENT, state, 273 startId, device); 274 mServiceHandler.sendMessageDelayed(newMsg, UNDOCKED_GRACE_PERIOD); 275 break; 276 277 case MSG_TYPE_DISABLE_BT: 278 if(DEBUG) Log.d(TAG, "BT DISABLE"); 279 if (mBtManager.getBluetoothAdapter().disable()) { 280 removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED); 281 } else { 282 // disable() returned an error. Persist a flag to disable BT later 283 setSetting(SHARED_PREFERENCES_KEY_DISABLE_BT, true); 284 mPendingTurnOffStartId = startId; 285 deferFinishCall = true; 286 if(DEBUG) Log.d(TAG, "disable failed. try again later " + startId); 287 } 288 break; 289 } 290 291 if (mDialog == null && mPendingDevice == null && msgType != MSG_TYPE_UNDOCKED_TEMPORARY 292 && !deferFinishCall) { 293 // NOTE: We MUST not call stopSelf() directly, since we need to 294 // make sure the wake lock acquired by the Receiver is released. 295 DockEventReceiver.finishStartingService(DockService.this, startId); 296 } 297 } 298 299 public synchronized boolean hasOtherConnectedDevices(BluetoothDevice dock) { 300 List<CachedBluetoothDevice> cachedDevices = mBtManager.getCachedDeviceManager() 301 .getCachedDevicesCopy(); 302 Set<BluetoothDevice> btDevices = mBtManager.getBluetoothAdapter().getBondedDevices(); 303 if (btDevices == null || cachedDevices == null || btDevices.size() == 0) { 304 return false; 305 } 306 if(DEBUG) Log.d(TAG, "btDevices = " + btDevices.size()); 307 if(DEBUG) Log.d(TAG, "cachedDevices = " + cachedDevices.size()); 308 309 for (CachedBluetoothDevice device : cachedDevices) { 310 BluetoothDevice btDevice = device.getDevice(); 311 if (!btDevice.equals(dock) && btDevices.contains(btDevice) && device.isConnected()) { 312 if(DEBUG) Log.d(TAG, "connected device = " + device.getName()); 313 return true; 314 } 315 } 316 return false; 317 } 318 319 private Message parseIntent(Intent intent) { 320 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 321 int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, -1234); 322 323 if (DEBUG) { 324 Log.d(TAG, "Action: " + intent.getAction() + " State:" + state 325 + " Device: " + (device == null ? "null" : device.getName())); 326 } 327 328 if (device == null) { 329 Log.w(TAG, "device is null"); 330 return null; 331 } 332 333 int msgType; 334 switch (state) { 335 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 336 msgType = MSG_TYPE_UNDOCKED_TEMPORARY; 337 break; 338 case Intent.EXTRA_DOCK_STATE_DESK: 339 case Intent.EXTRA_DOCK_STATE_CAR: 340 if (DockEventReceiver.ACTION_DOCK_SHOW_UI.equals(intent.getAction())) { 341 msgType = MSG_TYPE_SHOW_UI; 342 } else { 343 msgType = MSG_TYPE_DOCKED; 344 } 345 break; 346 default: 347 return null; 348 } 349 350 return mServiceHandler.obtainMessage(msgType, state, 0, device); 351 } 352 353 private boolean createDialog(DockService service, BluetoothDevice device, int state, 354 int startId) { 355 switch (state) { 356 case Intent.EXTRA_DOCK_STATE_CAR: 357 case Intent.EXTRA_DOCK_STATE_DESK: 358 break; 359 default: 360 return false; 361 } 362 363 startForeground(0, new Notification()); 364 365 // Device in a new dock. 366 boolean firstTime = !mBtManager.hasDockAutoConnectSetting(device.getAddress()); 367 368 CharSequence[] items = initBtSettings(service, device, state, firstTime); 369 370 final AlertDialog.Builder ab = new AlertDialog.Builder(service); 371 ab.setTitle(service.getString(R.string.bluetooth_dock_settings_title)); 372 373 // Profiles 374 ab.setMultiChoiceItems(items, mCheckedItems, service); 375 376 // Remember this settings 377 LayoutInflater inflater = (LayoutInflater) service 378 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 379 float pixelScaleFactor = service.getResources().getDisplayMetrics().density; 380 View view = inflater.inflate(R.layout.remember_dock_setting, null); 381 CheckBox rememberCheckbox = (CheckBox) view.findViewById(R.id.remember); 382 383 // check "Remember setting" by default if no value was saved 384 boolean checked = firstTime || mBtManager.getDockAutoConnectSetting(device.getAddress()); 385 rememberCheckbox.setChecked(checked); 386 rememberCheckbox.setOnCheckedChangeListener(this); 387 int viewSpacingLeft = (int) (14 * pixelScaleFactor); 388 int viewSpacingRight = (int) (14 * pixelScaleFactor); 389 ab.setView(view, viewSpacingLeft, 0 /* top */, viewSpacingRight, 0 /* bottom */); 390 if (DEBUG) { 391 Log.d(TAG, "Auto connect = " 392 + mBtManager.getDockAutoConnectSetting(device.getAddress())); 393 } 394 395 // Ok Button 396 ab.setPositiveButton(service.getString(android.R.string.ok), service); 397 398 mStartIdAssociatedWithDialog = startId; 399 mDialog = ab.create(); 400 mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 401 mDialog.setOnDismissListener(service); 402 mDialog.show(); 403 return true; 404 } 405 406 // Called when the individual bt profiles are clicked. 407 public void onClick(DialogInterface dialog, int which, boolean isChecked) { 408 if (DEBUG) Log.d(TAG, "Item " + which + " changed to " + isChecked); 409 mCheckedItems[which] = isChecked; 410 } 411 412 // Called when the "Remember" Checkbox is clicked 413 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 414 if (DEBUG) Log.d(TAG, "onCheckedChanged: Remember Settings = " + isChecked); 415 if (mDevice != null) { 416 mBtManager.saveDockAutoConnectSetting(mDevice.getAddress(), isChecked); 417 } 418 } 419 420 // Called when the dialog is dismissed 421 public void onDismiss(DialogInterface dialog) { 422 // NOTE: We MUST not call stopSelf() directly, since we need to 423 // make sure the wake lock acquired by the Receiver is released. 424 if (mPendingDevice == null) { 425 DockEventReceiver.finishStartingService(mContext, mStartIdAssociatedWithDialog); 426 } 427 mContext.stopForeground(true); 428 } 429 430 // Called when clicked on the OK button 431 public void onClick(DialogInterface dialog, int which) { 432 if (which == DialogInterface.BUTTON_POSITIVE && mDevice != null) { 433 if (!mBtManager.hasDockAutoConnectSetting(mDevice.getAddress())) { 434 mBtManager.saveDockAutoConnectSetting(mDevice.getAddress(), true); 435 } 436 437 applyBtSettings(mDevice, mStartIdAssociatedWithDialog); 438 } 439 } 440 441 private CharSequence[] initBtSettings(DockService service, BluetoothDevice device, int state, 442 boolean firstTime) { 443 // TODO Avoid hardcoding dock and profiles. Read from system properties 444 int numOfProfiles = 0; 445 switch (state) { 446 case Intent.EXTRA_DOCK_STATE_DESK: 447 numOfProfiles = 1; 448 break; 449 case Intent.EXTRA_DOCK_STATE_CAR: 450 numOfProfiles = 2; 451 break; 452 default: 453 return null; 454 } 455 456 mProfiles = new Profile[numOfProfiles]; 457 mCheckedItems = new boolean[numOfProfiles]; 458 CharSequence[] items = new CharSequence[numOfProfiles]; 459 460 switch (state) { 461 case Intent.EXTRA_DOCK_STATE_CAR: 462 items[0] = service.getString(R.string.bluetooth_dock_settings_headset); 463 items[1] = service.getString(R.string.bluetooth_dock_settings_a2dp); 464 mProfiles[0] = Profile.HEADSET; 465 mProfiles[1] = Profile.A2DP; 466 if (firstTime) { 467 // Enable by default for car dock 468 mCheckedItems[0] = true; 469 mCheckedItems[1] = true; 470 } else { 471 mCheckedItems[0] = LocalBluetoothProfileManager.getProfileManager(mBtManager, 472 Profile.HEADSET).isPreferred(device); 473 mCheckedItems[1] = LocalBluetoothProfileManager.getProfileManager(mBtManager, 474 Profile.A2DP).isPreferred(device); 475 } 476 break; 477 478 case Intent.EXTRA_DOCK_STATE_DESK: 479 items[0] = service.getString(R.string.bluetooth_dock_settings_a2dp); 480 mProfiles[0] = Profile.A2DP; 481 if (firstTime) { 482 // Disable by default for desk dock 483 mCheckedItems[0] = false; 484 } else { 485 mCheckedItems[0] = LocalBluetoothProfileManager.getProfileManager(mBtManager, 486 Profile.A2DP).isPreferred(device); 487 } 488 break; 489 } 490 return items; 491 } 492 493 private void handleBtStateChange(Intent intent, int startId) { 494 int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 495 synchronized (this) { 496 if(DEBUG) Log.d(TAG, "BtState = " + btState + " mPendingDevice = " + mPendingDevice); 497 if (btState == BluetoothAdapter.STATE_ON) { 498 if (mPendingDevice != null) { 499 if (mPendingDevice.equals(mDevice)) { 500 if(DEBUG) Log.d(TAG, "applying settings"); 501 applyBtSettings(mPendingDevice, mPendingStartId); 502 } else if(DEBUG) { 503 Log.d(TAG, "mPendingDevice (" + mPendingDevice + ") != mDevice (" 504 + mDevice + ")"); 505 } 506 507 mPendingDevice = null; 508 DockEventReceiver.finishStartingService(mContext, mPendingStartId); 509 } else { 510 if (DEBUG) { 511 Log.d(TAG, "A DISABLE_BT_WHEN_UNDOCKED = " 512 + getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)); 513 } 514 // Reconnect if docked and bluetooth was enabled by user. 515 Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); 516 if (i != null) { 517 int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, 518 Intent.EXTRA_DOCK_STATE_UNDOCKED); 519 if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { 520 BluetoothDevice device = i 521 .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 522 if (device != null) { 523 connectIfEnabled(device); 524 } 525 } else if (getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT) 526 && mBtManager.getBluetoothAdapter().disable()) { 527 mPendingTurnOffStartId = startId; 528 removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT); 529 return; 530 } 531 } 532 } 533 534 if (mPendingTurnOnStartId != INVALID_STARTID) { 535 DockEventReceiver.finishStartingService(this, mPendingTurnOnStartId); 536 mPendingTurnOnStartId = INVALID_STARTID; 537 } 538 539 DockEventReceiver.finishStartingService(this, startId); 540 } else if (btState == BluetoothAdapter.STATE_TURNING_OFF) { 541 // Remove the flag to disable BT if someone is turning off bt. 542 // The rational is that: 543 // a) if BT is off at undock time, no work needs to be done 544 // b) if BT is on at undock time, the user wants it on. 545 removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED); 546 DockEventReceiver.finishStartingService(this, startId); 547 } else if (btState == BluetoothAdapter.STATE_OFF) { 548 // Bluetooth was turning off as we were trying to turn it on. 549 // Let's try again 550 if(DEBUG) Log.d(TAG, "Bluetooth = OFF mPendingDevice = " + mPendingDevice); 551 552 if (mPendingTurnOffStartId != INVALID_STARTID) { 553 DockEventReceiver.finishStartingService(this, mPendingTurnOffStartId); 554 removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT); 555 mPendingTurnOffStartId = INVALID_STARTID; 556 } 557 558 if (mPendingDevice != null) { 559 mBtManager.getBluetoothAdapter().enable(); 560 mPendingTurnOnStartId = startId; 561 } else { 562 DockEventReceiver.finishStartingService(this, startId); 563 } 564 } 565 } 566 } 567 568 private synchronized void connectIfEnabled(BluetoothDevice device) { 569 CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager, device); 570 List<Profile> profiles = cachedDevice.getConnectableProfiles(); 571 for (int i = 0; i < profiles.size(); i++) { 572 LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 573 .getProfileManager(mBtManager, profiles.get(i)); 574 int auto; 575 if (Profile.A2DP == profiles.get(i)) { 576 auto = BluetoothA2dp.PRIORITY_AUTO_CONNECT; 577 } else if (Profile.HEADSET == profiles.get(i)) { 578 auto = BluetoothHeadset.PRIORITY_AUTO_CONNECT; 579 } else { 580 continue; 581 } 582 583 if (profileManager.getPreferred(device) == auto) { 584 cachedDevice.connect(); 585 break; 586 } 587 } 588 } 589 590 private synchronized void applyBtSettings(final BluetoothDevice device, int startId) { 591 if (device == null || mProfiles == null || mCheckedItems == null) 592 return; 593 594 // Turn on BT if something is enabled 595 synchronized (this) { 596 for (boolean enable : mCheckedItems) { 597 if (enable) { 598 int btState = mBtManager.getBluetoothState(); 599 if(DEBUG) Log.d(TAG, "BtState = " + btState); 600 // May have race condition as the phone comes in and out and in the dock. 601 // Always turn on BT 602 mBtManager.getBluetoothAdapter().enable(); 603 604 switch (btState) { 605 case BluetoothAdapter.STATE_OFF: 606 case BluetoothAdapter.STATE_TURNING_OFF: 607 case BluetoothAdapter.STATE_TURNING_ON: 608 if (mPendingDevice != null && mPendingDevice.equals(mDevice)) { 609 return; 610 } 611 612 mPendingDevice = device; 613 mPendingStartId = startId; 614 if (btState != BluetoothAdapter.STATE_TURNING_ON) { 615 setSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED, true); 616 } 617 return; 618 } 619 } 620 } 621 } 622 623 mPendingDevice = null; 624 625 boolean callConnect = false; 626 CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager, 627 device); 628 for (int i = 0; i < mProfiles.length; i++) { 629 LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 630 .getProfileManager(mBtManager, mProfiles[i]); 631 632 if (DEBUG) Log.d(TAG, mProfiles[i].toString() + " = " + mCheckedItems[i]); 633 634 if (mCheckedItems[i]) { 635 // Checked but not connected 636 callConnect = true; 637 } else if (!mCheckedItems[i]) { 638 // Unchecked but connected 639 if (DEBUG) Log.d(TAG, "applyBtSettings - Disconnecting"); 640 cachedDevice.disconnect(mProfiles[i]); 641 } 642 profileManager.setPreferred(device, mCheckedItems[i]); 643 if (DEBUG) { 644 if (mCheckedItems[i] != profileManager.isPreferred(device)) { 645 Log.e(TAG, "Can't save prefered value"); 646 } 647 } 648 } 649 650 if (callConnect) { 651 if (DEBUG) Log.d(TAG, "applyBtSettings - Connecting"); 652 cachedDevice.connect(); 653 } 654 } 655 656 private synchronized void handleUndocked(Context context, LocalBluetoothManager localManager, 657 BluetoothDevice device) { 658 if (mDialog != null) { 659 mDialog.dismiss(); 660 mDialog = null; 661 } 662 mDevice = null; 663 mPendingDevice = null; 664 CachedBluetoothDevice cachedBluetoothDevice = getCachedBluetoothDevice(context, 665 localManager, device); 666 cachedBluetoothDevice.disconnect(); 667 } 668 669 private static CachedBluetoothDevice getCachedBluetoothDevice(Context context, 670 LocalBluetoothManager localManager, BluetoothDevice device) { 671 CachedBluetoothDeviceManager cachedDeviceManager = localManager.getCachedDeviceManager(); 672 CachedBluetoothDevice cachedBluetoothDevice = cachedDeviceManager.findDevice(device); 673 if (cachedBluetoothDevice == null) { 674 cachedBluetoothDevice = new CachedBluetoothDevice(context, device); 675 } 676 return cachedBluetoothDevice; 677 } 678 679 private boolean getSetting(String key) { 680 SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME, 681 Context.MODE_PRIVATE); 682 return sharedPref.getBoolean(key, false); 683 } 684 685 private void setSetting(String key, boolean disableBt) { 686 SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME, 687 Context.MODE_PRIVATE).edit(); 688 editor.putBoolean(key, disableBt); 689 editor.commit(); 690 } 691 692 private void removeSetting(String key) { 693 SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME, 694 Context.MODE_PRIVATE); 695 SharedPreferences.Editor editor = sharedPref.edit(); 696 editor.remove(key); 697 editor.commit(); 698 return; 699 } 700} 701