I have created a service that tracks the device's location as it moves. The service is started in by an Activity that binds to it, and in this activity there is a "Start Tracking" button. When this button is pressed, I need the service to start in the foreground, so that it stores the Locations that the device has moved to, even if the Activity that binds to it is closed, or the app is minimised.
I understand that for the Service to be in the foreground, a notification must be displayed. I have attempted to do so, but I cannot get the notification to show or the Service to work in the foreground when the activity is destroyed.
It appears that notifications have changed in Oreo due to the notification channels, but I cannot figure out what needs to be done differently. The device I am testing this on is on 8.0.0.
Here is mys service:
public class LocationTrackerService extends Service {
private LocationListener locationListener;
private LocationManager locationManager;
private IBinder binder = new LocalBinder();
private boolean isTracking;
private ArrayList<Location> trackedWaypoints;
private String bestProvider;
private Timer timer;
private Distance distance;
@SuppressLint("MissingPermission")
@Override
public void onCreate() {
super.onCreate();
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
bestProvider = locationManager.getBestProvider(criteria, true);
isTracking = false;
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
Intent intent = new Intent("location_update");
intent.putExtra("latitude", location.getLatitude());
intent.putExtra("longitude", location.getLongitude());
sendBroadcast(intent);
if (isTracking) {
if (trackedWaypoints.size() > 1) {
distance.add(trackedWaypoints.get(trackedWaypoints.size() - 1).distanceTo(location));
}
trackedWaypoints.add(location);
}
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) { }
@Override
public void onProviderEnabled(String s) { }
@Override
public void onProviderDisabled(String s) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
};
locationManager.requestLocationUpdates(bestProvider, 0, 0, locationListener);
}
@Override
public void onDestroy() {
super.onDestroy();
if (locationManager != null) {
locationManager.removeUpdates(locationListener);
}
}
public void startTracking() {
trackedWaypoints = new ArrayList<Location>();
timer = new Timer();
distance = new Distance();
timer.start();
isTracking = true;
startInForeground();
}
private void startInForeground() {
Intent notificationIntent = new Intent(this, WorkoutActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification =
new Notification.Builder(this)
.setContentTitle("TEST")
.setContentText("HELLO")
.setSmallIcon(R.drawable.ic_directions_run_black_24dp)
.setContentIntent(pendingIntent)
.setTicker("TICKER")
.build();
startForeground(101, notification);
}
public void stopTracking() {
isTracking = false;
stopForeground(true);
}
public boolean isTracking() {
return isTracking;
}
public ArrayList<Location> getTrackedWaypoints() {
return trackedWaypoints;
}
public Timer getTime() {
timer.update();
return timer;
}
public Distance getDistance() {
return distance;
}
public int getSteps() {
return 0;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public class LocalBinder extends Binder {
public LocationTrackerService getLocationTrackerInstance() {
return LocationTrackerService.this;
}
}
}
The new context. startForegroundService() method starts a foreground service but with a implicit contract that service will call start foreground within 5 second of its creation. You can also call startService and startForegroundService for different OS version.
Inside the service, usually in onStartCommand() , you can request that your service run in the foreground. To do so, call startForeground() . This method takes two parameters: a positive integer that uniquely identifies the notification in the status bar and the Notification object itself.
A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn't interacting with the app.
Try to change your startInForeground() method with this code:
private void startInForeground() {
Intent notificationIntent = new Intent(this, WorkoutActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this,0,notificationIntent,0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.shsl_notification)
.setContentTitle("TEST")
.setContentText("HELLO")
.setTicker("TICKER")
.setContentIntent(pendingIntent);
Notification notification=builder.build();
if(Build.VERSION.SDK_INT>=26) {
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(NOTIFICATION_CHANNEL_DESC);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
startForeground(NOTIFICATION_ID, notification);
}
So, when your Android version is Oreo (or higher) notification channel will be created, otherwise not.
Before show notification you have to create notification channel:
private void createNotificationChannel() {
if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
NotificationChannel notificationChannel =
new NotificationChannel(PRIMARY_CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(notificationChannel);
}
}
and then change create notification builder
new Notification.Builder(context, PRIMARY_CHANNEL_ID)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With