109

I want to create a service and make it run in the foreground.

Most example codes have notifications on it. But I don't want to show any notification. Is that possible?

Can you give me some examples? Are there any alternatives?

My app service is doing mediaplayer. How to make system not kill my service except the app kill it itself (like pausing or stopping the music by button).

Jonathan Soifer
  • 2,715
  • 6
  • 27
  • 50
  • 13
    You can not have a "Foreground" service without a notification. Period. – Jug6ernaut Jun 09 '12 at 16:04
  • 1
    How about give a "fake" notification? that is a trick? – Muhammad Resna Rizki Pratama Jun 09 '12 at 16:19
  • Once the foreground notification is setup, you can remove "running in the background notifications" using the [Rubber app](https://play.google.com/store/apps/details?id=app.rubber.remove.is.running.in.the.background.notification). – Laurent Sep 12 '17 at 06:17
  • 1
    @MuhammadResnaRizkiPratama, would you consider changing the accepted answer? This question is extremely popular but the accepted answer is completely out-of-date, too heavy-handed, and makes assumptions why the developer needs this. I suggest [this answer](https://stackoverflow.com/a/41177817/238753) because it is reliable, doesn't exploit OS bugs, and works on most Android devices. – Sam Dec 31 '19 at 21:40

16 Answers16

106

As a security feature of the Android platform, you cannot, under any circumstance, have a foregrounded service without also having a notification. This is because a foregrounded service consumes a heavier amount of resources and is subject to different scheduling constraints (i.e., it doesn't get killed as quickly) than background services, and the user needs to know what's possibly eating their battery. So, don't do this.

However, it is possible to have a "fake" notification, i.e., you can make a transparent notification icon (iirc). This is extremely disingenuous to your users, and you have no reason to do it, other than killing their battery and thus creating malware.

Kristopher Micinski
  • 7,572
  • 3
  • 29
  • 34
  • 4
    Thanks. That makes me clear why setForeground needs the notification. – Muhammad Resna Rizki Pratama Jun 10 '12 at 05:54
  • 29
    Well it seems you do have a reason to do it, users have asked for it. Although it may be disingenuous as you say, it was requested for a product I am working on by the test groups. Maybe Android should have an option to hide notifications from some services you know are always running. Otherwise your notification bar will look like a Christmas tree. – Radu Jan 19 '13 at 14:28
  • 4
    @Radu actually you *shouldn't* have that many apps in the foreground: that will kill your battery life, because they are scheduled differently (essentially, they don't die). This might be acceptable for a mod, but I don't see that option making it into vanilla Android any time soon. "Users" usually don't know what's best for them.. – Kristopher Micinski Jan 19 '13 at 14:41
  • @KristopherMicinski I agree with that. Users don't know what's best for them. However, about the foreground tasks, award winning apps use them. Heavily. – Radu Jan 19 '13 at 16:07
  • 2
    @Radu that doesn't support your argument. "Award winning apps" are usually ones that actually "fix" Android's holes through system inconsistencies (like task killers). There's no reason that you should have to use a foreground service just because "award winning apps" do: if you do you're admitting to killing the user's battery. – Kristopher Micinski Jan 19 '13 at 17:01
  • 1
    It's worse I'm afraid. I mean I worked on those "award winning apps" and was shocked such behavior is approved. – Radu Jan 19 '13 at 20:39
  • Using a Foreground service that is not playing audio or doing something that the user is aware of, is bad practice and should be avoided. If the task is important enough, then there should be a way to know it's there. Notifications are the chosen Android way. I agree with Kristopher here. – Martin Marconcini Jun 04 '13 at 18:58
  • 2
    Apparently, this method will not work anymore starting in 4.3. https://plus.google.com/u/0/105051985738280261832/posts/MTinJWdNL8t – erbi Jul 29 '13 at 22:51
  • I just want to point out that the advice that `you cannot, under any circumstance, have a foregrounded service without also having a notification` is no longer correct as of Android 4.1 and higher. [Users now have the option of blocking apps' notifications, which can be used to hide foreground service notifications.](https://stackoverflow.com/a/41177817/238753) – Sam May 22 '17 at 20:28
  • @Sam that's something that *users* have the option to do: not the *app developer*. The principle is that this should never happen without user knowledge. If a user voluntarily chooses to disable this, they've (presumably) been at least informed of the risk. – Kristopher Micinski May 22 '17 at 22:20
  • @KristopherMicinski, that's right. If the app needs a foreground service but the user doesn't want the notification, the app or developer can direct the user to block the notification. – Sam May 22 '17 at 22:22
  • 1
    @Kristopher Micinski Battery usage depends what the service does. I have written my own to switch WiFi and Bluetooth on and off automatically under certain circumstances. Resource use is almost undetectable (and it saves battery compared to leaving an idle WiFi connection on on my phone). – nsandersen Jun 01 '19 at 09:55
83

Update: This was "fixed" on Android 7.1. https://code.google.com/p/android/issues/detail?id=213309

Since the 4.3 update, it's basically impossible to start a service with startForeground() without showing a notification.

You can, however, hide the icon using official APIs... no need for a transparent icon: (Use NotificationCompat to support older versions)

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(Notification.PRIORITY_MIN);

I've made peace with the fact the notification itself still needs to be there but for who ever who still wants to hide it, I may have found a workaround for that as well:

  1. Start a fake service with startForeground() with the notification and everything.
  2. Start the real service you want to run, also with startForeground() (same notification ID)
  3. Stop the first (fake) service (you can call stopSelf() and in onDestroy call stopForeground(true)).

Voilà! No notification at all and your second service keeps running.

Lior Iluz
  • 26,213
  • 16
  • 65
  • 114
  • 25
    Thanks for this. I think some people don't realize that there is Android development that goes on for internal business use (that is, it's not intended to ever appear on the market or be sold to Joe Blow). Sometimes people ask for things like "stop showing the service notification" and it's good to see work arounds even if it's not kosher for general consumption. – JamieB Aug 20 '13 at 15:48
  • 5
    @JamieB I couldn't agree more... I suggested to Dianne Hackborn they need to rethink the whole concept of background services and maybe add a permission to run a service in the background without the notifications. It's not like it matters to us the developers if there's a notification or not - it's the USER request to remove it! :) By the way, can you verify it works for you as well? – Lior Iluz Aug 20 '13 at 17:27
  • Actually I took user875707's route because that was easier -- built the notification with an ID of "0" (which the docs say you can't do...) and nothing showed up. I verified with dumpsys and the service has the foreground flag. If some problem crops up, your solution is next... or if we have to build it against latest 4.3 one day. I should probably note your method in the code, come to think of it... Posterity. – JamieB Aug 20 '13 at 18:26
  • 1
    @JamieB user875707 says to set the icon parameter(the resource id of the icon) to 0,not the id of notification(If so,as the docs says "startForeground" will not work). – wangqi060934 Aug 31 '13 at 14:54
  • 9
    You should, of course, assume this will not work in future versions of the platform. – hackbod Aug 14 '14 at 02:36
  • So I was doing the "0" icon fix for a while, which of course stopped working when we upgraded our phones to 4.4.2. I'm not seeing this method work, either, though. App calls Dummy Service, Dummy Service calls Real Service. At this point I have 2 notifications (they were both launched with the same ID in startForeground). App stops the Dummy Service who calls stopForeground(true). Real Service still has his notification up. I guess they plugged this hole? Got any others? :-p These phones are rooted but I hope to not do custom roms just for something like this. *shakes fist at google* – JamieB Nov 21 '14 at 00:05
  • 1
    @JamieB I actually tested this right now on Android 5.0.1 and it still works for me. – Lior Iluz Mar 02 '15 at 06:31
  • Tested and working in 4.0.2, 5.1.1 and M Preview 2. Thanks! – Sam Jul 13 '15 at 10:41
  • @JamieB, what model phone are you using? Are you using a non-zero notification id? – Sam Jul 13 '15 at 11:23
  • This method seems not working perfectly. There is always a notification `App is running, Touch for more information or to stop the...` showed. How to get rid of this? – alijandro Apr 27 '16 at 09:00
  • @alijandro, what device and Android version are you using? That didn't happen for me. – Sam May 26 '16 at 10:48
  • @Sam lollipop API 21, still didn't figure out how to solve it. – alijandro May 26 '16 at 11:10
  • @alijandro, and what was the model of the device that you ran the code on? – Sam May 27 '16 at 00:52
  • @Sam Tested on Samsung SM-A7009 with api 21, Nexus 4 with api 22, Nexus 5 with api 23, all have the same problem I described above. Is something wrong in my code? Could you show your implementation to me? – alijandro May 30 '16 at 08:00
  • @alijandro, the only explanations I can think of are: 1. You forgot to declare one of the services in your manifest and `startService` is silently failing, or 2. The devices you tested with all happen to have the bug fixed. – Sam Jun 01 '16 at 22:34
  • Here's my tested-and-working implementation of this: http://stackoverflow.com/a/37579862/238753 – Sam Jun 01 '16 at 22:34
  • @alijandro, see my above comment for my implementation. – Sam Jun 01 '16 at 22:35
  • @Sam Thanks for your sharing. Yes, the devices I tested all have this bug fixes. I tested on other devices, it worked. – alijandro Jun 02 '16 at 04:29
  • Looks like [hackbod](http://stackoverflow.com/users/236398/hackbod) finally [fixed this workaround in Android 7.1](https://github.com/android/platform_frameworks_base/commit/0ba4c710c6f8805175bde2dbd85d7d8788a15ee0) after CommonsWare [asked to get it fixed](https://code.google.com/p/android/issues/detail?id=213309), so it no longer works. – Sam Dec 03 '16 at 06:32
  • @Sam Thanks for the update.. we had a nice run while it lasted :) – Lior Iluz Dec 04 '16 at 11:19
  • Is there any example of creating a `VpnService` without any additional notification? I mean, `Android` already shows a notification while the service is running, and there should be no need for any additional notification, so, do you know of something? – Top-Master May 18 '19 at 05:05
  • why don't you do a favor for us and share a sample code =) – Hilal Jun 14 '19 at 01:55
