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