package org.robolectric.shadows; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.location.Criteria; import android.location.GpsStatus.Listener; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import junit.framework.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.TestRunners; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import static android.location.LocationManager.GPS_PROVIDER; import static android.location.LocationManager.NETWORK_PROVIDER; import static junit.framework.Assert.*; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertSame; import static org.robolectric.Shadows.shadowOf; @RunWith(TestRunners.MultiApiSelfTest.class) public class ShadowLocationManagerTest { private LocationManager locationManager; private ShadowLocationManager shadowLocationManager; @Before public void setUp() { locationManager = (LocationManager) RuntimeEnvironment.application.getSystemService(Context.LOCATION_SERVICE); shadowLocationManager = shadowOf(locationManager); } @Test public void shouldReturnNoProviderEnabledByDefault() { Boolean enabled = locationManager.isProviderEnabled(GPS_PROVIDER); assertFalse(enabled); enabled = locationManager.isProviderEnabled(NETWORK_PROVIDER); assertFalse(enabled); enabled = locationManager.isProviderEnabled("RANDOM_PROVIDER"); assertFalse(enabled); } @Test public void shouldDisableProvider() { // No provider is enabled by default, so it must be manually enabled shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); shadowLocationManager.setProviderEnabled(GPS_PROVIDER, false); assertFalse(locationManager.isProviderEnabled(GPS_PROVIDER)); } @Test public void shouldHaveListenerOnceAdded() { Listener listener = addGpsListenerToLocationManager(); assertTrue(shadowLocationManager.hasGpsStatusListener(listener)); } @Test public void shouldNotHaveListenerOnceRemoved() { Listener listener = addGpsListenerToLocationManager(); locationManager.removeGpsStatusListener(listener); assertFalse(shadowLocationManager.hasGpsStatusListener(listener)); } @Test public void getProviders_returnsProvidersBasedOnEnabledParameter() throws Exception { assertTrue(locationManager.getProviders(true).isEmpty()); assertThat(locationManager.getProviders(false).size()).isEqualTo(3); shadowLocationManager.setProviderEnabled(NETWORK_PROVIDER, true); List<String> providers = locationManager.getProviders(true); assertTrue(providers.contains(NETWORK_PROVIDER)); assertThat(providers.size()).isEqualTo(1); shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); providers = locationManager.getProviders(true); assertTrue(providers.contains(NETWORK_PROVIDER)); assertTrue(providers.contains(GPS_PROVIDER)); assertThat(providers.size()).isEqualTo(2); shadowLocationManager.setProviderEnabled(LocationManager.PASSIVE_PROVIDER, true); providers = locationManager.getProviders(true); assertTrue(providers.contains(NETWORK_PROVIDER)); assertTrue(providers.contains(GPS_PROVIDER)); assertTrue(providers.contains(LocationManager.PASSIVE_PROVIDER)); assertThat(providers.size()).isEqualTo(3); } @Test public void shouldReturnAllProviders() throws Exception { assertThat(locationManager.getAllProviders().size()).isEqualTo(3); shadowLocationManager.setProviderEnabled("MY_PROVIDER", false); assertThat(locationManager.getAllProviders().size()).isEqualTo(4); } @Test public void shouldReturnLastKnownLocationForAProvider() throws Exception { assertNull(locationManager.getLastKnownLocation(NETWORK_PROVIDER)); Location networkLocation = new Location(NETWORK_PROVIDER); Location gpsLocation = new Location(GPS_PROVIDER); shadowLocationManager.setLastKnownLocation(NETWORK_PROVIDER, networkLocation); shadowLocationManager.setLastKnownLocation(GPS_PROVIDER, gpsLocation); assertSame(locationManager.getLastKnownLocation(NETWORK_PROVIDER), networkLocation); assertSame(locationManager.getLastKnownLocation(GPS_PROVIDER), gpsLocation); } @Test public void shouldStoreRequestLocationUpdateListeners() throws Exception { TestLocationListener listener = new TestLocationListener(); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 2.0f, listener); assertSame(shadowLocationManager.getRequestLocationUpdateListeners().get(0), listener); } @Test public void shouldKeepTrackOfWhichProvidersAListenerIsBoundTo_withoutDuplicates_inAnyOrder() throws Exception { TestLocationListener listener1 = new TestLocationListener(); TestLocationListener listener2 = new TestLocationListener(); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, listener1); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1, 1, listener1); Set<String> listOfExpectedProvidersForListener1 = new HashSet<>(); listOfExpectedProvidersForListener1.add(LocationManager.NETWORK_PROVIDER); listOfExpectedProvidersForListener1.add(LocationManager.GPS_PROVIDER); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, listener2); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, listener2); Set<String> listOfExpectedProvidersForListener2 = new HashSet<>(); listOfExpectedProvidersForListener2.add(LocationManager.NETWORK_PROVIDER); assertEquals(listOfExpectedProvidersForListener1, new HashSet<>(shadowLocationManager.getProvidersForListener(listener1))); assertEquals(listOfExpectedProvidersForListener2, new HashSet<>(shadowLocationManager.getProvidersForListener(listener2))); locationManager.removeUpdates(listener1); assertEquals(0, shadowLocationManager.getProvidersForListener(listener1).size()); } @Test public void shouldRemoveLocationListeners() throws Exception { TestLocationListener listener = new TestLocationListener(); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 2.0f, listener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1, 2.0f, listener); TestLocationListener otherListener = new TestLocationListener(); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 2.0f, otherListener); locationManager.removeUpdates(listener); List<LocationListener> expected = new ArrayList<>(); expected.add(otherListener); assertThat(shadowLocationManager.getRequestLocationUpdateListeners()).isEqualTo(expected); } @Test public void shouldRemovePendingIntentsWhenRequestingLocationUpdatesUsingCriteria() throws Exception { Intent someIntent = new Intent("some_action"); PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(ShadowApplication.getInstance().getApplicationContext(), 0, someIntent, PendingIntent.FLAG_UPDATE_CURRENT); Intent someOtherIntent = new Intent("some_other_action"); PendingIntent someOtherLocationListenerPendingIntent = PendingIntent.getBroadcast( ShadowApplication.getInstance().getApplicationContext(), 0, someOtherIntent, PendingIntent.FLAG_UPDATE_CURRENT); shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); locationManager.requestLocationUpdates(0, 0, criteria, someLocationListenerPendingIntent); locationManager.requestLocationUpdates(0, 0, criteria, someOtherLocationListenerPendingIntent); locationManager.removeUpdates(someLocationListenerPendingIntent); Map<PendingIntent, Criteria> expectedCriteria = new HashMap<>(); expectedCriteria.put(someOtherLocationListenerPendingIntent, criteria); assertThat(shadowLocationManager.getRequestLocationUdpateCriteriaPendingIntents()).isEqualTo(expectedCriteria); } @Test public void shouldNotSetBestEnabledProviderIfProviderIsDisabled() throws Exception { shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); assertTrue(shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true)); } @Test public void shouldNotSetBestDisabledProviderIfProviderIsEnabled() throws Exception { shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); assertFalse(shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, false)); } @Test public void shouldRemovePendingIntentsWhenRequestingLocationUpdatesUsingLocationListeners() throws Exception { Intent someIntent = new Intent("some_action"); PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(ShadowApplication.getInstance().getApplicationContext(), 0, someIntent, PendingIntent.FLAG_UPDATE_CURRENT); Intent someOtherIntent = new Intent("some_other_action"); PendingIntent someOtherLocationListenerPendingIntent = PendingIntent.getBroadcast(ShadowApplication.getInstance().getApplicationContext(), 0, someOtherIntent, PendingIntent.FLAG_UPDATE_CURRENT); shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true); shadowLocationManager.setProviderEnabled(NETWORK_PROVIDER, true); locationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, someLocationListenerPendingIntent); locationManager.requestLocationUpdates(NETWORK_PROVIDER, 0, 0, someOtherLocationListenerPendingIntent); locationManager.removeUpdates(someLocationListenerPendingIntent); Map<PendingIntent, String> expectedProviders = new HashMap<>(); expectedProviders.put(someOtherLocationListenerPendingIntent, NETWORK_PROVIDER); assertThat(shadowLocationManager.getRequestLocationUdpateProviderPendingIntents()).isEqualTo(expectedProviders); } @Test public void shouldStoreBestProviderCriteriaAndEnabledOnlyFlag() throws Exception { Criteria criteria = new Criteria(); assertNull(locationManager.getBestProvider(criteria, true)); assertSame(criteria, shadowLocationManager.getLastBestProviderCriteria()); assertTrue(shadowLocationManager.getLastBestProviderEnabledOnly()); } @Test public void getBestProvider_returnsProviderBasedOnCriteriaAndEnabledState() throws Exception { Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); assertThat(locationManager.getBestProvider(null, false)).isEqualTo(LocationManager.GPS_PROVIDER); assertThat(locationManager.getBestProvider(null, true)).isNull(); assertThat(locationManager.getBestProvider(criteria, false)).isEqualTo(LocationManager.NETWORK_PROVIDER); assertThat(locationManager.getBestProvider(criteria, true)).isNull(); } @Test public void shouldThrowExceptionWhenRequestingLocationUpdatesWithANullIntent() throws Exception { try { shadowLocationManager.requestLocationUpdates(0, 0, new Criteria(), null); Assert.fail("When requesting location updates the intent must not be null!"); } catch (Exception e) { // No worries, everything is fine... } } @Test public void shouldThrowExceptionWhenRequestingLocationUpdatesAndNoProviderIsFound() throws Exception { Intent someIntent = new Intent("some_action"); PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(ShadowApplication.getInstance().getApplicationContext(), 0, someIntent, PendingIntent.FLAG_UPDATE_CURRENT); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); try { shadowLocationManager.requestLocationUpdates(0, 0, criteria, someLocationListenerPendingIntent); Assert.fail("When requesting location updates the intent must not be null!"); } catch (Exception e) { // No worries, everything is fine... } } @Test public void shouldThrowExceptionIfTheBestProviderIsUnknown() throws Exception { Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); try { shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", true); Assert.fail("The best provider is unknown!"); } catch (Exception e) { // No worries, everything is fine... } } @Test public void shouldReturnBestCustomProviderUsingCriteria() throws Exception { Criteria criteria = new Criteria(); Criteria customProviderCriteria = new Criteria(); // Manually set best provider should be returned ArrayList<Criteria> criteriaList = new ArrayList<>(); customProviderCriteria.setAccuracy(Criteria.ACCURACY_COARSE); criteriaList.add(customProviderCriteria); shadowLocationManager.setProviderEnabled("BEST_ENABLED_PROVIDER_WITH_CRITERIA", true, criteriaList); assertTrue(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER_WITH_CRITERIA", true)); criteria.setAccuracy(Criteria.ACCURACY_COARSE); criteria.setPowerRequirement(Criteria.NO_REQUIREMENT); assertThat("BEST_ENABLED_PROVIDER_WITH_CRITERIA").isEqualTo(locationManager.getBestProvider(criteria, true)); assertTrue(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER_WITH_CRITERIA", true)); assertThat("BEST_ENABLED_PROVIDER_WITH_CRITERIA").isEqualTo(locationManager.getBestProvider(criteria, false)); assertThat("BEST_ENABLED_PROVIDER_WITH_CRITERIA").isEqualTo(locationManager.getBestProvider(criteria, true)); } @Test public void shouldReturnBestProviderUsingCriteria() { Criteria criteria = new Criteria(); shadowLocationManager.setProviderEnabled(LocationManager.GPS_PROVIDER, false); criteria.setAccuracy(Criteria.ACCURACY_FINE); assertThat(LocationManager.GPS_PROVIDER).isEqualTo(locationManager.getBestProvider(criteria, false)); shadowLocationManager.setProviderEnabled(LocationManager.NETWORK_PROVIDER, false); criteria.setAccuracy(Criteria.ACCURACY_COARSE); assertThat(LocationManager.NETWORK_PROVIDER).isEqualTo(locationManager.getBestProvider(criteria, false)); criteria.setPowerRequirement(Criteria.POWER_LOW); criteria.setAccuracy(Criteria.ACCURACY_FINE); assertThat(LocationManager.NETWORK_PROVIDER).isEqualTo(locationManager.getBestProvider(criteria, false)); } @Test public void shouldReturnBestDisabledProvider() throws Exception { shadowLocationManager.setProviderEnabled("BEST_DISABLED_PROVIDER", false); shadowLocationManager.setBestProvider("BEST_DISABLED_PROVIDER", false); shadowLocationManager.setProviderEnabled("BEST_ENABLED_PROVIDER", true); shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", true); assertTrue(shadowLocationManager.setBestProvider("BEST_DISABLED_PROVIDER", false)); assertThat("BEST_DISABLED_PROVIDER").isEqualTo(locationManager.getBestProvider(null, false)); assertThat("BEST_ENABLED_PROVIDER").isEqualTo(locationManager.getBestProvider(null, true)); } @Test public void getBestProvider_returnsBestProviderBasedOnEnabledState() throws Exception { shadowLocationManager.setProviderEnabled("BEST_ENABLED_PROVIDER", true); assertThat(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", true)).isTrue(); assertThat(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", false)).isFalse(); assertThat(locationManager.getBestProvider(null, true)).isEqualTo("BEST_ENABLED_PROVIDER"); assertThat(locationManager.getBestProvider(null, false)).isEqualTo(LocationManager.GPS_PROVIDER); } @Test public void shouldNotifyAllListenersIfProviderStateChanges() { TestLocationListener listener = new TestLocationListener(); locationManager.requestLocationUpdates("TEST_PROVIDER", 0, 0, listener); shadowLocationManager.setProviderEnabled("TEST_PROVIDER", true); assertTrue(listener.providerEnabled); shadowLocationManager.setProviderEnabled("TEST_PROVIDER", false); assertFalse(listener.providerEnabled); } @Test public void shouldRegisterLocationUpdatesWhenProviderGiven() throws Exception { shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true); Intent someIntent = new Intent("some_action"); PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(ShadowApplication.getInstance().getApplicationContext(), 0, someIntent, PendingIntent.FLAG_UPDATE_CURRENT); locationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, someLocationListenerPendingIntent); assertThat(shadowLocationManager.getRequestLocationUdpateProviderPendingIntents().get(someLocationListenerPendingIntent)).isEqualTo(GPS_PROVIDER); } @Test public void shouldRegisterLocationUpdatesWhenCriteriaGiven() throws Exception { shadowLocationManager.setProviderEnabled(NETWORK_PROVIDER, true); shadowLocationManager.setBestProvider(LocationManager.NETWORK_PROVIDER, true); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); Intent someIntent = new Intent("some_action"); PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(ShadowApplication.getInstance().getApplicationContext(), 0, someIntent, PendingIntent.FLAG_UPDATE_CURRENT); Criteria someCriteria = new Criteria(); someCriteria.setAccuracy(Criteria.ACCURACY_COARSE); locationManager.requestLocationUpdates(0, 0, someCriteria, someLocationListenerPendingIntent); assertThat(shadowLocationManager.getRequestLocationUdpateCriteriaPendingIntents().get(someLocationListenerPendingIntent)).isEqualTo(someCriteria); } @Test public void simulateLocation_shouldNotNotifyListenerIfLessThanFastestInterval() throws Exception { TestLocationListener listener = new TestLocationListener(); shadowLocationManager.requestLocationUpdates(GPS_PROVIDER, 2000, 0, listener); long time = System.currentTimeMillis(); Location location1 = new Location(GPS_PROVIDER); location1.setTime(time); Location location2 = new Location(GPS_PROVIDER); location2.setTime(time + 1000); shadowLocationManager.simulateLocation(location1); shadowLocationManager.simulateLocation(location2); assertThat(listener.location.getTime()).isEqualTo(location1.getTime()); } @Test public void simulateLocation_shouldNotNotifyListenerIfLessThanMinimumDistance() throws Exception { TestLocationListener listener = new TestLocationListener(); locationManager.requestLocationUpdates(GPS_PROVIDER, 0, 200000, listener); Location location1 = new Location(GPS_PROVIDER); location1.setLatitude(1); location1.setLongitude(2); location1.setTime(0); Location location2 = new Location(GPS_PROVIDER); location2.setLatitude(1.5); location2.setLongitude(2.5); location2.setTime(1000); shadowLocationManager.simulateLocation(location1); shadowLocationManager.simulateLocation(location2); assertThat(listener.location.getLatitude()).isEqualTo(1); assertThat(listener.location.getLongitude()).isEqualTo(2); } @Test public void shouldNotThrowExceptionIfLocationListenerRemovedInsideOnLocationChanged() throws Exception { TestLocationListenerSelfRemoval listener = new TestLocationListenerSelfRemoval(locationManager); shadowLocationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, listener); Location location = new Location(GPS_PROVIDER); location.setLatitude(0); location.setLongitude(0); shadowLocationManager.simulateLocation(location); assertThat(shadowLocationManager.getRequestLocationUpdateListeners().size()).isEqualTo(0); } @Test public void requestLocationUpdates_shouldNotRegisterDuplicateListeners() throws Exception { TestLocationListener listener = new TestLocationListener(); shadowLocationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, listener); shadowLocationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, listener); shadowLocationManager.simulateLocation(new Location(GPS_PROVIDER)); assertThat(listener.updateCount).isEqualTo(1); } private Listener addGpsListenerToLocationManager() { Listener listener = new TestGpsListener(); locationManager.addGpsStatusListener(listener); return listener; } private static class TestLocationListener implements LocationListener { boolean providerEnabled; Location location; int updateCount; @Override public void onLocationChanged(Location location) { this.location = location; updateCount++; } @Override public void onStatusChanged(String s, int i, Bundle bundle) { } @Override public void onProviderEnabled(String s) { providerEnabled = true; } @Override public void onProviderDisabled(String s) { providerEnabled = false; } } private static class TestLocationListenerSelfRemoval implements LocationListener { LocationManager locationManager; public TestLocationListenerSelfRemoval(LocationManager locationManager) { this.locationManager = locationManager; } @Override public void onLocationChanged(Location location) { locationManager.removeUpdates(this); } @Override public void onStatusChanged(String s, int i, Bundle bundle) { } @Override public void onProviderEnabled(String s) { } @Override public void onProviderDisabled(String s) { } } private class TestGpsListener implements Listener { @Override public void onGpsStatusChanged(int event) { } } }