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.ui;
18 
19 import android.content.Context;
20 import android.net.wifi.WifiManager;
21 import android.os.RemoteException;
22 import android.provider.Settings;
23 import android.system.helpers.CommandsHelper;
24 import android.system.helpers.SettingsHelper;
25 import android.test.InstrumentationTestCase;
26 import android.util.Log;
27 
28 import androidx.test.filters.MediumTest;
29 import androidx.test.filters.Suppress;
30 import androidx.test.uiautomator.By;
31 import androidx.test.uiautomator.BySelector;
32 import androidx.test.uiautomator.Direction;
33 import androidx.test.uiautomator.StaleObjectException;
34 import androidx.test.uiautomator.UiDevice;
35 import androidx.test.uiautomator.UiObject2;
36 import androidx.test.uiautomator.Until;
37 
38 import org.junit.Ignore;
39 
40 /**
41  * Additional tests for Wifi Settings.
42  */
43 @Ignore
44 public class MoreWirelessSettingsTest2 extends InstrumentationTestCase {
45     // These back button presses are performed in tearDown() to exit Wifi
46     // Settings sub-menus that a test might finish in. This number should be
47     // high enough to account for the deepest sub-menu a test might enter.
48     private static final int NUM_BACK_BUTTON_PRESSES = 5;
49     private static final int TIMEOUT = 2000;
50     private static final int SLEEP_TIME = 500;
51     private static final String AIRPLANE_MODE_BROADCAST =
52             "am broadcast -a android.intent.action.AIRPLANE_MODE";
53     private static final String TAG="WirelessNetworkSettingsTests";
54 
55     // Note: The values of these variables might affect flakiness in tests that involve
56     // scrolling. Adjust where necessary.
57     private static final float SCROLL_UP_PERCENT = 10.0f;
58     private static final float SCROLL_DOWN_PERCENT = 0.5f;
59     private static final int MAX_SCROLL_ATTEMPTS = 10;
60     private static final int MAX_ADD_NETWORK_BUTTON_ATTEMPTS = 3;
61     private static final int SCROLL_SPEED = 2000;
62 
63     private static final String TEST_SSID = "testSsid";
64     private static final String TEST_PW_GE_8_CHAR = "testPasswordGreaterThan8Char";
65     private static final String TEST_PW_LT_8_CHAR = "lt8Char";
66     private static final String TEST_DOMAIN = "testDomain.com";
67 
68     private static final String SETTINGS_PACKAGE = "com.android.settings";
69 
70     private static final String CHECKBOX_CLASS = "android.widget.CheckBox";
71     private static final String SPINNER_CLASS = "android.widget.Spinner";
72     private static final String EDIT_TEXT_CLASS = "android.widget.EditText";
73     private static final String SCROLLVIEW_CLASS = "android.widget.ScrollView";
74     private static final String LISTVIEW_CLASS = "android.widget.ListView";
75 
76     private static final String ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT = "CANCEL";
77     private static final String ADD_NETWORK_MENU_SAVE_BUTTON_TEXT = "SAVE";
78     private static final String ADD_NETWORK_PREFERENCE_TEXT = "Add network";
79     private static final String CONFIGURE_WIFI_PREFERENCE_TEXT = "Wi‑Fi preferences";
80     private static final String CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT = "Advanced";
81     private static final String CACERT_MENU_PLEASE_SELECT_TEXT = "Please select";
82     private static final String CACERT_MENU_USE_SYSTEM_CERTS_TEXT = "Use system certificates";
83     private static final String CACERT_MENU_DO_NOT_VALIDATE_TEXT = "Do not validate";
84     private static final String USERCERT_MENU_PLEASE_SELECT_TEXT = "Please select";
85     private static final String USERCERT_MENU_DO_NOT_PROVIDE_TEXT = "Do not provide";
86     private static final String SECURITY_OPTION_NONE_TEXT = "None";
87     private static final String SECURITY_OPTION_WEP_TEXT = "WEP";
88     private static final String SECURITY_OPTION_PSK_TEXT = "WPA/WPA2 PSK";
89     private static final String SECURITY_OPTION_EAP_TEXT = "802.1x EAP";
90     private static final String EAP_METHOD_PEAP_TEXT = "PEAP";
91     private static final String EAP_METHOD_TLS_TEXT = "TLS";
92     private static final String EAP_METHOD_TTLS_TEXT = "TTLS";
93     private static final String EAP_METHOD_PWD_TEXT = "PWD";
94     private static final String EAP_METHOD_SIM_TEXT = "SIM";
95     private static final String EAP_METHOD_AKA_TEXT = "AKA";
96     private static final String EAP_METHOD_AKA_PRIME_TEXT = "AKA'";
97     private static final String PHASE2_MENU_NONE_TEXT = "None";
98     private static final String PHASE2_MENU_MSCHAPV2_TEXT = "MSCHAPV2";
99     private static final String PHASE2_MENU_GTC_TEXT = "GTC";
100 
101     private static final String ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID = "wifi_advanced_togglebox";
102     private static final String ADD_NETWORK_MENU_IP_SETTINGS_RES_ID = "ip_settings";
103     private static final String ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID = "proxy_settings";
104     private static final String ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID = "security";
105     private static final String ADD_NETWORK_MENU_EAP_METHOD_RES_ID = "method";
106     private static final String ADD_NETWORK_MENU_SSID_RES_ID = "ssid";
107     private static final String ADD_NETWORK_MENU_PHASE2_RES_ID = "phase2";
108     private static final String ADD_NETWORK_MENU_CACERT_RES_ID = "ca_cert";
109     private static final String ADD_NETWORK_MENU_USERCERT_RES_ID = "user_cert";
110     private static final String ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID = "no_domain_warning";
111     private static final String ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID = "no_ca_cert_warning";
112     private static final String ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID = "l_domain";
113     private static final String ADD_NETWORK_MENU_DOMAIN_RES_ID = "domain";
114     private static final String ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID = "l_identity";
115     private static final String ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID = "l_anonymous";
116     private static final String ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID = "password_layout";
117     private static final String ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID =
118             "show_password_layout";
119     private static final String ADD_NETWORK_MENU_PASSWORD_RES_ID = "password";
120 
121     private static final BySelector ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR =
122             By.scrollable(true).clazz(SCROLLVIEW_CLASS);
123     private static final BySelector SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR =
124             By.scrollable(true).clazz(LISTVIEW_CLASS);
125 
126     private UiDevice mDevice;
127     private CommandsHelper mCommandsHelper;
128 
129     @Override
setUp()130     public void setUp() throws Exception {
131         super.setUp();
132         mDevice = UiDevice.getInstance(getInstrumentation());
133         try {
134             mDevice.setOrientationNatural();
135         } catch (RemoteException e) {
136             throw new RuntimeException("failed to freeze device orientation", e);
137         }
138         // Ensure airplane mode is OFF so that wifi can be enabled using WiFiManager.
139         Settings.Global.putString(getInstrumentation().getContext().getContentResolver(),
140                 Settings.Global.AIRPLANE_MODE_ON, "0");
141         Log.d(TAG, "sending airplane mode broadcast to device");
142         mCommandsHelper = CommandsHelper.getInstance();
143         mCommandsHelper.executeShellCommand(AIRPLANE_MODE_BROADCAST);
144     }
145 
146     @Override
tearDown()147     protected void tearDown() throws Exception {
148         // Exit all settings sub-menus.
149         for (int i = 0; i < NUM_BACK_BUTTON_PRESSES; ++i) {
150             mDevice.pressBack();
151         }
152         mDevice.pressHome();
153         super.tearDown();
154     }
155 
156     @MediumTest
testWifiMenuLoadConfigure()157     public void testWifiMenuLoadConfigure() throws Exception {
158         loadWiFiConfigureMenu();
159         Thread.sleep(SLEEP_TIME);
160         UiObject2 configureWiFiHeading = mDevice.wait(Until.findObject
161                 (By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT);
162         assertNotNull("Configure WiFi menu has not loaded correctly", configureWiFiHeading);
163     }
164 
165     @MediumTest
testNetworkNotificationsOn()166     public void testNetworkNotificationsOn() throws Exception {
167         verifyNetworkNotificationsOnOrOff(true);
168     }
169 
170     @MediumTest
testNetworkNotificationsOff()171     public void testNetworkNotificationsOff() throws Exception {
172         verifyNetworkNotificationsOnOrOff(false);
173     }
174 
175     @MediumTest
testAddNetworkMenu_Default()176     public void testAddNetworkMenu_Default() throws Exception {
177         loadAddNetworkMenu();
178 
179         // Submit button should be disabled by default, while cancel button should be enabled.
180         assertFalse(mDevice.wait(Until.findObject(
181                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
182         assertTrue(mDevice.wait(Until.findObject(
183                 By.text(ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT)), TIMEOUT).isEnabled());
184 
185         // Check that the SSID field is defaults to the hint.
186         assertEquals("Enter the SSID", mDevice.wait(Until.findObject(By
187                 .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID)
188                 .clazz(EDIT_TEXT_CLASS)), TIMEOUT*2)
189                 .getText());
190 
191         // Check Security defaults to None.
192         assertEquals("None", mDevice.wait(Until.findObject(By
193                 .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID)
194                 .clazz(SPINNER_CLASS)), TIMEOUT)
195                 .getChildren().get(0).getText());
196 
197         // Check advanced options are collapsed by default.
198         assertFalse(mDevice.wait(Until.findObject(By
199                 .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID)
200                 .clazz(CHECKBOX_CLASS)), TIMEOUT).isChecked());
201 
202     }
203 
204     @Suppress
205     @MediumTest
testAddNetworkMenu_Proxy()206     public void testAddNetworkMenu_Proxy() throws Exception {
207         loadAddNetworkMenu();
208 
209         // Toggle advanced options.
210         mDevice.wait(Until.findObject(By
211                 .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID)
212                 .clazz(CHECKBOX_CLASS)), TIMEOUT).click();
213 
214         // Verify Proxy defaults to None.
215         BySelector proxySettingsBySelector =
216                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID)
217                 .clazz(SPINNER_CLASS);
218         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector);
219         assertEquals("None", mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT)
220                 .getChildren().get(0).getText());
221 
222         // Verify that Proxy Manual fields appear.
223         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector);
224         mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click();
225         mDevice.wait(Until.findObject(By.text("Manual")), TIMEOUT).click();
226         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
227                 By.res(SETTINGS_PACKAGE, "proxy_warning_limited_support"));
228         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
229                 By.res(SETTINGS_PACKAGE, "proxy_hostname"));
230         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
231                 By.res(SETTINGS_PACKAGE, "proxy_exclusionlist"));
232 
233         // Verify that Proxy Auto-Config options appear.
234         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector);
235         mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click();
236         mDevice.wait(Until.findObject(By.text("Proxy Auto-Config")), TIMEOUT).click();
237         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
238                 By.res(SETTINGS_PACKAGE, "proxy_pac"));
239     }
240 
241     @Suppress
242     @MediumTest
testAddNetworkMenu_IpSettings()243     public void testAddNetworkMenu_IpSettings() throws Exception {
244         loadAddNetworkMenu();
245 
246         // Toggle advanced options.
247         mDevice.wait(Until.findObject(By
248                 .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID)
249                 .clazz(CHECKBOX_CLASS)), TIMEOUT).click();
250 
251         // Verify IP settings defaults to DHCP.
252         BySelector ipSettingsBySelector =
253                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IP_SETTINGS_RES_ID).clazz(SPINNER_CLASS);
254         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector);
255         assertEquals("DHCP", mDevice.wait(Until.findObject(ipSettingsBySelector), TIMEOUT)
256                 .getChildren().get(0).getText());
257 
258         // Verify that Static IP settings options appear.
259         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector).click();
260         mDevice.wait(Until.findObject(By.text("Static")), TIMEOUT).click();
261         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
262                 By.res(SETTINGS_PACKAGE, "ipaddress"));
263         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
264                 By.res(SETTINGS_PACKAGE, "gateway"));
265         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
266                 By.res(SETTINGS_PACKAGE, "network_prefix_length"));
267         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
268                 By.res(SETTINGS_PACKAGE, "dns1"));
269         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
270                 By.res(SETTINGS_PACKAGE, "dns2"));
271     }
272 
273     @Suppress
274     @MediumTest
testPhase2Settings()275     public void testPhase2Settings() throws Exception {
276         loadAddNetworkMenu();
277         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
278 
279         BySelector phase2SettingsBySelector =
280                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID).clazz(SPINNER_CLASS);
281         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, phase2SettingsBySelector);
282         assertEquals(PHASE2_MENU_NONE_TEXT, mDevice.wait(Until
283                 .findObject(phase2SettingsBySelector), TIMEOUT).getChildren().get(0).getText());
284         mDevice.wait(Until.findObject(phase2SettingsBySelector), TIMEOUT).click();
285         Thread.sleep(SLEEP_TIME);
286 
287         // Verify Phase 2 authentication spinner options.
288         assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_NONE_TEXT)), TIMEOUT));
289         assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_MSCHAPV2_TEXT)), TIMEOUT));
290         assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_GTC_TEXT)), TIMEOUT));
291     }
292 
293     @Suppress
294     @MediumTest
testCaCertSettings()295     public void testCaCertSettings() throws Exception {
296         loadAddNetworkMenu();
297         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
298 
299         BySelector caCertSettingsBySelector =
300                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS);
301         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, caCertSettingsBySelector);
302         assertEquals(CACERT_MENU_PLEASE_SELECT_TEXT, mDevice.wait(Until
303                 .findObject(caCertSettingsBySelector), TIMEOUT).getChildren().get(0).getText());
304         mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click();
305         Thread.sleep(SLEEP_TIME);
306 
307         // Verify CA certificate spinner options.
308         assertNotNull(mDevice.wait(Until.findObject(
309                 By.text(CACERT_MENU_PLEASE_SELECT_TEXT)), TIMEOUT));
310         assertNotNull(mDevice.wait(Until.findObject(
311                 By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT));
312         assertNotNull(mDevice.wait(Until.findObject(
313                 By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT));
314 
315         // Verify that a domain field and warning appear when the user selects the
316         // "Use system certificates" option.
317         mDevice.wait(Until.findObject(By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT).click();
318         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
319                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID));
320         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
321                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID));
322 
323         // Verify that a warning appears when the user chooses the "Do Not Validate" option.
324         mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click();
325         mDevice.wait(Until.findObject(By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT).click();
326         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
327                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID));
328     }
329 
330     @Suppress
331     @MediumTest
testAddNetwork_NoSecurity()332     public void testAddNetwork_NoSecurity() throws Exception {
333         loadAddNetworkMenu();
334         selectSecurityOption(SECURITY_OPTION_NONE_TEXT);
335 
336         // Entering an SSID is enough to enable the submit button. // TODO THIS GUY
337         enterSSID(TEST_SSID);
338         assertTrue(mDevice.wait(Until
339                 .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
340     }
341 
342     @Suppress
343     @MediumTest
testAddNetwork_WEP()344     public void testAddNetwork_WEP() throws Exception {
345         loadAddNetworkMenu();
346         selectSecurityOption(SECURITY_OPTION_WEP_TEXT);
347         assertFalse(mDevice.wait(Until.findObject(
348                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
349 
350         // Verify that WEP fields appear.
351         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
352                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID));
353         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
354                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID));
355 
356         // Entering an SSID alone does not enable the submit button.
357         enterSSID(TEST_SSID);
358         assertFalse(mDevice.wait(Until.findObject(
359                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
360 
361         // Submit button is only enabled after a password is entered.
362         enterPassword(TEST_PW_GE_8_CHAR);
363         assertTrue(mDevice.wait(Until
364                 .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
365     }
366 
367     @Suppress
368     @MediumTest
testAddNetwork_PSK()369     public void testAddNetwork_PSK() throws Exception {
370         loadAddNetworkMenu();
371         selectSecurityOption(SECURITY_OPTION_PSK_TEXT);
372         assertFalse(mDevice.wait(Until.findObject(
373                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
374 
375         // Verify that PSK fields appear.
376         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
377                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID));
378         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
379                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID));
380 
381         // Entering an SSID alone does not enable the submit button.
382         enterSSID(TEST_SSID);
383         assertFalse(mDevice.wait(Until.findObject(
384                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
385 
386         // Entering an password that is too short does not enable submit button.
387         enterPassword(TEST_PW_LT_8_CHAR);
388         assertFalse(mDevice.wait(Until.findObject(
389                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
390 
391         // Submit button is only enabled after a password of valid length is entered.
392         enterPassword(TEST_PW_GE_8_CHAR);
393         assertTrue(mDevice.wait(Until.findObject(
394                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
395     }
396 
397     @Suppress
398     @MediumTest
testAddNetwork_EAP_PEAP()399     public void testAddNetwork_EAP_PEAP() throws Exception {
400         loadAddNetworkMenu();
401         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
402         assertFalse(mDevice.wait(Until.findObject(
403                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
404 
405         selectEAPMethod(EAP_METHOD_PEAP_TEXT);
406 
407         // Verify that EAP-PEAP fields appear.
408         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
409                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID));
410         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
411                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID));
412         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
413                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID));
414         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
415                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID));
416         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
417                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID));
418         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
419                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID));
420 
421         // Entering an SSID alone does not enable the submit button.
422         enterSSID(TEST_SSID);
423         assertFalse(mDevice.wait(Until.findObject(
424                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
425 
426         verifyCaCertificateSubmitConditions();
427     }
428 
429     @Suppress
430     @MediumTest
testAddNetwork_EAP_TLS()431     public void testAddNetwork_EAP_TLS() throws Exception {
432         loadAddNetworkMenu();
433         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
434         assertFalse(mDevice.wait(Until.findObject(
435                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
436 
437         selectEAPMethod(EAP_METHOD_TLS_TEXT);
438 
439         // Verify that EAP-TLS fields appear.
440         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
441                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID));
442         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
443                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID));
444         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
445                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID));
446 
447         // Entering an SSID alone does not enable the submit button.
448         enterSSID(TEST_SSID);
449         assertFalse(mDevice.wait(Until.findObject(
450                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
451 
452         // Selecting the User certificate "Do not provide" option alone does not enable the submit
453         // button.
454         selectUserCertificateOption(USERCERT_MENU_DO_NOT_PROVIDE_TEXT);
455         assertFalse(mDevice.wait(Until.findObject(
456                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
457 
458         verifyCaCertificateSubmitConditions();
459     }
460 
461     @Suppress
462     @MediumTest
testAddNetwork_EAP_TTLS()463     public void testAddNetwork_EAP_TTLS() throws Exception {
464         loadAddNetworkMenu();
465         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
466         assertFalse(mDevice.wait(Until.findObject(
467                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
468 
469         selectEAPMethod(EAP_METHOD_TTLS_TEXT);
470 
471         // Verify that EAP-TLS fields appear.
472         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
473                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID));
474         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
475                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID));
476         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
477                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID));
478         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
479                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID));
480         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
481                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID));
482 
483         // Entering an SSID alone does not enable the submit button.
484         enterSSID(TEST_SSID);
485         assertFalse(mDevice.wait(Until.findObject(
486                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
487 
488         verifyCaCertificateSubmitConditions();
489     }
490 
491     @Suppress
492     @MediumTest
testAddNetwork_EAP_PWD()493     public void testAddNetwork_EAP_PWD() throws Exception {
494         loadAddNetworkMenu();
495         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
496         assertFalse(mDevice.wait(Until.findObject(
497                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
498 
499         selectEAPMethod(EAP_METHOD_PWD_TEXT);
500 
501         // Verify that EAP-TLS fields appear.
502         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
503                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID));
504         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
505                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID));
506 
507         // Entering an SSID alone enables the submit button.
508         enterSSID(TEST_SSID);
509         assertTrue(mDevice.wait(Until.findObject(
510                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
511     }
512 
513     @Suppress
514     @MediumTest
testAddNetwork_EAP_SIM()515     public void testAddNetwork_EAP_SIM() throws Exception {
516         loadAddNetworkMenu();
517         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
518         assertFalse(mDevice.wait(Until.findObject(
519                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
520 
521         selectEAPMethod(EAP_METHOD_SIM_TEXT);
522 
523         // Entering an SSID alone enables the submit button.
524         enterSSID(TEST_SSID);
525         assertTrue(mDevice.wait(Until.findObject(
526                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
527     }
528 
529     @Suppress
530     @MediumTest
testAddNetwork_EAP_AKA()531     public void testAddNetwork_EAP_AKA() throws Exception {
532         loadAddNetworkMenu();
533         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
534         assertFalse(mDevice.wait(Until.findObject(
535                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
536 
537         selectEAPMethod(EAP_METHOD_AKA_TEXT);
538 
539         // Entering an SSID alone enables the submit button.
540         enterSSID(TEST_SSID);
541         assertTrue(mDevice.wait(Until.findObject(
542                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
543     }
544 
545     @Suppress
546     @MediumTest
testAddNetwork_EAP_AKA_PRIME()547     public void testAddNetwork_EAP_AKA_PRIME() throws Exception {
548         loadAddNetworkMenu();
549         selectSecurityOption(SECURITY_OPTION_EAP_TEXT);
550         assertFalse(mDevice.wait(Until.findObject(
551                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
552 
553         selectEAPMethod(EAP_METHOD_AKA_PRIME_TEXT);
554 
555         // Entering an SSID alone enables the submit button.
556         enterSSID(TEST_SSID);
557         assertTrue(mDevice.wait(Until.findObject(
558                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
559     }
560 
verifyKeepWiFiOnDuringSleep(String settingToBeVerified, int settingValue)561     private void verifyKeepWiFiOnDuringSleep(String settingToBeVerified, int settingValue)
562             throws Exception {
563         loadWiFiConfigureMenu();
564         mDevice.wait(Until.findObject(By.text("Keep Wi‑Fi on during sleep")), TIMEOUT)
565                 .click();
566         mDevice.wait(Until.findObject(By.clazz("android.widget.CheckedTextView")
567                 .text(settingToBeVerified)), TIMEOUT).click();
568         Thread.sleep(SLEEP_TIME);
569         int keepWiFiOnSetting =
570                 Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
571                 Settings.Global.WIFI_SLEEP_POLICY);
572         assertEquals(settingValue, keepWiFiOnSetting);
573     }
574 
verifyNetworkNotificationsOnOrOff(boolean verifyOn)575     private void verifyNetworkNotificationsOnOrOff(boolean verifyOn)
576             throws Exception {
577         // Enable network recommendations to enable the toggle switch for Network
578         // notifications
579         Settings.Global.putString(getInstrumentation().getContext().getContentResolver(),
580                 Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, "1");
581         if (verifyOn) {
582             Settings.Global.putString(getInstrumentation().getContext().getContentResolver(),
583                     Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "0");
584         }
585         else {
586             Settings.Global.putString(getInstrumentation().getContext().getContentResolver(),
587                     Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "1");
588         }
589         loadWiFiConfigureMenu();
590         mDevice.wait(Until.findObject(By.text("Open network notification")), TIMEOUT)
591                 .click();
592         Thread.sleep(SLEEP_TIME);
593         String wifiNotificationValue =
594                 Settings.Global.getString(getInstrumentation().getContext().getContentResolver(),
595                 Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
596         if (verifyOn) {
597             assertEquals("1", wifiNotificationValue);
598         }
599         else {
600             assertEquals("0", wifiNotificationValue);
601         }
602     }
603 
verifyWiFiOnOrOff(boolean verifyOn)604     private void verifyWiFiOnOrOff(boolean verifyOn) throws Exception {
605          String switchText = "On";
606          if (verifyOn) {
607              switchText = "Off";
608          }
609          loadWiFiSettingsPage(!verifyOn);
610          mDevice.wait(Until
611                  .findObject(By.res(SETTINGS_PACKAGE, "switch_bar").text(switchText)), TIMEOUT)
612                  .click();
613          Thread.sleep(SLEEP_TIME);
614          String wifiValue =
615                  Settings.Global.getString(getInstrumentation().getContext().getContentResolver(),
616                  Settings.Global.WIFI_ON);
617          if (verifyOn) {
618              // 1 is Enabled, 2 is Enabled while airplane mode is ON.
619              assertTrue(wifiValue.equals("1") || wifiValue.equals("2"));
620          }
621          else {
622              assertEquals("0", wifiValue);
623          }
624     }
625 
verifyCaCertificateSubmitConditions()626     private void verifyCaCertificateSubmitConditions() throws Exception {
627         // Selecting the CA certificate "Do not validate" option enables the submit button.
628         selectCaCertificateOption(CACERT_MENU_DO_NOT_VALIDATE_TEXT);
629         assertTrue(mDevice.wait(Until.findObject(
630                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
631 
632         // However, selecting the CA certificate "Use system certificates option" is not enough to
633         // enable the submit button.
634         selectCaCertificateOption(CACERT_MENU_USE_SYSTEM_CERTS_TEXT);
635         assertFalse(mDevice.wait(Until.findObject(
636                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
637 
638         // Submit button is only enabled after a domain is entered as well.
639         enterDomain(TEST_DOMAIN);
640         assertTrue(mDevice.wait(Until.findObject(
641                 By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled());
642     }
643 
loadWiFiSettingsPage(boolean wifiEnabled)644     private void loadWiFiSettingsPage(boolean wifiEnabled) throws Exception {
645         WifiManager wifiManager = (WifiManager)getInstrumentation().getContext()
646                 .getSystemService(Context.WIFI_SERVICE);
647         wifiManager.setWifiEnabled(wifiEnabled);
648         SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
649                 Settings.ACTION_WIFI_SETTINGS);
650     }
651 
loadWiFiConfigureMenu()652     private void loadWiFiConfigureMenu() throws Exception {
653         loadWiFiSettingsPage(false);
654         Thread.sleep(TIMEOUT);
655         mDevice.wait(Until.findObject(By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT).click();
656         mDevice.wait(Until.findObject(
657                 By.text(CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT)), TIMEOUT).click();
658     }
659 
loadAddNetworkMenu()660     private void loadAddNetworkMenu() throws Exception {
661         loadWiFiSettingsPage(true);
662         for (int attempts = 0; attempts < MAX_ADD_NETWORK_BUTTON_ATTEMPTS; ++attempts) {
663             try {
664                 findOrScrollToObject(By.scrollable(true), By.text(ADD_NETWORK_PREFERENCE_TEXT))
665                         .click();
666             } catch (StaleObjectException e) {
667                 // The network list might have been updated between when the Add network button was
668                 // found, and when it UI automator attempted to click on it. Retry.
669                 continue;
670             }
671             // If we get here, we successfully clicked on the Add network button, so we are done.
672             Thread.sleep(SLEEP_TIME*5);
673             return;
674         }
675 
676         fail("Failed to load Add Network Menu after " + MAX_ADD_NETWORK_BUTTON_ATTEMPTS
677                 + " retries");
678     }
679 
selectSecurityOption(String securityOption)680     private void selectSecurityOption(String securityOption) throws Exception {
681         // We might not need to scroll to the security options if not enough add network menu
682         // options are visible.
683         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
684                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID)
685                 .clazz(SPINNER_CLASS)).click();
686         Thread.sleep(SLEEP_TIME);
687         mDevice.wait(Until.findObject(By.text(securityOption)), TIMEOUT).click();
688     }
689 
selectEAPMethod(String eapMethod)690     private void selectEAPMethod(String eapMethod) throws Exception {
691         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
692                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_EAP_METHOD_RES_ID).clazz(SPINNER_CLASS))
693                 .click();
694         Thread.sleep(SLEEP_TIME);
695         findOrScrollToObject(SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR, By.text(eapMethod)).click();
696     }
697 
selectUserCertificateOption(String userCertificateOption)698     private void selectUserCertificateOption(String userCertificateOption) throws Exception {
699         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
700                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID).clazz(SPINNER_CLASS))
701                 .click();
702         mDevice.wait(Until.findObject(By.text(userCertificateOption)), TIMEOUT).click();
703     }
704 
selectCaCertificateOption(String caCertificateOption)705     private void selectCaCertificateOption(String caCertificateOption) throws Exception {
706         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
707                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS))
708                 .click();
709         mDevice.wait(Until.findObject(By.text(caCertificateOption)), TIMEOUT).click();
710     }
711 
enterSSID(String ssid)712     private void enterSSID(String ssid) throws Exception {
713         // We might not need to scroll to the SSID option if not enough add network menu options
714         // are visible.
715         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
716                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID).clazz(EDIT_TEXT_CLASS))
717                 .setText(ssid);
718     }
719 
enterPassword(String password)720     private void enterPassword(String password) throws Exception {
721         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
722                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_RES_ID).clazz(EDIT_TEXT_CLASS))
723                 .setText(password);
724     }
725 
enterDomain(String domain)726     private void enterDomain(String domain) throws Exception {
727         findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR,
728                 By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_RES_ID)).setText(domain);
729     }
730 
731     // Use this if the UI object might or might not need to be scrolled to.
findOrScrollToObject(BySelector scrollableSelector, BySelector objectSelector)732     private UiObject2 findOrScrollToObject(BySelector scrollableSelector, BySelector objectSelector)
733             throws Exception {
734         UiObject2 object = mDevice.wait(Until.findObject(objectSelector), TIMEOUT);
735         if (object == null) {
736             object = scrollToObject(scrollableSelector, objectSelector);
737         }
738         return object;
739     }
740 
scrollToObject(BySelector scrollableSelector, BySelector objectSelector)741     private UiObject2 scrollToObject(BySelector scrollableSelector, BySelector objectSelector)
742             throws Exception {
743         UiObject2 scrollable = mDevice.wait(Until.findObject(scrollableSelector), TIMEOUT);
744         if (scrollable == null) {
745             fail("Could not find scrollable UI object identified by " + scrollableSelector);
746         }
747         UiObject2 found = null;
748         // Scroll all the way up first, then all the way down.
749         while (true) {
750             // Optimization: terminate if we find the object while scrolling up to reset, so
751             // we save the time spent scrolling down again.
752             boolean canScrollAgain = scrollable.scroll(Direction.UP, SCROLL_UP_PERCENT,
753                     SCROLL_SPEED);
754             found = mDevice.findObject(objectSelector);
755             if (found != null) return found;
756             if (!canScrollAgain) break;
757         }
758         for (int attempts = 0; found == null && attempts < MAX_SCROLL_ATTEMPTS; ++attempts) {
759             // Return value of UiObject2.scroll() is not reliable, so do not use it in loop
760             // condition, in case it causes this loop to terminate prematurely.
761             scrollable.scroll(Direction.DOWN, SCROLL_DOWN_PERCENT, SCROLL_SPEED);
762             found = mDevice.findObject(objectSelector);
763         }
764         if (found == null) {
765             fail("Could not scroll to UI object identified by " + objectSelector);
766         }
767         return found;
768     }
769 }
770