Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting location updates when in doze mode

I'm trying to get location updates in my android app when in doze mode, this used to work up to android 5.x. With android 6 and the advent of doze, no matter what I do, the updates stop at some point. After reading a few articles and stackoverflow answers on the topic I made the following changes:

  • made my service a foreground service
  • made the service hold a partial wake lock
  • I've given my app the WAKE_LOCK permission
  • made the service run in a separate process (for a workaround to some android bug)
  • I've disabled battery optimizations for my app

But still, I'm not getting location updates when doze kicks in. I've verified that my service thread keeps running when doze starts (by periodically logging a message), but somehow the location manager stops sending updates. The documentation on doze and the LocationManager is pretty scant in this regard, so I was wondering if somebody knows of a way to keep the location manager alive in doze? Is there some method on LocationManager that if called periodically will keep the LocationManager active? Note that I'm interested in GPS updates only, with a high update frequency, once every second.

like image 306
Kornelius Elstner Avatar asked Sep 16 '17 13:09

Kornelius Elstner


2 Answers

In the end I found a workaround for the issue, after reading through the source code of com.android.internal.location.GpsLocationProvider I noticed that sending it an com.android.internal.location.ALARM_WAKEUP Intent prevented the location provider from dozing. So to keep the GPS from dozing I broadcast the Intent every 10 seconds, I added the following in my service class:

[...]
private Handler handler;
private PowerManager powerManager;

private PendingIntent wakeupIntent;
private final Runnable heartbeat = new Runnable() {
    public void run() {
        try {
            if (isRecording && powerManager != null && powerManager.isDeviceIdleMode()) {
                LOG.trace("Poking location service");
                try {
                    wakeupIntent.send();
                } catch (SecurityException | PendingIntent.CanceledException e) {
                    LOG.info("Heartbeat location manager keep-alive failed", e);
                }
            }
        } finally {
            if (handler != null) {
                handler.postDelayed(this, 10000);
            }
        }
    }
};

@Override
public void onCreate() {
    handler = new Handler();
    wakeupIntent = PendingIntent.getBroadcast(getBaseContext(), 0,
        new Intent("com.android.internal.location.ALARM_WAKEUP"), 0);
    locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TrackService");
    [...]
}
like image 121
Kornelius Elstner Avatar answered Sep 17 '22 16:09

Kornelius Elstner


If you test location and doze mode on the emulator with commands like "adb shell dumpsys deviceidle force-idle" etc. You probably noticed that location stops in Doze Mode.

But ... as "documentation" stands for :

"As soon as the user wakes the device by moving it, turning on the screen, or connecting a charger, the system exits Doze and all apps return to normal activity"

Source : https://developer.android.com/training/monitoring-device-state/doze-standby

So ... move Your emulator with GPS Joystick App or similar and You will notice that location wakes up from Doze Mode.

like image 28
Mateusz Wołkowicz Avatar answered Sep 17 '22 16:09

Mateusz Wołkowicz