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