Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2011 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.settingslib.bluetooth;
     18 
     19 import android.bluetooth.BluetoothA2dp;
     20 import android.bluetooth.BluetoothA2dpSink;
     21 import android.bluetooth.BluetoothDevice;
     22 import android.bluetooth.BluetoothHeadset;
     23 import android.bluetooth.BluetoothHeadsetClient;
     24 import android.bluetooth.BluetoothHearingAid;
     25 import android.bluetooth.BluetoothHidDevice;
     26 import android.bluetooth.BluetoothHidHost;
     27 import android.bluetooth.BluetoothMap;
     28 import android.bluetooth.BluetoothMapClient;
     29 import android.bluetooth.BluetoothPan;
     30 import android.bluetooth.BluetoothPbap;
     31 import android.bluetooth.BluetoothPbapClient;
     32 import android.bluetooth.BluetoothProfile;
     33 import android.bluetooth.BluetoothUuid;
     34 import android.content.Context;
     35 import android.content.Intent;
     36 import android.os.ParcelUuid;
     37 import android.support.annotation.VisibleForTesting;
     38 import android.util.Log;
     39 import com.android.internal.R;
     40 import java.util.ArrayList;
     41 import java.util.Collection;
     42 import java.util.HashMap;
     43 import java.util.List;
     44 import java.util.Map;
     45 
     46 
     47 /**
     48  * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
     49  * objects for the available Bluetooth profiles.
     50  */
     51 public class LocalBluetoothProfileManager {
     52     private static final String TAG = "LocalBluetoothProfileManager";
     53     private static final boolean DEBUG = Utils.D;
     54     /** Singleton instance. */
     55     private static LocalBluetoothProfileManager sInstance;
     56 
     57     /**
     58      * An interface for notifying BluetoothHeadset IPC clients when they have
     59      * been connected to the BluetoothHeadset service.
     60      * Only used by com.android.settings.bluetooth.DockService.
     61      */
     62     public interface ServiceListener {
     63         /**
     64          * Called to notify the client when this proxy object has been
     65          * connected to the BluetoothHeadset service. Clients must wait for
     66          * this callback before making IPC calls on the BluetoothHeadset
     67          * service.
     68          */
     69         void onServiceConnected();
     70 
     71         /**
     72          * Called to notify the client that this proxy object has been
     73          * disconnected from the BluetoothHeadset service. Clients must not
     74          * make IPC calls on the BluetoothHeadset service after this callback.
     75          * This callback will currently only occur if the application hosting
     76          * the BluetoothHeadset service, but may be called more often in future.
     77          */
     78         void onServiceDisconnected();
     79     }
     80 
     81     private final Context mContext;
     82     private final LocalBluetoothAdapter mLocalAdapter;
     83     private final CachedBluetoothDeviceManager mDeviceManager;
     84     private final BluetoothEventManager mEventManager;
     85 
     86     private A2dpProfile mA2dpProfile;
     87     private A2dpSinkProfile mA2dpSinkProfile;
     88     private HeadsetProfile mHeadsetProfile;
     89     private HfpClientProfile mHfpClientProfile;
     90     private MapProfile mMapProfile;
     91     private MapClientProfile mMapClientProfile;
     92     private final HidProfile mHidProfile;
     93     private HidDeviceProfile mHidDeviceProfile;
     94     private OppProfile mOppProfile;
     95     private final PanProfile mPanProfile;
     96     private PbapClientProfile mPbapClientProfile;
     97     private final PbapServerProfile mPbapProfile;
     98     private final boolean mUsePbapPce;
     99     private final boolean mUseMapClient;
    100     private HearingAidProfile mHearingAidProfile;
    101 
    102     /**
    103      * Mapping from profile name, e.g. "HEADSET" to profile object.
    104      */
    105     private final Map<String, LocalBluetoothProfile>
    106             mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
    107 
    108     LocalBluetoothProfileManager(Context context,
    109             LocalBluetoothAdapter adapter,
    110             CachedBluetoothDeviceManager deviceManager,
    111             BluetoothEventManager eventManager) {
    112         mContext = context;
    113 
    114         mLocalAdapter = adapter;
    115         mDeviceManager = deviceManager;
    116         mEventManager = eventManager;
    117         mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
    118         // MAP Client is typically used in the same situations as PBAP Client
    119         mUseMapClient = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
    120         // pass this reference to adapter and event manager (circular dependency)
    121         mLocalAdapter.setProfileManager(this);
    122         mEventManager.setProfileManager(this);
    123 
    124         ParcelUuid[] uuids = adapter.getUuids();
    125 
    126         // uuids may be null if Bluetooth is turned off
    127         if (uuids != null) {
    128             updateLocalProfiles(uuids);
    129         }
    130 
    131         // Always add HID host, HID device, and PAN profiles
    132         mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this);
    133         addProfile(mHidProfile, HidProfile.NAME,
    134                 BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
    135 
    136         mPanProfile = new PanProfile(context, mLocalAdapter);
    137         addPanProfile(mPanProfile, PanProfile.NAME,
    138                 BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
    139 
    140         mHidDeviceProfile = new HidDeviceProfile(context, mLocalAdapter, mDeviceManager, this);
    141         addProfile(mHidDeviceProfile, HidDeviceProfile.NAME,
    142                 BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
    143 
    144         if(DEBUG) Log.d(TAG, "Adding local MAP profile");
    145         if (mUseMapClient) {
    146             mMapClientProfile = new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
    147             addProfile(mMapClientProfile, MapClientProfile.NAME,
    148                 BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
    149         } else {
    150             mMapProfile = new MapProfile(mContext, mLocalAdapter, mDeviceManager, this);
    151             addProfile(mMapProfile, MapProfile.NAME,
    152                     BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
    153         }
    154 
    155         //Create PBAP server profile
    156         if(DEBUG) Log.d(TAG, "Adding local PBAP profile");
    157 
    158         mPbapProfile = new PbapServerProfile(context);
    159         addProfile(mPbapProfile, PbapServerProfile.NAME,
    160              BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED);
    161 
    162         List<Integer> supportedList = mLocalAdapter.getSupportedProfiles();
    163         if (supportedList.contains(BluetoothProfile.HEARING_AID)) {
    164             mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager,
    165                                                        this);
    166             addProfile(mHearingAidProfile, HearingAidProfile.NAME,
    167                        BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
    168         }
    169         if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
    170     }
    171 
    172     /**
    173      * Initialize or update the local profile objects. If a UUID was previously
    174      * present but has been removed, we print a warning but don't remove the
    175      * profile object as it might be referenced elsewhere, or the UUID might
    176      * come back and we don't want multiple copies of the profile objects.
    177      * @param uuids
    178      */
    179     void updateLocalProfiles(ParcelUuid[] uuids) {
    180         // A2DP SRC
    181         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
    182             if (mA2dpProfile == null) {
    183                 if(DEBUG) Log.d(TAG, "Adding local A2DP SRC profile");
    184                 mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
    185                 addProfile(mA2dpProfile, A2dpProfile.NAME,
    186                         BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
    187             }
    188         } else if (mA2dpProfile != null) {
    189             Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
    190         }
    191 
    192         // A2DP SINK
    193         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
    194             if (mA2dpSinkProfile == null) {
    195                 if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile");
    196                 mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this);
    197                 addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME,
    198                         BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
    199             }
    200         } else if (mA2dpSinkProfile != null) {
    201             Log.w(TAG, "Warning: A2DP Sink profile was previously added but the UUID is now missing.");
    202         }
    203 
    204         // Headset / Handsfree
    205         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
    206             BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
    207             if (mHeadsetProfile == null) {
    208                 if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
    209                 mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
    210                         mDeviceManager, this);
    211                 addHeadsetProfile(mHeadsetProfile, HeadsetProfile.NAME,
    212                         BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
    213                         BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
    214                         BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
    215             }
    216         } else if (mHeadsetProfile != null) {
    217             Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
    218         }
    219 
    220         // Headset HF
    221         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree)) {
    222             if (mHfpClientProfile == null) {
    223                 if(DEBUG) Log.d(TAG, "Adding local HfpClient profile");
    224                 mHfpClientProfile =
    225                     new HfpClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
    226                 addHeadsetProfile(mHfpClientProfile, HfpClientProfile.NAME,
    227                         BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED,
    228                         BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED,
    229                         BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
    230             }
    231         } else if (mHfpClientProfile != null) {
    232             Log.w(TAG,
    233                 "Warning: Hfp Client profile was previously added but the UUID is now missing.");
    234         } else {
    235             Log.d(TAG, "Handsfree Uuid not found.");
    236         }
    237 
    238         // Message Access Profile Client
    239         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.MNS)) {
    240             if (mMapClientProfile == null) {
    241                 if(DEBUG) Log.d(TAG, "Adding local Map Client profile");
    242                 mMapClientProfile =
    243                         new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
    244                 addProfile(mMapClientProfile, MapClientProfile.NAME,
    245                         BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
    246             }
    247         } else if (mMapClientProfile != null) {
    248             Log.w(TAG,
    249                     "Warning: MAP Client profile was previously added but the UUID is now missing.");
    250         } else {
    251             Log.d(TAG, "MAP Client Uuid not found.");
    252         }
    253 
    254         // OPP
    255         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
    256             if (mOppProfile == null) {
    257                 if(DEBUG) Log.d(TAG, "Adding local OPP profile");
    258                 mOppProfile = new OppProfile();
    259                 // Note: no event handler for OPP, only name map.
    260                 mProfileNameMap.put(OppProfile.NAME, mOppProfile);
    261             }
    262         } else if (mOppProfile != null) {
    263             Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
    264         }
    265 
    266         //PBAP Client
    267         if (mUsePbapPce) {
    268             if (mPbapClientProfile == null) {
    269                 if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile");
    270                 mPbapClientProfile = new PbapClientProfile(mContext, mLocalAdapter, mDeviceManager,
    271                         this);
    272                 addProfile(mPbapClientProfile, PbapClientProfile.NAME,
    273                         BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
    274             }
    275         } else if (mPbapClientProfile != null) {
    276             Log.w(TAG,
    277                 "Warning: PBAP Client profile was previously added but the UUID is now missing.");
    278         }
    279 
    280         //Hearing Aid Client
    281         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
    282             if (mHearingAidProfile == null) {
    283                 if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile");
    284                 mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
    285                 addProfile(mHearingAidProfile, HearingAidProfile.NAME,
    286                         BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
    287             }
    288         } else if (mHearingAidProfile != null) {
    289             Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing.");
    290         }
    291 
    292         mEventManager.registerProfileIntentReceiver();
    293 
    294         // There is no local SDP record for HID and Settings app doesn't control PBAP Server.
    295     }
    296 
    297     private void addHeadsetProfile(LocalBluetoothProfile profile, String profileName,
    298             String stateChangedAction, String audioStateChangedAction, int audioDisconnectedState) {
    299         BluetoothEventManager.Handler handler = new HeadsetStateChangeHandler(
    300                 profile, audioStateChangedAction, audioDisconnectedState);
    301         mEventManager.addProfileHandler(stateChangedAction, handler);
    302         mEventManager.addProfileHandler(audioStateChangedAction, handler);
    303         mProfileNameMap.put(profileName, profile);
    304     }
    305 
    306     private final Collection<ServiceListener> mServiceListeners =
    307             new ArrayList<ServiceListener>();
    308 
    309     private void addProfile(LocalBluetoothProfile profile,
    310             String profileName, String stateChangedAction) {
    311         mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile));
    312         mProfileNameMap.put(profileName, profile);
    313     }
    314 
    315     private void addPanProfile(LocalBluetoothProfile profile,
    316             String profileName, String stateChangedAction) {
    317         mEventManager.addProfileHandler(stateChangedAction,
    318                 new PanStateChangedHandler(profile));
    319         mProfileNameMap.put(profileName, profile);
    320     }
    321 
    322     public LocalBluetoothProfile getProfileByName(String name) {
    323         return mProfileNameMap.get(name);
    324     }
    325 
    326     // Called from LocalBluetoothAdapter when state changes to ON
    327     void setBluetoothStateOn() {
    328         ParcelUuid[] uuids = mLocalAdapter.getUuids();
    329         if (uuids != null) {
    330             updateLocalProfiles(uuids);
    331         }
    332         mEventManager.readPairedDevices();
    333     }
    334 
    335     /**
    336      * Generic handler for connection state change events for the specified profile.
    337      */
    338     private class StateChangedHandler implements BluetoothEventManager.Handler {
    339         final LocalBluetoothProfile mProfile;
    340 
    341         StateChangedHandler(LocalBluetoothProfile profile) {
    342             mProfile = profile;
    343         }
    344 
    345         public void onReceive(Context context, Intent intent, BluetoothDevice device) {
    346             CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
    347             if (cachedDevice == null) {
    348                 Log.w(TAG, "StateChangedHandler found new device: " + device);
    349                 cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
    350                         LocalBluetoothProfileManager.this, device);
    351             }
    352             onReceiveInternal(intent, cachedDevice);
    353         }
    354 
    355         protected void onReceiveInternal(Intent intent, CachedBluetoothDevice cachedDevice) {
    356             int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
    357             int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
    358             if (newState == BluetoothProfile.STATE_DISCONNECTED &&
    359                     oldState == BluetoothProfile.STATE_CONNECTING) {
    360                 Log.i(TAG, "Failed to connect " + mProfile + " device");
    361             }
    362 
    363             if (getHearingAidProfile() != null &&
    364                 mProfile instanceof HearingAidProfile &&
    365                 (newState == BluetoothProfile.STATE_CONNECTED)) {
    366                 // Check if the HiSyncID has being initialized
    367                 if (cachedDevice.getHiSyncId() == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
    368 
    369                     long newHiSyncId = getHearingAidProfile().getHiSyncId(cachedDevice.getDevice());
    370 
    371                     if (newHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
    372                         cachedDevice.setHiSyncId(newHiSyncId);
    373                         mDeviceManager.onHiSyncIdChanged(newHiSyncId);
    374                     }
    375                 }
    376             }
    377 
    378             mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
    379                     mProfile.getProfileId());
    380             cachedDevice.onProfileStateChanged(mProfile, newState);
    381             cachedDevice.refresh();
    382         }
    383     }
    384 
    385     /** Connectivity and audio state change handler for headset profiles. */
    386     private class HeadsetStateChangeHandler extends StateChangedHandler {
    387         private final String mAudioChangeAction;
    388         private final int mAudioDisconnectedState;
    389 
    390         HeadsetStateChangeHandler(LocalBluetoothProfile profile, String audioChangeAction,
    391                 int audioDisconnectedState) {
    392             super(profile);
    393             mAudioChangeAction = audioChangeAction;
    394             mAudioDisconnectedState = audioDisconnectedState;
    395         }
    396 
    397         @Override
    398         public void onReceiveInternal(Intent intent, CachedBluetoothDevice cachedDevice) {
    399             if (mAudioChangeAction.equals(intent.getAction())) {
    400                 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
    401                 if (newState != mAudioDisconnectedState) {
    402                     cachedDevice.onProfileStateChanged(mProfile, BluetoothProfile.STATE_CONNECTED);
    403                 }
    404                 cachedDevice.refresh();
    405             } else {
    406                 super.onReceiveInternal(intent, cachedDevice);
    407             }
    408         }
    409     }
    410 
    411     /** State change handler for NAP and PANU profiles. */
    412     private class PanStateChangedHandler extends StateChangedHandler {
    413 
    414         PanStateChangedHandler(LocalBluetoothProfile profile) {
    415             super(profile);
    416         }
    417 
    418         @Override
    419         public void onReceive(Context context, Intent intent, BluetoothDevice device) {
    420             PanProfile panProfile = (PanProfile) mProfile;
    421             int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
    422             panProfile.setLocalRole(device, role);
    423             super.onReceive(context, intent, device);
    424         }
    425     }
    426 
    427     // called from DockService
    428     public void addServiceListener(ServiceListener l) {
    429         mServiceListeners.add(l);
    430     }
    431 
    432     // called from DockService
    433     public void removeServiceListener(ServiceListener l) {
    434         mServiceListeners.remove(l);
    435     }
    436 
    437     // not synchronized: use only from UI thread! (TODO: verify)
    438     void callServiceConnectedListeners() {
    439         for (ServiceListener l : mServiceListeners) {
    440             l.onServiceConnected();
    441         }
    442     }
    443 
    444     // not synchronized: use only from UI thread! (TODO: verify)
    445     void callServiceDisconnectedListeners() {
    446         for (ServiceListener listener : mServiceListeners) {
    447             listener.onServiceDisconnected();
    448         }
    449     }
    450 
    451     // This is called by DockService, so check Headset and A2DP.
    452     public synchronized boolean isManagerReady() {
    453         // Getting just the headset profile is fine for now. Will need to deal with A2DP
    454         // and others if they aren't always in a ready state.
    455         LocalBluetoothProfile profile = mHeadsetProfile;
    456         if (profile != null) {
    457             return profile.isProfileReady();
    458         }
    459         profile = mA2dpProfile;
    460         if (profile != null) {
    461             return profile.isProfileReady();
    462         }
    463         profile = mA2dpSinkProfile;
    464         if (profile != null) {
    465             return profile.isProfileReady();
    466         }
    467         return false;
    468     }
    469 
    470     public A2dpProfile getA2dpProfile() {
    471         return mA2dpProfile;
    472     }
    473 
    474     public A2dpSinkProfile getA2dpSinkProfile() {
    475         if ((mA2dpSinkProfile != null) && (mA2dpSinkProfile.isProfileReady())) {
    476             return mA2dpSinkProfile;
    477         } else {
    478             return null;
    479         }
    480     }
    481 
    482     public HeadsetProfile getHeadsetProfile() {
    483         return mHeadsetProfile;
    484     }
    485 
    486     public HfpClientProfile getHfpClientProfile() {
    487         if ((mHfpClientProfile != null) && (mHfpClientProfile.isProfileReady())) {
    488             return mHfpClientProfile;
    489         } else {
    490           return null;
    491         }
    492     }
    493 
    494     public PbapClientProfile getPbapClientProfile() {
    495         return mPbapClientProfile;
    496     }
    497 
    498     public PbapServerProfile getPbapProfile(){
    499         return mPbapProfile;
    500     }
    501 
    502     public MapProfile getMapProfile(){
    503         return mMapProfile;
    504     }
    505 
    506     public MapClientProfile getMapClientProfile() {
    507         return mMapClientProfile;
    508     }
    509 
    510     public HearingAidProfile getHearingAidProfile() {
    511         return mHearingAidProfile;
    512     }
    513 
    514     @VisibleForTesting
    515     HidProfile getHidProfile() {
    516         return mHidProfile;
    517     }
    518 
    519     @VisibleForTesting
    520     HidDeviceProfile getHidDeviceProfile() {
    521         return mHidDeviceProfile;
    522     }
    523 
    524     /**
    525      * Fill in a list of LocalBluetoothProfile objects that are supported by
    526      * the local device and the remote device.
    527      *
    528      * @param uuids of the remote device
    529      * @param localUuids UUIDs of the local device
    530      * @param profiles The list of profiles to fill
    531      * @param removedProfiles list of profiles that were removed
    532      */
    533     synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
    534             Collection<LocalBluetoothProfile> profiles,
    535             Collection<LocalBluetoothProfile> removedProfiles,
    536             boolean isPanNapConnected, BluetoothDevice device) {
    537         // Copy previous profile list into removedProfiles
    538         removedProfiles.clear();
    539         removedProfiles.addAll(profiles);
    540         if (DEBUG) {
    541             Log.d(TAG,"Current Profiles" + profiles.toString());
    542         }
    543         profiles.clear();
    544 
    545         if (uuids == null) {
    546             return;
    547         }
    548 
    549         if (mHeadsetProfile != null) {
    550             if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
    551                     BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
    552                     (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
    553                             BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
    554                 profiles.add(mHeadsetProfile);
    555                 removedProfiles.remove(mHeadsetProfile);
    556             }
    557         }
    558 
    559         if ((mHfpClientProfile != null) &&
    560                 BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) &&
    561                 BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree)) {
    562             profiles.add(mHfpClientProfile);
    563             removedProfiles.remove(mHfpClientProfile);
    564         }
    565 
    566         if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
    567             mA2dpProfile != null) {
    568             profiles.add(mA2dpProfile);
    569             removedProfiles.remove(mA2dpProfile);
    570         }
    571 
    572         if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) &&
    573                 mA2dpSinkProfile != null) {
    574                 profiles.add(mA2dpSinkProfile);
    575                 removedProfiles.remove(mA2dpSinkProfile);
    576         }
    577 
    578         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
    579             mOppProfile != null) {
    580             profiles.add(mOppProfile);
    581             removedProfiles.remove(mOppProfile);
    582         }
    583 
    584         if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
    585              BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
    586             mHidProfile != null) {
    587             profiles.add(mHidProfile);
    588             removedProfiles.remove(mHidProfile);
    589         }
    590 
    591         if (mHidDeviceProfile != null && mHidDeviceProfile.getConnectionStatus(device)
    592                 != BluetoothProfile.STATE_DISCONNECTED) {
    593             profiles.add(mHidDeviceProfile);
    594             removedProfiles.remove(mHidDeviceProfile);
    595         }
    596 
    597         if(isPanNapConnected)
    598             if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
    599         if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
    600             mPanProfile != null) || isPanNapConnected) {
    601             profiles.add(mPanProfile);
    602             removedProfiles.remove(mPanProfile);
    603         }
    604 
    605         if ((mMapProfile != null) &&
    606             (mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
    607             profiles.add(mMapProfile);
    608             removedProfiles.remove(mMapProfile);
    609             mMapProfile.setPreferred(device, true);
    610         }
    611 
    612         if ((mPbapProfile != null) &&
    613             (mPbapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
    614             profiles.add(mPbapProfile);
    615             removedProfiles.remove(mPbapProfile);
    616             mPbapProfile.setPreferred(device, true);
    617         }
    618 
    619         if (mMapClientProfile != null) {
    620             profiles.add(mMapClientProfile);
    621             removedProfiles.remove(mMapClientProfile);
    622         }
    623 
    624         if (mUsePbapPce) {
    625             profiles.add(mPbapClientProfile);
    626             removedProfiles.remove(mPbapClientProfile);
    627         }
    628 
    629         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) &&
    630             mHearingAidProfile != null) {
    631             profiles.add(mHearingAidProfile);
    632             removedProfiles.remove(mHearingAidProfile);
    633         }
    634 
    635         if (DEBUG) {
    636             Log.d(TAG,"New Profiles" + profiles.toString());
    637         }
    638     }
    639 }
    640