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