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.Mockito.doReturn;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.spy;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import android.bluetooth.BluetoothDevice;
28 import android.content.Context;
29 import android.os.UserManager;
30 import android.view.ContextThemeWrapper;
31 
32 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
33 import com.android.settings.R;
34 import com.android.settings.testutils.FakeFeatureFactory;
35 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
36 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
37 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
38 import com.android.settingslib.testutils.DrawableTestHelper;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.mockito.Mock;
44 import org.mockito.MockitoAnnotations;
45 import org.robolectric.RobolectricTestRunner;
46 import org.robolectric.RuntimeEnvironment;
47 import org.robolectric.annotation.Config;
48 import org.robolectric.util.ReflectionHelpers;
49 
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.Comparator;
53 import java.util.List;
54 
55 @RunWith(RobolectricTestRunner.class)
56 @Config(shadows = {ShadowAlertDialogCompat.class})
57 public class BluetoothDevicePreferenceTest {
58     private static final boolean SHOW_DEVICES_WITHOUT_NAMES = true;
59     private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
60     private static final String MAC_ADDRESS_2 = "05:52:C7:0B:D8:3C";
61     private static final String MAC_ADDRESS_3 = "06:52:C7:0B:D8:3C";
62     private static final String MAC_ADDRESS_4 = "07:52:C7:0B:D8:3C";
63     private static final Comparator<BluetoothDevicePreference> COMPARATOR =
64             Comparator.naturalOrder();
65 
66     private Context mContext;
67     @Mock
68     private CachedBluetoothDevice mCachedBluetoothDevice;
69     @Mock
70     private CachedBluetoothDevice mCachedDevice1;
71     @Mock
72     private CachedBluetoothDevice mCachedDevice2;
73     @Mock
74     private CachedBluetoothDevice mCachedDevice3;
75 
76     private FakeFeatureFactory mFakeFeatureFactory;
77     private MetricsFeatureProvider mMetricsFeatureProvider;
78     private BluetoothDevicePreference mPreference;
79     private List<BluetoothDevicePreference> mPreferenceList = new ArrayList<>();
80 
81     @Before
setUp()82     public void setUp() {
83         MockitoAnnotations.initMocks(this);
84         Context context = spy(RuntimeEnvironment.application.getApplicationContext());
85         mContext = new ContextThemeWrapper(context, R.style.Theme_Settings);
86         mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
87         mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider();
88         when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
89         when(mCachedDevice1.getAddress()).thenReturn(MAC_ADDRESS_2);
90         when(mCachedDevice2.getAddress()).thenReturn(MAC_ADDRESS_3);
91         when(mCachedDevice3.getAddress()).thenReturn(MAC_ADDRESS_4);
92         mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
93                 SHOW_DEVICES_WITHOUT_NAMES, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
94     }
95 
96     @Test
onClicked_deviceConnected_shouldLogBluetoothDisconnectEvent()97     public void onClicked_deviceConnected_shouldLogBluetoothDisconnectEvent() {
98         when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
99 
100         mPreference.onClicked();
101 
102         verify(mMetricsFeatureProvider)
103                 .action(mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);
104     }
105 
106     @Test
onClicked_deviceBonded_shouldLogBluetoothConnectEvent()107     public void onClicked_deviceBonded_shouldLogBluetoothConnectEvent() {
108         when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
109         when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
110 
111         mPreference.onClicked();
112 
113         verify(mMetricsFeatureProvider)
114                 .action(mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT);
115     }
116 
117     @Test
onClicked_deviceNotBonded_shouldLogBluetoothPairEvent()118     public void onClicked_deviceNotBonded_shouldLogBluetoothPairEvent() {
119         when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
120         when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
121         when(mCachedBluetoothDevice.startPairing()).thenReturn(true);
122         when(mCachedBluetoothDevice.hasHumanReadableName()).thenReturn(true);
123 
124         mPreference.onClicked();
125 
126         verify(mMetricsFeatureProvider)
127                 .action(mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);
128         verify(mMetricsFeatureProvider, never())
129                 .action(mContext,
130                         MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
131     }
132 
133     @Test
onClicked_deviceNotBonded_shouldLogBluetoothPairEventAndPairWithoutNameEvent()134     public void onClicked_deviceNotBonded_shouldLogBluetoothPairEventAndPairWithoutNameEvent() {
135         when(mCachedBluetoothDevice.isConnected()).thenReturn(false);
136         when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
137         when(mCachedBluetoothDevice.startPairing()).thenReturn(true);
138         when(mCachedBluetoothDevice.hasHumanReadableName()).thenReturn(false);
139 
140         mPreference.onClicked();
141 
142         verify(mMetricsFeatureProvider)
143                 .action(mContext, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);
144         verify(mMetricsFeatureProvider)
145                 .action(mContext,
146                         MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
147     }
148 
149     @Test
getSecondTargetResource_shouldBeGearIconLayout()150     public void getSecondTargetResource_shouldBeGearIconLayout() {
151         assertThat(mPreference.getSecondTargetResId()).isEqualTo(R.layout.preference_widget_gear);
152     }
153 
154     @Test
shouldHideSecondTarget_noDevice_shouldReturnTrue()155     public void shouldHideSecondTarget_noDevice_shouldReturnTrue() {
156         ReflectionHelpers.setField(mPreference, "mCachedDevice", null);
157 
158         assertThat(mPreference.shouldHideSecondTarget()).isTrue();
159     }
160 
161     @Test
shouldHideSecondTarget_notBond_shouldReturnTrue()162     public void shouldHideSecondTarget_notBond_shouldReturnTrue() {
163         when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
164 
165         assertThat(mPreference.shouldHideSecondTarget()).isTrue();
166     }
167 
168     @Test
shouldHideSecondTarget_hasUserRestriction_shouldReturnTrue()169     public void shouldHideSecondTarget_hasUserRestriction_shouldReturnTrue() {
170         final UserManager um = mock(UserManager.class);
171         ReflectionHelpers.setField(mPreference, "mUserManager", um);
172         when(um.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH)).thenReturn(true);
173 
174         assertThat(mPreference.shouldHideSecondTarget()).isTrue();
175     }
176 
177     @Test
shouldHideSecondTarget_hasBoundDeviceAndNoRestriction_shouldReturnFalse()178     public void shouldHideSecondTarget_hasBoundDeviceAndNoRestriction_shouldReturnFalse() {
179         when(mCachedBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
180         final UserManager um = mock(UserManager.class);
181         ReflectionHelpers.setField(mPreference, "mUserManager", um);
182         when(um.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH)).thenReturn(false);
183 
184         assertThat(mPreference.shouldHideSecondTarget()).isFalse();
185     }
186 
187     @Test
isVisible_showDeviceWithoutNames_visible()188     public void isVisible_showDeviceWithoutNames_visible() {
189         doReturn(false).when(mCachedBluetoothDevice).hasHumanReadableName();
190         BluetoothDevicePreference preference =
191                 new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
192                         SHOW_DEVICES_WITHOUT_NAMES,
193                         BluetoothDevicePreference.SortType.TYPE_DEFAULT);
194 
195         assertThat(preference.isVisible()).isTrue();
196     }
197 
198     @Test
isVisible_hideDeviceWithoutNames_invisible()199     public void isVisible_hideDeviceWithoutNames_invisible() {
200         doReturn(false).when(mCachedBluetoothDevice).hasHumanReadableName();
201         BluetoothDevicePreference preference =
202                 new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
203                         false, BluetoothDevicePreference.SortType.TYPE_DEFAULT);
204 
205         assertThat(preference.isVisible()).isFalse();
206     }
207 
208     @Test
setNeedNotifyHierarchyChanged_updateValue()209     public void setNeedNotifyHierarchyChanged_updateValue() {
210         mPreference.setNeedNotifyHierarchyChanged(true);
211 
212         assertThat(mPreference.mNeedNotifyHierarchyChanged).isTrue();
213     }
214 
215     @Test
compareTo_sortTypeFIFO()216     public void compareTo_sortTypeFIFO() {
217         final BluetoothDevicePreference preference3 = new BluetoothDevicePreference(mContext,
218                 mCachedDevice3, SHOW_DEVICES_WITHOUT_NAMES,
219                 BluetoothDevicePreference.SortType.TYPE_FIFO);
220         final BluetoothDevicePreference preference2 = new BluetoothDevicePreference(mContext,
221                 mCachedDevice2, SHOW_DEVICES_WITHOUT_NAMES,
222                 BluetoothDevicePreference.SortType.TYPE_FIFO);
223         final BluetoothDevicePreference preference1 = new BluetoothDevicePreference(mContext,
224                 mCachedDevice1, SHOW_DEVICES_WITHOUT_NAMES,
225                 BluetoothDevicePreference.SortType.TYPE_FIFO);
226 
227         mPreferenceList.add(preference1);
228         mPreferenceList.add(preference2);
229         mPreferenceList.add(preference3);
230         Collections.sort(mPreferenceList, COMPARATOR);
231 
232         assertThat(mPreferenceList.get(0).getCachedDevice().getAddress())
233                 .isEqualTo(preference3.getCachedDevice().getAddress());
234         assertThat(mPreferenceList.get(1).getCachedDevice().getAddress())
235                 .isEqualTo(preference2.getCachedDevice().getAddress());
236         assertThat(mPreferenceList.get(2).getCachedDevice().getAddress())
237                 .isEqualTo(preference1.getCachedDevice().getAddress());
238     }
239 
240     @Test
compareTo_sortTypeDefault()241     public void compareTo_sortTypeDefault() {
242         final BluetoothDevicePreference preference3 = new BluetoothDevicePreference(mContext,
243                 mCachedDevice3, SHOW_DEVICES_WITHOUT_NAMES,
244                 BluetoothDevicePreference.SortType.TYPE_DEFAULT);
245         final BluetoothDevicePreference preference2 = new BluetoothDevicePreference(mContext,
246                 mCachedDevice2, SHOW_DEVICES_WITHOUT_NAMES,
247                 BluetoothDevicePreference.SortType.TYPE_DEFAULT);
248         final BluetoothDevicePreference preference1 = new BluetoothDevicePreference(mContext,
249                 mCachedDevice1, SHOW_DEVICES_WITHOUT_NAMES,
250                 BluetoothDevicePreference.SortType.TYPE_DEFAULT);
251 
252         mPreferenceList.add(preference1);
253         mPreferenceList.add(preference2);
254         mPreferenceList.add(preference3);
255         Collections.sort(mPreferenceList, COMPARATOR);
256 
257         assertThat(mPreferenceList.get(0).getCachedDevice().getAddress())
258                 .isEqualTo(preference1.getCachedDevice().getAddress());
259         assertThat(mPreferenceList.get(1).getCachedDevice().getAddress())
260                 .isEqualTo(preference2.getCachedDevice().getAddress());
261         assertThat(mPreferenceList.get(2).getCachedDevice().getAddress())
262                 .isEqualTo(preference3.getCachedDevice().getAddress());
263     }
264 }
265