23

This no longer works as of Android 7.1 and it may violate Google Play's developer policies.

Instead, have the user block the service notification.


Here's my implementation of the technique in the answer by Lior Iluz.

Code

ForegroundService.java

public class ForegroundService extends Service {

    static ForegroundService instance;

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

        instance = this;

        if (startService(new Intent(this, ForegroundEnablingService.class)) == null)
            throw new RuntimeException("Couldn't find " + ForegroundEnablingService.class.getSimpleName());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        instance = null;
    }

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

}

ForegroundEnablingService.java

public class ForegroundEnablingService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (ForegroundService.instance == null)
            throw new RuntimeException(ForegroundService.class.getSimpleName() + " not running");

        //Set both services to foreground using the same notification id, resulting in just one notification
        startForeground(ForegroundService.instance);
        startForeground(this);

        //Cancel this service's notification, resulting in zero notifications
        stopForeground(true);

        //Stop this service so we don't waste RAM.
        //Must only be called *after* doing the work or the notification won't be hidden.
        stopSelf();

        return START_NOT_STICKY;
    }

    private static final int NOTIFICATION_ID = 10;

    private static void startForeground(Service service) {
        Notification notification = new Notification.Builder(service).getNotification();
        service.startForeground(NOTIFICATION_ID, notification);
    }

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

}

