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
17package com.android.settingslib.bluetooth;
18
19import android.bluetooth.BluetoothA2dp;
20import android.bluetooth.BluetoothA2dpSink;
21import android.bluetooth.BluetoothDevice;
22import android.bluetooth.BluetoothHeadset;
23import android.bluetooth.BluetoothHeadsetClient;
24import android.bluetooth.BluetoothHearingAid;
25import android.bluetooth.BluetoothHidDevice;
26import android.bluetooth.BluetoothHidHost;
27import android.bluetooth.BluetoothMap;
28import android.bluetooth.BluetoothMapClient;
29import android.bluetooth.BluetoothPan;
30import android.bluetooth.BluetoothPbap;
31import android.bluetooth.BluetoothPbapClient;
32import android.bluetooth.BluetoothProfile;
33import android.bluetooth.BluetoothUuid;
34import android.content.Context;
35import android.content.Intent;
36import android.os.ParcelUuid;
37import android.support.annotation.VisibleForTesting;
38import android.util.Log;
39import com.android.internal.R;
40import java.util.ArrayList;
41import java.util.Collection;
42import java.util.HashMap;
43import java.util.List;
44import java.util.Map;
45
46
47/**
48 * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
49 * objects for the available Bluetooth profiles.
50 */
51public 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