35

I would like to have an ongoing notification for my ForegroundService that requires as small place as possible. I like the "Android System - USB charging this device" style, but I cannot find any example how to achieve this. enter image description here

Can anyone point me in the right direction?

Update

The style is given to the notification if the channel is assigned the importance IMPORTANCE_MIN.

It looks like there is no way to use Androids built in style for notifications of IMPORTANCE_MIN to be used with a ForegroundService.

Here is the description of IMPORTANCE_MIN:

Min notification importance: only shows in the shade, below the fold. This should not be used with Service.startForeground since a foreground service is supposed to be something the user cares about so it does not make semantic sense to mark its notification as minimum importance. If you do this as of Android version Build.VERSION_CODES.O, the system will show a higher-priority notification about your app running in the background.

Community
  • 1
  • 1
Sobvan
  • 1,376
  • 1
  • 15
  • 24

4 Answers4

9

To display a compact single line notification like the charging notification, you have to create a Notification Channel with priority to IMPORTANCE_MIN.

@TargetApi(Build.VERSION_CODES.O)
private static void createFgServiceChannel(Context context) {
   NotificationChannel channel = new NotificationChannel("channel_id", "Channel Name", NotificationManager.IMPORTANCE_MIN);
   NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
   mNotificationManager.createNotificationChannel(channel);
}

And then create an ongoing notification like that:

public static Notification getServiceNotification(Context context) {
   NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, "channel_id");
   mBuilder.setContentTitle("One line text");
   mBuilder.setSmallIcon(R.drawable.ic_notification);
   mBuilder.setProgress(0, 0, true);
   mBuilder.setOngoing(true);
   return mBuilder.build();
}

NOTE

Please note that I've tested it with an IntentService instead of a Service, and it works. Also I've just checked setting a Thread.sleep() of 15 seconds and the notification is showing perfectly until the IntentService stops itself.

There are some images (sorry some texts are in Spanish, but I think the images are still useful):

Single line ongoing notification

And if you drag down and opens the notification, it's shown as follows:

Single line ongoing notification opened

EXTRA

If you notice that Android System shows a notification indicating all apps which are using battery (apps with ongoing services), you can downgrade the priority of this kind of notifications and it will appear as one line notifications like the charging notification.

Take a look at this:

Battery applications

Just long click on this notification, and select ALL CATEGORIES:

Chennel notification for battery applications

And set the importance to LOW:

enter image description here

Next time, this "battery consumption" notification will be shown as the charging notification.

Marc Estrada
  • 1,657
  • 10
  • 20
  • 1
    I think the trick should be the IMPORTANCE_MIN setting. Here is the description of it: "Min notification importance: only shows in the shade, below the fold. This should not be used with Service.startForeground since a foreground service is supposed to be something the user cares about so it does not make semantic sense to mark its notification as minimum importance. If you do this as of Android version `Build.VERSION_CODES.O`, the system will show a higher-priority notification about your app running in the background." This means, that it might not be possible for a ForegroundService – Sobvan Jun 13 '18 at 13:29
  • This is why I wrote the extra tip, to set LOW priority to the system notification for apps that consumes battery, but unfortunately this must be done by the user and it's mostly possible to do it programmatically. – Marc Estrada Jun 13 '18 at 13:38
  • In my case it's working because I did the trick and I'm using a very fast `IntentService`. Sorry if it's not the answer you expected. – Marc Estrada Jun 13 '18 at 13:39
  • I will give you the bounty, as this answer made me realise (and actually read the right docs), that it might not be possible for a foreground service. Sorry @CodeChimp, actually your answer was already pretty close, but Marc needs the reputation more :) – Sobvan Jun 13 '18 at 13:39
  • 1
    Wow, thank you @Szobi, surprised because it's my first bounty :) – Marc Estrada Jun 13 '18 at 13:45
3

You need to set the Notification priority to Min, the Notification Channel importance to Min, and disable showing the Notification Channel Badge.

Here's a sample of how I do it. I've included creating the full notification as well for reference

private static final int MYAPP_NOTIFICATION_ID= -793531;

NotificationManager notificationManager = (NotificationManager) context
        .getSystemService(Context.NOTIFICATION_SERVICE);

