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.os.RemoteException;
20 import android.platform.test.annotations.Presubmit;
21 import android.provider.Settings;
22 import android.support.test.uiautomator.By;
23 import android.support.test.uiautomator.Direction;
24 import android.support.test.uiautomator.UiDevice;
25 import android.support.test.uiautomator.UiObject2;
26 import android.support.test.uiautomator.Until;
27 import android.system.helpers.SettingsHelper;
28 import android.test.InstrumentationTestCase;
29 import android.test.suitebuilder.annotation.MediumTest;
30 
31 
32 public 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
setUp()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
tearDown()50     protected void tearDown() throws Exception {
51         mDevice.pressBack();
52         mDevice.pressHome();
53         super.tearDown();
54     }
55 
56     @MediumTest
testLoadingLocationSettings()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
testLocationSettingOn()85     public void testLocationSettingOn() throws Exception {
86         verifyLocationSettingsOnOrOff(true);
87     }
88 
89     @MediumTest
testLocationSettingOff()90     public void testLocationSettingOff() throws Exception {
91         verifyLocationSettingsOnOrOff(false);
92     }
93 
94     @MediumTest
testLocationDeviceOnlyMode()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_ON);
99         dismissAlertDialogs();
100         Thread.sleep(TIMEOUT);
101         verifyLocationSettingsMode(Settings.Secure.LOCATION_MODE_SENSORS_ONLY);
102     }
103 
104     @MediumTest
testLocationBatterySavingMode()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
testLocationHighAccuracyMode()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_ON);
118     }
119 
120     @MediumTest
testLocationSettingsElements()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
testLocationSettingsOverflowMenuElements()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 
verifyLocationSettingsMode(int mode)145     private void verifyLocationSettingsMode(int mode) throws Exception {
146         int modeIntValue = 1;
147         String textMode = "Device only";
148         if (mode == Settings.Secure.LOCATION_MODE_ON) {
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_ON ||
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 
verifyLocationSettingsOnOrOff(boolean verifyOn)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_ON);
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.
dismissAlertDialogs()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