AndroidManifest.xml

<service android:name=".ForegroundEnablingService" />
<service android:name=".ForegroundService" />

Compatibility

Tested and working on:

  • Official Emulator
    • 4.0.2
    • 4.1.2
    • 4.2.2
    • 4.3.1
    • 4.4.2
    • 5.0.2
    • 5.1.1
    • 6.0
    • 7.0
  • Sony Xperia M
    • 4.1.2
    • 4.3
  • Samsung Galaxy ?
    • 4.4.2
    • 5.X
  • Genymotion
    • 5.0
    • 6.0
  • CyanogenMod
    • 5.1.1

No longer working as of Android 7.1.

Sam
  • 40,644
  • 36
  • 176
  • 219
  • 2
    Haven't tested it yet, but it would be nice to have at least a permission for that!!! +1 for the "To Google" part, My users are complaining about the notification required to keep the app running in background, I also complain about the notification required for skype/llama and any other app out there – Rami Dabain Sep 09 '16 at 15:39
  • sorry how this example can be used to listen for alarms. Im developing an app that set alarms with alarmManager and the problem I have is that when I close app (Recent apps-> Clear) all alarms get removed as well and Im traing to find a way to prevent this – Ares91 Aug 10 '17 at 15:24
  • @Ares91, try making a separate StackOverflow question for that, and make sure to include as much info as possible, including the relevant code. I don't know much about alarms, and this question is just about services. – Sam Aug 10 '17 at 21:08
  • @Sam which service should be called first,ForegroundEnablingService or Forground – K Guru Nov 16 '17 at 11:22
  • @AndroidMan `ForegroundService` – Sam Nov 16 '17 at 11:23
  • @Sam which are the actual service , which will run in background – K Guru Nov 16 '17 at 11:27
