• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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