1 /*
2  * Copyright (C) 2018 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;
18 
19 import static android.content.Intent.ACTION_MEDIA_SHARED;
20 import static android.content.Intent.ACTION_MEDIA_UNSHARED;
21 import static android.hardware.usb.UsbManager.ACTION_USB_STATE;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.anyInt;
27 import static org.mockito.Mockito.doNothing;
28 import static org.mockito.Mockito.doReturn;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.times;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35 
36 import android.bluetooth.BluetoothAdapter;
37 import android.bluetooth.BluetoothPan;
38 import android.content.BroadcastReceiver;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.IntentFilter;
42 import android.hardware.usb.UsbManager;
43 import android.net.ConnectivityManager;
44 import android.net.TetheringManager;
45 import android.net.wifi.WifiManager;
46 import android.os.UserHandle;
47 import android.os.UserManager;
48 import android.util.FeatureFlagUtils;
49 
50 import androidx.fragment.app.FragmentActivity;
51 import androidx.preference.Preference;
52 import androidx.preference.SwitchPreference;
53 
54 import com.android.settings.core.FeatureFlags;
55 import com.android.settingslib.RestrictedSwitchPreference;
56 
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.ArgumentCaptor;
61 import org.mockito.Mock;
62 import org.mockito.MockitoAnnotations;
63 import org.robolectric.RobolectricTestRunner;
64 import org.robolectric.RuntimeEnvironment;
65 
66 import java.util.ArrayList;
67 import java.util.List;
68 
69 @RunWith(RobolectricTestRunner.class)
70 public class TetherSettingsTest {
71 
72     private Context mContext;
73 
74     @Mock
75     private ConnectivityManager mConnectivityManager;
76     @Mock
77     private UserManager mUserManager;
78     @Mock
79     private TetheringManager mTetheringManager;
80 
81     @Before
setUp()82     public void setUp() throws Exception {
83         mContext = spy(RuntimeEnvironment.application);
84 
85         MockitoAnnotations.initMocks(this);
86         doReturn(mConnectivityManager)
87                 .when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
88         doReturn(mUserManager)
89                 .when(mContext).getSystemService(Context.USER_SERVICE);
90         doReturn(mTetheringManager)
91                 .when(mContext).getSystemService(Context.TETHERING_SERVICE);
92         doReturn(mContext).when(mContext).createPackageContextAsUser(
93                 any(String.class), anyInt(), any(UserHandle.class));
94 
95         setupIsTetherAvailable(true);
96 
97         when(mTetheringManager.getTetherableUsbRegexs()).thenReturn(new String[0]);
98         when(mTetheringManager.getTetherableBluetoothRegexs()).thenReturn(new String[0]);
99     }
100 
101     @Test
testTetherNonIndexableKeys_tetherAvailable_keysNotReturned()102     public void testTetherNonIndexableKeys_tetherAvailable_keysNotReturned() {
103         FeatureFlagUtils.setEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE, false);
104         // To let TetherUtil.isTetherAvailable return true, select one of the combinations
105         setupIsTetherAvailable(true);
106 
107         final List<String> niks =
108                 TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
109 
110         assertThat(niks).doesNotContain(TetherSettings.KEY_TETHER_PREFS_SCREEN);
111         assertThat(niks).doesNotContain(TetherSettings.KEY_WIFI_TETHER);
112     }
113 
114     @Test
testTetherNonIndexableKeys_tetherNotAvailable_keysReturned()115     public void testTetherNonIndexableKeys_tetherNotAvailable_keysReturned() {
116         // To let TetherUtil.isTetherAvailable return false, select one of the combinations
117         setupIsTetherAvailable(false);
118 
119         final List<String> niks =
120                 TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
121 
122         assertThat(niks).contains(TetherSettings.KEY_TETHER_PREFS_SCREEN);
123         assertThat(niks).contains(TetherSettings.KEY_WIFI_TETHER);
124     }
125 
126     @Test
testTetherNonIndexableKeys_usbNotAvailable_usbKeyReturned()127     public void testTetherNonIndexableKeys_usbNotAvailable_usbKeyReturned() {
128         when(mTetheringManager.getTetherableUsbRegexs()).thenReturn(new String[0]);
129 
130         final List<String> niks =
131             TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
132 
133         assertThat(niks).contains(TetherSettings.KEY_USB_TETHER_SETTINGS);
134     }
135 
136     @Test
testTetherNonIndexableKeys_usbAvailable_usbKeyNotReturned()137     public void testTetherNonIndexableKeys_usbAvailable_usbKeyNotReturned() {
138         FeatureFlagUtils.setEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE, false);
139         // We can ignore the condition of Utils.isMonkeyRunning()
140         // In normal case, monkey and robotest should not execute at the same time
141         when(mTetheringManager.getTetherableUsbRegexs()).thenReturn(new String[]{"fakeRegex"});
142 
143         final List<String> niks =
144             TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
145 
146         assertThat(niks).doesNotContain(TetherSettings.KEY_USB_TETHER_SETTINGS);
147     }
148 
149     @Test
testTetherNonIndexableKeys_bluetoothNotAvailable_bluetoothKeyReturned()150     public void testTetherNonIndexableKeys_bluetoothNotAvailable_bluetoothKeyReturned() {
151         when(mTetheringManager.getTetherableBluetoothRegexs()).thenReturn(new String[0]);
152 
153         final List<String> niks =
154             TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
155 
156         assertThat(niks).contains(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING);
157     }
158 
159     @Test
testTetherNonIndexableKeys_bluetoothAvailable_bluetoothKeyNotReturned()160     public void testTetherNonIndexableKeys_bluetoothAvailable_bluetoothKeyNotReturned() {
161         FeatureFlagUtils.setEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE, false);
162         when(mTetheringManager.getTetherableBluetoothRegexs())
163                 .thenReturn(new String[]{"fakeRegex"});
164 
165         final List<String> niks =
166             TetherSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
167 
168         assertThat(niks).doesNotContain(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING);
169     }
170 
171     @Test
testSetFooterPreferenceTitle_isStaApConcurrencySupported_showStaApString()172     public void testSetFooterPreferenceTitle_isStaApConcurrencySupported_showStaApString() {
173         final TetherSettings spyTetherSettings = spy(new TetherSettings());
174         spyTetherSettings.mContext = mContext;
175         final Preference mockPreference = mock(Preference.class);
176         when(spyTetherSettings.findPreference(TetherSettings.KEY_TETHER_PREFS_TOP_INTRO))
177             .thenReturn(mockPreference);
178         final WifiManager mockWifiManager = mock(WifiManager.class);
179         when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mockWifiManager);
180         when(mockWifiManager.isStaApConcurrencySupported()).thenReturn(true);
181 
182         spyTetherSettings.setTopIntroPreferenceTitle();
183 
184         verify(mockPreference, never()).setTitle(R.string.tethering_footer_info);
185         verify(mockPreference).setTitle(R.string.tethering_footer_info_sta_ap_concurrency);
186     }
187 
188     @Test
testBluetoothState_updateBluetoothState_bluetoothTetheringStateOn()189     public void testBluetoothState_updateBluetoothState_bluetoothTetheringStateOn() {
190         final TetherSettings spyTetherSettings = spy(new TetherSettings());
191         spyTetherSettings.mContext = mContext;
192         spyTetherSettings.mTm = mTetheringManager;
193         final SwitchPreference mockSwitchPreference = mock(SwitchPreference.class);
194         when(spyTetherSettings.findPreference(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING))
195             .thenReturn(mockSwitchPreference);
196         final FragmentActivity mockActivity = mock(FragmentActivity.class);
197         when(spyTetherSettings.getActivity()).thenReturn(mockActivity);
198         final ArgumentCaptor<BroadcastReceiver> captor =
199                 ArgumentCaptor.forClass(BroadcastReceiver.class);
200         when(mockActivity.registerReceiver(captor.capture(), any(IntentFilter.class)))
201             .thenReturn(null);
202         // Bluetooth tethering state is on
203         when(spyTetherSettings.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
204         when(spyTetherSettings.isBluetoothTetheringOn()).thenReturn(true);
205 
206         spyTetherSettings.setupTetherPreference();
207         spyTetherSettings.registerReceiver();
208         updateOnlyBluetoothState(spyTetherSettings);
209 
210         // Simulate Bluetooth tethering state changed
211         final BroadcastReceiver receiver = captor.getValue();
212         final Intent bluetoothTetheringOn = new Intent(BluetoothPan.ACTION_TETHERING_STATE_CHANGED);
213         bluetoothTetheringOn.putExtra(BluetoothPan.EXTRA_TETHERING_STATE,
214                 BluetoothPan.TETHERING_STATE_ON);
215         receiver.onReceive(mockActivity, bluetoothTetheringOn);
216 
217         verify(mockSwitchPreference).setEnabled(true);
218         verify(mockSwitchPreference).setChecked(true);
219     }
220 
221     @Test
testBluetoothState_updateBluetoothState_bluetoothTetheringStateOff()222     public void testBluetoothState_updateBluetoothState_bluetoothTetheringStateOff() {
223         final TetherSettings spyTetherSettings = spy(new TetherSettings());
224         spyTetherSettings.mContext = mContext;
225         spyTetherSettings.mTm = mTetheringManager;
226         final SwitchPreference mockSwitchPreference = mock(SwitchPreference.class);
227         when(spyTetherSettings.findPreference(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING))
228             .thenReturn(mockSwitchPreference);
229         final FragmentActivity mockActivity = mock(FragmentActivity.class);
230         when(spyTetherSettings.getActivity()).thenReturn(mockActivity);
231         final ArgumentCaptor<BroadcastReceiver> captor =
232                 ArgumentCaptor.forClass(BroadcastReceiver.class);
233         when(mockActivity.registerReceiver(captor.capture(), any(IntentFilter.class)))
234             .thenReturn(null);
235         // Bluetooth tethering state is off
236         when(spyTetherSettings.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
237         when(spyTetherSettings.isBluetoothTetheringOn()).thenReturn(false);
238 
239         spyTetherSettings.setupTetherPreference();
240         spyTetherSettings.registerReceiver();
241         updateOnlyBluetoothState(spyTetherSettings);
242 
243         // Simulate Bluetooth tethering state changed
244         final BroadcastReceiver receiver = captor.getValue();
245         final Intent bluetoothTetheringOn = new Intent(BluetoothPan.ACTION_TETHERING_STATE_CHANGED);
246         bluetoothTetheringOn.putExtra(BluetoothPan.EXTRA_TETHERING_STATE,
247                 BluetoothPan.TETHERING_STATE_ON);
248         receiver.onReceive(mockActivity, bluetoothTetheringOn);
249 
250         verify(mockSwitchPreference).setEnabled(true);
251         verify(mockSwitchPreference).setChecked(false);
252     }
253 
254     @Test
updateState_usbTetheringIsEnabled_checksUsbTethering()255     public void updateState_usbTetheringIsEnabled_checksUsbTethering() {
256         String [] tethered = {"rndis0"};
257         TetherSettings spyTetherSettings = spy(new TetherSettings());
258         RestrictedSwitchPreference tetheringPreference = mock(RestrictedSwitchPreference.class);
259         when(spyTetherSettings.findPreference(TetherSettings.KEY_USB_TETHER_SETTINGS))
260                 .thenReturn(tetheringPreference);
261         spyTetherSettings.mContext = mContext;
262         spyTetherSettings.mTm = mTetheringManager;
263         spyTetherSettings.setupTetherPreference();
264         spyTetherSettings.mUsbRegexs = tethered;
265 
266         spyTetherSettings.updateUsbState(tethered);
267 
268         verify(tetheringPreference).setEnabled(true);
269         verify(tetheringPreference).setChecked(true);
270     }
271 
272     @Test
updateState_usbTetheringIsDisabled_unchecksUsbTethering()273     public void updateState_usbTetheringIsDisabled_unchecksUsbTethering() {
274         String [] tethered = {"rndis0"};
275         TetherSettings spyTetherSettings = spy(new TetherSettings());
276         RestrictedSwitchPreference tetheringPreference = mock(RestrictedSwitchPreference.class);
277         when(spyTetherSettings.findPreference(TetherSettings.KEY_USB_TETHER_SETTINGS))
278                 .thenReturn(tetheringPreference);
279         spyTetherSettings.mContext = mContext;
280         spyTetherSettings.mTm = mTetheringManager;
281         spyTetherSettings.setupTetherPreference();
282         spyTetherSettings.mUsbRegexs = tethered;
283 
284         spyTetherSettings.updateUsbState(new String[0]);
285 
286         verify(tetheringPreference).setEnabled(false);
287         verify(tetheringPreference).setChecked(false);
288     }
289 
290     @Test
onReceive_usbIsConnected_tetheringPreferenceIsEnabled()291     public void onReceive_usbIsConnected_tetheringPreferenceIsEnabled() {
292         RestrictedSwitchPreference tetheringPreference = mock(RestrictedSwitchPreference.class);
293         FragmentActivity mockActivity = mock(FragmentActivity.class);
294         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
295         setupUsbStateComponents(tetheringPreference, captor, mockActivity);
296 
297         BroadcastReceiver receiver = captor.getValue();
298         Intent usbStateChanged = new Intent(ACTION_USB_STATE);
299         usbStateChanged.putExtra(UsbManager.USB_CONNECTED, true);
300         receiver.onReceive(mockActivity, usbStateChanged);
301 
302         verify(tetheringPreference).setEnabled(true);
303     }
304 
305     @Test
onReceive_usbIsDisconnected_tetheringPreferenceIsDisabled()306     public void onReceive_usbIsDisconnected_tetheringPreferenceIsDisabled() {
307         RestrictedSwitchPreference tetheringPreference = mock(RestrictedSwitchPreference.class);
308         FragmentActivity mockActivity = mock(FragmentActivity.class);
309         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
310         setupUsbStateComponents(tetheringPreference, captor, mockActivity);
311 
312         BroadcastReceiver receiver = captor.getValue();
313         Intent usbStateChanged = new Intent(ACTION_USB_STATE);
314         usbStateChanged.putExtra(UsbManager.USB_CONNECTED, false);
315         receiver.onReceive(mockActivity, usbStateChanged);
316 
317         verify(tetheringPreference).setEnabled(false);
318     }
319 
320     @Test
onReceive_mediaIsShared_tetheringPreferenceIsDisabled()321     public void onReceive_mediaIsShared_tetheringPreferenceIsDisabled() {
322         RestrictedSwitchPreference tetheringPreference = mock(RestrictedSwitchPreference.class);
323         FragmentActivity mockActivity = mock(FragmentActivity.class);
324         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
325         setupUsbStateComponents(tetheringPreference, captor, mockActivity);
326 
327         BroadcastReceiver receiver = captor.getValue();
328         Intent mediaIsShared = new Intent(ACTION_MEDIA_SHARED);
329         receiver.onReceive(mockActivity, mediaIsShared);
330 
331         verify(tetheringPreference).setEnabled(false);
332     }
333 
334     @Test
onReceive_mediaIsUnshared_tetheringPreferenceIsEnabled()335     public void onReceive_mediaIsUnshared_tetheringPreferenceIsEnabled() {
336         RestrictedSwitchPreference tetheringPreference = mock(RestrictedSwitchPreference.class);
337         FragmentActivity mockActivity = mock(FragmentActivity.class);
338         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
339         setupUsbStateComponents(tetheringPreference, captor, mockActivity);
340 
341         BroadcastReceiver receiver = captor.getValue();
342         Intent mediaIsShared = new Intent(ACTION_MEDIA_UNSHARED);
343         Intent usbStateChanged = new Intent(ACTION_USB_STATE);
344         usbStateChanged.putExtra(UsbManager.USB_CONNECTED, true);
345         receiver.onReceive(mockActivity, usbStateChanged);
346         receiver.onReceive(mockActivity, mediaIsShared);
347 
348         verify(tetheringPreference, times(2)).setEnabled(true);
349     }
350 
updateOnlyBluetoothState(TetherSettings tetherSettings)351     private void updateOnlyBluetoothState(TetherSettings tetherSettings) {
352         doReturn(mTetheringManager).when(tetherSettings)
353             .getSystemService(Context.TETHERING_SERVICE);
354         when(mTetheringManager.getTetherableIfaces()).thenReturn(new String[0]);
355         when(mTetheringManager.getTetheredIfaces()).thenReturn(new String[0]);
356         when(mTetheringManager.getTetheringErroredIfaces()).thenReturn(new String[0]);
357         doNothing().when(tetherSettings).updateUsbState(any(String[].class));
358         doNothing().when(tetherSettings).updateEthernetState(any(String[].class),
359                 any(String[].class));
360     }
361 
setupIsTetherAvailable(boolean returnValue)362     private void setupIsTetherAvailable(boolean returnValue) {
363         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
364 
365         // For RestrictedLockUtils.checkIfRestrictionEnforced
366         final int userId = UserHandle.myUserId();
367         List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>();
368         when(mUserManager.getUserRestrictionSources(
369                 UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
370                 .thenReturn(enforcingUsers);
371 
372         // For RestrictedLockUtils.hasBaseUserRestriction
373         when(mUserManager.hasBaseUserRestriction(
374                 UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.of(userId)))
375                 .thenReturn(!returnValue);
376     }
377 
setupUsbStateComponents(RestrictedSwitchPreference preference, ArgumentCaptor<BroadcastReceiver> captor, FragmentActivity activity)378     private void setupUsbStateComponents(RestrictedSwitchPreference preference,
379             ArgumentCaptor<BroadcastReceiver> captor, FragmentActivity activity) {
380         TetherSettings spyTetherSettings = spy(new TetherSettings());
381         SwitchPreference mockSwitchPreference = mock(SwitchPreference.class);
382 
383         when(spyTetherSettings.findPreference(TetherSettings.KEY_USB_TETHER_SETTINGS))
384                 .thenReturn(preference);
385         when(spyTetherSettings.findPreference(TetherSettings.KEY_ENABLE_BLUETOOTH_TETHERING))
386                 .thenReturn(mockSwitchPreference);
387         spyTetherSettings.mContext = mContext;
388         spyTetherSettings.mTm = mTetheringManager;
389         when(spyTetherSettings.getActivity()).thenReturn(activity);
390         when(activity.registerReceiver(captor.capture(), any(IntentFilter.class)))
391                 .thenReturn(null);
392 
393         spyTetherSettings.setupTetherPreference();
394         spyTetherSettings.registerReceiver();
395         updateOnlyBluetoothState(spyTetherSettings);
396     }
397 }
398