16

Warning: although this answer appears to work, it in fact silently prevents your service from becoming a foreground service.

Original answer:


Just set your notification's ID to zero:

// field for notification ID
private static final int NOTIF_ID = 0;

    ...
    startForeground(NOTIF_ID, mBuilder.build());
    NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    mNotificationManager.cancel(NOTIF_ID);
    ...

A benefit you can get is, a Service will be able to runs on high priority without destroyed by Android system, unless on high memory pressure.

To make it work with Pre-Honeycomb and Android 4.4 and higher, make sure that you use NotificationCompat.Builder which provided by Support Library v7, instead of Notification.Builder.

EDIT

This code will not work anymore due to security reasons in newer api level

NotificationId cannot be set to "0" (which will cause the app to crash)

startForeground(1, notification)

This is the perfect way to show notification (recommended method)

But if you need it reagrdless of the recommended method then try removing the "notificationManager.createNotificationChannel("channel_id")" from your code.

OR USE notificationManager.removeNotificationChannel(channel)

user7418129
  • 1,074
  • 14
  • 18
Anggrayudi H
  • 14,977
  • 11
  • 54
  • 87
  • 1
    This works perfectly for me on 4.3(18) @vlad sol. Why no other upvotes yet for this answer I wonder? – Rob McFeely Aug 11 '15 at 16:05
  • 1
    I tried this in Android N Preview 4 and it didn't work. I tried `Notification.Builder`, Support Library v4 `NotificationCompat.Builder` and Support Library v7 `NotificationCompat.Builder`. The notification didn't appear in the notification drawer or status bar, but the service wasn't running in foreground mode when I checked it using `getRunningServices()` and `dumpsys`. – Sam Jun 30 '16 at 10:19
  • @Sam, So this bug doesn't appear on earlier version, correct? – Anggrayudi H Jun 30 '16 at 16:41
  • @AnggrayudiH, by "this bug", do you mean the notification not appearing? Or do you mean the service not going into foreground mode? – Sam Jul 01 '16 at 06:46
  • I just tested this on the official Android 4.0 and 4.4 emulators, and the notification didn't appear, but the service didn't actually go into foreground state. – Sam Jul 01 '16 at 06:46
  • Also, as far as I can tell, the `notificationManager.cancel()` method call in your provided code is just testing code and not part of the technique to hide the notification? In my tests, the notification didn't appear when 0 was passed into `startForeground`, and I don't think `cancel()` works on foreground notifications, so as far as I can tell, that code is redundant. – Sam Jul 01 '16 at 06:48
  • 1
    This does not work for me. The process is started as foreground when id!=0 is sent, but NOT started as foreground when id=0. Use `adb shell dumpsys activity services` to verify. – beetree Nov 12 '16 at 03:37
  • I just tested this all the way from Android 4.0.2 through 7.1, and it didn't work in a single Android version. The notification doesn't appear, **but the service is not in the foreground**. – Sam Dec 16 '16 at 04:42
  • @AnggrayudiH superb answer. This must be accepted answer. – Hiren Patel Dec 28 '19 at 15:39
