5

I'm trying to get this bit of code to work:

Testing GPS in Android

The problem is, when I run the test, onLocationChanged() is never called:

public class LocationTest0 extends AndroidTestCase implements LocationListener {
private Location received = null;
public void testExample() {
    LocationManager lm = (LocationManager)this.getContext().getSystemService(Context.LOCATION_SERVICE);
    String testProvider = "Test";

    if (null == lm.getProvider(testProvider)){
        lm.addTestProvider(testProvider, false, false, false, false, false, false, false, Criteria.POWER_LOW, Criteria.ACCURACY_FINE);
    }

    lm.setTestProviderEnabled(testProvider, true);
    lm.requestLocationUpdates(testProvider, 0, 0, this);
    lm.setTestProviderStatus(testProvider, LocationProvider.AVAILABLE, null, System.currentTimeMillis());

    Location location = new Location(testProvider);
    location.setLatitude(1.0);
    location.setLongitude(2.0);
    location.setTime(System.currentTimeMillis());
    lm.setTestProviderLocation(testProvider, location);

    Assert.assertFalse("Received Location is null", received == null );

    lm.removeTestProvider(testProvider);
}
@Override
public void onLocationChanged(Location location) {
    received = location;
    Log.d("LocationTest0", "onLocationChanged CALLED");
    // Never gets called
}
Community
  • 1
  • 1
Jodes
  • 14,118
  • 26
  • 97
  • 156

6 Answers6

5

This is what worked for me

locationManager.addTestProvider(mocLocationProvider, false, false,
                    false, false, true, true, true, 0, 5);
locationManager.setTestProviderEnabled(mocLocationProvider, true);

.

Location mockLocation = new Location(mocLocationProvider); // a string
mockLocation.setLatitude(location.getLatitude());  // double 
mockLocation.setLongitude(location.getLongitude()); 
mockLocation.setAltitude(location.getAltitude()); 
mockLocation.setTime(System.currentTimeMillis()); 
locationManager.setTestProviderLocation( mocLocationProvider, mockLocation); 

.

<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION">

Also in the android phone settings make sure you have the "Allow mock locations" checkbox ticked

Reno
  • 33,594
  • 11
  • 89
  • 102
  • Your code seems to just do the same thing? I'm using the emulator, but it has Allow Mock Locations checked. – Jodes May 16 '11 at 09:31
  • I added setTime and setAltitude to the locations, still no calls to onLocationChanged(). – Jodes May 16 '11 at 09:38
  • If the code is the same as mine then it probably is the emulators fault. I rarely work with emulators when it comes to GPS. – Reno May 16 '11 at 10:08
  • Thanks again - sadly no luck, I'm getting the same problem testing on a real device. onLocationChanged() just doesn't want to get called – Jodes May 16 '11 at 10:36
  • Weird. What is the name of your mock location provider? – Reno May 16 '11 at 11:03
  • I've used "Test" as the name for the mock location provider – Jodes May 16 '11 at 11:14
  • 1
    I've used LocationManager.GPS_PROVIDER as mock name. I've no idea why I did it though. I know its wrong and stuff. Can you try it once? :) – Reno May 16 '11 at 11:31
  • 1
    When I do that, it tells me to add the permission ACCESS_FINE_LOCATION. And when I do that, IllegalArgumentException: Provider "gps" unknown, caused by `lm.setTestProviderEnabled(testProvider, true);` – Jodes May 16 '11 at 11:39
  • Although that new error is a problem with the conditional I use, which stops the testProvider "gps" being created. if I remove the conditional, it gets created but the old problem comes back, onLocationChanged is never called – Jodes May 16 '11 at 11:44
  • Say, can this be used to mock the location to other apps? I've noticed we have an option to choose which app will be allowed to mock the location in the developer options... Is this what some mocking apps do? Also, is it possible to use special commands that are available only for rooted devices? – android developer Sep 25 '21 at 18:25
2

I had the same issue and could get it to work. I'll share it here in case it can help anyone else.

The thing to consider is that any call to setTestProviderLocation will invoke any listener registered on the mock providers at the time of the invocation. So if you call setTestProviderLocation and right after that call requestLocationUpdates, the onLocationChanged callback never gets called.

My problem was that I had these two (setTestProviderLocation and requestLocationUpdates) in two different threads and requestLocationUpdates was called after, so I never got a callback to onLocationChanged. If your program is multi-threaded (which very likely is) make sure setTestProviderLocation is called after requestLocationUpdates.

Also I noticed for any call to setTestProviderLocation, onLocationChanged will be called once (approximately). So you can put setTestProviderLocation in a loop to simulate a series of calls to onLocationChanged. This way you can simulate a path as well.

m.hashemian
  • 1,786
  • 2
  • 15
  • 31
1

I had the same problem. Couldn't resolve it and finally I gave up and added a call to onLocationChanged( location) after locationManager.setTestProviderEnabled( PROVIDER, location) manually. It's not pretty but works.

v0rin
  • 510
  • 4
  • 11
0

After adding and enabling your Provider just use this line to get the updates :
locationManager.requestLocationUpdates(MOCK_PROVIDER, 0, 0, this);

I recommend to use a method like this on activity start-up :

    private void enableProvider() {
        
        try {
            locationManager.addTestProvider(
                    MOCK_PROVIDER,
                    false,
                    false,
                    false,
                    false,
                    true,
                    true,
                    true,
                    0,
                    5
            );
        } catch (IllegalArgumentException | SecurityException e) {
            Log.w(TAG, "addTestProvider" + e.getMessage());
        }
        try {
            locationManager.setTestProviderEnabled(MOCK_PROVIDER, true);
            locationManager.requestLocationUpdates(MOCK_PROVIDER, 0, 0, this); <-- Update Request
        } catch (IllegalArgumentException | SecurityException e) {
            Log.w(TAG, "setTestProviderEnabled" + e.getMessage());
        }
    }

Handle the exceptions as well.

alizeyn
  • 2,300
  • 1
  • 20
  • 30
0

I ran into a similar problem. Regardless of what I tried, I could never get onLocationChanged() to be automatically called. Eventually, I gave up and created a method that both set the location with setTestProviderLocation() and directly called onLocationChanged(). It's not a perfect solution, but it worked for my needs.

HappyCoder86
  • 2,267
  • 3
  • 25
  • 40
-1

I have the same problem with this issue, I think the problem is TestProvider, so I set

String mocLocationProvider= LocationManager.NETWORK_PROVIDER;

and then it can call onLocationChanged().

Khantahr
  • 8,156
  • 4
  • 37
  • 60
harvey
  • 11
  • 1
  • 2