• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.BluetoothAdapter;
20 import android.bluetooth.BluetoothCsipSetCoordinator;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothProfile;
23 import android.bluetooth.le.ScanFilter;
24 import android.content.Context;
25 import android.util.Log;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 
29 import java.sql.Timestamp;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Set;
35 
36 /**
37  * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
38  */
39 public class CachedBluetoothDeviceManager {
40     private static final String TAG = "CachedBluetoothDeviceManager";
41     private static final boolean DEBUG = BluetoothUtils.D;
42 
43     @VisibleForTesting static int sLateBondingTimeoutMillis = 5000; // 5s
44 
45     private Context mContext;
46     private final LocalBluetoothManager mBtManager;
47 
48     @VisibleForTesting
49     final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
50     @VisibleForTesting
51     HearingAidDeviceManager mHearingAidDeviceManager;
52     @VisibleForTesting
53     CsipDeviceManager mCsipDeviceManager;
54     BluetoothDevice mOngoingSetMemberPair;
55     boolean mIsLateBonding;
56     int mGroupIdOfLateBonding;
57 
CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager)58     public CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
59         mContext = context;
60         mBtManager = localBtManager;
61         mHearingAidDeviceManager = new HearingAidDeviceManager(context, localBtManager,
62                 mCachedDevices);
63         mCsipDeviceManager = new CsipDeviceManager(localBtManager, mCachedDevices);
64     }
65 
getCachedDevicesCopy()66     public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
67         return new ArrayList<>(mCachedDevices);
68     }
69 
onDeviceDisappeared(CachedBluetoothDevice cachedDevice)70     public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
71         cachedDevice.setJustDiscovered(false);
72         return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE;
73     }
74 
onDeviceNameUpdated(BluetoothDevice device)75     public void onDeviceNameUpdated(BluetoothDevice device) {
76         CachedBluetoothDevice cachedDevice = findDevice(device);
77         if (cachedDevice != null) {
78             cachedDevice.refreshName();
79         }
80     }
81 
82     /**
83      * Search for existing {@link CachedBluetoothDevice} or return null
84      * if this device isn't in the cache. Use {@link #addDevice}
85      * to create and return a new {@link CachedBluetoothDevice} for
86      * a newly discovered {@link BluetoothDevice}.
87      *
88      * @param device the address of the Bluetooth device
89      * @return the cached device object for this device, or null if it has
90      *   not been previously seen
91      */
findDevice(BluetoothDevice device)92     public synchronized CachedBluetoothDevice findDevice(BluetoothDevice device) {
93         for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
94             if (cachedDevice.getDevice().equals(device)) {
95                 return cachedDevice;
96             }
97             // Check the member devices for the coordinated set if it exists
98             final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
99             if (!memberDevices.isEmpty()) {
100                 for (CachedBluetoothDevice memberDevice : memberDevices) {
101                     if (memberDevice.getDevice().equals(device)) {
102                         return memberDevice;
103                     }
104                 }
105             }
106             // Check sub devices for hearing aid if it exists
107             CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
108             if (subDevice != null && subDevice.getDevice().equals(device)) {
109                 return subDevice;
110             }
111         }
112 
113         return null;
114     }
115 
116     /**
117      * Create and return a new {@link CachedBluetoothDevice}. This assumes
118      * that {@link #findDevice} has already been called and returned null.
119      * @param device the new Bluetooth device
120      * @return the newly created CachedBluetoothDevice object
121      */
addDevice(BluetoothDevice device)122     public CachedBluetoothDevice addDevice(BluetoothDevice device) {
123         return addDevice(device, /*leScanFilters=*/null);
124     }
125 
126     /**
127      * Create and return a new {@link CachedBluetoothDevice}. This assumes
128      * that {@link #findDevice} has already been called and returned null.
129      * @param device the new Bluetooth device
130      * @param leScanFilters the BLE scan filters which the device matched
131      * @return the newly created CachedBluetoothDevice object
132      */
addDevice(BluetoothDevice device, List<ScanFilter> leScanFilters)133     public CachedBluetoothDevice addDevice(BluetoothDevice device, List<ScanFilter> leScanFilters) {
134         CachedBluetoothDevice newDevice;
135         final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
136         synchronized (this) {
137             newDevice = findDevice(device);
138             if (newDevice == null) {
139                 newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
140                 mCsipDeviceManager.initCsipDeviceIfNeeded(newDevice);
141                 mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice, leScanFilters);
142                 if (!mCsipDeviceManager.setMemberDeviceIfNeeded(newDevice)
143                         && !mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
144                     mCachedDevices.add(newDevice);
145                     mBtManager.getEventManager().dispatchDeviceAdded(newDevice);
146                 }
147             }
148         }
149 
150         return newDevice;
151     }
152 
153     /**
154      * Returns device summary of the pair of the hearing aid / CSIP passed as the parameter.
155      *
156      * @param CachedBluetoothDevice device
157      * @return Device summary, or if the pair does not exist or if it is not a hearing aid or
158      * a CSIP set member, then {@code null}.
159      */
getSubDeviceSummary(CachedBluetoothDevice device)160     public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
161         final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
162         // TODO: check the CSIP group size instead of the real member device set size, and adjust
163         // the size restriction.
164         if (!memberDevices.isEmpty()) {
165             for (CachedBluetoothDevice memberDevice : memberDevices) {
166                 if (memberDevice.isConnected()) {
167                     return memberDevice.getConnectionSummary();
168                 }
169             }
170         }
171         CachedBluetoothDevice subDevice = device.getSubDevice();
172         if (subDevice != null && subDevice.isConnected()) {
173             return subDevice.getConnectionSummary();
174         }
175         return null;
176     }
177 
178     /**
179      * Sync device status of the pair of the hearing aid if needed.
180      *
181      * @param device the remote device
182      */
syncDeviceWithinHearingAidSetIfNeeded(CachedBluetoothDevice device, int state, int profileId)183     public synchronized void syncDeviceWithinHearingAidSetIfNeeded(CachedBluetoothDevice device,
184             int state, int profileId) {
185         if (profileId == BluetoothProfile.HAP_CLIENT
186                 || profileId == BluetoothProfile.HEARING_AID
187                 || profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
188             if (state == BluetoothProfile.STATE_CONNECTED) {
189                 mHearingAidDeviceManager.syncDeviceIfNeeded(device);
190             }
191         }
192     }
193 
194     /**
195      * Search for existing sub device {@link CachedBluetoothDevice}.
196      *
197      * @param device the address of the Bluetooth device
198      * @return true for found sub / member device or false.
199      */
isSubDevice(BluetoothDevice device)200     public synchronized boolean isSubDevice(BluetoothDevice device) {
201         for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
202             if (!cachedDevice.getDevice().equals(device)) {
203                 // Check the member devices of the coordinated set if it exists
204                 Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
205                 if (!memberDevices.isEmpty()) {
206                     for (CachedBluetoothDevice memberDevice : memberDevices) {
207                         if (memberDevice.getDevice().equals(device)) {
208                             return true;
209                         }
210                     }
211                     continue;
212                 }
213                 // Check sub devices of hearing aid if it exists
214                 CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
215                 if (subDevice != null && subDevice.getDevice().equals(device)) {
216                     return true;
217                 }
218             }
219         }
220         return false;
221     }
222 
223     /**
224      * Updates the Hearing Aid devices; specifically the HiSyncId's. This routine is called when the
225      * Hearing Aid Service is connected and the HiSyncId's are now available.
226      */
updateHearingAidsDevices()227     public synchronized void updateHearingAidsDevices() {
228         mHearingAidDeviceManager.updateHearingAidsDevices();
229     }
230 
231     /**
232      * Updates the Csip devices; specifically the GroupId's. This routine is called when the
233      * CSIS is connected and the GroupId's are now available.
234      */
updateCsipDevices()235     public synchronized void updateCsipDevices() {
236         mCsipDeviceManager.updateCsipDevices();
237     }
238 
239     /**
240      * Attempts to get the name of a remote device, otherwise returns the address.
241      *
242      * @param device The remote device.
243      * @return The name, or if unavailable, the address.
244      */
getName(BluetoothDevice device)245     public String getName(BluetoothDevice device) {
246         if (isOngoingPairByCsip(device)) {
247             CachedBluetoothDevice firstDevice =
248                     mCsipDeviceManager.getFirstMemberDevice(mGroupIdOfLateBonding);
249             if (firstDevice != null && firstDevice.getName() != null) {
250                 return firstDevice.getName();
251             }
252         }
253 
254         CachedBluetoothDevice cachedDevice = findDevice(device);
255         if (cachedDevice != null && cachedDevice.getName() != null) {
256             return cachedDevice.getName();
257         }
258 
259         String name = device.getAlias();
260         if (name != null) {
261             return name;
262         }
263 
264         return device.getAddress();
265     }
266 
clearNonBondedDevices()267     public synchronized void clearNonBondedDevices() {
268         clearNonBondedSubDevices();
269         final List<CachedBluetoothDevice> removedCachedDevice = new ArrayList<>();
270         mCachedDevices.stream()
271                 .filter(cachedDevice -> cachedDevice.getBondState() == BluetoothDevice.BOND_NONE)
272                 .forEach(cachedDevice -> {
273                     cachedDevice.release();
274                     removedCachedDevice.add(cachedDevice);
275                 });
276         mCachedDevices.removeAll(removedCachedDevice);
277     }
278 
clearNonBondedSubDevices()279     private void clearNonBondedSubDevices() {
280         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
281             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
282             Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
283             if (!memberDevices.isEmpty()) {
284                 for (Object it : memberDevices.toArray()) {
285                     CachedBluetoothDevice memberDevice = (CachedBluetoothDevice) it;
286                     // Member device exists and it is not bonded
287                     if (memberDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
288                         cachedDevice.removeMemberDevice(memberDevice);
289                     }
290                 }
291                 return;
292             }
293             CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
294             if (subDevice != null
295                     && subDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
296                 // Sub device exists and it is not bonded
297                 subDevice.release();
298                 cachedDevice.setSubDevice(null);
299             }
300         }
301     }
302 
onScanningStateChanged(boolean started)303     public synchronized void onScanningStateChanged(boolean started) {
304         if (!started) return;
305         // If starting a new scan, clear old visibility
306         // Iterate in reverse order since devices may be removed.
307         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
308             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
309             cachedDevice.setJustDiscovered(false);
310             final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
311             if (!memberDevices.isEmpty()) {
312                 for (CachedBluetoothDevice memberDevice : memberDevices) {
313                     memberDevice.setJustDiscovered(false);
314                 }
315                 return;
316             }
317             final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
318             if (subDevice != null) {
319                 subDevice.setJustDiscovered(false);
320             }
321         }
322     }
323 
onBluetoothStateChanged(int bluetoothState)324     public synchronized void onBluetoothStateChanged(int bluetoothState) {
325         // When Bluetooth is turning off, we need to clear the non-bonded devices
326         // Otherwise, they end up showing up on the next BT enable
327         if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
328             for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
329                 CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
330                 final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
331                 if (!memberDevices.isEmpty()) {
332                     for (CachedBluetoothDevice memberDevice : memberDevices) {
333                         if (memberDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
334                             cachedDevice.removeMemberDevice(memberDevice);
335                         }
336                     }
337                 } else {
338                     CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
339                     if (subDevice != null) {
340                         if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
341                             cachedDevice.setSubDevice(null);
342                         }
343                     }
344                 }
345                 if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
346                     cachedDevice.setJustDiscovered(false);
347                     cachedDevice.release();
348                     mCachedDevices.remove(i);
349                 }
350             }
351 
352             // To clear the SetMemberPair flag when the Bluetooth is turning off.
353             mOngoingSetMemberPair = null;
354             mIsLateBonding = false;
355             mGroupIdOfLateBonding = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
356         }
357     }
358 
removeDuplicateInstanceForIdentityAddress(BluetoothDevice device)359     synchronized void removeDuplicateInstanceForIdentityAddress(BluetoothDevice device) {
360         String identityAddress = device.getIdentityAddress();
361         if (identityAddress == null || identityAddress.equals(device.getAddress())) {
362             return;
363         }
364         mCachedDevices.removeIf(d -> {
365             boolean shouldRemove = d.getDevice().getAddress().equals(identityAddress);
366             if (shouldRemove) {
367                 Log.d(TAG, "Remove instance for identity address " + d);
368             }
369             return shouldRemove;
370         });
371     }
372 
onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice cachedDevice, int state, int profileId)373     public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
374             cachedDevice, int state, int profileId) {
375         if (profileId == BluetoothProfile.HEARING_AID) {
376             return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
377                 state);
378         }
379         if (profileId == BluetoothProfile.HEADSET
380                 || profileId == BluetoothProfile.A2DP
381                 || profileId == BluetoothProfile.LE_AUDIO
382                 || profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
383             return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
384                 state);
385         }
386         return false;
387     }
388 
389     /** Handles when the device been set as active/inactive. */
onActiveDeviceChanged(CachedBluetoothDevice cachedBluetoothDevice)390     public synchronized void onActiveDeviceChanged(CachedBluetoothDevice cachedBluetoothDevice) {
391         if (cachedBluetoothDevice.isHearingAidDevice()) {
392             mHearingAidDeviceManager.onActiveDeviceChanged(cachedBluetoothDevice);
393         }
394     }
395 
onDeviceUnpaired(CachedBluetoothDevice device)396     public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
397         device.setGroupId(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
398         CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
399         // Should iterate through the cloned set to avoid ConcurrentModificationException
400         final Set<CachedBluetoothDevice> memberDevices = new HashSet<>(device.getMemberDevice());
401         if (!memberDevices.isEmpty()) {
402             // Main device is unpaired, also unpair the member devices
403             for (CachedBluetoothDevice memberDevice : memberDevices) {
404                 memberDevice.unpair();
405                 memberDevice.setGroupId(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
406                 device.removeMemberDevice(memberDevice);
407             }
408         } else if (mainDevice != null) {
409             // Member device is unpaired, also unpair the main device
410             mainDevice.unpair();
411         }
412         mainDevice = mHearingAidDeviceManager.findMainDevice(device);
413         CachedBluetoothDevice subDevice = device.getSubDevice();
414         if (subDevice != null) {
415             // Main device is unpaired, to unpair sub device
416             subDevice.unpair();
417             device.setSubDevice(null);
418         } else if (mainDevice != null) {
419             // Sub device unpaired, to unpair main device
420             mainDevice.unpair();
421             mainDevice.setSubDevice(null);
422         }
423     }
424 
425     /**
426      * Called when we found a set member of a group. The function will check the {@code groupId} if
427      * it exists and the bond state of the device is BOND_NOE, and if there isn't any ongoing pair
428      * , and then return {@code true} to pair the device automatically.
429      *
430      * @param device The found device
431      * @param groupId The group id of the found device
432      *
433      * @return {@code true}, if the device should pair automatically; Otherwise, return
434      * {@code false}.
435      */
shouldPairByCsip(BluetoothDevice device, int groupId)436     private synchronized boolean shouldPairByCsip(BluetoothDevice device, int groupId) {
437         boolean isOngoingSetMemberPair = mOngoingSetMemberPair != null;
438         int bondState = device.getBondState();
439         boolean groupExists = mCsipDeviceManager.isExistedGroupId(groupId);
440         Log.d(TAG,
441                 "isOngoingSetMemberPair=" + isOngoingSetMemberPair + ", bondState=" + bondState
442                         + ", groupExists=" + groupExists + ", groupId=" + groupId);
443 
444         if (isOngoingSetMemberPair || bondState != BluetoothDevice.BOND_NONE || !groupExists) {
445             return false;
446         }
447         return true;
448     }
449 
checkLateBonding(int groupId)450     private synchronized boolean checkLateBonding(int groupId) {
451         CachedBluetoothDevice firstDevice = mCsipDeviceManager.getFirstMemberDevice(groupId);
452         if (firstDevice == null) {
453             Log.d(TAG, "No first device in group: " + groupId);
454             return false;
455         }
456 
457         Timestamp then = firstDevice.getBondTimestamp();
458         if (then == null) {
459             Log.d(TAG, "No bond timestamp");
460             return true;
461         }
462 
463         Timestamp now = new Timestamp(System.currentTimeMillis());
464 
465         long diff = (now.getTime() - then.getTime());
466         Log.d(TAG, "Time difference to first bonding: " + diff + "ms");
467 
468         return diff > sLateBondingTimeoutMillis;
469     }
470 
471     /**
472      * Called to check if there is an ongoing bonding for the device and it is late bonding.
473      * If the device is not matching the ongoing bonding device then false will be returned.
474      *
475      * @param device The device to check.
476      */
isLateBonding(BluetoothDevice device)477     public synchronized boolean isLateBonding(BluetoothDevice device) {
478         if (!isOngoingPairByCsip(device)) {
479             Log.d(TAG, "isLateBonding: pair not ongoing or not matching device");
480             return false;
481         }
482 
483         Log.d(TAG, "isLateBonding: " + mIsLateBonding);
484         return mIsLateBonding;
485     }
486 
487     /**
488      * Called when we found a set member of a group. The function will check the {@code groupId} if
489      * it exists and the bond state of the device is BOND_NONE, and if there isn't any ongoing pair
490      * , and then pair the device automatically.
491      *
492      * @param device The found device
493      * @param groupId The group id of the found device
494      */
pairDeviceByCsip(BluetoothDevice device, int groupId)495     public synchronized void pairDeviceByCsip(BluetoothDevice device, int groupId) {
496         if (!shouldPairByCsip(device, groupId)) {
497             return;
498         }
499         Log.d(TAG, "Bond " + device.getAnonymizedAddress() + " groupId=" + groupId + " by CSIP ");
500         mOngoingSetMemberPair = device;
501         mIsLateBonding = checkLateBonding(groupId);
502         mGroupIdOfLateBonding = groupId;
503         syncConfigFromMainDevice(device, groupId);
504         if (!device.createBond(BluetoothDevice.TRANSPORT_LE)) {
505             Log.d(TAG, "Bonding could not be started");
506             mOngoingSetMemberPair = null;
507             mIsLateBonding = false;
508             mGroupIdOfLateBonding = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
509         }
510     }
511 
syncConfigFromMainDevice(BluetoothDevice device, int groupId)512     private void syncConfigFromMainDevice(BluetoothDevice device, int groupId) {
513         if (!isOngoingPairByCsip(device)) {
514             return;
515         }
516         CachedBluetoothDevice memberDevice = findDevice(device);
517         CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(memberDevice);
518         if (mainDevice == null) {
519             mainDevice = mCsipDeviceManager.getCachedDevice(groupId);
520         }
521 
522         if (mainDevice == null || mainDevice.equals(memberDevice)) {
523             Log.d(TAG, "no mainDevice");
524             return;
525         }
526 
527         // The memberDevice set PhonebookAccessPermission
528         device.setPhonebookAccessPermission(mainDevice.getDevice().getPhonebookAccessPermission());
529     }
530 
531     /**
532      * Called when the bond state change. If the bond state change is related with the
533      * ongoing set member pair, the cachedBluetoothDevice will be created but the UI
534      * would not be updated. For the other case, return {@code false} to go through the normal
535      * flow.
536      *
537      * @param device The device
538      * @param bondState The new bond state
539      *
540      * @return {@code true}, if the bond state change for the device is handled inside this
541      * function, and would not like to update the UI. If not, return {@code false}.
542      */
onBondStateChangedIfProcess(BluetoothDevice device, int bondState)543     public synchronized boolean onBondStateChangedIfProcess(BluetoothDevice device, int bondState) {
544         if (!isOngoingPairByCsip(device)) {
545             return false;
546         }
547 
548         if (bondState == BluetoothDevice.BOND_BONDING) {
549             return true;
550         }
551 
552         mOngoingSetMemberPair = null;
553         mIsLateBonding = false;
554         mGroupIdOfLateBonding = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
555         if (bondState != BluetoothDevice.BOND_NONE) {
556             if (findDevice(device) == null) {
557                 final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
558                 CachedBluetoothDevice newDevice =
559                         new CachedBluetoothDevice(mContext, profileManager, device);
560                 mCachedDevices.add(newDevice);
561                 findDevice(device).connect();
562             }
563         }
564 
565         return true;
566     }
567 
568     /**
569      * Check if the device is the one which is initial paired locally by CSIP. The setting
570      * would depned on it to accept the pairing request automatically
571      *
572      * @param device The device
573      *
574      * @return {@code true}, if the device is ongoing pair by CSIP. Otherwise, return
575      * {@code false}.
576      */
isOngoingPairByCsip(BluetoothDevice device)577     public boolean isOngoingPairByCsip(BluetoothDevice device) {
578         return mOngoingSetMemberPair != null && mOngoingSetMemberPair.equals(device);
579     }
580 
log(String msg)581     private void log(String msg) {
582         if (DEBUG) {
583             Log.d(TAG, msg);
584         }
585     }
586 }
587