1

Right, the situation is as follows;

We have developed an app that checks the location of the user every 5-10 minutes for location specific content. To do so, I've created a Service to stick to the background (so it can update even when the app isn't directly in the foreground) in which a LocationController is created to check the latest known location. When it's finished, it cleans up and the location is sent to a database (which is a necessity for this concept).

This all works fine, as long as I check the location with GPS_PROVIDER. However, when I switch it around to NETWORK_PROVIDER, it may check the location once more before dying completely.

I've tried multiple options to prevent this problem, but nothing seems to be working with the update service when I swap that 1 setting.

Here are a few snippets which should be relevant to the service:

UpdateService:

 @Override
public void onCreate() {
    super.onCreate();
    Log.d("Debug", "Created service");
    PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
    wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
    wakeLock.acquire();
    IntentFilter filter = new IntentFilter();
    filter.addAction(UPDATE_ACTION);

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Log.d("Starting", "Starting Service");

    mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    mAlarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);

    Intent i = new Intent(UPDATE_ACTION);
    alarmManagerPendingIntent = PendingIntent.getBroadcast(this, 0, i, 0);
    alarmManagerPendingIntent.cancel();
    mAlarmManager.cancel(alarmManagerPendingIntent);

    mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                AlarmManager.INTERVAL_FIFTEEN_MINUTES,
                AlarmManager.INTERVAL_FIFTEEN_MINUTES, 
                alarmManagerPendingIntent);

    mLocationController = new LocationController(this, this);

    updateHandler = new Handler();

    return START_STICKY;
}

LocationController:

private LocationListener locationListener = new LocationListener() {
    private boolean didSendLocation;
    public void onLocationChanged(Location location) {
        mLastLocation = location;
        mCallback.locationUpdate(location,false);
        didSendLocation = true;
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        Log.d("Debug", "Status changed: "+status);
        Location _lastLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        Log.d("Debug", "Last location: "+_lastLocation); 
        if(!didSendLocation)
        {

            mCallback.locationUpdate(_lastLocation,false);
        }
        didSendLocation = false;
    }

    public void onProviderEnabled(String provider) {
        Log.d("Debug", "Provider Enabled");
    }

    public void onProviderDisabled(String provider) {
        Log.d("Debug", "Provider disabled");
    }
};

public LocationController(Context mContext, LocationControllerCallback callback) {
    this.mContext = mContext;
    mCallback = callback;
    Log.d("Debug", "Created LocationController");
    mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
    mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 300000, 100, locationListener);
    mLastLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

    mCallback.locationUpdate(mLastLocation,true);
}

So, the code works as it is now, but when I swap:

mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 300000, 100, locationListener);

with

mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 300000, 100, locationListener);

It will no longer update. Any ideas?

Grumpmeister
  • 31
  • 1
  • 6

4 Answers4

0

When you use this to get location updates:

mLocationManager.requestLocationUpdates(...)

you don't need AlarmManager methods as the first parameter of the requestLocationUpdates method already acts as a "timer". See here for more info.

Also, you may need to include the following directives in your AndroidManifest.xml file:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CONTROL_LOCATION_UPDATES"/>

Without these permissions, the requestLocationUpdates method may not work as you expected regardless of which provider you use.

UPDATE 1:

I would have your LocationController class initialiased in a Service, for example:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    this.mLocationController = new LocationController(this);
    return Service.START_NOT_STICKY;
}

