• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.settings.bluetooth;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyBoolean;
23 import static org.mockito.ArgumentMatchers.anyInt;
24 import static org.mockito.Mockito.doNothing;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.spy;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.bluetooth.BluetoothAdapter;
34 import android.bluetooth.BluetoothDevice;
35 import android.bluetooth.BluetoothProfile;
36 import android.content.Context;
37 import android.content.res.Resources;
38 
39 import androidx.preference.PreferenceGroup;
40 
41 import com.android.settings.R;
42 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
43 import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
44 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
45 import com.android.settingslib.bluetooth.LocalBluetoothManager;
46 import com.android.settingslib.widget.FooterPreference;
47 
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.Answers;
52 import org.mockito.Mock;
53 import org.mockito.MockitoAnnotations;
54 import org.robolectric.RobolectricTestRunner;
55 import org.robolectric.RuntimeEnvironment;
56 import org.robolectric.annotation.Config;
57 import org.robolectric.shadow.api.Shadow;
58 
59 @RunWith(RobolectricTestRunner.class)
60 @Config(shadows = {ShadowBluetoothAdapter.class})
61 public class BluetoothPairingDetailTest {
62     private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
63     private static final String TEST_DEVICE_ADDRESS_B = "00:B1:B1:B1:B1:B1";
64 
65     @Mock
66     private Resources mResource;
67     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
68     private LocalBluetoothManager mLocalManager;
69     @Mock
70     private PreferenceGroup mPreferenceGroup;
71     @Mock
72     private CachedBluetoothDevice mCachedBluetoothDevice;
73     private BluetoothPairingDetail mFragment;
74     private Context mContext;
75     private BluetoothProgressCategory mAvailableDevicesCategory;
76     private FooterPreference mFooterPreference;
77     private BluetoothAdapter mBluetoothAdapter;
78     private ShadowBluetoothAdapter mShadowBluetoothAdapter;
79     private BluetoothDevice mBluetoothDevice;
80 
81     @Before
setUp()82     public void setUp() {
83         MockitoAnnotations.initMocks(this);
84 
85         mContext = RuntimeEnvironment.application;
86         mFragment = spy(new BluetoothPairingDetail());
87         doReturn(mContext).when(mFragment).getContext();
88         doReturn(mResource).when(mFragment).getResources();
89         when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
90 
91         mAvailableDevicesCategory = spy(new BluetoothProgressCategory(mContext));
92         mFooterPreference = new FooterPreference(mContext);
93         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
94         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
95         mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
96 
97         mFragment.mBluetoothAdapter = mBluetoothAdapter;
98         mFragment.mLocalManager = mLocalManager;
99         mFragment.mDeviceListGroup = mPreferenceGroup;
100         mFragment.mAlwaysDiscoverable = new AlwaysDiscoverable(mContext);
101     }
102 
103     @Test
initPreferencesFromPreferenceScreen_findPreferences()104     public void initPreferencesFromPreferenceScreen_findPreferences() {
105         doReturn(mAvailableDevicesCategory).when(mFragment)
106             .findPreference(BluetoothPairingDetail.KEY_AVAIL_DEVICES);
107         doReturn(mFooterPreference).when(mFragment)
108             .findPreference(BluetoothPairingDetail.KEY_FOOTER_PREF);
109 
110         mFragment.initPreferencesFromPreferenceScreen();
111 
112         assertThat(mFragment.mAvailableDevicesCategory).isEqualTo(mAvailableDevicesCategory);
113         assertThat(mFragment.mFooterPreference).isEqualTo(mFooterPreference);
114     }
115 
116     @Test
startScanning_startScanAndRemoveDevices()117     public void startScanning_startScanAndRemoveDevices() {
118         mFragment.mAvailableDevicesCategory = mAvailableDevicesCategory;
119         mFragment.mDeviceListGroup = mAvailableDevicesCategory;
120 
121         mFragment.enableScanning();
122 
123         verify(mFragment).startScanning();
124         verify(mAvailableDevicesCategory).removeAll();
125     }
126 
127     @Test
updateContent_stateOn_addDevices()128     public void updateContent_stateOn_addDevices() {
129         mFragment.mAvailableDevicesCategory = mAvailableDevicesCategory;
130         mFragment.mFooterPreference = mFooterPreference;
131         doNothing().when(mFragment).addDeviceCategory(any(), anyInt(), any(), anyBoolean());
132 
133         mFragment.updateContent(BluetoothAdapter.STATE_ON);
134 
135         verify(mFragment).addDeviceCategory(mAvailableDevicesCategory,
136                 R.string.bluetooth_preference_found_media_devices,
137                 BluetoothDeviceFilter.ALL_FILTER, false);
138         assertThat(mBluetoothAdapter.getScanMode())
139                 .isEqualTo(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
140     }
141 
142     @Test
updateContent_stateOff_finish()143     public void updateContent_stateOff_finish() {
144         mFragment.updateContent(BluetoothAdapter.STATE_OFF);
145 
146         verify(mFragment).finish();
147     }
148 
149     @Test
updateBluetooth_bluetoothOff_turnOnBluetooth()150     public void updateBluetooth_bluetoothOff_turnOnBluetooth() {
151         mShadowBluetoothAdapter.setEnabled(false);
152 
153         mFragment.updateBluetooth();
154 
155         assertThat(mBluetoothAdapter.isEnabled()).isTrue();
156     }
157 
158     @Test
updateBluetooth_bluetoothOn_updateState()159     public void updateBluetooth_bluetoothOn_updateState() {
160         mShadowBluetoothAdapter.setEnabled(true);
161         doNothing().when(mFragment).updateContent(anyInt());
162 
163         mFragment.updateBluetooth();
164 
165         verify(mFragment).updateContent(anyInt());
166     }
167 
168     @Test
onScanningStateChanged_restartScanAfterInitialScanning()169     public void onScanningStateChanged_restartScanAfterInitialScanning() {
170         mFragment.mAvailableDevicesCategory = mAvailableDevicesCategory;
171         mFragment.mFooterPreference = mFooterPreference;
172         mFragment.mDeviceListGroup = mAvailableDevicesCategory;
173         doNothing().when(mFragment).addDeviceCategory(any(), anyInt(), any(), anyBoolean());
174 
175         // Initial Bluetooth ON will trigger scan enable, list clear and scan start
176         mFragment.updateContent(BluetoothAdapter.STATE_ON);
177         verify(mFragment).enableScanning();
178         assertThat(mAvailableDevicesCategory.getPreferenceCount()).isEqualTo(0);
179         verify(mFragment).startScanning();
180 
181         // Subsequent scan started event will not trigger start/stop nor list clear
182         mFragment.onScanningStateChanged(true);
183         verify(mFragment, times(1)).startScanning();
184         verify(mAvailableDevicesCategory, times(1)).setProgress(true);
185 
186         // Subsequent scan finished event will trigger scan start without list clean
187         mFragment.onScanningStateChanged(false);
188         verify(mFragment, times(2)).startScanning();
189         verify(mAvailableDevicesCategory, times(2)).setProgress(true);
190 
191         // Subsequent scan started event will not trigger any change
192         mFragment.onScanningStateChanged(true);
193         verify(mFragment, times(2)).startScanning();
194         verify(mAvailableDevicesCategory, times(3)).setProgress(true);
195         verify(mFragment, never()).stopScanning();
196 
197         // Disable scanning will trigger scan stop
198         mFragment.disableScanning();
199         verify(mFragment, times(1)).stopScanning();
200 
201         // Subsequent scan start event will not trigger any change besides progress circle
202         mFragment.onScanningStateChanged(true);
203         verify(mAvailableDevicesCategory, times(4)).setProgress(true);
204 
205         // However, subsequent scan finished event won't trigger new scan start and will stop
206         // progress circle from spinning
207         mFragment.onScanningStateChanged(false);
208         verify(mAvailableDevicesCategory, times(1)).setProgress(false);
209         verify(mFragment, times(2)).startScanning();
210         verify(mFragment, times(1)).stopScanning();
211 
212         // Verify that clean up only happen once at initialization
213         verify(mAvailableDevicesCategory, times(1)).removeAll();
214     }
215 
216     @Test
onBluetoothStateChanged_whenTurnedOnBTShowToast()217     public void onBluetoothStateChanged_whenTurnedOnBTShowToast() {
218         doNothing().when(mFragment).updateContent(anyInt());
219 
220         mFragment.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
221 
222         verify(mFragment).showBluetoothTurnedOnToast();
223     }
224 
225     @Test
onProfileConnectionStateChanged_deviceInSelectedListAndConnected_finish()226     public void onProfileConnectionStateChanged_deviceInSelectedListAndConnected_finish() {
227         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
228         mFragment.mSelectedList.add(mBluetoothDevice);
229         mFragment.mSelectedList.add(device);
230 
231         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
232         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
233 
234         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
235                 BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
236 
237         verify(mFragment).finish();
238     }
239 
240     @Test
onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing()241     public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
242         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
243         mFragment.mSelectedList.add(device);
244 
245         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
246         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
247 
248         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
249                 BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
250 
251         // not crash
252     }
253 
254     @Test
onProfileConnectionStateChanged_deviceDisconnected_doNothing()255     public void onProfileConnectionStateChanged_deviceDisconnected_doNothing() {
256         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
257         mFragment.mSelectedList.add(mBluetoothDevice);
258         mFragment.mSelectedList.add(device);
259 
260         when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
261         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
262 
263         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
264                 BluetoothProfile.A2DP, BluetoothAdapter.STATE_DISCONNECTED);
265 
266         // not crash
267     }
268 
269     @Test
onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed()270     public void onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed() {
271         final BluetoothDevicePreference preference =
272                 new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
273                 true, BluetoothDevicePreference.SortType.TYPE_FIFO);
274         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
275         mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
276 
277         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
278         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
279 
280         mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
281                 BluetoothProfile.A2DP, BluetoothAdapter.STATE_CONNECTED);
282 
283         assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
284     }
285 
286     @Test
onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing()287     public void onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing() {
288         final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
289         final BluetoothDevicePreference preference =
290                 new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
291                         true, BluetoothDevicePreference.SortType.TYPE_FIFO);
292         final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
293         final BluetoothDevice device2 = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
294         mFragment.mDevicePreferenceMap.put(mCachedBluetoothDevice, preference);
295 
296         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
297         when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
298         when(cachedDevice.isConnected()).thenReturn(true);
299         when(cachedDevice.getDevice()).thenReturn(device2);
300         when(cachedDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS_B);
301 
302         mFragment.onProfileConnectionStateChanged(cachedDevice, BluetoothProfile.A2DP,
303                 BluetoothAdapter.STATE_CONNECTED);
304 
305         // not crash
306     }
307 }