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