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 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 85 protected void onSaveInstanceState(Bundle outState) { 86 outState.putInt(STATE, mState); 87 } 88 89 @Override 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 > Settings so the user can set the location mode. Public because it 188 * is referenced by layout. 189 */ 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 */ 197 protected void next() { 198 mHandler.post(mRunner); 199 } 200 201 /** 202 * Wait for things to settle before returning to the state machine. 203 */ 204 protected void delay() { 205 mHandler.postDelayed(mRunner, 2000); 206 } 207 208 // Tests 209 210 private int getLocationMode() { 211 ContentResolver cr = getContentResolver(); 212 return Secure.getInt(cr, Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF); 213 } 214 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 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 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 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 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 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 266 protected abstract void testAdvance(int state); 267 } 268