Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to continuously track the location of an Android mobile phone?

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.

like image 725
Dmitrii Pisarenko Avatar asked Aug 15 '13 19:08

Dmitrii Pisarenko


1 Answers

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).

like image 50
msh Avatar answered Nov 11 '22 14:11

msh