15

You can use this (as suggested by @Kristopher Micinski):

Notification note = new Notification( 0, null, System.currentTimeMillis() );
note.flags |= Notification.FLAG_NO_CLEAR;
startForeground( 42, note );

UPDATE:

Please note that this is not allowed anymore with Android KitKat+ releases. And keep in mind that this is more or less violating the design principle in Android that makes background operations visible to users as mentioned by @Kristopher Micinski

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • 2
    Note that this doesn't seem to be accepted anymore with SDK 17. The service won't go to foreground if the drawable passed to the notification is 0. – Snicolas Mar 11 '13 at 08:07
  • It was a bug and hopefully got fixed. The idea of Foreground services is that they are less prone to be killed, and this is a way to ensure the user is aware of its existence. – Martin Marconcini Jun 04 '13 at 18:56
  • 4
    With Android 18 the notification isn't invisible any more but shows saying "App is running, Touch for more information or to stop the app" – Emanuel Moecklin Jul 29 '13 at 21:00
  • 1
    Screenshot from one of my customers: http://1gravity.com/k10/Screenshot_2013-07-25-12-35-49.jpg. I have a 4.3 device too and can confirm that finding. – Emanuel Moecklin Jul 30 '13 at 15:52
  • @EmanuelMoecklin thanks. I like that new feature, it's really clean. – Snicolas Jul 31 '13 at 06:17
  • 2
    Warning: I am receiving crash reports from Sony Ericsson LT26i (Xperia S) with Android 4.1.2 (SDK 16): android.app.RemoteServiceException: Bad notification posted from package ...: Couldn't create icon: StatusBarIcon(pkg=... id=0x7f020052 level=0 visible=true num=0 ) I have set icon id to 0 until SDK 17, too. From SDK 18 I have set it to a valid drawable resource. Maybe, you need a valid icon id from SDK 16! – almisoft Sep 20 '13 at 11:02
  • I've confirmed that this was fixed in Android 4.3 (API 18) as pointed out earlier by @EmanuelMoecklin. – Sam Dec 16 '16 at 04:44
12

You can hide notification on Android 9+ by using custom layout with layout_height = "0dp"

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.custom_notif);
builder.setContent(remoteViews);
builder.setPriority(NotificationCompat.PRIORITY_LOW);
builder.setVisibility(Notification.VISIBILITY_SECRET);

custom_notif.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="0dp">
</LinearLayout>

Tested on Pixel 1, android 9. This solution doesn't work on Android 8 or less

phnmnn
  • 12,813
  • 11
  • 47
  • 64
8

Update: this no longer works in Android 4.3 and above


There is one workaround. Try creating notification without setting icon, and the notification would not show. Don't know how it works, but it does :)

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle("Title")
            .setTicker("Title")
            .setContentText("App running")
            //.setSmallIcon(R.drawable.picture)
            .build();
    startForeground(101,  notification);
Sam
  • 40,644
  • 36
  • 176
  • 219
Vladimir Petrovski
  • 1,966
  • 21
  • 25
  • 3
    In Android N Preview 4, this doesn't work. Android shows a `(YourServiceName) is running` notification instead of your own when you don't specify an icon. According to CommonsWare, this has been the case since Android 4.3: https://commonsware.com/blog/2013/07/30/notifications-foreground-services-android-4p3.html – Sam Jun 30 '16 at 10:24
  • 1
    I did some testing today and confirmed that this does not work in Android 4.3 and above. – Sam Dec 16 '16 at 04:47
8

Block the foreground service notification

Most answers here either don't work, break the foreground service, or violate Google Play policies.

The only way to reliably and safely hide the notification is to have the user block it.

Android 4.1 - 7.1

The only way is to block all notifications from your app:

  1. Send user to app's details screen:

    Uri uri = Uri.fromParts("package", getPackageName(), null);
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri);
    startActivity(intent);
    
  2. Have user block app's notifications

Note this also blocks your app's toasts.

Android 8.0 - 8.1

