18

After upgrade to Android 5.0 Lollipop it started showing automatically ongoing notification on lock screen.

Sometimes users don't want to see all of them so they are asking developers how to let notification in status area but hide them on lock screen.

Only way I found is to force users use screen lock (eg. Gesture or PIN) and programatically setVisibility() to VISIBILITY_SECRET. But not all them want to use screen lock.

Is there any flag (or combination of flags) saying to notification: don't be visible on Lock screen but be visible in notification area?

Tomáš Hubálek
  • 1,162
  • 1
  • 10
  • 28
  • This sounds like it should be configurable under privacy options. Weird design decision, though I recall iPhone doing something like this years ago – G_V Nov 20 '14 at 09:26
  • Nope. Not even in the notification settings of the global settings app. Users can lock out of notifications completely for specific apps but not out of lockscreen notifications only. Would like to see the latter as a user! – Wolfram Rittmeyer Nov 20 '14 at 22:21
  • This is not possible right now, unfortunately. It seems like a strange decision by Android to prevent this; some apps (llama, SignalCheck, Battery Status) are very useful in the notification bar, but do not need to be on the lockscreen. A request has been filed to change this behavior; if you 'star' it, perhaps Google will adjust this in the future: https://code.google.com/p/android/issues/detail?id=80061 – mike47 Mar 12 '15 at 17:54
  • Hello Tomas , I am looking for similar functionality as you asked , so have you found way to achieve it. ? – user2028 Apr 02 '16 at 04:13

4 Answers4

14

Use visibility and priority

As covered by this answer, you can use VISIBILITY_SECRET to suppress the notification on the lock screen when the user has a secure keyguard (not just swipe or no keyguard) and has sensitive notifications suppressed.

To cover the rest of the cases, you can programmatically hide the notification from the lock screen and status bar by setting the notification's priority to PRIORITY_MIN whenever the keyguard is present and then reset the priority whenever the keyguard is absent.

Disadvantages

  • Using an Android 5 emulator, this seems to result in the notification very briefly appearing on the lock screen but then disappearing.
  • No longer working as of Android O when the user doesn't have a secure lock screen (eg swipe only) since notification priorities are deprecated.

Example

final BroadcastReceiver notificationUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        NotificationManager notificationManager =
            (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

        NotificationCompat.Builder builder =
            new NotificationCompat.Builder(context, YOUR_NOTIFICATION_CHANNEL_ID)
                .setSmallIcon(R.drawable.your_icon)
                .setVisibility(NotificationCompat.VISIBILITY_SECRET);
        
        KeyguardManager keyguardManager =
            (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);

        if (keyguardManager.isKeyguardLocked())
            builder.setPriority(NotificationCompat.PRIORITY_MIN);
        
        notificationManager.notify(YOUR_NOTIFICATION_ID, builder.build());
    }
};

//For when the screen might have been locked
context.registerReceiver(notificationUpdateReceiver,
    new IntentFilter(Intent.ACTION_SCREEN_OFF));

//Just in case the screen didn't get a chance to finish turning off but still locked
context.registerReceiver(notificationUpdateReceiver,
    new IntentFilter(Intent.ACTION_SCREEN_ON));

//For when the user unlocks the device
context.registerReceiver(notificationUpdateReceiver,
    new IntentFilter(Intent.ACTION_USER_PRESENT));

//For when the user changes users
context.registerReceiver(notificationUpdateReceiver,
    new IntentFilter(Intent.ACTION_USER_BACKGROUND));
context.registerReceiver(notificationUpdateReceiver,
    new IntentFilter(Intent.ACTION_USER_FOREGROUND));
Community
  • 1
  • 1
Sam
  • 40,644
  • 36
  • 176
  • 219
  • Folks seems to be missing this in the Android docs for `setLockScreenVisibility()`: "Only modifiable by the system and notification ranker." – Jeffrey Blattman Jun 08 '20 at 20:04
  • @JeffreyBlattman, you can't change the visibility on the *channel*, but you can still change it on the *notification* itself. I just tested this on Android 10 and confirmed it still works. – Sam Jun 10 '20 at 08:59
  • Correct, my mistake. I tested it working on the notification also. – Jeffrey Blattman Jun 10 '20 at 19:07
7

Seems like VISIBILITY_SECRET does the cleanest approach. As per the documentation:

a notification can be made VISIBILITY_SECRET, which will suppress its icon and ticker until the user has bypassed the lockscreen.

Per the source (NotificationData in the SystemUI AOSP project), VISIBILITY_SECRET is the only way to do it:

boolean shouldFilterOut(StatusBarNotification sbn) {
    if (!(mEnvironment.isDeviceProvisioned() ||
            showNotificationEvenIfUnprovisioned(sbn))) {
        return true;
    }

    if (!mEnvironment.isNotificationForCurrentProfiles(sbn)) {
        return true;
    }

    if (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET &&
            mEnvironment.shouldHideSensitiveContents(sbn.getUserId())) {
        return true;
    }
    return false;
}

The only other type of notifications that appear to be filtered out are child notifications in a group where a summary is present. So unless you have multiple with a valid reason for a summary, VISIBILITY_SECRET is the best that can currently be done.

gprathour
  • 14,813
  • 5
  • 66
  • 90
Jim Vitek
  • 4,174
  • 3
  • 23
  • 32
  • 1
    The problem is this does not apply if a user does not have a PIN or lock pattern enabled, and it hides the icon in the notification area. This does not satisfy the OP's needs (or mine, or many others). – mike47 Mar 12 '15 at 17:57
4

You could set the notification's priority to PRIORITY_MIN. This should hide the notification on the lock screen. It also hides the icon from the statusbar (not sure if you want that), but the notification itself is still visible in the notification area.

Floern
  • 33,559
  • 24
  • 104
  • 119
0

I've created a 'LockscreenIntentReceiver' for my ongoing notification that looks like this:


    private class LockscreenIntentReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        try { 
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                Log.d(TAG, "LockscreenIntentReceiver: ACTION_SCREEN_OFF");
                disableNotification();
            } else if (action.equals(Intent.ACTION_USER_PRESENT)){
                Log.d(TAG, "LockscreenIntentReceiver: ACTION_USER_PRESENT");
                // NOTE: Swipe unlocks don't have an official Intent/API in android for detection yet,
                // and if we set ungoing control without a delay, it will get negated before it's created
                // when pressing the lock/unlock button too fast consequently.
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (NotificationService.this.isNotificationAllowed()) {
                            enableNotification((Context)NotificationService.this);
                        }
                    }
                }, 800);
            }
        } catch (Exception e) {
            Log.e(TAG, "LockscreenIntentReceiver exception: " + e.toString());
        }
    }
}

This code will basically remove the ongoing notification when the user locks the phone (removal will be visible very briefly). And once the user unlocks the phone, the ongoing notification will be restored after the delay time (800 ms here). enableNotification() is a method which will create the notification, and call startForeground(). Currently verified to work on Android 7.1.1 .

You only have to remember to register & unregister the receiver accordingly.

ItWillDo
  • 468
  • 4
  • 9