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