It's not worth blocking the notification on Android O because the OS will just replace it with a "running in the background" or "using battery" notification.

Android 9+

Use a Notification Channel to block the service notification without affecting your other notifications.

  1. Assign service notification to notification channel
  2. Send user to notification channel's settings

    Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
        .putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName())
        .putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId());
    startActivity(intent);
    
  3. Have user block channel's notifications

Sam
  • 40,644
  • 36
  • 176
  • 219
6

Update: this no longer works in Android 4.3 and above


I set the icon parameter to the constructor for Notification to zero, and then passed the resulting notification to startForeground(). No errors in the log and no notification shows up. I don't know, though, whether the service was successfully foregrounded--is there any way to check?

Edited: Checked with dumpsys, and indeed the service is foregrounded on my 2.3 system. Haven't checked with other OS versions yet.

Sam
  • 40,644
  • 36
  • 176
  • 219
Alexander Pruss
  • 365
  • 3
  • 10
  • 9
    Use the command "adb shell dumpsys activity services" to check if "isForeground" is set to true. – black Jun 27 '12 at 19:40
  • 1
    Or just call the empty `Notification()` constructor. – johsin18 Jul 24 '12 at 10:12
  • This worked for me. First time I got my service to run overnight so it's definitely in the foreground (plus dumpsys says it is) and no notification. – JamieB Aug 21 '13 at 19:42
  • Note that this no longer works in Android 4.3 (API 18). The OS puts a placeholder notification in the notification drawer. – Sam Dec 16 '16 at 04:46
4

version 4.3(18) and above hiding service notification is not possible , but you could disable the icon , version 4.3(18) and below is possible to hide the notification

Notification noti = new Notification();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
    noti.priority = Notification.PRIORITY_MIN;
}
startForeground(R.string.app_name, noti);
vlad sol
  • 99
  • 1
  • 5
  • While this answer is probably correct and useful, it is preferred if you include some explanation along with it to explain how it helps to solve the problem. This becomes especially useful in the future, if there is a change (possibly unrelated) that causes it to stop working and users need to understand how it once worked. – Kevin Brown-Silva Mar 10 '15 at 00:42
  • I think Android 4.3 is actually API 18. Also, this method only hides the icon from the status bar; the icon still exists in the notification. – Sam Jul 13 '15 at 11:16
  • for hiding icon from the notification you could add empty image mBuilder.setSmallIcon(R.drawable.blank); – vlad sol Aug 03 '15 at 20:22
  • 1
    i'm looking at the kitkat source, and the zero ID method does not seem like it can work. if the ID is zero, the service record is updated to NOT foreground. – Jeffrey Blattman Oct 05 '15 at 17:34
3

I've found on Android 8.0 it's still possible by not using a notification channel.

public class BootCompletedIntentReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

                Intent notificationIntent = new Intent(context, BluetoothService.class);    
                context.startForegroundService(notificationIntent);

            } else {
                //...
            }

        }
    }
}

And in BluetoothService.class:

 @Override
    public void onCreate(){    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            Intent notificationIntent = new Intent(this, BluetoothService.class);

            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

            Notification notification = new Notification.Builder(this)
                    .setContentTitle("Title")
                    .setContentText("App is running")
                    .setSmallIcon(R.drawable.notif)
                    .setContentIntent(pendingIntent)
                    .setTicker("Title")
                    .setPriority(Notification.PRIORITY_DEFAULT)
                    .build();

            startForeground(15, notification);

        }

    }

A persistent notification is not shown, however you will see the Android 'x apps are running in the background' notification.

Pete
  • 597
  • 1
  • 8
  • 27
  • 1
    In Android 8.1: "Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification" – T-igra Jul 08 '18 at 22:27
  • Personally, I think the `apps are running in the background` notification is even worse than an app-specific notification, so I'm not sure this approach is worth it. – Sam Feb 17 '19 at 09:50
2

Even though it's not the direct question, many of you searching for this can easily solve your challenges of creating a persistent, long running task by using a WorkManager

