Android 如何在安卓5(棒棒糖)中抑制锁屏上的通知,但让它进入通知区域?

Android 如何在安卓5(棒棒糖)中抑制锁屏上的通知,但让它进入通知区域?,android,notifications,android-notifications,android-5.0-lollipop,Android,Notifications,Android Notifications,Android 5.0 Lollipop,升级到安卓5.0棒棒糖后,它开始在锁屏上自动显示正在进行的通知 有时,用户不想看到所有的通知,所以他们会询问开发人员如何让通知进入状态区域,但将其隐藏在锁屏上 我发现的唯一方法是强制用户使用屏幕锁定(如手势或PIN)并通过编程来锁定。但并不是所有人都想使用屏幕锁 是否有任何标志(或标志组合)对通知说:在锁屏上不可见,但在通知区域可见?您可以将通知的优先级设置为。这将隐藏锁屏上的通知。它也会在状态栏中隐藏图标(不确定是否需要),但通知本身在通知区域中仍然可见。似乎是最干净的方法。根据文件: 可以将

升级到安卓5.0棒棒糖后,它开始在锁屏上自动显示正在进行的通知

有时,用户不想看到所有的通知,所以他们会询问开发人员如何让通知进入状态区域,但将其隐藏在锁屏上

我发现的唯一方法是强制用户使用屏幕锁定(如手势或PIN)并通过编程来锁定。但并不是所有人都想使用屏幕锁


是否有任何标志(或标志组合)对通知说:在锁屏上不可见,但在通知区域可见?

您可以将通知的优先级设置为。这将隐藏锁屏上的通知。它也会在状态栏中隐藏图标(不确定是否需要),但通知本身在通知区域中仍然可见。

似乎是最干净的方法。根据文件:

可以将通知设置为VISIBILITY_SECRET,这将抑制其图标和股票代码,直到用户绕过锁屏

根据来源(SystemUI AOSP项目中的NotificationData),VISIBILITY_SECRET是实现此目的的唯一方法:

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;
}
似乎要过滤掉的唯一其他类型的通知是存在摘要的组中的子通知。因此,除非您有多个摘要,并且有一个有效的理由,否则可见性\u SECRET是当前可以做到的最好的方法。

使用可见性和优先级 如中所述,当用户拥有安全的键盘防护装置(不仅仅是刷卡或没有键盘防护装置)并且已抑制敏感通知时,可以使用来抑制锁定屏幕上的通知

为了涵盖其余的情况,您可以通过编程方式将通知的优先级设置为每当键盘守卫打开时,从锁屏和状态栏隐藏通知 存在,然后在没有键盘保护时重置优先级

缺点
  • 使用安卓5模拟器,这似乎会导致通知在锁定屏幕上短暂出现,但随后消失
  • 当用户没有安全的锁屏(如仅刷卡)时,不再像Android O那样工作
例子
我已经为我的持续通知创建了一个“LockscreenIntentReceiver”,如下所示:


此代码基本上会在用户锁定手机时删除正在进行的通知(删除将非常短暂)。一旦用户解锁手机,正在进行的通知将在延迟时间(此处为800毫秒)后恢复。enableNotification()是一种方法,它将创建通知并调用startForeground()。目前已验证可在Android 7.1.1上运行


您只需记住相应地注册和注销接收器。

这听起来应该可以在隐私选项下进行配置。奇怪的设计决定,尽管我记得iPhone今年做了类似的事情。甚至在全局设置应用程序的通知设置中也没有。用户可以完全锁定特定应用的通知,但不能仅锁定锁定屏幕通知。希望将后者视为用户!不幸的是,这在现在是不可能的。安卓阻止这种情况似乎是一个奇怪的决定;一些应用程序(llama、SignalCheck、电池状态)在通知栏中非常有用,但不需要在锁屏上。已提交更改此行为的请求;如果你“星”它,也许谷歌会在未来调整这一点:你好托马斯,我正在寻找类似的功能,因为你问,所以你找到了实现它的方法?不,这不是我的本意。人们想在状态栏中看到通知,但不想在锁屏上看到。我已经找了好几天了。如果可以,我会给它+2。非常感谢。不幸的是,这在Android O Developer Preview 1中不再有效。问题是,如果用户没有启用PIN或锁定模式,则这不适用,并且它会隐藏通知区域中的图标。这并不能满足OP(或我的,或其他许多人)的需要。人们似乎在Android文档中缺少这一点,
setLockScreenVisibility()
:“只能由系统和通知ranker修改。”@JeffreyBlattman,你不能在频道上更改可见性,但你仍然可以在通知本身上更改它。我刚刚在安卓10上测试了它,确认它仍然有效。纠正我的错误。我也在通知上测试了它。
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));
    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());
        }
    }
}