9

I need to write an app, which every 5 minutes determines the current location of the mobile phone (using all free, available location providers) and sends it to a server.

If some location provider doesn't work at the start of the application, but becomes available later, the application should process its location data as well.

In order to do this, I implemented following class. In one of my activities, I create an instance of it and call its startTrackingUpdates method. locationChangeHandler does the processing of location data.

public class LocationTracker implements ILocationTracker, LocationListener {
    public static final long MIN_TIME_BETWEEN_UPDATES = 1000 * 60 * 5; // 5 minutes
    public static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
    private ILocationManager locationManager;
    private ILocationChangeHandler locationChangeHandler;

    public LocationTracker(final ILocationManager aLocationManager,
            final ILocationChangeHandler aLocationChangeHandler) {
        this.locationManager = aLocationManager;
        this.locationChangeHandler = aLocationChangeHandler;
    }

    public void startTrackingUpdates() {
        final List<String> providers = locationManager.getAllProviders();

        for (final String curProviderName : providers)
        {
            final ILocationProvider provider = locationManager.getLocationProvider(curProviderName);

            if (!provider.hasMonetaryCost())
            {
                subscribeToLocationChanges(provider);
            }
        }
    }

    private void subscribeToLocationChanges(final ILocationProvider aProvider) {
        locationManager.requestLocationUpdates(aProvider.getName(), MIN_TIME_BETWEEN_UPDATES, 
                (float)MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
    }

    public void onLocationChanged(final Location aLocation) {
        locationChangeHandler.processLocationChange(new LocationWrapper(aLocation));
    }

    public void onProviderDisabled(final String aProvider) {
    }

    public void onProviderEnabled(final String aProvider) {
    }

    public void onStatusChanged(final String aProvider, final int aStatus, 
            final Bundle aExtras) {
    }
}

I built the application and installed it on my mobile phone. Then, in the morning I took my phone, went to work, then went back home. At home I checked the results of a day-long work of the application and found only one record in the database.

Provided that the rest of the system (transmission of location data to the server, saving in the database) works correctly, I must have some problem in the location tracking code (onLocationChanged wasn't invoked even though I changed my location several times).

What's wrong with my code (how should I change it, in order for the onLocationChanged to be called whenever the location of the phone changes by more than MIN_DISTANCE_CHANGE_FOR_UPDATES meters according to one of the locatin providers) ?

Update 1 (18.08.2013 13:59 MSK):

I changed my code according to msh recommendations. I start the timer using following code:

public void startSavingGeoData() {
    final IAlarmManager alarmManager = activity.getAlarmManager();
    final IPendingIntent pendingIntent = activity.createPendingResult(
            ALARM_ID, intentFactory.createEmptyIntent(), 0);
    alarmManager.setRepeating(INTERVAL, pendingIntent);
}

In the activity I put following timer event handler:

@Override
protected void onActivityResult(final int aRequestCode, final int aResultCode, 
        final Intent aData) {
    geoDataSender.processOnActivityResult(aRequestCode, aResultCode, 
            new IntentWrapper(aData));
}

When the phone is turned on, everything works as expected - onActivityResult is executed once in INTERVAL milliseconds.

But when I press the power button (screen becomes disabled), onActivityResult is not invoked at all. When I press the power button again, onActivityResult is executed as many times, as INTERVAL has passed since the time when I turned the phone off. If I turned the phone off for 1 * INTERVAL milliseconds, it will fire once. If I turned the phone off for 2 * INTERVAL milliseconds, it will fire twice etc.

Note: By "turning off" I mean a short press of the power button (the phone still "lives" and reacts to incoming SMS, for example).

How should I modify the code of startSavingGeoData in order for the method onActivityResult to be executed every INTERVAL milliseconds, even when the phone sleeps?

Update 2 (18.08.2013 19:29 MSK): Neither alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 0, INTERVAL, pendingIntent), nor alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, INTERVAL, INTERVAL, pendingIntent) solved the problem.

Community
  • 1
  • 1
Glory to Russia
  • 17,289
  • 56
  • 182
  • 325
  • Alarm type must be one of the _WAKEUP constants, for example RTC_WAKEUP – msh Aug 18 '13 at 12:49
  • Try http://stackoverflow.com/questions/4459058/alarm-manager-example first - if it works, base on it. Note that it only keeps wakelock until onReceive returns, if you need to run longer - acquire your own – msh Aug 18 '13 at 15:41

1 Answers1

8

Your code is probably correct, but location providers are not running when your phone is sleeping. You may need to acquire a wakelock (if you don't care about power draw), or use AlarmManager and schedule your application to wake up and check location periodically (you still need to have active wakelock while you are waiting for an update, either acquired by AlamManager, or your own).

msh
  • 2,700
  • 1
  • 17
  • 23
  • I changed the code (see "Update 1"), but it still doesn't work as expected. Any ideas? – Glory to Russia Aug 18 '13 at 10:01
  • You could base your alarm code on this example http://stackoverflow.com/questions/4459058/alarm-manager-example – msh Aug 18 '13 at 12:39
  • Yes, that example works, at least method for getting the location is executed even, when the phone sleeps. – Glory to Russia Aug 19 '13 at 05:59
  • Is it true that I have to execute `subscribeToLocationChanges` whenever the alarms fires up (every 5 minutes, for example) ? – Glory to Russia Aug 19 '13 at 06:28
  • I wouldn't be surprised if subscription is lost when location provider is stopped. Are you sure you wait long enough to receive an update and hold partial wakelock while you are waiting? – msh Aug 19 '13 at 15:15
  • Are 3 minutes long enough? – Glory to Russia Aug 19 '13 at 21:43
  • I don't know - that depends on your phone, location, A-GPS availability and so on. You may need to experiment a bit. – msh Aug 20 '13 at 14:58