As of 2022 it's Google's recommended API for running background tasks of all types (One-time, Periodic, Expedited, Foreground, etc).

Cody
  • 1,801
  • 3
  • 28
  • 53
1

Its a quite troublesome for developer's sometime client did not want permanent notification for foreground service. I have created a Fake notification to start the service after that I cancel that by notificationManager.cancel(1);

  final String NOTIFICATION_CHANNEL_ID = "com.exmaple.project";
    final String channelName = "Notification";
   @RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onCreate() {
    super.onCreate();
    stopForeground(true);
    Intent stopSelf = new Intent(this, Notification_Service.class);
    stopSelf.setAction("ACTION_STOP_SERVICE");
    PendingIntent pStopSelf = PendingIntent
            .getService(this, 0, stopSelf
                    , PendingIntent.FLAG_CANCEL_CURRENT);
    Notification notification;
    NotificationCompat.Action action =
            new NotificationCompat.Action.Builder(
                    0, "Close", pStopSelf
            ).build();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel serviceChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "Notification One", NotificationManager.IMPORTANCE_DEFAULT);
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(serviceChannel);
        notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentText("Welcome to App.")
                .setPriority(Notification.PRIORITY_MIN)
                .addAction(action)
                .build();
    } else {
        notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setContentTitle("App")
                .setContentText("Welcome to App.")
                .setPriority(Notification.PRIORITY_MIN)
                .addAction(action)
                .build();
    }
    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE);
    notificationManager.notify(1, notification);
    startForeground(1, notification);
    notificationManager.cancel(1);
}

Sometime the permanent notification does not remove by notificationManager.cancel(1); for that I have add fake close action button.

Action button result:

 @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            super.onStartCommand(intent, flags, startId);
            if ("ACTION_STOP_SERVICE".equals(intent.getAction())) {
                stopSelf();
            }
     
            return START_STICKY;
        }

Start Service:

 if (!isMyServiceRunning()) {
       Intent serviceIntent = new Intent(this, Notification_Service.class);
                ContextCompat.startForegroundService(this, serviceIntent);
            }

Check if the service is already running.

private boolean isMyServiceRunning() {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (Notification_Service.class.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }
ahmad bajwa
  • 966
  • 2
  • 10
  • 30
0

The most suitable solution is to work with Notification Channel.

All you need to do is removing notificationManager.createNotificationChannel(channel) from your class.

val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val channel = NotificationChannel(
            notificationChannelId,
            "Endless Service notifications channel",
            NotificationManager.IMPORTANCE_HIGH
        ).let {
            it.description = "Endless Service channel"
            it.enableLights(true)
            it.lightColor = Color.RED
            it.enableVibration(true)
            it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
            it
        }
        notificationManager.createNotificationChannel(channel)

OR

by simply using notificationManager.deleteNotificationChannel("channel_id")

Although, removing a notification that used by a Foreground service is not recommended.

user7418129
  • 1,074
  • 14
  • 18
-1

Update: this no longer works in Android 7.1 and above


Here is a way to make your app 's oom_adj to 1 (Tested in ANDROID 6.0 SDK emulator). Add a temporary service, In your main service call startForgroundService(NOTIFICATION_ID, notificion). And then start the temporary service call startForgroundService(NOTIFICATION_ID, notificion) with same notification id again, after a while in the temporary service call stopForgroundService(true) to dismiss the onging ontification.

Sam
  • 40,644
  • 36
  • 176
  • 219
Tshunglee
  • 337
  • 2
  • 11
  • This is the only working solution that I'm aware of. However, it is already covered by [another answer](http://stackoverflow.com/a/18281520/238753). – Sam Jun 01 '16 at 21:27
-2

You can also declare your application as persistent.

<application
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:theme="@style/Theme"
    *android:persistent="true"* >
</application>

This essentially sets your app at a higher memory priority, decreasing the probability of it being killed.

Denizen
  • 335
  • 5
  • 17
  • 5
    This is wrong, only system apps can be persistent : https://groups.google.com/forum/?fromgroups=#!topic/android-developers/2E10ZSnaK2Q – Snicolas Oct 12 '12 at 01:55