【问题标题】:How to suppress notification on lock screen in Android 5 (Lollipop) but let it in notification area?如何在 Android 5 (Lollipop) 中抑制锁定屏幕上的通知但让它在通知区域中?
【发布时间】:2014-11-20 08:47:20
【问题描述】:

升级到 Android 5.0 Lollipop 后,它开始在锁定屏幕上自动显示正在进行的通知。

有时用户不想看到所有这些,所以他们询问开发人员如何让通知显示在状态区域但将它们隐藏在锁定屏幕上。

我发现的唯一方法是强制用户使用屏幕锁定(例如手势或 PIN)并以编程方式将setVisibility() 转换为VISIBILITY_SECRET。但并非所有人都想使用屏幕锁定。

是否有任何标志(或标志组合)告诉通知:在锁定屏幕上不可见但在通知区域中可见?

【问题讨论】:

  • 这听起来应该可以在隐私选项下进行配置。奇怪的设计决定,虽然我记得 iPhone 几年前做过类似的事情
  • 不。甚至在全局设置应用程序的通知设置中也没有。用户可以完全锁定特定应用的通知,但不能仅锁定屏幕通知。希望看到后者作为用户!
  • 很遗憾,这现在是不可能的。 Android 阻止这种情况似乎是一个奇怪的决定;一些应用程序(llama、SignalCheck、Battery Status)在通知栏中非常有用,但不需要在锁屏上。已提交更改此行为的请求;如果你给它加星,也许谷歌将来会调整它:code.google.com/p/android/issues/detail?id=80061
  • 您好 Tomas,我正在寻找您所要求的类似功能,您是否找到了实现它的方法。 ?

标签: android notifications android-notifications android-5.0-lollipop


【解决方案1】:

使用可见性和优先级

this answer 所述,当用户有安全的键盘保护(不仅仅是滑动或没有键盘保护)并且敏感通知被禁止时,您可以使用VISIBILITY_SECRET 禁止锁定屏幕上的通知。

要涵盖其余情况,您可以通过将通知的优先级设置为PRIORITY_MIN 以编程方式从锁定屏幕和状态栏中隐藏通知 存在,然后在键盘保护不存在时重置优先级。

缺点

  • 使用 Android 5 模拟器,这似乎会导致通知非常短暂地出现在锁定屏幕上,然后消失。
  • notification priorities are deprecated 以来,当用户没有安全的锁定屏幕(例如,仅滑动)时,Android O 将不再工作。

示例

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));

【讨论】:

  • 人们似乎在 setLockScreenVisibility() 的 Android 文档中遗漏了这一点:“只能由系统和通知排名器修改。”
  • @JeffreyBlattman,您无法更改 channel 上的可见性,但您仍然可以在 notification 本身上更改它。我刚刚在 Android 10 上对此进行了测试,并确认它仍然有效。
  • 正确,我的错误。我也在通知上对其进行了测试。
【解决方案2】:

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

可以发出 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;
}

似乎被过滤掉的唯一其他类型的通知是存在摘要的组中的子通知。因此,除非您有多个有正当理由的摘要,否则 VISIBILITY_SECRET 是目前可以做到的最好的。

【讨论】:

  • 问题在于,如果用户没有启用 PIN 或锁定模式,这将不适用,并且它会隐藏通知区域中的图标。这不能满足 OP 的需求(或我的需求,或许多其他需求)。
【解决方案3】:

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

【讨论】:

  • 不,这不是我的本意。人们希望在状态栏中看到通知,而不是在锁定屏幕上。
  • 我几天来一直在寻找这个答案。如果可以的话,我会给它+2。谢谢!
  • 很遗憾,这在 Android O Developer Preview 1 中不再适用。
【解决方案4】:

我为正在进行的通知创建了一个“LockscreenIntentReceiver”,如下所示:


    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());
        }
    }
}

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多