1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.btservice; 18 19 import android.bluetooth.BluetoothA2dp; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothDevice; 22 import android.bluetooth.BluetoothHeadset; 23 import android.bluetooth.BluetoothProfile; 24 import android.bluetooth.BluetoothUuid; 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.os.Handler; 30 import android.os.Looper; 31 import android.os.Message; 32 import android.os.ParcelUuid; 33 import android.os.Parcelable; 34 import android.support.annotation.VisibleForTesting; 35 import android.util.Log; 36 37 import com.android.bluetooth.a2dp.A2dpService; 38 import com.android.bluetooth.hearingaid.HearingAidService; 39 import com.android.bluetooth.hfp.HeadsetService; 40 import com.android.bluetooth.hid.HidHostService; 41 import com.android.bluetooth.pan.PanService; 42 import com.android.internal.R; 43 44 import java.util.HashSet; 45 import java.util.List; 46 47 // Describes the phone policy 48 // 49 // The policy should be as decoupled from the stack as possible. In an ideal world we should not 50 // need to have this policy talk with any non-public APIs and one way to enforce that would be to 51 // keep this file outside the Bluetooth process. Unfortunately, keeping a separate process alive is 52 // an expensive and a tedious task. 53 // 54 // Best practices: 55 // a) PhonePolicy should be ALL private methods 56 // -- Use broadcasts which can be listened in on the BroadcastReceiver 57 // b) NEVER call from the PhonePolicy into the Java stack, unless public APIs. It is OK to call into 58 // the non public versions as long as public versions exist (so that a 3rd party policy can mimick) 59 // us. 60 // 61 // Policy description: 62 // 63 // Policies are usually governed by outside events that may warrant an action. We talk about various 64 // events and the resulting outcome from this policy: 65 // 66 // 1. Adapter turned ON: At this point we will try to auto-connect the (device, profile) pairs which 67 // have PRIORITY_AUTO_CONNECT. The fact that we *only* auto-connect Headset and A2DP is something 68 // that is hardcoded and specific to phone policy (see autoConnect() function) 69 // 2. When the profile connection-state changes: At this point if a new profile gets CONNECTED we 70 // will try to connect other profiles on the same device. This is to avoid collision if devices 71 // somehow end up trying to connect at same time or general connection issues. 72 class PhonePolicy { 73 private static final boolean DBG = true; 74 private static final String TAG = "BluetoothPhonePolicy"; 75 76 // Message types for the handler (internal messages generated by intents or timeouts) 77 private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED = 1; 78 private static final int MESSAGE_PROFILE_INIT_PRIORITIES = 2; 79 private static final int MESSAGE_CONNECT_OTHER_PROFILES = 3; 80 private static final int MESSAGE_ADAPTER_STATE_TURNED_ON = 4; 81 private static final int MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED = 5; 82 83 // Timeouts 84 @VisibleForTesting static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s 85 86 private final AdapterService mAdapterService; 87 private final ServiceFactory mFactory; 88 private final Handler mHandler; 89 private final HashSet<BluetoothDevice> mHeadsetRetrySet = new HashSet<>(); 90 private final HashSet<BluetoothDevice> mA2dpRetrySet = new HashSet<>(); 91 private final HashSet<BluetoothDevice> mConnectOtherProfilesDeviceSet = new HashSet<>(); 92 93 // Broadcast receiver for all changes to states of various profiles 94 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 95 @Override 96 public void onReceive(Context context, Intent intent) { 97 String action = intent.getAction(); 98 if (action == null) { 99 errorLog("Received intent with null action"); 100 return; 101 } 102 switch (action) { 103 case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: 104 mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED, 105 BluetoothProfile.HEADSET, -1, // No-op argument 106 intent).sendToTarget(); 107 break; 108 case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED: 109 mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED, 110 BluetoothProfile.A2DP, -1, // No-op argument 111 intent).sendToTarget(); 112 break; 113 case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED: 114 mHandler.obtainMessage(MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED, 115 BluetoothProfile.A2DP, -1, // No-op argument 116 intent).sendToTarget(); 117 break; 118 case BluetoothAdapter.ACTION_STATE_CHANGED: 119 // Only pass the message on if the adapter has actually changed state from 120 // non-ON to ON. NOTE: ON is the state depicting BREDR ON and not just BLE ON. 121 int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); 122 if (newState == BluetoothAdapter.STATE_ON) { 123 mHandler.obtainMessage(MESSAGE_ADAPTER_STATE_TURNED_ON).sendToTarget(); 124 } 125 break; 126 case BluetoothDevice.ACTION_UUID: 127 mHandler.obtainMessage(MESSAGE_PROFILE_INIT_PRIORITIES, intent).sendToTarget(); 128 break; 129 default: 130 Log.e(TAG, "Received unexpected intent, action=" + action); 131 break; 132 } 133 } 134 }; 135 136 @VisibleForTesting 137 BroadcastReceiver getBroadcastReceiver() { 138 return mReceiver; 139 } 140 141 // Handler to handoff intents to class thread 142 class PhonePolicyHandler extends Handler { 143 PhonePolicyHandler(Looper looper) { 144 super(looper); 145 } 146 147 @Override 148 public void handleMessage(Message msg) { 149 switch (msg.what) { 150 case MESSAGE_PROFILE_INIT_PRIORITIES: { 151 Intent intent = (Intent) msg.obj; 152 BluetoothDevice device = 153 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 154 Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID); 155 debugLog("Received ACTION_UUID for device " + device); 156 if (uuids != null) { 157 ParcelUuid[] uuidsToSend = new ParcelUuid[uuids.length]; 158 for (int i = 0; i < uuidsToSend.length; i++) { 159 uuidsToSend[i] = (ParcelUuid) uuids[i]; 160 debugLog("index=" + i + "uuid=" + uuidsToSend[i]); 161 } 162 processInitProfilePriorities(device, uuidsToSend); 163 } 164 } 165 break; 166 167 case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: { 168 Intent intent = (Intent) msg.obj; 169 BluetoothDevice device = 170 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 171 int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); 172 int nextState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 173 processProfileStateChanged(device, msg.arg1, nextState, prevState); 174 } 175 break; 176 177 case MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED: { 178 Intent intent = (Intent) msg.obj; 179 BluetoothDevice activeDevice = 180 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 181 processProfileActiveDeviceChanged(activeDevice, msg.arg1); 182 } 183 break; 184 185 case MESSAGE_CONNECT_OTHER_PROFILES: { 186 // Called when we try connect some profiles in processConnectOtherProfiles but 187 // we send a delayed message to try connecting the remaining profiles 188 BluetoothDevice device = (BluetoothDevice) msg.obj; 189 processConnectOtherProfiles(device); 190 mConnectOtherProfilesDeviceSet.remove(device); 191 break; 192 } 193 case MESSAGE_ADAPTER_STATE_TURNED_ON: 194 // Call auto connect when adapter switches state to ON 195 resetStates(); 196 autoConnect(); 197 break; 198 } 199 } 200 } 201 202 ; 203 204 // Policy API functions for lifecycle management (protected) 205 protected void start() { 206 IntentFilter filter = new IntentFilter(); 207 filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 208 filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 209 filter.addAction(BluetoothDevice.ACTION_UUID); 210 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 211 filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED); 212 mAdapterService.registerReceiver(mReceiver, filter); 213 } 214 215 protected void cleanup() { 216 mAdapterService.unregisterReceiver(mReceiver); 217 resetStates(); 218 } 219 220 PhonePolicy(AdapterService service, ServiceFactory factory) { 221 mAdapterService = service; 222 mFactory = factory; 223 mHandler = new PhonePolicyHandler(service.getMainLooper()); 224 } 225 226 // Policy implementation, all functions MUST be private 227 private void processInitProfilePriorities(BluetoothDevice device, ParcelUuid[] uuids) { 228 debugLog("processInitProfilePriorities() - device " + device); 229 HidHostService hidService = mFactory.getHidHostService(); 230 A2dpService a2dpService = mFactory.getA2dpService(); 231 HeadsetService headsetService = mFactory.getHeadsetService(); 232 PanService panService = mFactory.getPanService(); 233 HearingAidService hearingAidService = mFactory.getHearingAidService(); 234 235 // Set profile priorities only for the profiles discovered on the remote device. 236 // This avoids needless auto-connect attempts to profiles non-existent on the remote device 237 if ((hidService != null) && (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) 238 || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) && ( 239 hidService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)) { 240 hidService.setPriority(device, BluetoothProfile.PRIORITY_ON); 241 } 242 243 // If we do not have a stored priority for HFP/A2DP (all roles) then default to on. 244 if ((headsetService != null) && ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP) 245 || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree)) && ( 246 headsetService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED))) { 247 headsetService.setPriority(device, BluetoothProfile.PRIORITY_ON); 248 } 249 250 if ((a2dpService != null) && (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink) 251 || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AdvAudioDist)) && ( 252 a2dpService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)) { 253 a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON); 254 } 255 256 if ((panService != null) && (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU) && ( 257 panService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED) 258 && mAdapterService.getResources() 259 .getBoolean(R.bool.config_bluetooth_pan_enable_autoconnect))) { 260 panService.setPriority(device, BluetoothProfile.PRIORITY_ON); 261 } 262 263 if ((hearingAidService != null) && BluetoothUuid.isUuidPresent(uuids, 264 BluetoothUuid.HearingAid) && (hearingAidService.getPriority(device) 265 == BluetoothProfile.PRIORITY_UNDEFINED)) { 266 debugLog("setting hearing aid profile priority for device " + device); 267 hearingAidService.setPriority(device, BluetoothProfile.PRIORITY_ON); 268 } 269 } 270 271 private void processProfileStateChanged(BluetoothDevice device, int profileId, int nextState, 272 int prevState) { 273 debugLog("processProfileStateChanged, device=" + device + ", profile=" + profileId + ", " 274 + prevState + " -> " + nextState); 275 if (((profileId == BluetoothProfile.A2DP) || (profileId == BluetoothProfile.HEADSET))) { 276 if (nextState == BluetoothProfile.STATE_CONNECTED) { 277 switch (profileId) { 278 case BluetoothProfile.A2DP: 279 mA2dpRetrySet.remove(device); 280 break; 281 case BluetoothProfile.HEADSET: 282 mHeadsetRetrySet.remove(device); 283 break; 284 } 285 connectOtherProfile(device); 286 } 287 if (prevState == BluetoothProfile.STATE_CONNECTING 288 && nextState == BluetoothProfile.STATE_DISCONNECTED) { 289 HeadsetService hsService = mFactory.getHeadsetService(); 290 boolean hsDisconnected = hsService == null || hsService.getConnectionState(device) 291 == BluetoothProfile.STATE_DISCONNECTED; 292 A2dpService a2dpService = mFactory.getA2dpService(); 293 boolean a2dpDisconnected = a2dpService == null 294 || a2dpService.getConnectionState(device) 295 == BluetoothProfile.STATE_DISCONNECTED; 296 debugLog("processProfileStateChanged, device=" + device + ", a2dpDisconnected=" 297 + a2dpDisconnected + ", hsDisconnected=" + hsDisconnected); 298 if (hsDisconnected && a2dpDisconnected) { 299 removeAutoConnectFromA2dpSink(device); 300 removeAutoConnectFromHeadset(device); 301 } 302 } 303 } 304 } 305 306 private void processProfileActiveDeviceChanged(BluetoothDevice activeDevice, int profileId) { 307 debugLog("processProfileActiveDeviceChanged, activeDevice=" + activeDevice + ", profile=" 308 + profileId); 309 switch (profileId) { 310 // Tracking active device changed intent only for A2DP so that we always connect to a 311 // single device after toggling Bluetooth 312 case BluetoothProfile.A2DP: 313 // Ignore null active device since we don't know if the change is triggered by 314 // normal device disconnection during Bluetooth shutdown or user action 315 if (activeDevice == null) { 316 warnLog("processProfileActiveDeviceChanged: ignore null A2DP active device"); 317 return; 318 } 319 for (BluetoothDevice device : mAdapterService.getBondedDevices()) { 320 removeAutoConnectFromA2dpSink(device); 321 removeAutoConnectFromHeadset(device); 322 } 323 setAutoConnectForA2dpSink(activeDevice); 324 setAutoConnectForHeadset(activeDevice); 325 break; 326 } 327 } 328 329 private void resetStates() { 330 mHeadsetRetrySet.clear(); 331 mA2dpRetrySet.clear(); 332 } 333 334 private void autoConnect() { 335 if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) { 336 errorLog("autoConnect: BT is not ON. Exiting autoConnect"); 337 return; 338 } 339 340 if (!mAdapterService.isQuietModeEnabled()) { 341 debugLog("autoConnect: Initiate auto connection on BT on..."); 342 final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices(); 343 if (bondedDevices == null) { 344 errorLog("autoConnect: bondedDevices are null"); 345 return; 346 } 347 for (BluetoothDevice device : bondedDevices) { 348 autoConnectHeadset(device); 349 autoConnectA2dp(device); 350 } 351 } else { 352 debugLog("autoConnect() - BT is in quiet mode. Not initiating auto connections"); 353 } 354 } 355 356 private void autoConnectA2dp(BluetoothDevice device) { 357 final A2dpService a2dpService = mFactory.getA2dpService(); 358 if (a2dpService == null) { 359 warnLog("autoConnectA2dp: service is null, failed to connect to " + device); 360 return; 361 } 362 int a2dpPriority = a2dpService.getPriority(device); 363 if (a2dpPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) { 364 debugLog("autoConnectA2dp: connecting A2DP with " + device); 365 a2dpService.connect(device); 366 } else { 367 debugLog("autoConnectA2dp: skipped auto-connect A2DP with device " + device 368 + " priority " + a2dpPriority); 369 } 370 } 371 372 private void autoConnectHeadset(BluetoothDevice device) { 373 final HeadsetService hsService = mFactory.getHeadsetService(); 374 if (hsService == null) { 375 warnLog("autoConnectHeadset: service is null, failed to connect to " + device); 376 return; 377 } 378 int headsetPriority = hsService.getPriority(device); 379 if (headsetPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) { 380 debugLog("autoConnectHeadset: Connecting HFP with " + device); 381 hsService.connect(device); 382 } else { 383 debugLog("autoConnectHeadset: skipped auto-connect HFP with device " + device 384 + " priority " + headsetPriority); 385 } 386 } 387 388 private void connectOtherProfile(BluetoothDevice device) { 389 if (mAdapterService.isQuietModeEnabled()) { 390 debugLog("connectOtherProfile: in quiet mode, skip connect other profile " + device); 391 return; 392 } 393 if (mConnectOtherProfilesDeviceSet.contains(device)) { 394 debugLog("connectOtherProfile: already scheduled callback for " + device); 395 return; 396 } 397 mConnectOtherProfilesDeviceSet.add(device); 398 Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES); 399 m.obj = device; 400 mHandler.sendMessageDelayed(m, sConnectOtherProfilesTimeoutMillis); 401 } 402 403 // This function is called whenever a profile is connected. This allows any other bluetooth 404 // profiles which are not already connected or in the process of connecting to attempt to 405 // connect to the device that initiated the connection. In the event that this function is 406 // invoked and there are no current bluetooth connections no new profiles will be connected. 407 private void processConnectOtherProfiles(BluetoothDevice device) { 408 debugLog("processConnectOtherProfiles, device=" + device); 409 if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) { 410 warnLog("processConnectOtherProfiles, adapter is not ON " + mAdapterService.getState()); 411 return; 412 } 413 HeadsetService hsService = mFactory.getHeadsetService(); 414 A2dpService a2dpService = mFactory.getA2dpService(); 415 PanService panService = mFactory.getPanService(); 416 417 boolean atLeastOneProfileConnectedForDevice = false; 418 boolean allProfilesEmpty = true; 419 List<BluetoothDevice> a2dpConnDevList = null; 420 List<BluetoothDevice> hsConnDevList = null; 421 List<BluetoothDevice> panConnDevList = null; 422 423 if (hsService != null) { 424 hsConnDevList = hsService.getConnectedDevices(); 425 allProfilesEmpty &= hsConnDevList.isEmpty(); 426 atLeastOneProfileConnectedForDevice |= hsConnDevList.contains(device); 427 } 428 if (a2dpService != null) { 429 a2dpConnDevList = a2dpService.getConnectedDevices(); 430 allProfilesEmpty &= a2dpConnDevList.isEmpty(); 431 atLeastOneProfileConnectedForDevice |= a2dpConnDevList.contains(device); 432 } 433 if (panService != null) { 434 panConnDevList = panService.getConnectedDevices(); 435 allProfilesEmpty &= panConnDevList.isEmpty(); 436 atLeastOneProfileConnectedForDevice |= panConnDevList.contains(device); 437 } 438 439 if (!atLeastOneProfileConnectedForDevice) { 440 // Consider this device as fully disconnected, don't bother connecting others 441 debugLog("processConnectOtherProfiles, all profiles disconnected for " + device); 442 mHeadsetRetrySet.remove(device); 443 mA2dpRetrySet.remove(device); 444 if (allProfilesEmpty) { 445 debugLog("processConnectOtherProfiles, all profiles disconnected for all devices"); 446 // reset retry status so that in the next round we can start retrying connections 447 resetStates(); 448 } 449 return; 450 } 451 452 if (hsService != null) { 453 if (!mHeadsetRetrySet.contains(device) && (hsService.getPriority(device) 454 >= BluetoothProfile.PRIORITY_ON) && (hsService.getConnectionState(device) 455 == BluetoothProfile.STATE_DISCONNECTED)) { 456 debugLog("Retrying connection to Headset with device " + device); 457 mHeadsetRetrySet.add(device); 458 hsService.connect(device); 459 } 460 } 461 if (a2dpService != null) { 462 if (!mA2dpRetrySet.contains(device) && (a2dpService.getPriority(device) 463 >= BluetoothProfile.PRIORITY_ON) && (a2dpService.getConnectionState(device) 464 == BluetoothProfile.STATE_DISCONNECTED)) { 465 debugLog("Retrying connection to A2DP with device " + device); 466 mA2dpRetrySet.add(device); 467 a2dpService.connect(device); 468 } 469 } 470 if (panService != null) { 471 // TODO: the panConnDevList.isEmpty() check below should be removed once 472 // Multi-PAN is supported. 473 if (panConnDevList.isEmpty() && (panService.getPriority(device) 474 >= BluetoothProfile.PRIORITY_ON) && (panService.getConnectionState(device) 475 == BluetoothProfile.STATE_DISCONNECTED)) { 476 debugLog("Retrying connection to PAN with device " + device); 477 panService.connect(device); 478 } 479 } 480 } 481 482 /** 483 * Set a device's headset profile priority to PRIORITY_AUTO_CONNECT if device support that 484 * profile 485 * 486 * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT 487 */ 488 private void setAutoConnectForHeadset(BluetoothDevice device) { 489 HeadsetService hsService = mFactory.getHeadsetService(); 490 if (hsService == null) { 491 warnLog("setAutoConnectForHeadset: HEADSET service is null"); 492 return; 493 } 494 if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) { 495 debugLog("setAutoConnectForHeadset: device " + device + " PRIORITY_AUTO_CONNECT"); 496 hsService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT); 497 } 498 } 499 500 /** 501 * Set a device's A2DP profile priority to PRIORITY_AUTO_CONNECT if device support that profile 502 * 503 * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT 504 */ 505 private void setAutoConnectForA2dpSink(BluetoothDevice device) { 506 A2dpService a2dpService = mFactory.getA2dpService(); 507 if (a2dpService == null) { 508 warnLog("setAutoConnectForA2dpSink: A2DP service is null"); 509 return; 510 } 511 if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) { 512 debugLog("setAutoConnectForA2dpSink: device " + device + " PRIORITY_AUTO_CONNECT"); 513 a2dpService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT); 514 } 515 } 516 517 /** 518 * Remove PRIORITY_AUTO_CONNECT from all headsets and set headset that used to have 519 * PRIORITY_AUTO_CONNECT to PRIORITY_ON 520 * 521 * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed 522 */ 523 private void removeAutoConnectFromHeadset(BluetoothDevice device) { 524 HeadsetService hsService = mFactory.getHeadsetService(); 525 if (hsService == null) { 526 warnLog("removeAutoConnectFromHeadset: HEADSET service is null"); 527 return; 528 } 529 if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) { 530 debugLog("removeAutoConnectFromHeadset: device " + device + " PRIORITY_ON"); 531 hsService.setPriority(device, BluetoothProfile.PRIORITY_ON); 532 } 533 } 534 535 /** 536 * Remove PRIORITY_AUTO_CONNECT from all A2DP sinks and set A2DP sink that used to have 537 * PRIORITY_AUTO_CONNECT to PRIORITY_ON 538 * 539 * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed 540 */ 541 private void removeAutoConnectFromA2dpSink(BluetoothDevice device) { 542 A2dpService a2dpService = mFactory.getA2dpService(); 543 if (a2dpService == null) { 544 warnLog("removeAutoConnectFromA2dpSink: A2DP service is null"); 545 return; 546 } 547 if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) { 548 debugLog("removeAutoConnectFromA2dpSink: device " + device + " PRIORITY_ON"); 549 a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON); 550 } 551 } 552 553 private static void debugLog(String msg) { 554 if (DBG) { 555 Log.i(TAG, msg); 556 } 557 } 558 559 private static void warnLog(String msg) { 560 Log.w(TAG, msg); 561 } 562 563 private static void errorLog(String msg) { 564 Log.e(TAG, msg); 565 } 566 } 567