String CHANNEL_ID = "myapp_ongoing";
CharSequence name = context.getString(R.string.channel_name_ongoing);

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
    NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_MIN);
    channel.setShowBadge(false);

    notificationManager.createNotificationChannel(channel);
}

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
        context, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_stat_notification_add_reminder)
        .setContentTitle(context.getString(R.string.app_name))
        .setContentText(context.getString(R.string.create_new))
        .setOngoing(true).setWhen(0)
        .setChannelId(CHANNEL_ID)
        .setPriority(NotificationCompat.PRIORITY_MIN);

// Creates an intent for clicking on notification
Intent resultIntent = new Intent(context, MyActivity.class);
...

// The stack builder object will contain an artificial back stack
// for the
// started Activity.
// This ensures that navigating backward from the Activity leads out
// of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MyActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
        PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);

notificationManager.notify(MYAPP_NOTIFICATION_ID, mBuilder.build());
CodeChimp
  • 4,745
  • 6
  • 45
  • 61
  • Thanks for the answer @CodeChimp. I tried setting the priorities to low. On one hand, it did not work. The style of the notification did not change to the single line one. On the other hand, the documentation for Android Services explicitly states that you need to set the priority to least `PRIORITY_LOW` [https://developer.android.com/guide/components/services#Foreground]. As a result, my service got killed quite fast with priority set to PRIORITY_MIN – Sobvan Jun 04 '18 at 11:02
  • I am not using a foreground service with mine, it only triggers an activity upon click. Did the channel.setShowBadge(false); not help either? – CodeChimp Jun 04 '18 at 11:26
  • I have already been using `setShowBadge(false)` did not work either, unfortunately. I am still experimenting, but it is hard to believe that there is no example out there yet :) – Sobvan Jun 04 '18 at 11:41
  • 1
    I'm afraid that's the limit of my answer then. Leaving here in case someone doesn't need a foreground service notification but will be interested to see an answer. – CodeChimp Jun 04 '18 at 11:50
  • @Szobi are you using an `IntentService` or just a `Service`? I'm using a foreground `IntentService` and my one line silent notification works great. – Marc Estrada Jun 08 '18 at 22:30
  • @MarcEstrada, I am using a `Service`, I'll look into IntentService. Can you please post a screenshot about your Notification? – Sobvan Jun 13 '18 at 11:44
  • Yes, I'll post it as an answer because it's easier to read and display images. – Marc Estrada Jun 13 '18 at 12:14
2

To answer the original question:

There seems to be no built-in way on Android O to get a single line, ongoing notification for a ForegroundService. One could try adding a custom design, but as different phones have different designs for notification, that solution is hardly a good one.

There is hope, however :)

On Android P the notification in a NotificationChannel of IMPORTANCE_LOW with a priority of PRIORITY_LOW is compacted to a single line even for a ForegroundService. Yeah!!

Sobvan
  • 1,376
  • 1
  • 15
  • 24
  • 1
    PRIORITY_LOW is deprecated use {@link NotificationChannel#setImportance(int)} instead. – Mike Yang Oct 14 '19 at 08:02
  • I am also still not sure what makes android decide to display a notification in compact view. I guess that the rules are complex, and there is no easy way to signal your wish towards the Android system – Sobvan Jan 27 '21 at 13:03
0

I made the size of foreground service notification smaller by creating an empty custom view like this:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">


</LinearLayout>

and then creating the notification like this:

RemoteViews notifiactionCollapsed = new RemoteViews(getPackageName(),R.layout.notification_collapsed);
    Notification notification = new NotificationCompat.Builder(this,CHANNEL_ID)
            .setSmallIcon(R.drawable.eq_icon)
            .setCustomContentView(notifiactionCollapsed)
            .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
            .setShowWhen(false)
            .setContentIntent(pendingIntent)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setOngoing(true)
            .setVisibility(NotificationCompat.VISIBILITY_SECRET)
            .build();
    startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
            notification);

This helps in reducing the height of the notification but still I am not sure about how to hide the notification icon.

Jazib Khan
  • 408
  • 4
  • 13