• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getBroadcastReceiver()137     BroadcastReceiver getBroadcastReceiver() {
138         return mReceiver;
139     }
140 
141     // Handler to handoff intents to class thread
142     class PhonePolicyHandler extends Handler {
PhonePolicyHandler(Looper looper)143         PhonePolicyHandler(Looper looper) {
144             super(looper);
145         }
146 
147         @Override
handleMessage(Message msg)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)
start()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 
cleanup()215     protected void cleanup() {
216         mAdapterService.unregisterReceiver(mReceiver);
217         resetStates();
218     }
219 
PhonePolicy(AdapterService service, ServiceFactory factory)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
processInitProfilePriorities(BluetoothDevice device, ParcelUuid[] uuids)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 
processProfileStateChanged(BluetoothDevice device, int profileId, int nextState, int prevState)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 
processProfileActiveDeviceChanged(BluetoothDevice activeDevice, int profileId)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 
resetStates()329     private void resetStates() {
330         mHeadsetRetrySet.clear();
331         mA2dpRetrySet.clear();
332     }
333 
autoConnect()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 
autoConnectA2dp(BluetoothDevice device)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 
autoConnectHeadset(BluetoothDevice device)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 
connectOtherProfile(BluetoothDevice device)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.
processConnectOtherProfiles(BluetoothDevice device)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      */
setAutoConnectForHeadset(BluetoothDevice device)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      */
setAutoConnectForA2dpSink(BluetoothDevice device)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      */
removeAutoConnectFromHeadset(BluetoothDevice device)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      */
removeAutoConnectFromA2dpSink(BluetoothDevice device)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 
debugLog(String msg)553     private static void debugLog(String msg) {
554         if (DBG) {
555             Log.i(TAG, msg);
556         }
557     }
558 
warnLog(String msg)559     private static void warnLog(String msg) {
560         Log.w(TAG, msg);
561     }
562 
errorLog(String msg)563     private static void errorLog(String msg) {
564         Log.e(TAG, msg);
565     }
566 }
567