1 /*
2  * Copyright (C) 2013 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.cts.verifier.location;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.location.LocationManager;
23 import android.os.Bundle;
24 import android.provider.Settings;
25 import android.provider.Settings.Secure;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.ImageView;
30 import android.widget.TextView;
31 import com.android.cts.verifier.PassFailButtons;
32 import com.android.cts.verifier.R;
33 
34 /**
35  * Asks the user to put the device in one of the four location modes and then checks to see if
36  * {@link Secure#isLocationProviderEnabled(ContentResolver, String)} and {@link
37  * LocationManager#isProviderEnabled(String)} have the expected values for GPS and Wi-Fi. For
38  * example in battery saving mode, Wi-Fi should be on but GPS should be off.
39  *
40  * It would be hard to automate these tests because the {@link Secure#LOCATION_MODE} API is only
41  * accessible to apps in the system image. Furthermore, selecting two of the modes requires the user
42  * to accept the NLP confirmation dialog.
43  */
44 public abstract class LocationModeTestActivity
45         extends PassFailButtons.Activity implements Runnable {
46 
47     private static final String STATE = "state";
48     protected static final int PASS = 1;
49     protected static final int FAIL = 2;
50     protected static final int WAIT_FOR_USER = 3;
51 
52     protected int mState;
53     protected int[] mStatus;
54     private LayoutInflater mInflater;
55     private ViewGroup mItemList;
56     private Runnable mRunner;
57     private View mHandler;
58 
59     @Override
onCreate(Bundle savedInstanceState)60     protected void onCreate(Bundle savedInstanceState) {
61         super.onCreate(savedInstanceState);
62 
63         if (savedInstanceState != null) {
64             mState = savedInstanceState.getInt(STATE, 0);
65         }
66 
67         mRunner = this;
68         mInflater = getLayoutInflater();
69         View view = mInflater.inflate(R.layout.location_mode_main, null);
70         mItemList = (ViewGroup) view.findViewById(R.id.test_items);
71         mHandler = mItemList;
72 
73         createTestItems();
74         mStatus = new int[mItemList.getChildCount()];
75         setContentView(view);
76 
77         setPassFailButtonClickListeners();
78 
79         setInfoResources();
80 
81         getPassButton().setEnabled(false);
82     }
83 
84     @Override
onSaveInstanceState(Bundle outState)85     protected void onSaveInstanceState(Bundle outState) {
86         outState.putInt(STATE, mState);
87     }
88 
89     @Override
onResume()90     protected void onResume() {
91         super.onResume();
92         next();
93     }
94 
95     /**
96      * Template method used by the subclass to create the checks corresponding to each value of
97      * {@link #mState}. Subclass should call {@link #createUserItem(int)} and {@link
98      * #createAutoItem(int)} as appropriate to generate each item.
99      */
createTestItems()100     protected abstract void createTestItems();
101 
102     /**
103      * Template method used by the subclass to call {@link #setInfoResources(int, int, int)} with
104      * the appropriate resources.
105      */
setInfoResources()106     protected abstract void setInfoResources();
107 
108     /**
109      * Subclass can call this to create a test step where the user must perform some action such
110      * as setting the location mode.
111      */
createUserItem(int stringId)112     protected View createUserItem(int stringId) {
113         View item = mInflater.inflate(R.layout.location_mode_item, mItemList, false);
114         TextView instructions = (TextView) item.findViewById(R.id.instructions);
115         instructions.setText(stringId);
116         mItemList.addView(item);
117         return item;
118     }
119 
120     /**
121      * Subclass can call this to create a test step where the test automatically evaluates whether
122      * an expected condition is satisfied, such as GPS is off.
123      */
createAutoItem(int stringId)124     protected View createAutoItem(int stringId) {
125         View item = mInflater.inflate(R.layout.location_mode_item, mItemList, false);
126         TextView instructions = (TextView) item.findViewById(R.id.instructions);
127         instructions.setText(stringId);
128         View button = item.findViewById(R.id.launch_settings);
129         button.setVisibility(View.GONE);
130         mItemList.addView(item);
131         return item;
132     }
133 
134     /**
135      * Set the visible state of a test item to passed or failed.
136      */
setItemState(int index, boolean passed)137     private void setItemState(int index, boolean passed) {
138         ViewGroup item = (ViewGroup) mItemList.getChildAt(index);
139         ImageView status = (ImageView) item.findViewById(R.id.status);
140         status.setImageResource(passed ? R.drawable.fs_good : R.drawable.fs_error);
141         View button = item.findViewById(R.id.launch_settings);
142         button.setClickable(false);
143         button.setEnabled(false);
144         status.invalidate();
145     }
146 
147     /**
148      * Set the visible state of a test item to waiting.
149      */
markItemWaiting(int index)150     protected void markItemWaiting(int index) {
151         ViewGroup item = (ViewGroup) mItemList.getChildAt(index);
152         ImageView status = (ImageView) item.findViewById(R.id.status);
153         status.setImageResource(R.drawable.fs_warning);
154         status.invalidate();
155     }
156 
157     /**
158      * Advances the state machine.
159      */
run()160     public void run() {
161         // Advance test state until we find case where it hasn't passed (yet)
162         while (mState < mStatus.length && mStatus[mState] != WAIT_FOR_USER) {
163             if (mStatus[mState] == PASS) {
164                 setItemState(mState, true);
165                 mState++;
166             } else if (mStatus[mState] == FAIL) {
167                 setItemState(mState, false);
168                 return;
169             } else {
170                 break;
171             }
172         }
173 
174         if (mState < mStatus.length && mStatus[mState] == WAIT_FOR_USER) {
175             markItemWaiting(mState);
176         }
177 
178         testAdvance(mState);
179 
180         if (mState == mStatus.length - 1 && mStatus[mState] == PASS) {
181             // All tests run and pass
182             getPassButton().setEnabled(true);
183         }
184     }
185 
186     /**
187      * Launches Locations &gt; Settings so the user can set the location mode. Public because it
188      * is referenced by layout.
189      */
launchSettings(View button)190     public void launchSettings(View button) {
191         startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
192     }
193 
194     /**
195      * Return to the state machine to progress through the tests.
196      */
next()197     protected void next() {
198         mHandler.post(mRunner);
199     }
200 
201     /**
202      * Wait for things to settle before returning to the state machine.
203      */
delay()204     protected void delay() {
205         mHandler.postDelayed(mRunner, 2000);
206     }
207 
208     // Tests
209 
getLocationMode()210     private int getLocationMode() {
211         ContentResolver cr = getContentResolver();
212         return Secure.getInt(cr, Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF);
213     }
214 
testIsOn(int i)215     protected void testIsOn(int i) {
216         int mode = getLocationMode();
217         boolean passed = mode != Secure.LOCATION_MODE_OFF;
218         if (passed) {
219             mStatus[i] = PASS;
220         } else {
221             mStatus[i] = WAIT_FOR_USER;
222         }
223         next();
224     }
225 
testIsExpectedMode(int i, int expectedMode)226     protected void testIsExpectedMode(int i, int expectedMode) {
227         int mode = getLocationMode();
228         boolean passed = mode == expectedMode;
229         if (passed) {
230             mStatus[i] = PASS;
231             next();
232         } else {
233             mStatus[i] = WAIT_FOR_USER;
234             delay();
235         }
236     }
237 
testSecureProviderIsEnabled(int i, String provider)238     protected void testSecureProviderIsEnabled(int i, String provider) {
239         ContentResolver cr = getContentResolver();
240         boolean enabled = Secure.isLocationProviderEnabled(cr, provider);
241         mStatus[i] = enabled ? PASS : FAIL;
242         next();
243     }
244 
testSecureProviderIsDisabled(int i, String provider)245     protected void testSecureProviderIsDisabled(int i, String provider) {
246         ContentResolver cr = getContentResolver();
247         boolean enabled = Secure.isLocationProviderEnabled(cr, provider);
248         mStatus[i] = !enabled ? PASS : FAIL;
249         next();
250     }
251 
testManagerProviderIsEnabled(int i, String gpsProvider)252     protected void testManagerProviderIsEnabled(int i, String gpsProvider) {
253         LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
254         boolean enabled = manager.isProviderEnabled(gpsProvider);
255         mStatus[i] = enabled ? PASS : FAIL;
256         next();
257     }
258 
testManagerProviderIsDisabled(int i, String gpsProvider)259     protected void testManagerProviderIsDisabled(int i, String gpsProvider) {
260         LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
261         boolean enabled = manager.isProviderEnabled(gpsProvider);
262         mStatus[i] = !enabled ? PASS : FAIL;
263         next();
264     }
265 
testAdvance(int state)266     protected abstract void testAdvance(int state);
267 }
268