1 /*
2  * Copyright (C) 2017 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.bluetooth.mapclient;
18 
19 import static org.mockito.Mockito.*;
20 
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.BluetoothDevice;
23 import android.bluetooth.BluetoothProfile;
24 import android.bluetooth.IBluetoothMapClient;
25 import android.content.Context;
26 import android.os.UserHandle;
27 
28 import androidx.test.InstrumentationRegistry;
29 import androidx.test.filters.MediumTest;
30 import androidx.test.rule.ServiceTestRule;
31 import androidx.test.runner.AndroidJUnit4;
32 
33 import com.android.bluetooth.R;
34 import com.android.bluetooth.TestUtils;
35 import com.android.bluetooth.Utils;
36 import com.android.bluetooth.btservice.AdapterService;
37 import com.android.bluetooth.btservice.storage.DatabaseManager;
38 
39 import org.junit.After;
40 import org.junit.Assert;
41 import org.junit.Assume;
42 import org.junit.Before;
43 import org.junit.Rule;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 
49 import java.util.ArrayList;
50 import java.util.List;
51 import java.util.Map;
52 
53 @MediumTest
54 @RunWith(AndroidJUnit4.class)
55 public class MapClientTest {
56     private static final String TAG = MapClientTest.class.getSimpleName();
57     private MapClientService mService = null;
58     private BluetoothAdapter mAdapter = null;
59     private Context mTargetContext;
60 
61     @Mock private AdapterService mAdapterService;
62     @Mock private MnsService mMockMnsService;
63     @Mock private DatabaseManager mDatabaseManager;
64 
65     @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();
66 
67     @Before
setUp()68     public void setUp() throws Exception {
69         mTargetContext = InstrumentationRegistry.getTargetContext();
70         Assume.assumeTrue("Ignore test when MapClientService is not enabled",
71                 mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce));
72         MockitoAnnotations.initMocks(this);
73         TestUtils.setAdapterService(mAdapterService);
74         when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager);
75         doReturn(true, false).when(mAdapterService).isStartedProfile(anyString());
76         MapUtils.setMnsService(mMockMnsService);
77         TestUtils.startService(mServiceRule, MapClientService.class);
78         mService = MapClientService.getMapClientService();
79         Assert.assertNotNull(mService);
80         mAdapter = BluetoothAdapter.getDefaultAdapter();
81     }
82 
83     @After
tearDown()84     public void tearDown() throws Exception {
85         if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce)) {
86             return;
87         }
88         TestUtils.stopService(mServiceRule, MapClientService.class);
89         mService = MapClientService.getMapClientService();
90         Assert.assertNull(mService);
91         TestUtils.clearAdapterService(mAdapterService);
92     }
93 
94     /**
95      * Mock the priority of a bluetooth device
96      *
97      * @param device - The bluetooth device you wish to mock the priority of
98      * @param priority - The priority value you want the device to have
99      */
mockDevicePriority(BluetoothDevice device, int priority)100     private void mockDevicePriority(BluetoothDevice device, int priority) {
101         when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.MAP_CLIENT))
102                 .thenReturn(priority);
103     }
104 
105     @Test
testInitialize()106     public void testInitialize() {
107         Assert.assertNotNull(MapClientService.getMapClientService());
108     }
109 
110     /**
111      * Test connection of one device.
112      */
113     @Test
testConnect()114     public void testConnect() {
115         // make sure there is no statemachine already defined for this device
116         BluetoothDevice device = makeBluetoothDevice("11:11:11:11:11:11");
117         Assert.assertNull(mService.getInstanceMap().get(device));
118 
119         // connect a bluetooth device
120         mockDevicePriority(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
121         Assert.assertTrue(mService.connect(device));
122 
123         // is the statemachine created
124         Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
125         Assert.assertEquals(1, map.size());
126         Assert.assertNotNull(map.get(device));
127         TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
128 
129         Assert.assertEquals(map.get(device).getState(), BluetoothProfile.STATE_CONNECTING);
130         mService.cleanupDevice(device);
131         Assert.assertNull(mService.getInstanceMap().get(device));
132     }
133 
134     /**
135      * Test that a PRIORITY_OFF device is not connected to
136      */
137     @Test
testConnectPriorityOffDevice()138     public void testConnectPriorityOffDevice() {
139         // make sure there is no statemachine already defined for this device
140         BluetoothDevice device = makeBluetoothDevice("11:11:11:11:11:11");
141         Assert.assertNull(mService.getInstanceMap().get(device));
142 
143         // connect a bluetooth device
144         mockDevicePriority(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
145         Assert.assertFalse(mService.connect(device));
146 
147         // is the statemachine created
148         Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
149         Assert.assertEquals(0, map.size());
150         Assert.assertNull(map.get(device));
151     }
152 
153     /**
154      * Test connecting MAXIMUM_CONNECTED_DEVICES devices.
155      */
156     @Test
testConnectMaxDevices()157     public void testConnectMaxDevices() {
158         // Create bluetoothdevice & mock statemachine objects to be used in this test
159         List<BluetoothDevice> list = new ArrayList<>();
160         String address = "11:11:11:11:11:1";
161         for (int i = 0; i < MapClientService.MAXIMUM_CONNECTED_DEVICES; ++i) {
162             list.add(makeBluetoothDevice(address + i));
163         }
164 
165         // make sure there is no statemachine already defined for the devices defined above
166         for (BluetoothDevice d : list) {
167             Assert.assertNull(mService.getInstanceMap().get(d));
168         }
169 
170         // run the test - connect all devices, set their priorities to on
171         for (BluetoothDevice d : list) {
172             mockDevicePriority(d, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
173             Assert.assertTrue(mService.connect(d));
174         }
175 
176         // verify
177         Map<BluetoothDevice, MceStateMachine> map = mService.getInstanceMap();
178         Assert.assertEquals(MapClientService.MAXIMUM_CONNECTED_DEVICES, map.size());
179         for (BluetoothDevice d : list) {
180             Assert.assertNotNull(map.get(d));
181         }
182 
183         // Try to connect one more device. Should fail.
184         BluetoothDevice last = makeBluetoothDevice("11:22:33:44:55:66");
185         Assert.assertFalse(mService.connect(last));
186     }
187 
188     /**
189      * Test calling connect via Binder
190      */
191     @Test
testConnectViaBinder()192     public void testConnectViaBinder() {
193         BluetoothDevice device = makeBluetoothDevice("11:11:11:11:11:11");
194         mockDevicePriority(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
195         IBluetoothMapClient.Stub mapClientBinder = (IBluetoothMapClient.Stub) mService.initBinder();
196         try {
197             Utils.setForegroundUserId(UserHandle.getCallingUserId());
198             Assert.assertTrue(mapClientBinder.connect(device, mAdapter.getAttributionSource()));
199         } catch (Exception e) {
200             Assert.fail(e.toString());
201         }
202     }
203 
makeBluetoothDevice(String address)204     private BluetoothDevice makeBluetoothDevice(String address) {
205         return mAdapter.getRemoteDevice(address);
206     }
207 }
208