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 package com.android.settings.bluetooth;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.Mockito.doReturn;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.verify;
24 import static org.mockito.Mockito.when;
25 
26 import android.bluetooth.BluetoothAdapter;
27 import android.bluetooth.BluetoothDevice;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.graphics.drawable.Drawable;
31 import android.util.Pair;
32 
33 import androidx.preference.Preference;
34 
35 import com.android.settings.SettingsActivity;
36 import com.android.settings.connecteddevice.DevicePreferenceCallback;
37 import com.android.settings.dashboard.DashboardFragment;
38 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
39 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
40 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
41 import com.android.settingslib.bluetooth.LocalBluetoothManager;
42 
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.mockito.ArgumentCaptor;
47 import org.mockito.Mock;
48 import org.mockito.MockitoAnnotations;
49 import org.robolectric.RobolectricTestRunner;
50 import org.robolectric.RuntimeEnvironment;
51 import org.robolectric.annotation.Config;
52 import org.robolectric.shadow.api.Shadow;
53 
54 import java.util.ArrayList;
55 import java.util.List;
56 
57 @RunWith(RobolectricTestRunner.class)
58 @Config(shadows = {ShadowBluetoothAdapter.class})
59 public class BluetoothDeviceUpdaterTest {
60 
61     private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
62     private static final String SUB_MAC_ADDRESS = "05:52:C7:0B:D8:3C";
63     private static final String TEST_NAME = "test_name";
64 
65     @Mock
66     private DashboardFragment mDashboardFragment;
67     @Mock
68     private DevicePreferenceCallback mDevicePreferenceCallback;
69     @Mock
70     private CachedBluetoothDevice mCachedBluetoothDevice;
71     @Mock
72     private CachedBluetoothDevice mSubCachedBluetoothDevice;
73     @Mock
74     private BluetoothDevice mBluetoothDevice;
75     @Mock
76     private BluetoothDevice mSubBluetoothDevice;
77     @Mock
78     private SettingsActivity mSettingsActivity;
79     @Mock
80     private LocalBluetoothManager mLocalManager;
81     @Mock
82     private CachedBluetoothDeviceManager mCachedDeviceManager;
83     @Mock
84     private Drawable mDrawable;
85 
86     private Context mContext;
87     private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
88     private BluetoothDevicePreference mPreference;
89     private ShadowBluetoothAdapter mShadowBluetoothAdapter;
90     private List<CachedBluetoothDevice> mCachedDevices = new ArrayList<>();
91 
92     @Before
setUp()93     public void setUp() {
94         MockitoAnnotations.initMocks(this);
95 
96         Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
97         mContext = RuntimeEnvironment.application;
98         mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
99         mCachedDevices.add(mCachedBluetoothDevice);
100         doReturn(mContext).when(mDashboardFragment).getContext();
101         when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
102         when(mSubCachedBluetoothDevice.getDevice()).thenReturn(mSubBluetoothDevice);
103         when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
104         when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
105         when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
106         when(mSubBluetoothDevice.getAddress()).thenReturn(SUB_MAC_ADDRESS);
107         when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
108 
109         mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
110                 false, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
111         mBluetoothDeviceUpdater =
112             new BluetoothDeviceUpdater(mContext, mDashboardFragment, mDevicePreferenceCallback,
113                     mLocalManager) {
114                 @Override
115                 public boolean isFilterMatched(CachedBluetoothDevice cachedBluetoothDevice) {
116                     return true;
117                 }
118 
119                 @Override
120                 protected String getPreferenceKey() {
121                     return "test_bt";
122                 }
123             };
124         mBluetoothDeviceUpdater.setPrefContext(mContext);
125     }
126 
127     @Test
testAddPreference_deviceExist_doNothing()128     public void testAddPreference_deviceExist_doNothing() {
129         mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
130 
131         mBluetoothDeviceUpdater.addPreference(mCachedBluetoothDevice);
132 
133         verify(mDevicePreferenceCallback, never()).onDeviceAdded(any(Preference.class));
134     }
135 
136     @Test
testAddPreference_deviceNotExist_addPreference()137     public void testAddPreference_deviceNotExist_addPreference() {
138         mBluetoothDeviceUpdater.addPreference(mCachedBluetoothDevice);
139 
140         final Preference preference = mBluetoothDeviceUpdater.mPreferenceMap.get(mBluetoothDevice);
141         assertThat(preference).isNotNull();
142         verify(mDevicePreferenceCallback).onDeviceAdded(preference);
143     }
144 
145     @Test
testRemovePreference_deviceExist_removePreference()146     public void testRemovePreference_deviceExist_removePreference() {
147         mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
148 
149         mBluetoothDeviceUpdater.removePreference(mCachedBluetoothDevice);
150 
151         verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference);
152         assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse();
153     }
154 
155     @Test
testOnDeviceDeleted_deviceExists_removePreference()156     public void testOnDeviceDeleted_deviceExists_removePreference() {
157         mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
158 
159         mBluetoothDeviceUpdater.onDeviceDeleted(mCachedBluetoothDevice);
160 
161         verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference);
162         assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse();
163     }
164 
165     @Test
testRemovePreference_deviceNotExist_doNothing()166     public void testRemovePreference_deviceNotExist_doNothing() {
167         mBluetoothDeviceUpdater.removePreference(mCachedBluetoothDevice);
168 
169         verify(mDevicePreferenceCallback, never()).onDeviceRemoved(any(Preference.class));
170     }
171 
172     @Test
testRemovePreference_subDeviceExist_removePreference()173     public void testRemovePreference_subDeviceExist_removePreference() {
174         when(mCachedBluetoothDevice.getSubDevice()).thenReturn(mSubCachedBluetoothDevice);
175         mBluetoothDeviceUpdater.mPreferenceMap.put(mSubBluetoothDevice, mPreference);
176 
177         assertThat(mBluetoothDeviceUpdater.mPreferenceMap.
178                 containsKey(mSubBluetoothDevice)).isTrue();
179         mBluetoothDeviceUpdater.removePreference(mCachedBluetoothDevice);
180 
181         verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference);
182         assertThat(mBluetoothDeviceUpdater.mPreferenceMap.
183                 containsKey(mSubBluetoothDevice)).isFalse();
184     }
185 
186     @Test
testDeviceProfilesListener_click_startBluetoothDeviceDetailPage()187     public void testDeviceProfilesListener_click_startBluetoothDeviceDetailPage() {
188         doReturn(mSettingsActivity).when(mDashboardFragment).getContext();
189 
190         final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
191         mBluetoothDeviceUpdater.mDeviceProfilesListener.onGearClick(mPreference);
192 
193         verify(mSettingsActivity).startActivity(intentCaptor.capture());
194         assertThat(intentCaptor.getValue().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
195                 .isEqualTo(BluetoothDeviceDetailsFragment.class.getName());
196     }
197 
198     @Test
isDeviceConnected_deviceConnected()199     public void isDeviceConnected_deviceConnected() {
200         doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState();
201         doReturn(true).when(mBluetoothDevice).isConnected();
202 
203         assertThat(mBluetoothDeviceUpdater.isDeviceConnected(mCachedBluetoothDevice)).isTrue();
204     }
205 
206     @Test
isDeviceConnected_deviceNotConnected()207     public void isDeviceConnected_deviceNotConnected() {
208         doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState();
209         doReturn(false).when(mBluetoothDevice).isConnected();
210 
211         assertThat(mBluetoothDeviceUpdater.isDeviceConnected(mCachedBluetoothDevice)).isFalse();
212     }
213 
214     @Test
registerCallback_localBluetoothManagerNull_shouldNotCrash()215     public void registerCallback_localBluetoothManagerNull_shouldNotCrash() {
216         mBluetoothDeviceUpdater.mLocalManager = null;
217 
218         // Shouldn't crash
219         mBluetoothDeviceUpdater.registerCallback();
220     }
221 
222     @Test
unregisterCallback_localBluetoothManagerNull_shouldNotCrash()223     public void unregisterCallback_localBluetoothManagerNull_shouldNotCrash() {
224         mBluetoothDeviceUpdater.mLocalManager = null;
225 
226         // Shouldn't crash
227         mBluetoothDeviceUpdater.unregisterCallback();
228     }
229 
230     @Test
forceUpdate_bluetoothDisabled_removeAllDevicesFromPreference()231     public void forceUpdate_bluetoothDisabled_removeAllDevicesFromPreference() {
232         mShadowBluetoothAdapter.setEnabled(false);
233         mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
234 
235         mBluetoothDeviceUpdater.forceUpdate();
236 
237         verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference);
238         assertThat(mBluetoothDeviceUpdater.mPreferenceMap).isEmpty();
239     }
240 
241     @Test
forceUpdate_bluetoothEnabled_addPreference()242     public void forceUpdate_bluetoothEnabled_addPreference() {
243         mShadowBluetoothAdapter.setEnabled(true);
244         mBluetoothDeviceUpdater.forceUpdate();
245 
246         verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class));
247     }
248 
249     @Test
onBluetoothStateChanged_bluetoothStateIsOn_forceUpdate()250     public void onBluetoothStateChanged_bluetoothStateIsOn_forceUpdate() {
251         mShadowBluetoothAdapter.setEnabled(true);
252         mBluetoothDeviceUpdater.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
253 
254         verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class));
255     }
256 
257     @Test
onBluetoothStateChanged_bluetoothStateIsOff_removeAllDevicesFromPreference()258     public void onBluetoothStateChanged_bluetoothStateIsOff_removeAllDevicesFromPreference() {
259         mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
260 
261         mBluetoothDeviceUpdater.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
262 
263         verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference);
264         assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse();
265     }
266 
267     @Test
havePreference_refreshPreference()268     public void havePreference_refreshPreference() {
269         mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
270         mPreference.setTitle("fake_name");
271 
272         when(mCachedBluetoothDevice.getName()).thenReturn(TEST_NAME);
273         mBluetoothDeviceUpdater.refreshPreference();
274 
275         assertThat(mPreference.getTitle()).isEqualTo(TEST_NAME);
276     }
277 }
278