1 /* 2 * Copyright (C) 2008 Google Inc. 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 package android.location; 17 18 import android.app.PendingIntent; 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.location.Criteria; 24 import android.location.Location; 25 import android.location.LocationManager; 26 import android.provider.Settings; 27 import android.test.AndroidTestCase; 28 import android.test.suitebuilder.annotation.MediumTest; 29 import android.test.suitebuilder.annotation.Suppress; 30 import android.util.Log; 31 32 /** 33 * Tests for LocationManager.addProximityAlert 34 * 35 * TODO: add tests for more scenarios 36 * 37 * To run: 38 * adb shell am instrument -e class android.location.LocationManagerProximityTest \ 39 * -w android.core/android.test.InstrumentationTestRunner 40 * 41 * This test requires that the "Allow mock locations" setting be enabled. 42 * To ensure reliable results, all location providers should be disabled. 43 * 44 */ 45 @Suppress 46 @MediumTest 47 public class LocationManagerProximityTest extends AndroidTestCase { 48 49 private static final int UPDATE_LOCATION_WAIT_TIME = 1000; 50 private static final int PROXIMITY_WAIT_TIME = 2000; 51 52 private LocationManager mLocationManager; 53 private PendingIntent mPendingIntent; 54 private TestIntentReceiver mIntentReceiver; 55 56 private static final String LOG_TAG = "LocationProximityTest"; 57 58 private static final String PROVIDER_NAME = "test"; 59 60 @Override setUp()61 protected void setUp() throws Exception { 62 super.setUp(); 63 64 // test that mock locations are allowed so a more descriptive error message can be logged 65 if (Settings.Secure.getInt(getContext().getContentResolver(), 66 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) { 67 fail("Mock locations are currently disabled in Settings - this test requires " + 68 "mock locations"); 69 } 70 71 mLocationManager = (LocationManager) getContext(). 72 getSystemService(Context.LOCATION_SERVICE); 73 if (mLocationManager.getProvider(PROVIDER_NAME) != null) { 74 mLocationManager.removeTestProvider(PROVIDER_NAME); 75 } 76 77 mLocationManager.addTestProvider(PROVIDER_NAME, true, //requiresNetwork, 78 false, // requiresSatellite, 79 true, // requiresCell, 80 false, // hasMonetaryCost, 81 false, // supportsAltitude, 82 false, // supportsSpeed, s 83 false, // upportsBearing, 84 Criteria.POWER_MEDIUM, // powerRequirement 85 Criteria.ACCURACY_FINE); // accuracy 86 mLocationManager.setTestProviderEnabled(PROVIDER_NAME, true); 87 } 88 89 @Override tearDown()90 protected void tearDown() throws Exception { 91 mLocationManager.removeTestProvider(PROVIDER_NAME); 92 93 if (mPendingIntent != null) { 94 mLocationManager.removeProximityAlert(mPendingIntent); 95 } 96 if (mIntentReceiver != null) { 97 getContext().unregisterReceiver(mIntentReceiver); 98 } 99 } 100 101 /** 102 * Tests basic proximity alert when entering proximity 103 */ testEnterProximity()104 public void testEnterProximity() throws Exception { 105 doTestEnterProximity(10000); 106 } 107 108 /** 109 * Tests proximity alert when entering proximity, with no expiration 110 */ testEnterProximity_noexpire()111 public void testEnterProximity_noexpire() throws Exception { 112 doTestEnterProximity(-1); 113 } 114 115 /** 116 * Helper variant for testing enter proximity scenario 117 * TODO: add additional parameters as more scenarios are added 118 * 119 * @param expiration - expiry of proximity alert 120 */ doTestEnterProximity(long expiration)121 private void doTestEnterProximity(long expiration) throws Exception { 122 // update location to outside proximity range 123 synchronousSendLocation(30, 30); 124 registerProximityListener(0, 0, 1000, expiration); 125 sendLocation(0, 0); 126 waitForAlert(); 127 assertProximityType(true); 128 } 129 130 /** 131 * Tests basic proximity alert when exiting proximity 132 */ testExitProximity()133 public void testExitProximity() throws Exception { 134 // first do enter proximity scenario 135 doTestEnterProximity(-1); 136 137 // now update to trigger exit proximity proximity 138 mIntentReceiver.clearReceivedIntents(); 139 sendLocation(20, 20); 140 waitForAlert(); 141 assertProximityType(false); 142 } 143 144 /** 145 * Registers the proximity intent receiver 146 */ registerProximityListener(double latitude, double longitude, float radius, long expiration)147 private void registerProximityListener(double latitude, double longitude, 148 float radius, long expiration) { 149 String intentKey = "testProximity"; 150 Intent proximityIntent = new Intent(intentKey); 151 mPendingIntent = PendingIntent.getBroadcast(getContext(), 0, 152 proximityIntent, PendingIntent.FLAG_CANCEL_CURRENT); 153 mIntentReceiver = new TestIntentReceiver(intentKey); 154 155 mLocationManager.addProximityAlert(latitude, longitude, radius, 156 expiration, mPendingIntent); 157 158 getContext().registerReceiver(mIntentReceiver, 159 mIntentReceiver.getFilter()); 160 161 } 162 163 /** 164 * Blocks until proximity intent notification is received 165 * @throws InterruptedException 166 */ waitForAlert()167 private void waitForAlert() throws InterruptedException { 168 Log.d(LOG_TAG, "Waiting for proximity update"); 169 synchronized (mIntentReceiver) { 170 mIntentReceiver.wait(PROXIMITY_WAIT_TIME); 171 } 172 173 assertNotNull("Did not receive proximity alert", 174 mIntentReceiver.getLastReceivedIntent()); 175 } 176 177 /** 178 * Asserts that the received intent had the enter proximity property set as 179 * expected 180 * @param expectedEnterProximity - true if enter proximity expected, false if 181 * exit expected 182 */ assertProximityType(boolean expectedEnterProximity)183 private void assertProximityType(boolean expectedEnterProximity) 184 throws Exception { 185 boolean proximityTest = mIntentReceiver.getLastReceivedIntent(). 186 getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, 187 !expectedEnterProximity); 188 assertEquals("proximity alert not set to expected enter proximity value", 189 expectedEnterProximity, proximityTest); 190 } 191 192 /** 193 * Synchronous variant of sendLocation 194 */ synchronousSendLocation(final double latitude, final double longitude)195 private void synchronousSendLocation(final double latitude, 196 final double longitude) 197 throws InterruptedException { 198 sendLocation(latitude, longitude, this); 199 // wait for location to be set 200 synchronized (this) { 201 wait(UPDATE_LOCATION_WAIT_TIME); 202 } 203 } 204 205 /** 206 * Asynchronously update the mock location provider without notification 207 */ sendLocation(final double latitude, final double longitude)208 private void sendLocation(final double latitude, final double longitude) { 209 sendLocation(latitude, longitude, null); 210 } 211 212 /** 213 * Asynchronously update the mock location provider with given latitude and 214 * longitude 215 * 216 * @param latitude - update location 217 * @param longitude - update location 218 * @param observer - optionally, object to notify when update is sent.If 219 * null, no update will be sent 220 */ sendLocation(final double latitude, final double longitude, final Object observer)221 private void sendLocation(final double latitude, final double longitude, 222 final Object observer) { 223 Thread locationUpdater = new Thread() { 224 @Override 225 public void run() { 226 Location loc = new Location(PROVIDER_NAME); 227 loc.setLatitude(latitude); 228 loc.setLongitude(longitude); 229 230 loc.setTime(java.lang.System.currentTimeMillis()); 231 Log.d(LOG_TAG, "Sending update for " + PROVIDER_NAME); 232 mLocationManager.setTestProviderLocation(PROVIDER_NAME, loc); 233 if (observer != null) { 234 synchronized (observer) { 235 observer.notify(); 236 } 237 } 238 } 239 }; 240 locationUpdater.start(); 241 242 } 243 244 /** 245 * Helper class that receives a proximity intent and notifies the main class 246 * when received 247 */ 248 private static class TestIntentReceiver extends BroadcastReceiver { 249 250 private String mExpectedAction; 251 private Intent mLastReceivedIntent; 252 TestIntentReceiver(String expectedAction)253 public TestIntentReceiver(String expectedAction) { 254 mExpectedAction = expectedAction; 255 mLastReceivedIntent = null; 256 } 257 getFilter()258 public IntentFilter getFilter() { 259 IntentFilter filter = new IntentFilter(mExpectedAction); 260 return filter; 261 } 262 263 @Override onReceive(Context context, Intent intent)264 public void onReceive(Context context, Intent intent) { 265 if (intent != null && mExpectedAction.equals(intent.getAction())) { 266 Log.d(LOG_TAG, "Intent Received: " + intent.toString()); 267 mLastReceivedIntent = intent; 268 synchronized (this) { 269 notify(); 270 } 271 } 272 } 273 getLastReceivedIntent()274 public Intent getLastReceivedIntent() { 275 return mLastReceivedIntent; 276 } 277 clearReceivedIntents()278 public void clearReceivedIntents() { 279 mLastReceivedIntent = null; 280 } 281 } 282 } 283