I have a requirement in an app to permanently send the location, even when the app is in the background or has been terminated.
For this, I have a foreground service that works excellently, but when the device is in standby mode, the location updates become less frequent, up to several hours apart.
This is likely due to the OS’s power-saving measures, but for this use case, it needs to be overridden somehow.
I have tried using wakeLock.acquire() in onStart, which didn’t make any difference, and also restarting the service via AlarmManager, but then it doesn’t get any location updates at all when started from the background.
How can I ensure that the service continues to work at least every 5 minutes, even at the cost of battery life?
public class GetLocationService extends Service {
private static final int NOTIF_ID = 2;
private static final int TWO_MINUTES = 1000 * 60 * 2;
private LocationManager mLocationManager;
private LocationListener mLocationListener;
private PowerManager.WakeLock wakeLock;
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("SERVICE_LIFECYCLE", "GetLocationService STARTED");
Notification noti = createNotification("Location Service", "Running", "Location Service");
startForeground(NOTIF_ID, noti);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GetLocationService::WakeLock");
wakeLock.acquire();
mLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
Log.d("GetLocationService", "Location update received");
Log.d("GetLocationService", "save position");
}
@Override
public void onProviderDisabled(String provider) {
Log.d("GetLocationService", "Provider disabled");
}
@Override
public void onProviderEnabled(String provider) {
Log.d("GetLocationService", "Provider enabled");
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d("GetLocationService", "Status changed");
}
};
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.d("GetLocationService", "Permissions not granted");
return;
}
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 1, mLocationListener);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 1, mLocationListener);
}
private Notification createNotification(String title, String text, String ticker) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = "location_service_channel";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, "Location Service", NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setOngoing(true)
.setSmallIcon(android.R.drawable.ic_menu_mylocation)
.setPriority(PRIORITY_MIN)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setTicker(ticker)
.setContentTitle(title)
.setContentText(text);
return builder.build();
}
@Override
public void onDestroy() {
mLocationManager.removeUpdates(mLocationListener);
wakeLock.release();
stopForeground(true);
super.onDestroy();
}
}