Then, start the above Service in the onResume method of an activity (MainActivity or another activity in your project), and pause the Service in the onPause method of the same activity.

  • The locationcontroller refers back to the UpdateService with a LocationControllerCallback though, so I believe I tried that before, but it eventually stopped working due to the callback not being able to be done. As for the manifests, the COARSE and FINE locations are in there already, but I'll try adding CONTROL_LOCATION_UPDATES. – Grumpmeister Apr 14 '14 at 14:29
  • Update 1: Would that still allow updates of the location to continue as the app is in the background (and potentially killed by Android)? The service was running specifically for that reason, since the app would be able to be used at the start of going out and still be up to date on your location, lets say, 3 hours later with your phone in your pocket. – Grumpmeister Apr 14 '14 at 14:55
  • Well, you may need to change to `Service.START_STICKY;` in your case. But try `Service.START_NOT_STICKY` first before you made the changes to see it it satisfies your requirement. –  Apr 14 '14 at 14:58
  • Hmm, this situation is being used right now, but sadly does not seem to be solving the problem. When using NETWORK_PROVIDER it only seems to update 1 or 2 times, but with GPS_PROVIDER it still works :( – Grumpmeister Apr 14 '14 at 15:09
  • Don't work? On a real device or on an AVD? Please elaborate. Please note that you may need to enable the **Use wireless networks** option if you use `LocationManager.NETWORK_PROVIDER`. Else, enable the **Use GPS satellites** option if you use `LocationManager.GPS_PROVIDER`. These options are found in **Settings | Location Services** menu options on your Android device. –  Apr 14 '14 at 15:19
  • We're testing on a Samsung Galaxy S3; basically what happens is the following: The app starts and the location manager starts up, finds a location and waits 5 minutes (or depending a bit on the setInexactRepeating). When using GPS_PROVIDER, it will continue this trend. Update the location and wait. When using NETWORK_PROVIDER, it updates the first time, but no longer updates from that point onward. When GPS_PROVIDER cant provide a location, I get the last known location of the network (which works). It's just that the service/location doesn't send a new location when set to NETWORK_PROVIDER. – Grumpmeister Apr 14 '14 at 15:31
  • I don't use the `AlarmManager` methods. I just use a `Service` to initialise the `LocationListener` class and I get updates with new location after each time interval specified by the first parameter of the `requestLocationUpdates` method. So, maybe your AlarmManager is interfering with the `requestLocationUpdates` method. You may need to debug and see if the `AlarmManager` methods still run after a period of time, or it gets killed by Android. –  Apr 14 '14 at 15:40
  • It indeed seems to conflict a little, however the interval in which it currently updates is really unpredictable. It first updates within 10 minutes, but then goes without an update for 22 minutes (which sadly for the purposes of the app is too long). It mainly seems to be a bit more likely to update if you actually move, but when you're sitting still it just refuses the update. I've currently set it to an update once a minute, but it's just not updating with the suggested timer. – Grumpmeister Apr 15 '14 at 11:32
  • Just as I suspected: Your `AlarmManager` methods are interfering with the `requestLocationUpdates` method so the update interval will not be correct. Can you please comment out the `AlarmManager` methods for now, and change your codes to **only** use the `requestLocationUpdates` method like what I posted in my updated answer. –  Apr 15 '14 at 23:03
  • I've done that (as noted in my previous comment), but it still updates very unpredictably and only once or twice after starting the service. I've now made the swap to the Google Play Fused Location provider, set the interval to 10 minutes and the priority to PRIORITY_BALANCED_POWER_ACCURACY. This framework does seem to update consistently so eventually does what was needed. – Grumpmeister Apr 16 '14 at 11:41
0

If its specific to the NETWORK_PROVIDER, you may be seeing this bug: https://code.google.com/p/android/issues/detail?id=57707

Original bug report included the Samsung Galaxy S3 as an affected device.

To help troubleshoot - you may also want to try selecting the NETWORK_PROVIDER in the GPS Benchmark app (full disclosure - its my app) to see if this app exhibits the same behavior. If so, its likely an issue with the device.

If you determine you're seeing the above issue, please be sure to star it on the issue page if you'd like to see it fixed.

Sean Barbeau
  • 11,496
  • 8
  • 58
  • 111
  • Thanks, I've checked and it's not a device problem. So at least that means I can look at something that should be solvable :p – Grumpmeister Apr 15 '14 at 12:45
0

I've solved the problem by switching to the Google Play Fused Location provider. A more detailed post around this can be found here: https://stackoverflow.com/a/19282976/3532181

Sadly the standard network provider just seemed too unreliable when it came to updates, ranging from an update within 8 minutes to hours before a new update was sent to the app.

Community
  • 1
  • 1
Grumpmeister
  • 31
  • 1
  • 6
0

I had a similar issue. I was able to fix this by adding the required permissions. The issue is related to new background service limitations.

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

Check this documentation for better understanding.