Photo by Pathum Danthanarayana on Unsplash
I had a goal in mind: I needed a GPS tracking app that would replace a my handheld GPS device as a location tracker and that would automatically load the track (or parts of it) to my desired location for others to see.
For a while now I’ve used my GeoApe portal to share my GPS tracks with others. I used to travel around, track my route with a handheld GPS and afterwards I’d upload the track for others to see. This was quite useful about 10 years ago. Today I mostly use a phone for navigation and carrying a GPS just for tracking purposes doesn’t seem that reasonable. I also wanted to share my routes online.
So I decided to write my first Android application that does the following:
There are plenty of great examples out there. Unfortunately they didn’t help me with the third point of my “functional requirements”. Most of the examples stopped when navigating to Desktop or opening the ‘Overview’ screen. I looked through background services, using pendingIntents, created custom locationListeners etc, but nothing seemed to work.
Android Developers site has an articale called “Background Location Limits”, that reveals the cause of this behaviour: “In an effort to reduce power consumption, Android 8.0 (API level 26) limits how frequently background apps can retrieve the user’s current location. Apps can receive location updates only a few times each hour.”. Or in other words: don’t use background services for location services if you need frequent location update as I did!
How ever — this doesn’t mean that there is no solution: applications like Google Maps etc still use your location while being on the background, so there has to be a solution. The same page gives you some hints:
An app is considered to be in the foreground if any of the following is true:* It has a visible activity, whether the activity is started or paused.* It has a foreground service.* Another foreground app is connected to the app /../
So as a solution: create a foreground service!
Some say that it is possible to bind the service as a foreground service as follows:
final Intent intent = new Intent(this.getApplication(), BackgroundService.class);this.getApplication().startForegroundService(intent);this.getApplication().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Well, for some reason this didn’t work. So I took a different approach. I created a notification generator
private Notification getNotification() {NotificationChannel channel = new NotificationChannel(“channel_01”,“My Channel”,NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager notificationManager = getSystemService(NotificationManager.class);notificationManager.createNotificationChannel(channel);
Notification.Builder builder = new Notification.Builder(getApplicationContext(), “channel_01”);
return builder.build();}
and added the following to my service’s onCreate() method:
@Overridepublic void onCreate() {startForeground(12345678, getNotification());}
and Voila: the application works as needed. Even when sending the Application to the background for a longer period of time, it still fetches the coordinates and is able to deal with them.
The full PoC application can be found here. NB! Be aware, that Notification channel is not needed before Android 8.0 (API level 26).