1package com.xtremelabs.robolectric.shadows;
2
3import android.app.PendingIntent;
4import android.content.Context;
5import android.content.Intent;
6import android.location.Criteria;
7import android.location.GpsStatus.Listener;
8import android.location.Location;
9import android.location.LocationListener;
10import android.location.LocationManager;
11import android.os.Bundle;
12import com.xtremelabs.robolectric.Robolectric;
13import com.xtremelabs.robolectric.WithTestDefaultsRunner;
14import junit.framework.Assert;
15import org.junit.Before;
16import org.junit.Test;
17import org.junit.runner.RunWith;
18
19import java.util.*;
20
21import static android.location.LocationManager.GPS_PROVIDER;
22import static android.location.LocationManager.NETWORK_PROVIDER;
23import static com.xtremelabs.robolectric.Robolectric.shadowOf;
24import static junit.framework.Assert.*;
25import static org.hamcrest.core.IsEqual.equalTo;
26import static org.junit.Assert.assertSame;
27import static org.junit.Assert.assertThat;
28
29@RunWith(WithTestDefaultsRunner.class)
30public class LocationManagerTest {
31    private LocationManager locationManager;
32    private ShadowLocationManager shadowLocationManager;
33
34    @Before
35    public void setUp() {
36        locationManager = (LocationManager) Robolectric.application.getSystemService(Context.LOCATION_SERVICE);
37        shadowLocationManager = shadowOf(locationManager);
38    }
39
40    @Test
41    public void shouldReturnNoProviderEnabledByDefault() {
42        Boolean enabled = locationManager.isProviderEnabled(GPS_PROVIDER);
43        assertFalse(enabled);
44        enabled = locationManager.isProviderEnabled(NETWORK_PROVIDER);
45        assertFalse(enabled);
46        enabled = locationManager.isProviderEnabled("RANDOM_PROVIDER");
47        assertFalse(enabled);
48    }
49
50    @Test
51    public void shouldDisableProvider() {
52        // No provider is enabled by default, so it must be manually enabled
53        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true);
54        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, false);
55        assertFalse(locationManager.isProviderEnabled(GPS_PROVIDER));
56    }
57
58    @Test
59    public void shouldHaveListenerOnceAdded() {
60        Listener listener = addGpsListenerToLocationManager();
61        assertTrue(shadowLocationManager.hasGpsStatusListener(listener));
62    }
63
64    @Test
65    public void shouldNotHaveListenerOnceRemoved() {
66        Listener listener = addGpsListenerToLocationManager();
67
68        locationManager.removeGpsStatusListener(listener);
69
70        assertFalse(shadowLocationManager.hasGpsStatusListener(listener));
71    }
72
73    @Test
74    public void shouldReturnEnabledProviders() throws Exception {
75        shadowLocationManager.setProviderEnabled(NETWORK_PROVIDER, false);
76        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, false);
77        shadowLocationManager.setProviderEnabled(LocationManager.PASSIVE_PROVIDER, false);
78
79        assertTrue(locationManager.getProviders(true).isEmpty());
80        assertThat(locationManager.getProviders(false).size(), equalTo(3));
81
82        shadowLocationManager.setProviderEnabled(NETWORK_PROVIDER, true);
83
84        List<String> providers = locationManager.getProviders(true);
85        assertTrue(providers.contains(NETWORK_PROVIDER));
86        assertThat(providers.size(), equalTo(1));
87
88        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true);
89        providers = locationManager.getProviders(true);
90        assertTrue(providers.contains(NETWORK_PROVIDER));
91        assertTrue(providers.contains(GPS_PROVIDER));
92        assertThat(providers.size(), equalTo(2));
93
94        shadowLocationManager.setProviderEnabled(LocationManager.PASSIVE_PROVIDER, true);
95        providers = locationManager.getProviders(true);
96        assertTrue(providers.contains(NETWORK_PROVIDER));
97        assertTrue(providers.contains(GPS_PROVIDER));
98        assertTrue(providers.contains(LocationManager.PASSIVE_PROVIDER));
99        assertThat(providers.size(), equalTo(3));
100    }
101
102    @Test
103    public void shouldReturnAllProviders() throws Exception {
104        assertThat(locationManager.getAllProviders().size(), equalTo(3));
105
106        shadowLocationManager.setProviderEnabled("MY_PROVIDER", false);
107        assertThat(locationManager.getAllProviders().size(), equalTo(4));
108    }
109
110    @Test
111    public void shouldReturnLastKnownLocationForAProvider() throws Exception {
112        assertNull(locationManager.getLastKnownLocation(NETWORK_PROVIDER));
113
114        Location networkLocation = new Location(NETWORK_PROVIDER);
115        Location gpsLocation = new Location(GPS_PROVIDER);
116
117        shadowLocationManager.setLastKnownLocation(NETWORK_PROVIDER, networkLocation);
118        shadowLocationManager.setLastKnownLocation(GPS_PROVIDER, gpsLocation);
119
120        assertSame(locationManager.getLastKnownLocation(NETWORK_PROVIDER), networkLocation);
121        assertSame(locationManager.getLastKnownLocation(GPS_PROVIDER), gpsLocation);
122    }
123
124    @Test
125    public void shouldStoreRequestLocationUpdateListeners() throws Exception {
126        TestLocationListener listener = new TestLocationListener();
127        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 2.0f, listener);
128        assertSame(shadowLocationManager.getRequestLocationUpdateListeners().get(0), listener);
129    }
130
131    @Test
132    public void shouldKeepTrackOfWhichProvidersAListenerIsBoundTo_withoutDuplicates_inAnyOrder() throws Exception {
133        TestLocationListener listener1 = new TestLocationListener();
134        TestLocationListener listener2 = new TestLocationListener();
135
136        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, listener1);
137        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1, 1, listener1);
138
139        Set<String> listOfExpectedProvidersForListener1 = new HashSet<String>();
140        listOfExpectedProvidersForListener1.add(LocationManager.NETWORK_PROVIDER);
141        listOfExpectedProvidersForListener1.add(LocationManager.GPS_PROVIDER);
142
143        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, listener2);
144        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, listener2);
145
146        Set<String> listOfExpectedProvidersForListener2 = new HashSet<String>();
147        listOfExpectedProvidersForListener2.add(LocationManager.NETWORK_PROVIDER);
148
149        assertEquals(listOfExpectedProvidersForListener1, new HashSet<String>(shadowLocationManager.getProvidersForListener(listener1)));
150        assertEquals(listOfExpectedProvidersForListener2, new HashSet<String>(shadowLocationManager.getProvidersForListener(listener2)));
151
152        locationManager.removeUpdates(listener1);
153        assertEquals(0, shadowLocationManager.getProvidersForListener(listener1).size());
154    }
155
156    @Test
157    public void shouldRemoveLocationListeners() throws Exception {
158        TestLocationListener listener = new TestLocationListener();
159        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 2.0f, listener);
160        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1, 2.0f, listener);
161
162        TestLocationListener otherListener = new TestLocationListener();
163        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 2.0f, otherListener);
164
165        locationManager.removeUpdates(listener);
166
167        List<LocationListener> expected = new ArrayList<LocationListener>();
168        expected.add(otherListener);
169        assertThat(shadowLocationManager.getRequestLocationUpdateListeners(), equalTo(expected));
170    }
171
172    @Test
173    public void shouldRemovePendingIntentsWhenRequestingLocationUpdatesUsingCriteria() throws Exception {
174        Intent someIntent = new Intent("some_action");
175        PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(Robolectric
176                .getShadowApplication().getApplicationContext(), 0, someIntent,
177                PendingIntent.FLAG_UPDATE_CURRENT);
178        Intent someOtherIntent = new Intent("some_other_action");
179        PendingIntent someOtherLocationListenerPendingIntent = PendingIntent.getBroadcast(
180                Robolectric.getShadowApplication().getApplicationContext(), 0, someOtherIntent,
181                PendingIntent.FLAG_UPDATE_CURRENT);
182
183        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true);
184        shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true);
185        Criteria criteria = new Criteria();
186        criteria.setAccuracy(Criteria.ACCURACY_FINE);
187
188        locationManager.requestLocationUpdates(0, 0, criteria, someLocationListenerPendingIntent);
189        locationManager.requestLocationUpdates(0, 0, criteria, someOtherLocationListenerPendingIntent);
190
191        locationManager.removeUpdates(someLocationListenerPendingIntent);
192
193        Map<PendingIntent, Criteria> expectedCriteria = new HashMap<PendingIntent, Criteria>();
194        expectedCriteria.put(someOtherLocationListenerPendingIntent, criteria);
195        assertThat(shadowLocationManager.getRequestLocationUdpateCriteriaPendingIntents(), equalTo(expectedCriteria));
196    }
197
198    @Test
199    public void shouldNotSetBestEnabledProviderIfProviderIsDisabled() throws Exception {
200        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true);
201        assertTrue(shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true));
202    }
203
204    @Test
205    public void shouldNotSetBestDisabledProviderIfProviderIsEnabled() throws Exception {
206        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true);
207        assertFalse(shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, false));
208    }
209
210    @Test
211    public void shouldRemovePendingIntentsWhenRequestingLocationUpdatesUsingLocationListeners() throws Exception {
212        Intent someIntent = new Intent("some_action");
213        PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(Robolectric.getShadowApplication().getApplicationContext(), 0,
214                someIntent, PendingIntent.FLAG_UPDATE_CURRENT);
215        Intent someOtherIntent = new Intent("some_other_action");
216        PendingIntent someOtherLocationListenerPendingIntent = PendingIntent.getBroadcast(Robolectric.getShadowApplication().getApplicationContext(),
217                0, someOtherIntent, PendingIntent.FLAG_UPDATE_CURRENT);
218
219        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true);
220        shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true);
221        shadowLocationManager.setProviderEnabled(NETWORK_PROVIDER, true);
222
223        locationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, someLocationListenerPendingIntent);
224        locationManager.requestLocationUpdates(NETWORK_PROVIDER, 0, 0, someOtherLocationListenerPendingIntent);
225
226        locationManager.removeUpdates(someLocationListenerPendingIntent);
227
228        Map<PendingIntent, String> expectedProviders = new HashMap<PendingIntent, String>();
229        expectedProviders.put(someOtherLocationListenerPendingIntent, NETWORK_PROVIDER);
230        assertThat(shadowLocationManager.getRequestLocationUdpateProviderPendingIntents(),
231                equalTo(expectedProviders));
232    }
233
234    @Test
235    public void shouldStoreBestProviderCriteriaAndEnabledOnlyFlag() throws Exception {
236        Criteria criteria = new Criteria();
237        assertNull(locationManager.getBestProvider(criteria, true));
238        assertSame(criteria, shadowLocationManager.getLastBestProviderCriteria());
239        assertTrue(shadowLocationManager.getLastBestProviderEnabledOnly());
240    }
241
242    @Test
243    public void shouldReturnNullIfBestProviderNotExplicitlySet() throws Exception {
244        Criteria criteria = new Criteria();
245        assertNull(locationManager.getBestProvider(null, false));
246        assertNull(locationManager.getBestProvider(null, true));
247        assertNull(locationManager.getBestProvider(criteria, false));
248        assertNull(locationManager.getBestProvider(criteria, true));
249    }
250
251    @Test
252    public void shouldThrowExceptionWhenRequestingLocationUpdatesWithANullIntent() throws Exception {
253        try {
254            shadowLocationManager.requestLocationUpdates(0, 0, new Criteria(), null);
255            Assert.fail("When requesting location updates the intent must not be null!");
256        } catch (Exception e) {
257            // No worries, everything is fine...
258        }
259    }
260
261    @Test
262    public void shouldThrowExceptionWhenRequestingLocationUpdatesAndNoProviderIsFound() throws Exception {
263        Intent someIntent = new Intent("some_action");
264        PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(Robolectric.getShadowApplication().getApplicationContext(), 0,
265                someIntent, PendingIntent.FLAG_UPDATE_CURRENT);
266        Criteria criteria = new Criteria();
267        criteria.setAccuracy(Criteria.ACCURACY_FINE);
268        try {
269            shadowLocationManager.requestLocationUpdates(0, 0, criteria, someLocationListenerPendingIntent);
270            Assert.fail("When requesting location updates the intent must not be null!");
271        } catch (Exception e) {
272            // No worries, everything is fine...
273        }
274    }
275
276    @Test
277    public void shouldThrowExceptionIfTheBestProviderIsUnknown() throws Exception {
278        Criteria criteria = new Criteria();
279        criteria.setAccuracy(Criteria.ACCURACY_FINE);
280        try {
281            shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", true);
282            Assert.fail("The best provider is unknown!");
283        } catch (Exception e) {
284            // No worries, everything is fine...
285        }
286    }
287
288    @Test
289    public void shouldReturnBestCustomProviderUsingCriteria() throws Exception {
290        Criteria criteria = new Criteria();
291        Criteria customProviderCriteria = new Criteria();
292
293        // Manually set best provider should be returned
294        ArrayList<Criteria> criteriaList = new ArrayList<Criteria>();
295        customProviderCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
296        criteriaList.add(customProviderCriteria);
297        shadowLocationManager.setProviderEnabled("BEST_ENABLED_PROVIDER_WITH_CRITERIA", true, criteriaList);
298        assertTrue(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER_WITH_CRITERIA", true));
299        criteria.setAccuracy(Criteria.ACCURACY_COARSE);
300        criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
301        assertThat("BEST_ENABLED_PROVIDER_WITH_CRITERIA", equalTo(locationManager.getBestProvider(criteria, true)));
302        assertTrue(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER_WITH_CRITERIA", true));
303        assertThat("BEST_ENABLED_PROVIDER_WITH_CRITERIA", equalTo(locationManager.getBestProvider(criteria, false)));
304        assertThat("BEST_ENABLED_PROVIDER_WITH_CRITERIA", equalTo(locationManager.getBestProvider(criteria, true)));
305    }
306
307    @Test
308    public void shouldReturnBestProviderUsingCriteria() {
309        Criteria criteria = new Criteria();
310
311        shadowLocationManager.setProviderEnabled(LocationManager.GPS_PROVIDER, false);
312        criteria.setAccuracy(Criteria.ACCURACY_FINE);
313        assertThat(LocationManager.GPS_PROVIDER, equalTo(locationManager.getBestProvider(criteria, false)));
314
315        shadowLocationManager.setProviderEnabled(LocationManager.NETWORK_PROVIDER, false);
316        criteria.setAccuracy(Criteria.ACCURACY_COARSE);
317        assertThat(LocationManager.NETWORK_PROVIDER, equalTo(locationManager.getBestProvider(criteria, false)));
318
319        criteria.setPowerRequirement(Criteria.POWER_LOW);
320        criteria.setAccuracy(Criteria.ACCURACY_FINE);
321        assertThat(LocationManager.NETWORK_PROVIDER, equalTo(locationManager.getBestProvider(criteria, false)));
322    }
323
324    @Test
325    public void shouldReturnBestDisabledProvider() throws Exception {
326        shadowLocationManager.setProviderEnabled("BEST_DISABLED_PROVIDER", false);
327        shadowLocationManager.setBestProvider("BEST_DISABLED_PROVIDER", false);
328        shadowLocationManager.setProviderEnabled("BEST_ENABLED_PROVIDER", true);
329        shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", true);
330
331        assertTrue(shadowLocationManager.setBestProvider("BEST_DISABLED_PROVIDER", false));
332        assertThat("BEST_DISABLED_PROVIDER", equalTo(locationManager.getBestProvider(null, false)));
333        assertThat("BEST_ENABLED_PROVIDER", equalTo(locationManager.getBestProvider(null, true)));
334    }
335
336    @Test
337    public void shouldReturnBestEnabledProvider() throws Exception {
338        shadowLocationManager.setProviderEnabled("BEST_ENABLED_PROVIDER", true);
339
340        assertTrue(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", true));
341        assertFalse(shadowLocationManager.setBestProvider("BEST_ENABLED_PROVIDER", false));
342        assertThat("BEST_ENABLED_PROVIDER", equalTo(locationManager.getBestProvider(null, true)));
343        assertNull(locationManager.getBestProvider(null, false));
344    }
345
346    @Test
347    public void shouldNotifyAllListenersIfProviderStateChanges() {
348        TestLocationListener listener = new TestLocationListener();
349        locationManager.requestLocationUpdates("TEST_PROVIDER", 0, 0, listener);
350        shadowLocationManager.setProviderEnabled("TEST_PROVIDER", true);
351        assertTrue(listener.providerEnabled);
352        shadowLocationManager.setProviderEnabled("TEST_PROVIDER", false);
353        assertFalse(listener.providerEnabled);
354    }
355
356    @Test
357    public void shouldRegisterLocationUpdatesWhenProviderGiven() throws Exception {
358        shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true);
359        shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true);
360
361        Intent someIntent = new Intent("some_action");
362        PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(Robolectric.getShadowApplication().getApplicationContext(), 0,
363                someIntent, PendingIntent.FLAG_UPDATE_CURRENT);
364        locationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, someLocationListenerPendingIntent);
365
366        assertThat(shadowLocationManager.getRequestLocationUdpateProviderPendingIntents().get(someLocationListenerPendingIntent),
367                equalTo(GPS_PROVIDER));
368    }
369
370    @Test
371    public void shouldRegisterLocationUpdatesWhenCriteriaGiven() throws Exception {
372        shadowLocationManager.setProviderEnabled(NETWORK_PROVIDER, true);
373        shadowLocationManager.setBestProvider(LocationManager.NETWORK_PROVIDER, true);
374        Criteria criteria = new Criteria();
375        criteria.setAccuracy(Criteria.ACCURACY_COARSE);
376
377        Intent someIntent = new Intent("some_action");
378        PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(Robolectric.getShadowApplication().getApplicationContext(), 0,
379                someIntent, PendingIntent.FLAG_UPDATE_CURRENT);
380        Criteria someCriteria = new Criteria();
381        someCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
382        locationManager.requestLocationUpdates(0, 0, someCriteria, someLocationListenerPendingIntent);
383
384        assertThat(shadowLocationManager.getRequestLocationUdpateCriteriaPendingIntents().get(someLocationListenerPendingIntent),
385                equalTo(someCriteria));
386    }
387
388    private Listener addGpsListenerToLocationManager() {
389        Listener listener = new TestGpsListener();
390        locationManager.addGpsStatusListener(listener);
391        return listener;
392    }
393
394    private static class TestLocationListener implements LocationListener {
395        public boolean providerEnabled;
396
397        @Override
398        public void onLocationChanged(Location location) {
399        }
400
401        @Override
402        public void onStatusChanged(String s, int i, Bundle bundle) {
403        }
404
405        @Override
406        public void onProviderEnabled(String s) {
407            providerEnabled = true;
408        }
409
410        @Override
411        public void onProviderDisabled(String s) {
412            providerEnabled = false;
413        }
414    }
415
416    private class TestGpsListener implements Listener {
417
418        @Override
419        public void onGpsStatusChanged(int event) {
420
421        }
422    }
423}
424