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