Foreground service notification always shown for at least 5 seconds
Asked Answered
H

2

6

I noticed some very strange behavior when testing foreground notifications on Android 9.

Situation: I have some foreground services where I don't know how long they'll need to run for, be it 1 second or a whole minute. Finally, when the service is done, it will call stopForeground(true). This used to work fine on all Android 8, 9 and 10 devices, where stopForeground(true), even if called immediately, always reliably removed the notification.

Problem: Testing on a Fairphone 3 (and I hope someone else encountered this on some other devices, because for me this is not happening on any emulator or other device), stopForeground is not working as expected. Instead of immediately removing the notification, the notification always shows for at least 5 seconds, even if I call stopForeground straight away. These 5 seconds happen to be the exact 5 second limit of the dreaded error Context.startForegroundService() did not then call Service.startForeground() - still a problem. Very peculiar! Reproducing this and checking whether your device is affected is very easy with the code below.

Inside AndroidManifest.xml:

<service
    android:name="<your package name>.TestService"
    android:exported="false" />

Class TestService.java:

package <your package name>;

import android.annotation.TargetApi;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

@TargetApi(Build.VERSION_CODES.O)
public class TestService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        showNotification();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        showNotification();
        stopForeground(true);
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void showNotification() {
        String channelId = "TEST";
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager.getNotificationChannel(channelId) == null)
            notificationManager.createNotificationChannel(new NotificationChannel(channelId, "TEST NOTIFICATIONS", NotificationManager.IMPORTANCE_DEFAULT));
        startForeground(1, new NotificationCompat.Builder(this, channelId).setContentText("TEST NOTIFICATION").build());
    }
}

Finally, simply start the service (for example on button click) via startForegroundService(new Intent(this, TestService.class));

Has anyone else experienced this issue or is able to reproduce it with the code above? How can I fix or even just debug it, considering I'm testing on Android 9 and the behaviour is different simply because of the OEM?

Hulbig answered 30/12, 2019 at 5:47 Comment(6)
try using IntentService or JobIntentService if possibleVoltmer
@AmitGoswami whether to use a Service or IntentService solely depends on one's use case and is not in the scope of this question, which aims to provide a Minimal, Reproducible Example. I tried switching the above snippet to IntentService and onHandleIntent but the effect was all the same.Hulbig
Hmm, so you're saying stopForeground() starts executing, and it blocks for ~5 seconds inside that function?Frontality
@Frontality actually when debugging it seemed not to block the execution, but the notification is removed only after those 5 seconds.Hulbig
So your issue could be restated simply as, "foreground notification always shows for at least 5 seconds on Fairphone 3". I can see why you would find this behavior curious or even objectionable, but at the same time I think the OEM is within their rights to do things this way. Discourages people from creating sneaky foreground services that "hide" in the background by only running for a few ms at a time. Have you considered using a regular old background service, instead, for those occasions when you know you won't have to execute for very long?Frontality
@Frontality correct. Yes, I considered background services. For the use case I originally provided (stopping a service immediately after starting it) you're right, it's easy to use background services instead. But they're still not an option in my case. Take a look at my updated answer where it should be clear why not.Hulbig
S
5

Latest security patch claims that it's normal behaviour: https://issuetracker.google.com/issues/147792378

However I'm not sure why it's happening already on Android 9.

Serb answered 22/1, 2020 at 9:28 Comment(2)
Balls! Thanks for finding that. I can imagine it's the case on Fairphone Android 9 specifically because they tend to be on the forefront when it comes to security patches, so they probably included the patch manually.Hulbig
Super confusing behaviour that's not mentioned anywhere in the documentation (or is it?)Windbreak
A
0

Try this when you start your service, I saw someone using it and it worked.

ContextCompat.startForegroundService(this, serviceIntent);

Here is the link: https://gist.github.com/codinginflow/1ab6d2689780be6d764215c3a40f2166

Arbitrage answered 23/5, 2023 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.