| /* |
| * 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.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 |
| * |
| */ |
| @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; |
| } |
| } |
| } |