1 /*
2  * Copyright (C) 2019 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.car;
18 
19 import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_HFP_CLIENT_DEVICES;
20 
21 import static org.mockito.Mockito.*;
22 
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothHeadsetClient;
26 import android.bluetooth.BluetoothProfile;
27 import android.bluetooth.BluetoothUuid;
28 import android.car.ICarBluetoothUserService;
29 import android.content.BroadcastReceiver;
30 import android.content.ContentResolver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.os.Handler;
35 import android.os.Looper;
36 import android.os.ParcelUuid;
37 import android.os.UserHandle;
38 import android.provider.Settings;
39 import android.test.mock.MockContentResolver;
40 import android.test.suitebuilder.annotation.Suppress;
41 import android.text.TextUtils;
42 
43 import androidx.test.InstrumentationRegistry;
44 import androidx.test.filters.RequiresDevice;
45 
46 import com.android.internal.util.test.BroadcastInterceptingContext;
47 import com.android.internal.util.test.FakeSettingsProvider;
48 
49 import org.junit.After;
50 import org.junit.Assert;
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 import org.mockito.InOrder;
55 import org.mockito.Mock;
56 import org.mockito.invocation.InvocationOnMock;
57 import org.mockito.junit.MockitoJUnitRunner;
58 import org.mockito.stubbing.Answer;
59 
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.Collections;
63 import java.util.List;
64 
65 /**
66  * Unit tests for {@link BluetoothProfileDeviceManager}
67  *
68  * Run:
69  * atest BluetoothProfileDeviceManagerTest
70  */
71 @RequiresDevice
72 @RunWith(MockitoJUnitRunner.class)
73 public class BluetoothProfileDeviceManagerTest {
74     private static final int CONNECT_LATENCY_MS = 100;
75     private static final int CONNECT_TIMEOUT_MS = 8000;
76     private static final int ADAPTER_STATE_ANY = 0;
77     private static final int ADAPTER_STATE_OFF = 1;
78     private static final int ADAPTER_STATE_OFF_NOT_PERSISTED = 2;
79     private static final int ADAPTER_STATE_ON = 3;
80 
81     private static final List<String> EMPTY_DEVICE_LIST = Arrays.asList();
82     private static final List<String> SINGLE_DEVICE_LIST = Arrays.asList("DE:AD:BE:EF:00:00");
83     private static final List<String> SMALL_DEVICE_LIST = Arrays.asList(
84             "DE:AD:BE:EF:00:00",
85             "DE:AD:BE:EF:00:01",
86             "DE:AD:BE:EF:00:02");
87     private static final List<String> LARGE_DEVICE_LIST = Arrays.asList(
88             "DE:AD:BE:EF:00:00",
89             "DE:AD:BE:EF:00:01",
90             "DE:AD:BE:EF:00:02",
91             "DE:AD:BE:EF:00:03",
92             "DE:AD:BE:EF:00:04",
93             "DE:AD:BE:EF:00:05",
94             "DE:AD:BE:EF:00:06",
95             "DE:AD:BE:EF:00:07");
96 
97     private static final String EMPTY_SETTINGS_STRING = "";
98     private static final String SINGLE_SETTINGS_STRING = makeSettingsString(SINGLE_DEVICE_LIST);
99     private static final String SMALL_SETTINGS_STRING = makeSettingsString(SMALL_DEVICE_LIST);
100     private static final String LARGE_SETTINGS_STRING = makeSettingsString(LARGE_DEVICE_LIST);
101 
102     BluetoothProfileDeviceManager mProfileDeviceManager;
103 
104     private final int mUserId = 0;
105     private final int mProfileId = BluetoothProfile.HEADSET_CLIENT;
106     private final String mSettingsKey = KEY_BLUETOOTH_HFP_CLIENT_DEVICES;
107     private final String mConnectionAction = BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED;
108     private ParcelUuid[] mUuids = new ParcelUuid[] {
109             BluetoothUuid.HFP_AG,
110             BluetoothUuid.HSP_AG};
111     private ParcelUuid[] mBadUuids = new ParcelUuid[] {
112             BluetoothUuid.PANU};
113     private final int[] mProfileTriggers = new int[] {
114             BluetoothProfile.MAP_CLIENT,
115             BluetoothProfile.PBAP_CLIENT};
116 
117     @Mock private ICarBluetoothUserService mMockProxies;
118     private Handler mHandler;
119     private static final Object HANDLER_TOKEN = new Object();
120 
121     private MockContext mMockContext;
122 
123     private BluetoothAdapterHelper mBluetoothAdapterHelper;
124     private BluetoothAdapter mBluetoothAdapter;
125 
126     public class MockContext extends BroadcastInterceptingContext {
127         private MockContentResolver mContentResolver;
128         private FakeSettingsProvider mContentProvider;
129 
MockContext(Context base)130         MockContext(Context base) {
131             super(base);
132             FakeSettingsProvider.clearSettingsProvider();
133             mContentResolver = new MockContentResolver(this);
134             mContentProvider = new FakeSettingsProvider();
135             mContentResolver.addProvider(Settings.AUTHORITY, mContentProvider);
136         }
137 
release()138         public void release() {
139             FakeSettingsProvider.clearSettingsProvider();
140         }
141 
142         @Override
getContentResolver()143         public ContentResolver getContentResolver() {
144             return mContentResolver;
145         }
146 
147         @Override
registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, IntentFilter filter, String broadcastPermission, Handler scheduler)148         public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
149                 IntentFilter filter, String broadcastPermission, Handler scheduler) {
150             // We're basically ignoring the userhandle since the tests only assume one user anyway.
151             // BroadcastInterceptingContext doesn't implement this hook either so this has to do.
152             return super.registerReceiver(receiver, filter);
153         }
154     }
155 
156     //--------------------------------------------------------------------------------------------//
157     // Setup/TearDown                                                                             //
158     //--------------------------------------------------------------------------------------------//
159 
160     @Before
setUp()161     public void setUp() {
162         mMockContext = new MockContext(InstrumentationRegistry.getTargetContext());
163         setSettingsDeviceList("");
164         assertSettingsContains("");
165 
166         mBluetoothAdapterHelper = new BluetoothAdapterHelper();
167         mBluetoothAdapterHelper.init();
168 
169         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
170         Assert.assertTrue(mBluetoothAdapter != null);
171 
172         mHandler = new Handler(Looper.getMainLooper());
173 
174         mProfileDeviceManager = BluetoothProfileDeviceManager.create(mMockContext, mUserId,
175                 mMockProxies, mProfileId);
176         Assert.assertTrue(mProfileDeviceManager != null);
177     }
178 
179     @After
tearDown()180     public void tearDown() {
181         if (mProfileDeviceManager != null) {
182             mProfileDeviceManager.stop();
183             mProfileDeviceManager = null;
184         }
185         if (mHandler != null) {
186             mHandler.removeCallbacksAndMessages(HANDLER_TOKEN);
187             mHandler = null;
188         }
189         mBluetoothAdapter = null;
190         if (mBluetoothAdapterHelper != null) {
191             mBluetoothAdapterHelper.release();
192             mBluetoothAdapterHelper = null;
193         }
194         mMockProxies = null;
195         if (mMockContext != null) {
196             mMockContext.release();
197             mMockContext = null;
198         }
199     }
200 
201     //--------------------------------------------------------------------------------------------//
202     // Utilities                                                                                  //
203     //--------------------------------------------------------------------------------------------//
204 
setSettingsDeviceList(String devicesStr)205     private void setSettingsDeviceList(String devicesStr) {
206         Settings.Secure.putStringForUser(mMockContext.getContentResolver(), mSettingsKey,
207                 devicesStr, mUserId);
208     }
209 
getSettingsDeviceList()210     private String getSettingsDeviceList() {
211         String devices = Settings.Secure.getStringForUser(mMockContext.getContentResolver(),
212                 mSettingsKey, mUserId);
213         if (devices == null) devices = "";
214         return devices;
215     }
216 
makeDeviceList(List<String> addresses)217     private ArrayList<BluetoothDevice> makeDeviceList(List<String> addresses) {
218         ArrayList<BluetoothDevice> devices = new ArrayList<>();
219         for (String address : addresses) {
220             BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
221             if (device == null) continue;
222             devices.add(device);
223         }
224         return devices;
225     }
226 
makeSettingsString(List<String> addresses)227     private static String makeSettingsString(List<String> addresses) {
228         return TextUtils.join(",", addresses);
229     }
230 
setPreconditionsAndStart(int adapterState, String settings, List<String> devices)231     private void setPreconditionsAndStart(int adapterState, String settings,
232             List<String> devices) {
233         switch (adapterState) {
234             case ADAPTER_STATE_ON:
235                 mBluetoothAdapterHelper.forceAdapterOn();
236                 break;
237             case ADAPTER_STATE_OFF:
238                 mBluetoothAdapterHelper.forceAdapterOff();
239                 break;
240             case ADAPTER_STATE_OFF_NOT_PERSISTED:
241                 mBluetoothAdapterHelper.forceAdapterOffDoNotPersist();
242                 break;
243             case ADAPTER_STATE_ANY:
244                 break;
245             default:
246                 break;
247         }
248 
249         setSettingsDeviceList(settings);
250 
251         mProfileDeviceManager.start();
252 
253         for (BluetoothDevice device : makeDeviceList(devices)) {
254             mProfileDeviceManager.addDevice(device);
255         }
256     }
257 
mockDeviceAvailability(BluetoothDevice device, boolean available)258     private void mockDeviceAvailability(BluetoothDevice device, boolean available)
259             throws Exception {
260         doAnswer(new Answer<Boolean>() {
261             @Override
262             public Boolean answer(InvocationOnMock invocation) throws Throwable {
263                 Object[] arguments = invocation.getArguments();
264                 if (arguments != null && arguments.length == 2 && arguments[1] != null) {
265                     BluetoothDevice device = (BluetoothDevice) arguments[1];
266                     int state = (available
267                             ? BluetoothProfile.STATE_CONNECTED
268                             : BluetoothProfile.STATE_DISCONNECTED);
269                     mHandler.postDelayed(() -> {
270                         sendConnectionStateChanged(device, state);
271                     }, HANDLER_TOKEN, CONNECT_LATENCY_MS);
272                 }
273                 return true;
274             }
275         }).when(mMockProxies).bluetoothConnectToProfile(mProfileId, device);
276     }
277 
captureDevicePriority(BluetoothDevice device)278     private void captureDevicePriority(BluetoothDevice device) throws Exception {
279         doAnswer(new Answer<Void>() {
280             @Override
281             public Void answer(InvocationOnMock invocation) throws Throwable {
282                 Object[] arguments = invocation.getArguments();
283                 if (arguments != null && arguments.length == 3 && arguments[1] != null) {
284                     BluetoothDevice device = (BluetoothDevice) arguments[1];
285                     int priority = (int) arguments[2];
286                     mockDevicePriority(device, priority);
287                 }
288                 return null;
289             }
290         }).when(mMockProxies).setProfilePriority(mProfileId, device, anyInt());
291     }
292 
mockDevicePriority(BluetoothDevice device, int priority)293     private void mockDevicePriority(BluetoothDevice device, int priority) throws Exception {
294         when(mMockProxies.getProfilePriority(mProfileId, device)).thenReturn(priority);
295     }
296 
sendAdapterStateChanged(int newState)297     private void sendAdapterStateChanged(int newState) {
298         Assert.assertTrue(mMockContext != null);
299         Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
300         intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
301         mMockContext.sendBroadcast(intent);
302     }
303 
sendBondStateChanged(BluetoothDevice device, int newState)304     private void sendBondStateChanged(BluetoothDevice device, int newState) {
305         Assert.assertTrue(mMockContext != null);
306         Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
307         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
308         intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState);
309         mMockContext.sendBroadcast(intent);
310     }
311 
sendDeviceUuids(BluetoothDevice device, ParcelUuid[] uuids)312     private void sendDeviceUuids(BluetoothDevice device, ParcelUuid[] uuids) {
313         Assert.assertTrue(mMockContext != null);
314         Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
315         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
316         intent.putExtra(BluetoothDevice.EXTRA_UUID, uuids);
317         mMockContext.sendBroadcast(intent);
318     }
319 
sendConnectionStateChanged(BluetoothDevice device, int newState)320     private void sendConnectionStateChanged(BluetoothDevice device, int newState) {
321         Assert.assertTrue(mMockContext != null);
322         Intent intent = new Intent(mConnectionAction);
323         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
324         intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
325         mMockContext.sendBroadcast(intent);
326     }
327 
assertSettingsContains(String expected)328     private synchronized void assertSettingsContains(String expected) {
329         Assert.assertTrue(expected != null);
330         String settings = getSettingsDeviceList();
331         if (settings == null) settings = "";
332         Assert.assertEquals(expected, settings);
333     }
334 
assertDeviceList(List<String> expected)335     private void assertDeviceList(List<String> expected) {
336         ArrayList<BluetoothDevice> devices = mProfileDeviceManager.getDeviceListSnapshot();
337         ArrayList<BluetoothDevice> expectedDevices = makeDeviceList(expected);
338         Assert.assertEquals(expectedDevices, devices);
339     }
340 
341     //--------------------------------------------------------------------------------------------//
342     // Load from persistent memory tests                                                          //
343     //--------------------------------------------------------------------------------------------//
344 
345     /**
346      * Preconditions:
347      * - Settings contains no devices
348      *
349      * Actions:
350      * - Initialize the device manager
351      *
352      * Outcome:
353      * - device manager should initialize
354      */
355     @Test
testEmptySettingsString_loadNoDevices()356     public void testEmptySettingsString_loadNoDevices() {
357         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
358         assertDeviceList(EMPTY_DEVICE_LIST);
359     }
360 
361     /**
362      * Preconditions:
363      * - Settings contains a single device
364      *
365      * Actions:
366      * - Initialize the device manager
367      *
368      * Outcome:
369      * - The single device is now located in the device manager's device list
370      */
371     @Test
testSingleDeviceSettingsString_loadSingleDevice()372     public void testSingleDeviceSettingsString_loadSingleDevice() {
373         setPreconditionsAndStart(ADAPTER_STATE_ANY, SINGLE_SETTINGS_STRING, EMPTY_DEVICE_LIST);
374         assertDeviceList(SINGLE_DEVICE_LIST);
375     }
376 
377     /**
378      * Preconditions:
379      * - Settings contains several devices
380      *
381      * Actions:
382      * - Initialize the device manager
383      *
384      * Outcome:
385      * - All devices are now in the device manager's list, all in the proper order.
386      */
387     @Test
testSeveralDevicesSettingsString_loadAllDevices()388     public void testSeveralDevicesSettingsString_loadAllDevices() {
389         setPreconditionsAndStart(ADAPTER_STATE_ANY, LARGE_SETTINGS_STRING, EMPTY_DEVICE_LIST);
390         assertDeviceList(LARGE_DEVICE_LIST);
391     }
392 
393     //--------------------------------------------------------------------------------------------//
394     // Commit to persistent memory tests                                                          //
395     //--------------------------------------------------------------------------------------------//
396 
397     /**
398      * Preconditions:
399      * - The device manager is initialized and the list contains no devices
400      *
401      * Actions:
402      * - An event forces the device manager to commit it's list
403      *
404      * Outcome:
405      * - The empty list should be written to Settings.Secure as an empty string, ""
406      */
407     @Test
testNoDevicesCommit_commitEmptyDeviceString()408     public void testNoDevicesCommit_commitEmptyDeviceString() {
409         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
410         sendAdapterStateChanged(BluetoothAdapter.STATE_OFF);
411         assertSettingsContains(EMPTY_SETTINGS_STRING);
412     }
413 
414     /**
415      * Preconditions:
416      * - The device manager contains several devices
417      *
418      * Actions:
419      * - An event forces the device manager to commit it's list
420      *
421      * Outcome:
422      * - The ordered device list should be written to Settings.Secure as a comma separated list
423      */
424     @Test
testSeveralDevicesCommit_commitAllDeviceString()425     public void testSeveralDevicesCommit_commitAllDeviceString() {
426         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, LARGE_DEVICE_LIST);
427         sendAdapterStateChanged(BluetoothAdapter.STATE_OFF);
428         assertSettingsContains(LARGE_SETTINGS_STRING);
429     }
430 
431     //--------------------------------------------------------------------------------------------//
432     // Add Device tests                                                                           //
433     //--------------------------------------------------------------------------------------------//
434 
435     /**
436      * Preconditions:
437      * - The device manager is initialized and contains no devices.
438      *
439      * Actions:
440      * - Add a single device
441      *
442      * Outcome:
443      * - The device manager priority list contains the single device
444      */
445     @Test
testAddSingleDevice_devicesAppearInPriorityList()446     public void testAddSingleDevice_devicesAppearInPriorityList() {
447         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST);
448         assertDeviceList(SINGLE_DEVICE_LIST);
449     }
450 
451     /**
452      * Preconditions:
453      * - The device manager is initialized and contains no devices.
454      *
455      * Actions:
456      * - Add several devices
457      *
458      * Outcome:
459      * - The device manager priority list contains all devices, ordered properly
460      */
461     @Test
testAddMultipleDevices_devicesAppearInPriorityList()462     public void testAddMultipleDevices_devicesAppearInPriorityList() {
463         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, LARGE_DEVICE_LIST);
464         assertDeviceList(LARGE_DEVICE_LIST);
465     }
466 
467     /**
468      * Preconditions:
469      * - The device manager is initialized and contains one device
470      *
471      * Actions:
472      * - Add the device that is already in the list
473      *
474      * Outcome:
475      * - The device manager's list remains unchanged with only one device in it
476      */
477     @Test
testAddDeviceAlreadyInList_priorityListUnchanged()478     public void testAddDeviceAlreadyInList_priorityListUnchanged() {
479         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST);
480         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
481         mProfileDeviceManager.addDevice(device);
482         assertDeviceList(SINGLE_DEVICE_LIST);
483     }
484 
485     //--------------------------------------------------------------------------------------------//
486     // Remove Device tests                                                                        //
487     //--------------------------------------------------------------------------------------------//
488 
489     /**
490      * Preconditions:
491      * - The device manager is initialized and contains no devices.
492      *
493      * Actions:
494      * - Remove a device from the list
495      *
496      * Outcome:
497      * - The device manager does not error out and continues to have an empty list
498      */
499     @Test
testRemoveDeviceFromEmptyList_priorityListUnchanged()500     public void testRemoveDeviceFromEmptyList_priorityListUnchanged() {
501         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
502         mProfileDeviceManager.removeDevice(mBluetoothAdapter.getRemoteDevice("DE:AD:BE:EF:00:00"));
503         assertDeviceList(EMPTY_DEVICE_LIST);
504     }
505 
506     /**
507      * Preconditions:
508      * - The device manager is initialized and contains several devices.
509      *
510      * Actions:
511      * - Remove the device with the highest priority (front of list)
512      *
513      * Outcome:
514      * - The device manager removes the leading device. The other devices have been shifted down.
515      */
516     @Test
testRemoveDeviceFront_deviceNoLongerInPriorityList()517     public void testRemoveDeviceFront_deviceNoLongerInPriorityList() {
518         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
519         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
520         mProfileDeviceManager.removeDevice(device);
521         ArrayList<String> expected = new ArrayList(SMALL_DEVICE_LIST);
522         expected.remove(0);
523         assertDeviceList(expected);
524     }
525 
526     /**
527      * Preconditions:
528      * - The device manager is initialized and contains several devices.
529      *
530      * Actions:
531      * - Remove a device from the middle of the list
532      *
533      * Outcome:
534      * - The device manager removes the device. The other devices with larger priorities have been
535      *   shifted down.
536      */
537     @Test
testRemoveDeviceMiddle_deviceNoLongerInPriorityList()538     public void testRemoveDeviceMiddle_deviceNoLongerInPriorityList() {
539         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
540         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SMALL_DEVICE_LIST.get(1));
541         mProfileDeviceManager.removeDevice(device);
542         ArrayList<String> expected = new ArrayList(SMALL_DEVICE_LIST);
543         expected.remove(1);
544         assertDeviceList(expected);
545     }
546 
547     /**
548      * Preconditions:
549      * - The device manager is initialized and contains several devices.
550      *
551      * Actions:
552      * - Remove the device from the end of the list
553      *
554      * Outcome:
555      * - The device manager removes the device. The other devices remain in their places, unchanged
556      */
557     @Test
testRemoveDeviceEnd_deviceNoLongerInPriorityList()558     public void testRemoveDeviceEnd_deviceNoLongerInPriorityList() {
559         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
560         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SMALL_DEVICE_LIST.get(2));
561         mProfileDeviceManager.removeDevice(device);
562         ArrayList<String> expected = new ArrayList(SMALL_DEVICE_LIST);
563         expected.remove(2); // 00, 01
564         assertDeviceList(expected);
565     }
566 
567     /**
568      * Preconditions:
569      * - The device manager is initialized and contains several devices.
570      *
571      * Actions:
572      * - Remove a device thats not in the list
573      *
574      * Outcome:
575      * - The device manager's list remains unchanged.
576      */
577     @Test
testRemoveDeviceNotInList_priorityListUnchanged()578     public void testRemoveDeviceNotInList_priorityListUnchanged() {
579         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
580         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice("10:20:30:40:50:60");
581         mProfileDeviceManager.removeDevice(device);
582         assertDeviceList(SMALL_DEVICE_LIST);
583     }
584 
585     //--------------------------------------------------------------------------------------------//
586     // GetDeviceConnectionPriority() tests                                                        //
587     //--------------------------------------------------------------------------------------------//
588 
589     /**
590      * Preconditions:
591      * - The device manager is initialized and contains several devices.
592      *
593      * Actions:
594      * - Get the priority of each device in the list
595      *
596      * Outcome:
597      * - The device manager returns the proper priority for each device
598      */
599     @Test
testGetConnectionPriority_prioritiesReturned()600     public void testGetConnectionPriority_prioritiesReturned() {
601         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
602         ArrayList<BluetoothDevice> devices = makeDeviceList(SMALL_DEVICE_LIST);
603         for (int i = 0; i < devices.size(); i++) {
604             int priority = mProfileDeviceManager.getDeviceConnectionPriority(devices.get(i));
605             Assert.assertEquals(i, priority);
606         }
607     }
608 
609     /**
610      * Preconditions:
611      * - The device manager is initialized and contains several devices.
612      *
613      * Actions:
614      * - Get the priority of a device that is not in the list
615      *
616      * Outcome:
617      * - The device manager returns a -1
618      */
619     @Test
testGetConnectionPriorityDeviceNotInList_negativeOneReturned()620     public void testGetConnectionPriorityDeviceNotInList_negativeOneReturned() {
621         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
622         BluetoothDevice deviceNotPresent = mBluetoothAdapter.getRemoteDevice("10:20:30:40:50:60");
623         int priority = mProfileDeviceManager.getDeviceConnectionPriority(deviceNotPresent);
624         Assert.assertEquals(-1, priority);
625     }
626 
627     //--------------------------------------------------------------------------------------------//
628     // setDeviceConnectionPriority() tests                                                        //
629     //--------------------------------------------------------------------------------------------//
630 
631     /**
632      * Preconditions:
633      * - The device manager is initialized and contains several devices.
634      *
635      * Actions:
636      * - Set the priority of several devices in the list, testing the following moves:
637      *      Mid priority -> higher priority
638      *      Mid priority -> lower priority
639      *      Highest priority -> lower priority
640      *      Lowest priority -> higher priority
641      *      Any priority -> same priority
642      *
643      * Outcome:
644      * - Increased prioritied shuffle devices to proper lower priorities, decreased priorities
645      *   shuffle devices to proper high priorities, and a request to set the same priority yields no
646      *   change.
647      */
648     @Test
testSetConnectionPriority_listOrderedCorrectly()649     public void testSetConnectionPriority_listOrderedCorrectly() {
650         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
651 
652         // move middle device to front
653         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SMALL_DEVICE_LIST.get(1));
654         mProfileDeviceManager.setDeviceConnectionPriority(device, 0);
655         Assert.assertEquals(0, mProfileDeviceManager.getDeviceConnectionPriority(device));
656         ArrayList<String> expected = new ArrayList(SMALL_DEVICE_LIST);
657         Collections.swap(expected, 1, 0); // expected: 00, [01], 02 -> [01], 00, 02
658         assertDeviceList(expected);
659 
660         // move front device to the end
661         mProfileDeviceManager.setDeviceConnectionPriority(device, 2);
662         Assert.assertEquals(2, mProfileDeviceManager.getDeviceConnectionPriority(device));
663         Collections.swap(expected, 0, 2); // expected: [01], 00, 02 -> 00, 02, [01]
664         Collections.swap(expected, 0, 1);
665         assertDeviceList(expected);
666 
667         // move end device to middle
668         mProfileDeviceManager.setDeviceConnectionPriority(device, 1);
669         Assert.assertEquals(1, mProfileDeviceManager.getDeviceConnectionPriority(device));
670         Collections.swap(expected, 2, 1); // expected: 00, 02, [01] -> 00, [01], 02
671         assertDeviceList(expected);
672 
673         // move middle to end
674         mProfileDeviceManager.setDeviceConnectionPriority(device, 2);
675         Assert.assertEquals(2, mProfileDeviceManager.getDeviceConnectionPriority(device));
676         Collections.swap(expected, 1, 2); // expected: 00, [01], 02 -> 00, 02, [01]
677         assertDeviceList(expected);
678 
679         // move end to front
680         mProfileDeviceManager.setDeviceConnectionPriority(device, 0);
681         Assert.assertEquals(0, mProfileDeviceManager.getDeviceConnectionPriority(device));
682         Collections.swap(expected, 2, 0); // expected: 00, 02, [01] -> [01], 00, 02
683         Collections.swap(expected, 1, 2);
684         assertDeviceList(expected);
685 
686         // move front to middle
687         mProfileDeviceManager.setDeviceConnectionPriority(device, 1);
688         Assert.assertEquals(1, mProfileDeviceManager.getDeviceConnectionPriority(device));
689         Collections.swap(expected, 0, 1); // expected: [01], 00, 02 -> 00, [01], 02
690         assertDeviceList(expected);
691 
692         // move middle to middle (i.e same to same)
693         mProfileDeviceManager.setDeviceConnectionPriority(device, 1);
694         Assert.assertEquals(1, mProfileDeviceManager.getDeviceConnectionPriority(device));
695         assertDeviceList(expected); // expected: 00, [01], 02 -> 00, [01], 02
696     }
697 
698     /**
699      * Preconditions:
700      * - The device manager is initialized and contains several devices.
701      *
702      * Actions:
703      * - Set the priority of a device that is not currently in the list
704      *
705      * Outcome:
706      * - Device is added to the list in the requested spot. Devices with lower priorities have had
707      *   their priorities adjusted accordingly.
708      */
709     @Test
testSetConnectionPriorityNewDevice_listOrderedCorrectly()710     public void testSetConnectionPriorityNewDevice_listOrderedCorrectly() {
711         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
712 
713         // add new device to the middle
714         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice("10:20:30:40:50:60");
715         mProfileDeviceManager.setDeviceConnectionPriority(device, 1);
716         Assert.assertEquals(1, mProfileDeviceManager.getDeviceConnectionPriority(device));
717         ArrayList<String> expected = new ArrayList(SMALL_DEVICE_LIST);
718         expected.add(1, "10:20:30:40:50:60"); // 00, 60, 01, 02
719         assertDeviceList(expected);
720 
721         // add new device to the front
722         device = mBluetoothAdapter.getRemoteDevice("10:20:30:40:50:61");
723         mProfileDeviceManager.setDeviceConnectionPriority(device, 0);
724         Assert.assertEquals(0, mProfileDeviceManager.getDeviceConnectionPriority(device));
725         expected.add(0, "10:20:30:40:50:61"); // 61, 00, 60, 01, 02
726         assertDeviceList(expected);
727 
728         // add new device to the end
729         device = mBluetoothAdapter.getRemoteDevice("10:20:30:40:50:62");
730         mProfileDeviceManager.setDeviceConnectionPriority(device, 5);
731         Assert.assertEquals(5, mProfileDeviceManager.getDeviceConnectionPriority(device));
732         expected.add(5, "10:20:30:40:50:62"); // 61, 00, 60, 01, 02, 62
733         assertDeviceList(expected);
734     }
735 
736     /**
737      * Preconditions:
738      * - The device manager is initialized and contains several devices.
739      *
740      * Actions:
741      * - Request to set a priority that exceeds the bounds of the list (upper)
742      *
743      * Outcome:
744      * - No operation is taken
745      */
746     @Test
testSetConnectionPriorityLargerThanSize_priorityListUnchanged()747     public void testSetConnectionPriorityLargerThanSize_priorityListUnchanged() {
748         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
749 
750         // Attempt to move middle device to end with huge end priority
751         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SMALL_DEVICE_LIST.get(1));
752         mProfileDeviceManager.setDeviceConnectionPriority(device, 100000);
753         Assert.assertEquals(1, mProfileDeviceManager.getDeviceConnectionPriority(device));
754         assertDeviceList(SMALL_DEVICE_LIST);
755     }
756 
757     /**
758      * Preconditions:
759      * - The device manager is initialized and contains several devices.
760      *
761      * Actions:
762      * - Request to set a priority that exceeds the bounds of the list (lower)
763      *
764      * Outcome:
765      * - No operation is taken
766      */
767     @Test
testSetConnectionPriorityNegative_priorityListUnchanged()768     public void testSetConnectionPriorityNegative_priorityListUnchanged() {
769         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
770 
771         // Attempt to move middle device to negative priority
772         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SMALL_DEVICE_LIST.get(1));
773         mProfileDeviceManager.setDeviceConnectionPriority(device, -1);
774         assertDeviceList(SMALL_DEVICE_LIST);
775     }
776 
777     /**
778      * Preconditions:
779      * - The device manager is initialized and contains several devices.
780      *
781      * Actions:
782      * - Request to set a priority for a null device
783      *
784      * Outcome:
785      * - No operation is taken
786      */
787     @Test
testSetConnectionPriorityNullDevice_priorityListUnchanged()788     public void testSetConnectionPriorityNullDevice_priorityListUnchanged() {
789         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
790         mProfileDeviceManager.setDeviceConnectionPriority(null, 1);
791         assertDeviceList(SMALL_DEVICE_LIST);
792     }
793 
794     //--------------------------------------------------------------------------------------------//
795     // beginAutoConnecting() tests                                                                //
796     //--------------------------------------------------------------------------------------------//
797 
798     /**
799      * Preconditions:
800      * - The Bluetooth adapter is ON, the device manager is initialized and no devices are in the
801      *   list.
802      *
803      * Actions:
804      * - Initiate an auto connection
805      *
806      * Outcome:
807      * - Auto connect returns immediately with no connection attempts made.
808      */
809     @Test
testAutoConnectNoDevices_returnsImmediately()810     public void testAutoConnectNoDevices_returnsImmediately() throws Exception {
811         setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
812         mProfileDeviceManager.beginAutoConnecting();
813         verify(mMockProxies, times(0)).bluetoothConnectToProfile(eq(mProfileId),
814                 any(BluetoothDevice.class));
815         Assert.assertFalse(mProfileDeviceManager.isAutoConnecting());
816     }
817 
818     /**
819      * Preconditions:
820      * - The Bluetooth adapter is OFF, the device manager is initialized and there are several
821      *    devices are in the list.
822      *
823      * Actions:
824      * - Initiate an auto connection
825      *
826      * Outcome:
827      * - Auto connect returns immediately with no connection attempts made.
828      */
829     @Test
testAutoConnectAdapterOff_returnsImmediately()830     public void testAutoConnectAdapterOff_returnsImmediately() throws Exception {
831         setPreconditionsAndStart(ADAPTER_STATE_OFF, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
832         mProfileDeviceManager.beginAutoConnecting();
833         verify(mMockProxies, times(0)).bluetoothConnectToProfile(eq(mProfileId),
834                 any(BluetoothDevice.class));
835         Assert.assertFalse(mProfileDeviceManager.isAutoConnecting());
836     }
837 
838     /**
839      * Preconditions:
840      * - The Bluetooth adapter is ON, the device manager is initialized and there are several
841      *    devices are in the list.
842      *
843      * Actions:
844      * - Initiate an auto connection
845      *
846      * Outcome:
847      * - Auto connect attempts to connect each device in the list, in order of priority.
848      */
849     @Test
testAutoConnectSeveralDevices_attemptsToConnectEachDevice()850     public void testAutoConnectSeveralDevices_attemptsToConnectEachDevice() throws Exception {
851         setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
852         ArrayList<BluetoothDevice> devices = makeDeviceList(SMALL_DEVICE_LIST);
853         for (BluetoothDevice device : devices) {
854             mockDeviceAvailability(device, true);
855         }
856 
857         mProfileDeviceManager.beginAutoConnecting();
858 
859         InOrder ordered = inOrder(mMockProxies);
860         for (BluetoothDevice device : devices) {
861             ordered.verify(mMockProxies, timeout(CONNECT_TIMEOUT_MS).times(1))
862                     .bluetoothConnectToProfile(mProfileId, device);
863         }
864     }
865 
866     //--------------------------------------------------------------------------------------------//
867     // Bluetooth stack device connection status changed event tests                               //
868     //--------------------------------------------------------------------------------------------//
869 
870     /**
871      * Preconditions:
872      * - The device manager is initialized, there are no devices in the list. We are not auto
873      *   connecting
874      *
875      * Actions:
876      * - A connection action comes in for the profile we're tracking and the device's priority is
877      *   PRIORITY_AUTO_CONNECT.
878      *
879      * Outcome:
880      * - The device is added to the list. Related/configured trigger profiles are connected.
881      */
882     @Test
testReceiveDeviceConnectPriorityAutoConnect_deviceAdded()883     public void testReceiveDeviceConnectPriorityAutoConnect_deviceAdded() throws Exception {
884         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
885         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
886         mockDevicePriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
887         sendConnectionStateChanged(device, BluetoothProfile.STATE_CONNECTED);
888         assertDeviceList(SINGLE_DEVICE_LIST);
889         for (int profile : mProfileTriggers) {
890             verify(mMockProxies, times(1)).bluetoothConnectToProfile(profile, device);
891         }
892     }
893 
894     /**
895      * Preconditions:
896      * - The device manager is initialized, there are no devices in the list.
897      *
898      * Actions:
899      * - A connection action comes in for the profile we're tracking and the device's priority is
900      *   PRIORITY_ON.
901      *
902      * Outcome:
903      * - The device is added to the list. Related/configured trigger profiles are connected.
904      */
905     @Test
testReceiveDeviceConnectPriorityOn_deviceAdded()906     public void testReceiveDeviceConnectPriorityOn_deviceAdded() throws Exception {
907         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
908         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
909         mockDevicePriority(device, BluetoothProfile.PRIORITY_ON);
910         sendConnectionStateChanged(device, BluetoothProfile.STATE_CONNECTED);
911         assertDeviceList(SINGLE_DEVICE_LIST);
912         for (int profile : mProfileTriggers) {
913             verify(mMockProxies, times(1)).bluetoothConnectToProfile(profile, device);
914         }
915     }
916 
917     /**
918      * Preconditions:
919      * - The device manager is initialized, there are no devices in the list.
920      *
921      * Actions:
922      * - A connection action comes in for the profile we're tracking and the device's priority is
923      *   PRIORITY_OFF.
924      *
925      * Outcome:
926      * - The device is not added to the list. Related/configured trigger profiles are connected.
927      */
928     @Test
testReceiveDeviceConnectPriorityOff_deviceNotAdded()929     public void testReceiveDeviceConnectPriorityOff_deviceNotAdded() throws Exception {
930         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
931         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
932         mockDevicePriority(device, BluetoothProfile.PRIORITY_OFF);
933         sendConnectionStateChanged(device, BluetoothProfile.STATE_CONNECTED);
934         assertDeviceList(EMPTY_DEVICE_LIST);
935         for (int profile : mProfileTriggers) {
936             verify(mMockProxies, times(1)).bluetoothConnectToProfile(profile, device);
937         }
938     }
939 
940     /**
941      * Preconditions:
942      * - The device manager is initialized, there are no devices in the list.
943      *
944      * Actions:
945      * - A connection action comes in for the profile we're tracking and the device's priority is
946      *   PRIORITY_UNDEFINED.
947      *
948      * Outcome:
949      * - The device is not added to the list. Related/configured trigger profiles are connected.
950      */
951     @Test
testReceiveDeviceConnectPriorityUndefined_deviceNotAdded()952     public void testReceiveDeviceConnectPriorityUndefined_deviceNotAdded() throws Exception {
953         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
954         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
955         mockDevicePriority(device, BluetoothProfile.PRIORITY_UNDEFINED);
956         sendConnectionStateChanged(device, BluetoothProfile.STATE_CONNECTED);
957         assertDeviceList(EMPTY_DEVICE_LIST);
958         for (int profile : mProfileTriggers) {
959             verify(mMockProxies, times(1)).bluetoothConnectToProfile(profile, device);
960         }
961     }
962 
963     /**
964      * Preconditions:
965      * - The device manager is initialized, there are is one device in the list.
966      *
967      * Actions:
968      * - A disconnection action comes in for the profile we're tracking and the device's priority is
969      *   PRIORITY_AUTO_CONNECT.
970      *
971      * Outcome:
972      * - The device list is unchanged.
973      */
974     @Test
testReceiveDeviceDisconnectPriorityAutoConnect_listUnchanged()975     public void testReceiveDeviceDisconnectPriorityAutoConnect_listUnchanged() throws Exception {
976         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST);
977         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
978         mockDevicePriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
979         sendConnectionStateChanged(device, BluetoothProfile.STATE_DISCONNECTED);
980         assertDeviceList(SINGLE_DEVICE_LIST);
981     }
982 
983     /**
984      * Preconditions:
985      * - The device manager is initialized, there are is one device in the list.
986      *
987      * Actions:
988      * - A disconnection action comes in for the profile we're tracking and the device's priority is
989      *   PRIORITY_ON.
990      *
991      * Outcome:
992      * - The device list is unchanged.
993      */
994     @Test
testReceiveDeviceDisconnectPriorityOn_listUnchanged()995     public void testReceiveDeviceDisconnectPriorityOn_listUnchanged() throws Exception {
996         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST);
997         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
998         mockDevicePriority(device, BluetoothProfile.PRIORITY_ON);
999         sendConnectionStateChanged(device, BluetoothProfile.STATE_DISCONNECTED);
1000         assertDeviceList(SINGLE_DEVICE_LIST);
1001     }
1002 
1003     /**
1004      * Preconditions:
1005      * - The device manager is initialized, there are is one device in the list.
1006      *
1007      * Actions:
1008      * - A disconnection action comes in for the profile we're tracking and the device's priority is
1009      *   PRIORITY_OFF.
1010      *
1011      * Outcome:
1012      * - The device list is unchanged.
1013      */
1014     @Test
testReceiveDeviceDisconnectPriorityOff_deviceRemoved()1015     public void testReceiveDeviceDisconnectPriorityOff_deviceRemoved() throws Exception {
1016         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST);
1017         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1018         mockDevicePriority(device, BluetoothProfile.PRIORITY_OFF);
1019         sendConnectionStateChanged(device, BluetoothProfile.STATE_DISCONNECTED);
1020         assertDeviceList(SINGLE_DEVICE_LIST);
1021     }
1022 
1023     /**
1024      * Preconditions:
1025      * - The device manager is initialized, there are is one device in the list.
1026      *
1027      * Actions:
1028      * - A disconnection action comes in for the profile we're tracking and the device's priority is
1029      *   PRIORITY_OFF.
1030      *
1031      * Outcome:
1032      * - The device list is unchanged.
1033      */
1034     @Test
testReceiveDeviceDisconnectPriorityUndefined_listUnchanged()1035     public void testReceiveDeviceDisconnectPriorityUndefined_listUnchanged() throws Exception {
1036         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST);
1037         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1038         mockDevicePriority(device, BluetoothProfile.PRIORITY_UNDEFINED);
1039         sendConnectionStateChanged(device, BluetoothProfile.STATE_DISCONNECTED);
1040         assertDeviceList(SINGLE_DEVICE_LIST);
1041     }
1042 
1043     //--------------------------------------------------------------------------------------------//
1044     // Bluetooth stack device bond status changed event tests                                     //
1045     //--------------------------------------------------------------------------------------------//
1046 
1047     /**
1048      * Preconditions:
1049      * - The device manager is initialized, there are is one device in the list.
1050      *
1051      * Actions:
1052      * - A device from the list has unbonded
1053      *
1054      * Outcome:
1055      * - The device is removed from the list.
1056      */
1057     @Test
testReceiveDeviceUnbonded_deviceRemoved()1058     public void testReceiveDeviceUnbonded_deviceRemoved() {
1059         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SINGLE_DEVICE_LIST);
1060         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1061         sendBondStateChanged(device, BluetoothDevice.BOND_NONE);
1062         assertDeviceList(EMPTY_DEVICE_LIST);
1063     }
1064 
1065     /**
1066      * Preconditions:
1067      * - The device manager is initialized, there are no devices in the list.
1068      *
1069      * Actions:
1070      * - A device has bonded and its UUID set claims it supports this profile.
1071      *
1072      * Outcome:
1073      * - The device is added to the list.
1074      *
1075      * NOTE: Car Service version of Mockito does not support mocking final classes and
1076      * BluetoothDevice is a final class. Unsuppress this when we can support it.
1077      */
1078     @Test
1079     @Suppress
testReceiveSupportedDeviceBonded_deviceAdded()1080     public void testReceiveSupportedDeviceBonded_deviceAdded() {
1081         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1082         BluetoothDevice device = mock(BluetoothDevice.class);
1083         doReturn(SINGLE_DEVICE_LIST.get(0)).when(device).getAddress();
1084         doReturn(mUuids).when(device).getUuids();
1085         sendBondStateChanged(device, BluetoothDevice.BOND_BONDED);
1086         assertDeviceList(SINGLE_DEVICE_LIST);
1087     }
1088 
1089     /**
1090      * Preconditions:
1091      * - The device manager is initialized, there are no devices in the list.
1092      *
1093      * Actions:
1094      * - A device has bonded and its UUID set claims it does not support this profile.
1095      *
1096      * Outcome:
1097      * - The device is ignored.
1098      */
1099     @Test
testReceiveUnsupportedDeviceBonded_deviceNotAdded()1100     public void testReceiveUnsupportedDeviceBonded_deviceNotAdded() {
1101         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1102         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1103         sendBondStateChanged(device, BluetoothDevice.BOND_BONDED);
1104         assertDeviceList(EMPTY_DEVICE_LIST);
1105     }
1106 
1107     //--------------------------------------------------------------------------------------------//
1108     // Bluetooth stack device UUID event tests                                                    //
1109     //--------------------------------------------------------------------------------------------//
1110 
1111     /**
1112      * Preconditions:
1113      * - The device manager is initialized, there are no devices in the list.
1114      *
1115      * Actions:
1116      * - A Uuid set is received for a device that has PRIORITY_AUTO_CONNECT
1117      *
1118      * Outcome:
1119      * - The device is ignored, no priority update is made.
1120      */
1121     @Test
testReceiveUuidDevicePriorityAutoConnect_doNothing()1122     public void testReceiveUuidDevicePriorityAutoConnect_doNothing() throws Exception {
1123         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1124         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1125         mockDevicePriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
1126         sendDeviceUuids(device, mUuids);
1127         assertDeviceList(EMPTY_DEVICE_LIST);
1128         verify(mMockProxies, times(0)).setProfilePriority(eq(mProfileId),
1129                 any(BluetoothDevice.class), anyInt());
1130     }
1131 
1132     /**
1133      * Preconditions:
1134      * - The device manager is initialized, there are no devices in the list.
1135      *
1136      * Actions:
1137      * - A Uuid set is received for a device that has PRIORITY_ON
1138      *
1139      * Outcome:
1140      * - The device is ignored, no priority update is made.
1141      */
1142     @Test
testReceiveUuidDevicePriorityOn_doNothing()1143     public void testReceiveUuidDevicePriorityOn_doNothing() throws Exception {
1144         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1145         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1146         mockDevicePriority(device, BluetoothProfile.PRIORITY_ON);
1147         sendDeviceUuids(device, mUuids);
1148         assertDeviceList(EMPTY_DEVICE_LIST);
1149         verify(mMockProxies, times(0)).setProfilePriority(eq(mProfileId),
1150                 any(BluetoothDevice.class), anyInt());
1151     }
1152 
1153     /**
1154      * Preconditions:
1155      * - The device manager is initialized, there are no devices in the list.
1156      *
1157      * Actions:
1158      * - A Uuid set is received for a device that has PRIORITY_OFF
1159      *
1160      * Outcome:
1161      * - The device is ignored, no priority update is made.
1162      */
1163     @Test
testReceiveUuidDevicePriorityOff_doNothing()1164     public void testReceiveUuidDevicePriorityOff_doNothing() throws Exception {
1165         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1166         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1167         mockDevicePriority(device, BluetoothProfile.PRIORITY_OFF);
1168         sendDeviceUuids(device, mUuids);
1169         assertDeviceList(EMPTY_DEVICE_LIST);
1170         verify(mMockProxies, times(0)).setProfilePriority(eq(mProfileId),
1171                 any(BluetoothDevice.class), anyInt());
1172     }
1173 
1174     /**
1175      * Preconditions:
1176      * - The device manager is initialized, there are no devices in the list.
1177      *
1178      * Actions:
1179      * - A Bonding state change with state == BOND_BONDING is received
1180      * - A Uuid set is received for a device that has PRIORITY_UNDEFINED
1181      *
1182      * Outcome:
1183      * - The device has its priority updated to PRIORITY_ON.
1184      */
1185     @Test
testReceiveUuidDevicePriorityUndefinedBonding_setPriorityOn()1186     public void testReceiveUuidDevicePriorityUndefinedBonding_setPriorityOn() throws Exception {
1187         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1188         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1189         mockDevicePriority(device, BluetoothProfile.PRIORITY_UNDEFINED);
1190         sendBondStateChanged(device, BluetoothDevice.BOND_BONDING);
1191         sendDeviceUuids(device, mUuids);
1192         assertDeviceList(EMPTY_DEVICE_LIST);
1193         verify(mMockProxies, times(1)).setProfilePriority(mProfileId, device,
1194                 BluetoothProfile.PRIORITY_ON);
1195     }
1196 
1197         /**
1198      * Preconditions:
1199      * - The device manager is initialized, there are no devices in the list.
1200      * - The designated device is not in a bonding state.
1201      *
1202      * Actions:
1203      * - A Uuid set is received for a device that has PRIORITY_UNDEFINED
1204      *
1205      * Outcome:
1206      * - The device has its priority updated to PRIORITY_ON.
1207      */
1208     @Test
testReceiveUuidDevicePriorityUndefined_setPriorityOn()1209     public void testReceiveUuidDevicePriorityUndefined_setPriorityOn() throws Exception {
1210         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1211         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1212         mockDevicePriority(device, BluetoothProfile.PRIORITY_UNDEFINED);
1213         sendDeviceUuids(device, mUuids);
1214         assertDeviceList(EMPTY_DEVICE_LIST);
1215         verify(mMockProxies, times(0)).setProfilePriority(mProfileId, device,
1216                 BluetoothProfile.PRIORITY_ON);
1217     }
1218 
1219     /**
1220      * Preconditions:
1221      * - The device manager is initialized, there are no devices in the list.
1222      *
1223      * Actions:
1224      * - A Uuid set is received for a device that is not supported for this profile
1225      *
1226      * Outcome:
1227      * - The device is ignored, no priority update is made.
1228      */
1229     @Test
testReceiveUuidsDeviceUnsupported_doNothing()1230     public void testReceiveUuidsDeviceUnsupported_doNothing() throws Exception {
1231         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, EMPTY_DEVICE_LIST);
1232         BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(SINGLE_DEVICE_LIST.get(0));
1233         mockDevicePriority(device, BluetoothProfile.PRIORITY_UNDEFINED);
1234         sendDeviceUuids(device, mBadUuids);
1235         assertDeviceList(EMPTY_DEVICE_LIST);
1236         verify(mMockProxies, times(0)).getProfilePriority(eq(mProfileId),
1237                 any(BluetoothDevice.class));
1238     }
1239 
1240     //--------------------------------------------------------------------------------------------//
1241     // Bluetooth stack adapter status changed event tests                                         //
1242     //--------------------------------------------------------------------------------------------//
1243 
1244     /**
1245      * Preconditions:
1246      * - The device manager is initialized, there are several devices in the list. The adapter is on
1247      *   and we are currently connecting devices.
1248      *
1249      * Actions:
1250      * - The adapter is turning off
1251      *
1252      * Outcome:
1253      * - Auto-connecting is cancelled
1254      */
1255     @Test
testReceiveAdapterTurningOff_cancel()1256     public void testReceiveAdapterTurningOff_cancel() {
1257         setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
1258         mProfileDeviceManager.beginAutoConnecting();
1259         Assert.assertTrue(mProfileDeviceManager.isAutoConnecting());
1260         // We have 24 seconds of auto connecting time while we force it to quit
1261         sendAdapterStateChanged(BluetoothAdapter.STATE_TURNING_OFF);
1262         Assert.assertFalse(mProfileDeviceManager.isAutoConnecting());
1263     }
1264 
1265     /**
1266      * Preconditions:
1267      * - The device manager is initialized, there are several devices in the list. The adapter is on
1268      *   and we are currently connecting devices.
1269      *
1270      * Actions:
1271      * - The adapter becomes off
1272      *
1273      * Outcome:
1274      * - Auto-connecting is cancelled. The device list is committed
1275      */
1276     @Test
testReceiveAdapterOff_cancelAndCommit()1277     public void testReceiveAdapterOff_cancelAndCommit() {
1278         setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
1279         mProfileDeviceManager.beginAutoConnecting();
1280         Assert.assertTrue(mProfileDeviceManager.isAutoConnecting());
1281         // We have 24 seconds of auto connecting time while we force it to quit
1282         sendAdapterStateChanged(BluetoothAdapter.STATE_OFF);
1283         Assert.assertFalse(mProfileDeviceManager.isAutoConnecting());
1284         assertSettingsContains(SMALL_SETTINGS_STRING);
1285     }
1286 
1287     /**
1288      * Preconditions:
1289      * - The device manager is initialized, there are several devices in the list. The adapter is on
1290      *   and we are currently connecting devices.
1291      *
1292      * Actions:
1293      * - The adapter sends a turning on. (This can happen in weird cases in the stack where the
1294      *   adapter is ON but the intent is sent away. Additionally, being ON and sending the intent is
1295      *   a great way to make sure we called cancel)
1296      *
1297      * Outcome:
1298      * - Auto-connecting is cancelled
1299      */
1300     @Test
testReceiveAdapterTurningOn_cancel()1301     public void testReceiveAdapterTurningOn_cancel() {
1302         setPreconditionsAndStart(ADAPTER_STATE_ON, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
1303         mProfileDeviceManager.beginAutoConnecting();
1304         Assert.assertTrue(mProfileDeviceManager.isAutoConnecting());
1305         sendAdapterStateChanged(BluetoothAdapter.STATE_TURNING_ON);
1306         Assert.assertFalse(mProfileDeviceManager.isAutoConnecting());
1307     }
1308 
1309     /**
1310      * Preconditions:
1311      * - The device manager is initialized, there are several devices in the list.
1312      *
1313      * Actions:
1314      * - The adapter becomes on
1315      *
1316      * Outcome:
1317      * - No actions are taken
1318      */
1319     @Test
testReceiveAdapterOn_doNothing()1320     public void testReceiveAdapterOn_doNothing() {
1321         setPreconditionsAndStart(ADAPTER_STATE_ANY, EMPTY_SETTINGS_STRING, SMALL_DEVICE_LIST);
1322         sendAdapterStateChanged(BluetoothAdapter.STATE_ON);
1323         verifyNoMoreInteractions(mMockProxies);
1324     }
1325 }
1326