blob: e82d8780ddefb24f89e4f582a62d6919a0dedbf8 [file] [log] [blame]
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.location;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.provider.Settings;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
/**
* Tests for LocationManager.addProximityAlert
*
* TODO: add tests for more scenarios
*
* To run:
* adb shell am instrument -e class android.location.LocationManagerProximityTest \
* -w android.core/android.test.InstrumentationTestRunner
*
* This test requires that the "Allow mock locations" setting be enabled.
* To ensure reliable results, all location providers should be disabled.
*
*/
@Suppress
@MediumTest
public class LocationManagerProximityTest extends AndroidTestCase {
private static final int UPDATE_LOCATION_WAIT_TIME = 1000;
private static final int PROXIMITY_WAIT_TIME = 2000;
private LocationManager mLocationManager;
private PendingIntent mPendingIntent;
private TestIntentReceiver mIntentReceiver;
private static final String LOG_TAG = "LocationProximityTest";
private static final String PROVIDER_NAME = "test";
@Override
protected void setUp() throws Exception {
super.setUp();
// test that mock locations are allowed so a more descriptive error message can be logged
if (Settings.Secure.getInt(getContext().getContentResolver(),
Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
fail("Mock locations are currently disabled in Settings - this test requires " +
"mock locations");
}
mLocationManager = (LocationManager) getContext().
getSystemService(Context.LOCATION_SERVICE);
if (mLocationManager.getProvider(PROVIDER_NAME) != null) {
mLocationManager.removeTestProvider(PROVIDER_NAME);
}
mLocationManager.addTestProvider(PROVIDER_NAME, true, //requiresNetwork,
false, // requiresSatellite,
true, // requiresCell,
false, // hasMonetaryCost,
false, // supportsAltitude,
false, // supportsSpeed, s
false, // upportsBearing,
Criteria.POWER_MEDIUM, // powerRequirement
Criteria.ACCURACY_FINE); // accuracy
mLocationManager.setTestProviderEnabled(PROVIDER_NAME, true);
}
@Override
protected void tearDown() throws Exception {
mLocationManager.removeTestProvider(PROVIDER_NAME);
if (mPendingIntent != null) {
mLocationManager.removeProximityAlert(mPendingIntent);
}
if (mIntentReceiver != null) {
getContext().unregisterReceiver(mIntentReceiver);
}
}
/**
* Tests basic proximity alert when entering proximity
*/
public void testEnterProximity() throws Exception {
doTestEnterProximity(10000);
}
/**
* Tests proximity alert when entering proximity, with no expiration
*/
public void testEnterProximity_noexpire() throws Exception {
doTestEnterProximity(-1);
}
/**
* Helper variant for testing enter proximity scenario
* TODO: add additional parameters as more scenarios are added
*
* @param expiration - expiry of proximity alert
*/
private void doTestEnterProximity(long expiration) throws Exception {
// update location to outside proximity range
synchronousSendLocation(30, 30);
registerProximityListener(0, 0, 1000, expiration);
sendLocation(0, 0);
waitForAlert();
assertProximityType(true);
}
/**
* Tests basic proximity alert when exiting proximity
*/
public void testExitProximity() throws Exception {
// first do enter proximity scenario
doTestEnterProximity(-1);
// now update to trigger exit proximity proximity
mIntentReceiver.clearReceivedIntents();
sendLocation(20, 20);
waitForAlert();
assertProximityType(false);
}
/**
* Registers the proximity intent receiver
*/
private void registerProximityListener(double latitude, double longitude,
float radius, long expiration) {
String intentKey = "testProximity";
Intent proximityIntent = new Intent(intentKey);
mPendingIntent = PendingIntent.getBroadcast(getContext(), 0,
proximityIntent, PendingIntent.FLAG_CANCEL_CURRENT);
mIntentReceiver = new TestIntentReceiver(intentKey);
mLocationManager.addProximityAlert(latitude, longitude, radius,
expiration, mPendingIntent);
getContext().registerReceiver(mIntentReceiver,
mIntentReceiver.getFilter());
}
/**
* Blocks until proximity intent notification is received
* @throws InterruptedException
*/
private void waitForAlert() throws InterruptedException {
Log.d(LOG_TAG, "Waiting for proximity update");
synchronized (mIntentReceiver) {
mIntentReceiver.wait(PROXIMITY_WAIT_TIME);
}
assertNotNull("Did not receive proximity alert",
mIntentReceiver.getLastReceivedIntent());
}
/**
* Asserts that the received intent had the enter proximity property set as
* expected
* @param expectedEnterProximity - true if enter proximity expected, false if
* exit expected
*/
private void assertProximityType(boolean expectedEnterProximity)
throws Exception {
boolean proximityTest = mIntentReceiver.getLastReceivedIntent().
getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING,
!expectedEnterProximity);
assertEquals("proximity alert not set to expected enter proximity value",
expectedEnterProximity, proximityTest);
}
/**
* Synchronous variant of sendLocation
*/
private void synchronousSendLocation(final double latitude,
final double longitude)
throws InterruptedException {
sendLocation(latitude, longitude, this);
// wait for location to be set
synchronized (this) {
wait(UPDATE_LOCATION_WAIT_TIME);
}
}
/**
* Asynchronously update the mock location provider without notification
*/
private void sendLocation(final double latitude, final double longitude) {
sendLocation(latitude, longitude, null);
}
/**
* Asynchronously update the mock location provider with given latitude and
* longitude
*
* @param latitude - update location
* @param longitude - update location
* @param observer - optionally, object to notify when update is sent.If
* null, no update will be sent
*/
private void sendLocation(final double latitude, final double longitude,
final Object observer) {
Thread locationUpdater = new Thread() {
@Override
public void run() {
Location loc = new Location(PROVIDER_NAME);
loc.setLatitude(latitude);
loc.setLongitude(longitude);
loc.setTime(java.lang.System.currentTimeMillis());
Log.d(LOG_TAG, "Sending update for " + PROVIDER_NAME);
mLocationManager.setTestProviderLocation(PROVIDER_NAME, loc);
if (observer != null) {
synchronized (observer) {
observer.notify();
}
}
}
};
locationUpdater.start();
}
/**
* Helper class that receives a proximity intent and notifies the main class
* when received
*/
private static class TestIntentReceiver extends BroadcastReceiver {
private String mExpectedAction;
private Intent mLastReceivedIntent;
public TestIntentReceiver(String expectedAction) {
mExpectedAction = expectedAction;
mLastReceivedIntent = null;
}
public IntentFilter getFilter() {
IntentFilter filter = new IntentFilter(mExpectedAction);
return filter;
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && mExpectedAction.equals(intent.getAction())) {
Log.d(LOG_TAG, "Intent Received: " + intent.toString());
mLastReceivedIntent = intent;
synchronized (this) {
notify();
}
}
}
public Intent getLastReceivedIntent() {
return mLastReceivedIntent;
}
public void clearReceivedIntents() {
mLastReceivedIntent = null;
}
}
}