Home | History | Annotate | Download | only in btservice
      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