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.os.RemoteException;
20import android.platform.test.annotations.Presubmit;
21import android.provider.Settings;
22import android.support.test.uiautomator.By;
23import android.support.test.uiautomator.Direction;
24import android.support.test.uiautomator.UiDevice;
25import android.support.test.uiautomator.UiObject2;
26import android.support.test.uiautomator.Until;
27import android.system.helpers.SettingsHelper;
28import android.test.InstrumentationTestCase;
29import android.test.suitebuilder.annotation.MediumTest;
30
31
32public class LocationSettingsTests extends InstrumentationTestCase {
33
34    private static final String SETTINGS_PACKAGE = "com.android.settings";
35    private static final int TIMEOUT = 2000;
36    private UiDevice mDevice;
37
38    @Override
39    public void setUp() throws Exception {
40        super.setUp();
41        mDevice = UiDevice.getInstance(getInstrumentation());
42        try {
43            mDevice.setOrientationNatural();
44        } catch (RemoteException e) {
45            throw new RuntimeException("failed to freeze device orientaion", e);
46        }
47    }
48
49    @Override
50    protected void tearDown() throws Exception {
51        mDevice.pressBack();
52        mDevice.pressHome();
53        super.tearDown();
54    }
55
56    @MediumTest
57    public void testLoadingLocationSettings () throws Exception {
58        // Load Security
59        SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
60                Settings.ACTION_SECURITY_SETTINGS);
61
62        SettingsHelper helper = new SettingsHelper();
63        helper.scrollVert(true);
64        // Tap on location
65        UiObject2 settingsPanel = mDevice.wait(Until.findObject
66                (By.res(SETTINGS_PACKAGE, "main_content")), TIMEOUT);
67        int count = 0;
68        UiObject2 locationTitle = null;
69        while(count < 6 && locationTitle == null) {
70            locationTitle = mDevice.wait(Until.findObject(By.text("Location")), TIMEOUT);
71            if (locationTitle == null) {
72                settingsPanel.scroll(Direction.DOWN, 1.0f);
73            }
74            count++;
75        }
76        // Verify location settings loads.
77        locationTitle.click();
78        Thread.sleep(TIMEOUT);
79        assertNotNull("Location screen has not loaded correctly",
80                mDevice.wait(Until.findObject(By.text("Location services")), TIMEOUT));
81    }
82
83    @Presubmit
84    @MediumTest
85    public void testLocationSettingOn() throws Exception {
86        verifyLocationSettingsOnOrOff(true);
87    }
88
89    @MediumTest
90    public void testLocationSettingOff() throws Exception {
91        verifyLocationSettingsOnOrOff(false);
92    }
93
94    @MediumTest
95    public void testLocationDeviceOnlyMode() throws Exception {
96        // Changing the value from default before testing the toggle to Device only mode
97        Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(),
98                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
99        dismissAlertDialogs();
100        Thread.sleep(TIMEOUT);
101        verifyLocationSettingsMode(Settings.Secure.LOCATION_MODE_SENSORS_ONLY);
102    }
103
104    @MediumTest
105    public void testLocationBatterySavingMode() throws Exception {
106        Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(),
107                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_SENSORS_ONLY);
108        Thread.sleep(TIMEOUT);
109        verifyLocationSettingsMode(Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
110    }
111
112    @MediumTest
113    public void testLocationHighAccuracyMode() throws Exception {
114        Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(),
115                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_SENSORS_ONLY);
116        Thread.sleep(TIMEOUT);
117        verifyLocationSettingsMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
118    }
119
120    @MediumTest
121    public void testLocationSettingsElements() throws Exception {
122        String[] textElements = {"Location", "Mode", "Recent location requests",
123                "Location services"};
124        SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
125                Settings.ACTION_LOCATION_SOURCE_SETTINGS);
126        Thread.sleep(TIMEOUT);
127        for (String element : textElements) {
128            assertNotNull(element + " item not found under Location Settings",
129                    mDevice.wait(Until.findObject(By.text(element)), TIMEOUT));
130        }
131    }
132
133    @MediumTest
134    public void testLocationSettingsOverflowMenuElements() throws Exception {
135        SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
136                            Settings.ACTION_LOCATION_SOURCE_SETTINGS);
137        // Verify help & feedback
138        assertNotNull("Help & feedback item not found under Location Settings",
139                mDevice.wait(Until.findObject(By.desc("Help & feedback")), TIMEOUT));
140        // Verify scanning
141        assertNotNull("Scanning item not found under Location Settings",
142                mDevice.wait(Until.findObject(By.text("Scanning")), TIMEOUT));
143    }
144
145    private void verifyLocationSettingsMode(int mode) throws Exception {
146        int modeIntValue = 1;
147        String textMode = "Device only";
148        if (mode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY) {
149            modeIntValue = 3;
150            textMode = "High accuracy";
151        }
152        else if (mode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING) {
153            modeIntValue = 2;
154            textMode = "Battery saving";
155        }
156        // Load location settings
157        SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
158                Settings.ACTION_LOCATION_SOURCE_SETTINGS);
159        // Tap on mode
160        dismissAlertDialogs();
161        // Load location settings
162        mDevice.wait(Until.findObject(By.text("Mode")), TIMEOUT).click();
163        Thread.sleep(TIMEOUT);
164        assertNotNull("Location mode screen not loaded", mDevice.wait(Until.findObject
165                (By.text("Location mode")), TIMEOUT));
166        // Choose said mode
167        mDevice.wait(Until.findObject(By.text(textMode)), TIMEOUT).click();
168        Thread.sleep(TIMEOUT);
169        dismissAlertDialogs();
170        mDevice.wait(Until.findObject(By.desc("Navigate up")), TIMEOUT).click();
171        Thread.sleep(TIMEOUT);
172        if (mode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY ||
173                mode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING) {
174            dismissAlertDialogs();
175        }
176        // get setting and verify value
177        // Verify change of mode
178        int locationSettingMode =
179                Settings.Secure.getInt(getInstrumentation().getContext().getContentResolver(),
180                Settings.Secure.LOCATION_MODE);
181        assertEquals(mode + " value not set correctly for location.", modeIntValue,
182                locationSettingMode);
183    }
184
185    private void verifyLocationSettingsOnOrOff(boolean verifyOn) throws Exception {
186        // Set location flag
187        if (verifyOn) {
188            Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(),
189                    Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
190        }
191        else {
192            Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(),
193                    Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
194        }
195        dismissAlertDialogs();
196        // Load location settings
197        SettingsHelper.launchSettingsPage(getInstrumentation().getContext(),
198                Settings.ACTION_LOCATION_SOURCE_SETTINGS);
199        dismissAlertDialogs();
200        // Toggle UI
201        mDevice.wait(Until.findObject(By.res(SETTINGS_PACKAGE, "switch_widget")), TIMEOUT).click();
202        dismissAlertDialogs();
203        Thread.sleep(TIMEOUT);
204        // Verify change in setting
205        int locationEnabled = Settings.Secure.getInt(getInstrumentation()
206                 .getContext().getContentResolver(),
207                 Settings.Secure.LOCATION_MODE);
208        if (verifyOn) {
209            assertFalse("Location not enabled correctly", locationEnabled == 0);
210        }
211        else {
212            assertEquals("Location not disabled correctly", 0, locationEnabled);
213        }
214    }
215
216    // This method dismisses both alert dialogs that might popup and
217    // interfere with the test. Since the order in which the dialog
218    // shows up changes in no specific known way, we're checking for
219    // both dialogs in any order for a robust test. Bug b/36233151
220    // filed against Location team for specifications. This is a
221    // workaround in the meantime to ensure coverage.
222    private void dismissAlertDialogs() throws Exception {
223        for (int count = 0; count < 2; count++) {
224            UiObject2 agreeDialog = mDevice.wait(Until.findObject
225                    (By.text("Improve location accuracy?")), TIMEOUT);
226            UiObject2 previousChoiceYesButton = mDevice.wait(Until.findObject
227                    (By.text("YES")), TIMEOUT);
228            if (agreeDialog != null) {
229                mDevice.wait(Until.findObject
230                        (By.text("AGREE")), TIMEOUT).click();
231                Thread.sleep(TIMEOUT);
232                assertNull("Improve location dialog not dismissed",
233                        mDevice.wait(Until.findObject
234                        (By.text("Improve location accuracy?")), TIMEOUT));
235            }
236            if (previousChoiceYesButton != null) {
237                previousChoiceYesButton.click();
238                // Short sleep to wait for the new screen
239                Thread.sleep(TIMEOUT);
240            }
241        }
242    }
243}
244