blob: 6413aab0c0da43023d58a31a797e2c1ab225617d [file] [log] [blame]
Jason Monk7ce96b92015-02-02 11:27:58 -05001/*
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;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070020import android.bluetooth.BluetoothA2dpSink;
Jason Monk7ce96b92015-02-02 11:27:58 -050021import android.bluetooth.BluetoothDevice;
22import android.bluetooth.BluetoothHeadset;
Sanket Agarwalf8a1c912016-01-26 20:12:52 -080023import android.bluetooth.BluetoothHeadsetClient;
Jakub Pawlowskiea580fa2017-11-22 11:02:34 -080024import android.bluetooth.BluetoothHearingAid;
Hansong Zhangdcae2932017-11-13 10:56:23 -080025import android.bluetooth.BluetoothHidDevice;
Hansong Zhang0edf7542017-10-20 15:55:59 -070026import android.bluetooth.BluetoothHidHost;
Jason Monk7ce96b92015-02-02 11:27:58 -050027import android.bluetooth.BluetoothMap;
Joseph Pirozzo631768d2016-09-01 14:19:28 -070028import android.bluetooth.BluetoothMapClient;
Jason Monk7ce96b92015-02-02 11:27:58 -050029import android.bluetooth.BluetoothPan;
Hemant Guptadbc3d8d2017-05-12 21:14:44 +053030import android.bluetooth.BluetoothPbap;
Joseph Pirozzo563c7002016-03-21 15:49:48 -070031import android.bluetooth.BluetoothPbapClient;
Jason Monk7ce96b92015-02-02 11:27:58 -050032import android.bluetooth.BluetoothProfile;
33import android.bluetooth.BluetoothUuid;
34import android.content.Context;
35import android.content.Intent;
36import android.os.ParcelUuid;
37import android.util.Log;
Andrew Sapperstein7aeb3f52017-04-19 20:03:42 -070038import com.android.internal.R;
Jason Monk7ce96b92015-02-02 11:27:58 -050039import java.util.ArrayList;
40import java.util.Collection;
41import java.util.HashMap;
42import java.util.Map;
Jason Monk7ce96b92015-02-02 11:27:58 -050043
44/**
45 * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
46 * objects for the available Bluetooth profiles.
47 */
Antony Sargent374d2592017-04-20 11:23:34 -070048public class LocalBluetoothProfileManager {
Jason Monk7ce96b92015-02-02 11:27:58 -050049 private static final String TAG = "LocalBluetoothProfileManager";
50 private static final boolean DEBUG = Utils.D;
51 /** Singleton instance. */
52 private static LocalBluetoothProfileManager sInstance;
53
54 /**
55 * An interface for notifying BluetoothHeadset IPC clients when they have
56 * been connected to the BluetoothHeadset service.
57 * Only used by com.android.settings.bluetooth.DockService.
58 */
59 public interface ServiceListener {
60 /**
61 * Called to notify the client when this proxy object has been
62 * connected to the BluetoothHeadset service. Clients must wait for
63 * this callback before making IPC calls on the BluetoothHeadset
64 * service.
65 */
66 void onServiceConnected();
67
68 /**
69 * Called to notify the client that this proxy object has been
70 * disconnected from the BluetoothHeadset service. Clients must not
71 * make IPC calls on the BluetoothHeadset service after this callback.
72 * This callback will currently only occur if the application hosting
73 * the BluetoothHeadset service, but may be called more often in future.
74 */
75 void onServiceDisconnected();
76 }
77
78 private final Context mContext;
79 private final LocalBluetoothAdapter mLocalAdapter;
80 private final CachedBluetoothDeviceManager mDeviceManager;
81 private final BluetoothEventManager mEventManager;
82
83 private A2dpProfile mA2dpProfile;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -070084 private A2dpSinkProfile mA2dpSinkProfile;
Jason Monk7ce96b92015-02-02 11:27:58 -050085 private HeadsetProfile mHeadsetProfile;
Sanket Agarwalf8a1c912016-01-26 20:12:52 -080086 private HfpClientProfile mHfpClientProfile;
Jason Monk7ce96b92015-02-02 11:27:58 -050087 private MapProfile mMapProfile;
Joseph Pirozzo631768d2016-09-01 14:19:28 -070088 private MapClientProfile mMapClientProfile;
Jason Monk7ce96b92015-02-02 11:27:58 -050089 private final HidProfile mHidProfile;
Hansong Zhangdcae2932017-11-13 10:56:23 -080090 private HidDeviceProfile mHidDeviceProfile;
Jason Monk7ce96b92015-02-02 11:27:58 -050091 private OppProfile mOppProfile;
92 private final PanProfile mPanProfile;
Joseph Pirozzo563c7002016-03-21 15:49:48 -070093 private PbapClientProfile mPbapClientProfile;
Jason Monk7ce96b92015-02-02 11:27:58 -050094 private final PbapServerProfile mPbapProfile;
Joseph Pirozzo563c7002016-03-21 15:49:48 -070095 private final boolean mUsePbapPce;
Joseph Pirozzo631768d2016-09-01 14:19:28 -070096 private final boolean mUseMapClient;
Jakub Pawlowskiea580fa2017-11-22 11:02:34 -080097 private HearingAidProfile mHearingAidProfile;
Jason Monk7ce96b92015-02-02 11:27:58 -050098
99 /**
100 * Mapping from profile name, e.g. "HEADSET" to profile object.
101 */
102 private final Map<String, LocalBluetoothProfile>
103 mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
104
105 LocalBluetoothProfileManager(Context context,
106 LocalBluetoothAdapter adapter,
107 CachedBluetoothDeviceManager deviceManager,
108 BluetoothEventManager eventManager) {
109 mContext = context;
110
111 mLocalAdapter = adapter;
112 mDeviceManager = deviceManager;
113 mEventManager = eventManager;
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700114 mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
Joseph Pirozzo631768d2016-09-01 14:19:28 -0700115 // MAP Client is typically used in the same situations as PBAP Client
116 mUseMapClient = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
Jason Monk7ce96b92015-02-02 11:27:58 -0500117 // pass this reference to adapter and event manager (circular dependency)
118 mLocalAdapter.setProfileManager(this);
119 mEventManager.setProfileManager(this);
120
121 ParcelUuid[] uuids = adapter.getUuids();
122
123 // uuids may be null if Bluetooth is turned off
124 if (uuids != null) {
125 updateLocalProfiles(uuids);
126 }
127
Hansong Zhangdcae2932017-11-13 10:56:23 -0800128 // Always add HID host, HID device, and PAN profiles
Jason Monk7ce96b92015-02-02 11:27:58 -0500129 mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this);
130 addProfile(mHidProfile, HidProfile.NAME,
Hansong Zhang0edf7542017-10-20 15:55:59 -0700131 BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
Jason Monk7ce96b92015-02-02 11:27:58 -0500132
133 mPanProfile = new PanProfile(context);
134 addPanProfile(mPanProfile, PanProfile.NAME,
135 BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
136
Hansong Zhangdcae2932017-11-13 10:56:23 -0800137 mHidDeviceProfile = new HidDeviceProfile(context, mLocalAdapter, mDeviceManager, this);
138 addProfile(mHidDeviceProfile, HidDeviceProfile.NAME,
139 BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
140
Jason Monk7ce96b92015-02-02 11:27:58 -0500141 if(DEBUG) Log.d(TAG, "Adding local MAP profile");
Joseph Pirozzo631768d2016-09-01 14:19:28 -0700142 if (mUseMapClient) {
143 mMapClientProfile = new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
144 addProfile(mMapClientProfile, MapClientProfile.NAME,
145 BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
146 } else {
147 mMapProfile = new MapProfile(mContext, mLocalAdapter, mDeviceManager, this);
148 addProfile(mMapProfile, MapProfile.NAME,
149 BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
150 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500151
Hemant Guptadbc3d8d2017-05-12 21:14:44 +0530152 //Create PBAP server profile
153 if(DEBUG) Log.d(TAG, "Adding local PBAP profile");
Jakub Pawlowskiea580fa2017-11-22 11:02:34 -0800154
Jason Monk7ce96b92015-02-02 11:27:58 -0500155 mPbapProfile = new PbapServerProfile(context);
Hemant Guptadbc3d8d2017-05-12 21:14:44 +0530156 addProfile(mPbapProfile, PbapServerProfile.NAME,
157 BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED);
Jason Monk7ce96b92015-02-02 11:27:58 -0500158
Jakub Pawlowskiea580fa2017-11-22 11:02:34 -0800159 mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
160 addProfile(mHearingAidProfile, HearingAidProfile.NAME,
161 BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
Jason Monk7ce96b92015-02-02 11:27:58 -0500162 if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
163 }
164
165 /**
166 * Initialize or update the local profile objects. If a UUID was previously
167 * present but has been removed, we print a warning but don't remove the
168 * profile object as it might be referenced elsewhere, or the UUID might
169 * come back and we don't want multiple copies of the profile objects.
170 * @param uuids
171 */
172 void updateLocalProfiles(ParcelUuid[] uuids) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700173 // A2DP SRC
Jason Monk7ce96b92015-02-02 11:27:58 -0500174 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
175 if (mA2dpProfile == null) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700176 if(DEBUG) Log.d(TAG, "Adding local A2DP SRC profile");
Jason Monk7ce96b92015-02-02 11:27:58 -0500177 mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
178 addProfile(mA2dpProfile, A2dpProfile.NAME,
179 BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
180 }
181 } else if (mA2dpProfile != null) {
182 Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
183 }
184
Sanket Agarwalf8a1c912016-01-26 20:12:52 -0800185 // A2DP SINK
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700186 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
187 if (mA2dpSinkProfile == null) {
188 if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile");
189 mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this);
190 addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME,
191 BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
192 }
193 } else if (mA2dpSinkProfile != null) {
194 Log.w(TAG, "Warning: A2DP Sink profile was previously added but the UUID is now missing.");
195 }
196
Jason Monk7ce96b92015-02-02 11:27:58 -0500197 // Headset / Handsfree
198 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
199 BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
200 if (mHeadsetProfile == null) {
201 if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
202 mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
203 mDeviceManager, this);
Amin Shaikhddcb7df2018-04-05 14:05:56 -0400204 addHeadsetProfile(mHeadsetProfile, HeadsetProfile.NAME,
205 BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
206 BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
207 BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
Jason Monk7ce96b92015-02-02 11:27:58 -0500208 }
209 } else if (mHeadsetProfile != null) {
210 Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
211 }
212
Sanket Agarwalf8a1c912016-01-26 20:12:52 -0800213 // Headset HF
214 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree)) {
215 if (mHfpClientProfile == null) {
216 if(DEBUG) Log.d(TAG, "Adding local HfpClient profile");
217 mHfpClientProfile =
218 new HfpClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
Amin Shaikhddcb7df2018-04-05 14:05:56 -0400219 addHeadsetProfile(mHfpClientProfile, HfpClientProfile.NAME,
220 BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED,
221 BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED,
222 BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
Sanket Agarwalf8a1c912016-01-26 20:12:52 -0800223 }
224 } else if (mHfpClientProfile != null) {
225 Log.w(TAG,
226 "Warning: Hfp Client profile was previously added but the UUID is now missing.");
227 } else {
228 Log.d(TAG, "Handsfree Uuid not found.");
229 }
230
Joseph Pirozzo631768d2016-09-01 14:19:28 -0700231 // Message Access Profile Client
232 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.MNS)) {
233 if (mMapClientProfile == null) {
234 if(DEBUG) Log.d(TAG, "Adding local Map Client profile");
235 mMapClientProfile =
236 new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
237 addProfile(mMapClientProfile, MapClientProfile.NAME,
238 BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
239 }
240 } else if (mMapClientProfile != null) {
241 Log.w(TAG,
242 "Warning: MAP Client profile was previously added but the UUID is now missing.");
243 } else {
244 Log.d(TAG, "MAP Client Uuid not found.");
245 }
246
Jason Monk7ce96b92015-02-02 11:27:58 -0500247 // OPP
248 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
249 if (mOppProfile == null) {
250 if(DEBUG) Log.d(TAG, "Adding local OPP profile");
251 mOppProfile = new OppProfile();
252 // Note: no event handler for OPP, only name map.
253 mProfileNameMap.put(OppProfile.NAME, mOppProfile);
254 }
255 } else if (mOppProfile != null) {
256 Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
257 }
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700258
259 //PBAP Client
260 if (mUsePbapPce) {
261 if (mPbapClientProfile == null) {
262 if(DEBUG) Log.d(TAG, "Adding local PBAP Client profile");
263 mPbapClientProfile = new PbapClientProfile(mContext, mLocalAdapter, mDeviceManager,
264 this);
265 addProfile(mPbapClientProfile, PbapClientProfile.NAME,
266 BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
267 }
268 } else if (mPbapClientProfile != null) {
269 Log.w(TAG,
270 "Warning: PBAP Client profile was previously added but the UUID is now missing.");
271 }
272
Jakub Pawlowskiea580fa2017-11-22 11:02:34 -0800273 //Hearing Aid Client
274 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
275 if (mHearingAidProfile == null) {
276 if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile");
277 mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
278 addProfile(mHearingAidProfile, HearingAidProfile.NAME,
279 BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
280 }
281 } else if (mHearingAidProfile != null) {
282 Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing.");
283 }
284
Jason Monk7ce96b92015-02-02 11:27:58 -0500285 mEventManager.registerProfileIntentReceiver();
286
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700287 // There is no local SDP record for HID and Settings app doesn't control PBAP Server.
Jason Monk7ce96b92015-02-02 11:27:58 -0500288 }
289
Amin Shaikhddcb7df2018-04-05 14:05:56 -0400290 private void addHeadsetProfile(LocalBluetoothProfile profile, String profileName,
291 String stateChangedAction, String audioStateChangedAction, int audioDisconnectedState) {
292 BluetoothEventManager.Handler handler = new HeadsetStateChangeHandler(
293 profile, audioStateChangedAction, audioDisconnectedState);
294 mEventManager.addProfileHandler(stateChangedAction, handler);
295 mEventManager.addProfileHandler(audioStateChangedAction, handler);
296 mProfileNameMap.put(profileName, profile);
297 }
298
Jason Monk7ce96b92015-02-02 11:27:58 -0500299 private final Collection<ServiceListener> mServiceListeners =
300 new ArrayList<ServiceListener>();
301
302 private void addProfile(LocalBluetoothProfile profile,
303 String profileName, String stateChangedAction) {
304 mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile));
305 mProfileNameMap.put(profileName, profile);
306 }
307
308 private void addPanProfile(LocalBluetoothProfile profile,
309 String profileName, String stateChangedAction) {
310 mEventManager.addProfileHandler(stateChangedAction,
311 new PanStateChangedHandler(profile));
312 mProfileNameMap.put(profileName, profile);
313 }
314
315 public LocalBluetoothProfile getProfileByName(String name) {
316 return mProfileNameMap.get(name);
317 }
318
319 // Called from LocalBluetoothAdapter when state changes to ON
320 void setBluetoothStateOn() {
321 ParcelUuid[] uuids = mLocalAdapter.getUuids();
322 if (uuids != null) {
323 updateLocalProfiles(uuids);
324 }
325 mEventManager.readPairedDevices();
326 }
327
328 /**
329 * Generic handler for connection state change events for the specified profile.
330 */
331 private class StateChangedHandler implements BluetoothEventManager.Handler {
332 final LocalBluetoothProfile mProfile;
333
334 StateChangedHandler(LocalBluetoothProfile profile) {
335 mProfile = profile;
336 }
337
338 public void onReceive(Context context, Intent intent, BluetoothDevice device) {
339 CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
340 if (cachedDevice == null) {
341 Log.w(TAG, "StateChangedHandler found new device: " + device);
342 cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
343 LocalBluetoothProfileManager.this, device);
344 }
Amin Shaikhddcb7df2018-04-05 14:05:56 -0400345 onReceiveInternal(intent, cachedDevice);
346 }
347
348 protected void onReceiveInternal(Intent intent, CachedBluetoothDevice cachedDevice) {
Jason Monk7ce96b92015-02-02 11:27:58 -0500349 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
350 int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
351 if (newState == BluetoothProfile.STATE_DISCONNECTED &&
352 oldState == BluetoothProfile.STATE_CONNECTING) {
353 Log.i(TAG, "Failed to connect " + mProfile + " device");
354 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500355 cachedDevice.onProfileStateChanged(mProfile, newState);
356 cachedDevice.refresh();
357 }
358 }
359
Amin Shaikhddcb7df2018-04-05 14:05:56 -0400360 /** Connectivity and audio state change handler for headset profiles. */
361 private class HeadsetStateChangeHandler extends StateChangedHandler {
362 private final String mAudioChangeAction;
363 private final int mAudioDisconnectedState;
364
365 HeadsetStateChangeHandler(LocalBluetoothProfile profile, String audioChangeAction,
366 int audioDisconnectedState) {
367 super(profile);
368 mAudioChangeAction = audioChangeAction;
369 mAudioDisconnectedState = audioDisconnectedState;
370 }
371
372 @Override
373 public void onReceiveInternal(Intent intent, CachedBluetoothDevice cachedDevice) {
374 if (mAudioChangeAction.equals(intent.getAction())) {
375 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
376 if (newState != mAudioDisconnectedState) {
377 cachedDevice.onProfileStateChanged(mProfile, BluetoothProfile.STATE_CONNECTED);
378 }
379 cachedDevice.refresh();
380 } else {
381 super.onReceiveInternal(intent, cachedDevice);
382 }
383 }
384 }
385
Jason Monk7ce96b92015-02-02 11:27:58 -0500386 /** State change handler for NAP and PANU profiles. */
387 private class PanStateChangedHandler extends StateChangedHandler {
388
389 PanStateChangedHandler(LocalBluetoothProfile profile) {
390 super(profile);
391 }
392
393 @Override
394 public void onReceive(Context context, Intent intent, BluetoothDevice device) {
395 PanProfile panProfile = (PanProfile) mProfile;
396 int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
397 panProfile.setLocalRole(device, role);
398 super.onReceive(context, intent, device);
399 }
400 }
401
402 // called from DockService
403 public void addServiceListener(ServiceListener l) {
404 mServiceListeners.add(l);
405 }
406
407 // called from DockService
408 public void removeServiceListener(ServiceListener l) {
409 mServiceListeners.remove(l);
410 }
411
412 // not synchronized: use only from UI thread! (TODO: verify)
413 void callServiceConnectedListeners() {
414 for (ServiceListener l : mServiceListeners) {
415 l.onServiceConnected();
416 }
417 }
418
419 // not synchronized: use only from UI thread! (TODO: verify)
420 void callServiceDisconnectedListeners() {
421 for (ServiceListener listener : mServiceListeners) {
422 listener.onServiceDisconnected();
423 }
424 }
425
426 // This is called by DockService, so check Headset and A2DP.
427 public synchronized boolean isManagerReady() {
428 // Getting just the headset profile is fine for now. Will need to deal with A2DP
429 // and others if they aren't always in a ready state.
430 LocalBluetoothProfile profile = mHeadsetProfile;
431 if (profile != null) {
432 return profile.isProfileReady();
433 }
434 profile = mA2dpProfile;
435 if (profile != null) {
436 return profile.isProfileReady();
437 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700438 profile = mA2dpSinkProfile;
439 if (profile != null) {
440 return profile.isProfileReady();
441 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500442 return false;
443 }
444
445 public A2dpProfile getA2dpProfile() {
446 return mA2dpProfile;
447 }
448
Sanket Agarwalf8a1c912016-01-26 20:12:52 -0800449 public A2dpSinkProfile getA2dpSinkProfile() {
450 if ((mA2dpSinkProfile != null) && (mA2dpSinkProfile.isProfileReady())) {
451 return mA2dpSinkProfile;
452 } else {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700453 return null;
Sanket Agarwalf8a1c912016-01-26 20:12:52 -0800454 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700455 }
456
Jason Monk7ce96b92015-02-02 11:27:58 -0500457 public HeadsetProfile getHeadsetProfile() {
458 return mHeadsetProfile;
459 }
460
Sanket Agarwalf8a1c912016-01-26 20:12:52 -0800461 public HfpClientProfile getHfpClientProfile() {
462 if ((mHfpClientProfile != null) && (mHfpClientProfile.isProfileReady())) {
463 return mHfpClientProfile;
464 } else {
465 return null;
466 }
467 }
468
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700469 public PbapClientProfile getPbapClientProfile() {
470 return mPbapClientProfile;
471 }
472
Jason Monk7ce96b92015-02-02 11:27:58 -0500473 public PbapServerProfile getPbapProfile(){
474 return mPbapProfile;
475 }
476
477 public MapProfile getMapProfile(){
478 return mMapProfile;
479 }
480
Joseph Pirozzo631768d2016-09-01 14:19:28 -0700481 public MapClientProfile getMapClientProfile() {
482 return mMapClientProfile;
483 }
484
Jakub Pawlowskiea580fa2017-11-22 11:02:34 -0800485 public HearingAidProfile getHearingAidProfile() {
486 return mHearingAidProfile;
487 }
488
Jason Monk7ce96b92015-02-02 11:27:58 -0500489 /**
490 * Fill in a list of LocalBluetoothProfile objects that are supported by
491 * the local device and the remote device.
492 *
493 * @param uuids of the remote device
494 * @param localUuids UUIDs of the local device
495 * @param profiles The list of profiles to fill
496 * @param removedProfiles list of profiles that were removed
497 */
498 synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
499 Collection<LocalBluetoothProfile> profiles,
500 Collection<LocalBluetoothProfile> removedProfiles,
501 boolean isPanNapConnected, BluetoothDevice device) {
502 // Copy previous profile list into removedProfiles
503 removedProfiles.clear();
504 removedProfiles.addAll(profiles);
Joseph Pirozzo99fecc02016-04-07 13:43:49 -0700505 if (DEBUG) {
506 Log.d(TAG,"Current Profiles" + profiles.toString());
507 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500508 profiles.clear();
509
510 if (uuids == null) {
511 return;
512 }
513
514 if (mHeadsetProfile != null) {
515 if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
516 BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
517 (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
518 BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
519 profiles.add(mHeadsetProfile);
520 removedProfiles.remove(mHeadsetProfile);
521 }
522 }
523
Joseph Pirozzo99fecc02016-04-07 13:43:49 -0700524 if ((mHfpClientProfile != null) &&
525 BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) &&
526 BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree)) {
527 profiles.add(mHfpClientProfile);
528 removedProfiles.remove(mHfpClientProfile);
529 }
530
Jason Monk7ce96b92015-02-02 11:27:58 -0500531 if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
532 mA2dpProfile != null) {
533 profiles.add(mA2dpProfile);
534 removedProfiles.remove(mA2dpProfile);
535 }
536
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700537 if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) &&
538 mA2dpSinkProfile != null) {
539 profiles.add(mA2dpSinkProfile);
540 removedProfiles.remove(mA2dpSinkProfile);
Joseph Pirozzo99fecc02016-04-07 13:43:49 -0700541 }
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700542
Jason Monk7ce96b92015-02-02 11:27:58 -0500543 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
544 mOppProfile != null) {
545 profiles.add(mOppProfile);
546 removedProfiles.remove(mOppProfile);
547 }
548
549 if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
550 BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
551 mHidProfile != null) {
552 profiles.add(mHidProfile);
553 removedProfiles.remove(mHidProfile);
554 }
555
Hansong Zhangdcae2932017-11-13 10:56:23 -0800556 if (mHidProfile != null && mHidDeviceProfile.getConnectionStatus(device)
557 != BluetoothProfile.STATE_DISCONNECTED) {
558 profiles.add(mHidDeviceProfile);
559 removedProfiles.remove(mHidDeviceProfile);
560 }
561
Jason Monk7ce96b92015-02-02 11:27:58 -0500562 if(isPanNapConnected)
563 if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
564 if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
565 mPanProfile != null) || isPanNapConnected) {
566 profiles.add(mPanProfile);
567 removedProfiles.remove(mPanProfile);
568 }
569
570 if ((mMapProfile != null) &&
571 (mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
572 profiles.add(mMapProfile);
573 removedProfiles.remove(mMapProfile);
574 mMapProfile.setPreferred(device, true);
575 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500576
Hemant Guptadbc3d8d2017-05-12 21:14:44 +0530577 if ((mPbapProfile != null) &&
578 (mPbapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
579 profiles.add(mPbapProfile);
580 removedProfiles.remove(mPbapProfile);
581 mPbapProfile.setPreferred(device, true);
582 }
583
Joseph Pirozzo631768d2016-09-01 14:19:28 -0700584 if (mMapClientProfile != null) {
585 profiles.add(mMapClientProfile);
586 removedProfiles.remove(mMapClientProfile);
587 }
588
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700589 if (mUsePbapPce) {
590 profiles.add(mPbapClientProfile);
591 removedProfiles.remove(mPbapClientProfile);
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700592 }
Joseph Pirozzo99fecc02016-04-07 13:43:49 -0700593
Jakub Pawlowskiea580fa2017-11-22 11:02:34 -0800594 if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) &&
595 mHearingAidProfile != null) {
596 profiles.add(mHearingAidProfile);
597 removedProfiles.remove(mHearingAidProfile);
598 }
599
Joseph Pirozzo99fecc02016-04-07 13:43:49 -0700600 if (DEBUG) {
601 Log.d(TAG,"New Profiles" + profiles.toString());
602 }
Joseph Pirozzo563c7002016-03-21 15:49:48 -0700603 }
Jason Monk7ce96b92015-02-02 11:27:58 -0500604}