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