棒棒糖通知的setVisibility()方法无效?

21

我正在尝试编写一个演示如何使用setVisibility()来控制Android 5.0锁屏上的Notification显示内容的示例。然而,似乎没有任何效果:

  • 默认的VISIBILITY_PRIVATE仍然显示私有Notification,而不是其公共对应项

  • VISIBILITY_SECRET通知仍会出现在锁屏上

换句话说,至少在我使用一个运行着Android 5.0镜像的Nexus 7测试时,一切都表现得好像VISIBILITY_PUBLIC被强制执行一样。因此,我不知道问题是与我的代码、这个设备还是与Android中的错误相关。

我有两个版本的相同示例应用:

  • 一个使用NotificationCompatNotificationManagerCompat

  • 另一个使用NotificationNotificationManager,其中minSdkVersion为21,targetSdkVersion为21

(请注意,这些项目主要用于在Android Studio中使用;Eclipse用户可以导入这些项目,但可能需要进行一些微小的修复,特别是针对第一个示例中support-v13库的引用)

示例使用AlarmManager来触发Notification工作,主要是因为您有机会返回锁屏界面查看结果。以下是由AlarmManager触发的BroadcastReceiver(显示了NotificationCompat版本):

/***
 Copyright (c) 2014 CommonsWare, LLC
 Licensed under the Apache License, Version 2.0 (the "License"); you may not
 use this file except in compliance with the License. You may obtain a copy
 of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.

 From _The Busy Coder's Guide to Android Development_
 http://commonsware.com/Android
 */

package com.commonsware.android.lollipopnotify;

import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;

public class AlarmReceiver extends BroadcastReceiver {
  private static final int NOTIFY_ID=1337;
  static final String EXTRA_TYPE="type";

  @Override
  public void onReceive(Context ctxt, Intent i) {
    NotificationManagerCompat mgr=NotificationManagerCompat.from(ctxt);

    switch (i.getIntExtra(EXTRA_TYPE, -1)) {
      case 0:
        notifyPrivate(ctxt, mgr);
        break;

      case 1:
        notifyPublic(ctxt, mgr);
        break;

      case 2:
        notifySecret(ctxt, mgr);
        break;

      case 3:
        notifyHeadsUp(ctxt, mgr);
        break;
    }
  }

  private void notifyPrivate(Context ctxt, NotificationManagerCompat mgr) {
    Notification pub=buildPublic(ctxt).build();

    mgr.notify(NOTIFY_ID, buildNormal(ctxt).setPublicVersion(pub).build());
  }

  private void notifyPublic(Context ctxt, NotificationManagerCompat mgr) {
    mgr.notify(NOTIFY_ID,
        buildNormal(ctxt)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .build());
  }

  private void notifySecret(Context ctxt, NotificationManagerCompat mgr) {
    mgr.notify(NOTIFY_ID,
        buildNormal(ctxt)
            .setVisibility(NotificationCompat.VISIBILITY_SECRET)
            .build());
  }

  private void notifyHeadsUp(Context ctxt, NotificationManagerCompat mgr) {
    mgr.notify(NOTIFY_ID,
        buildNormal(ctxt)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build());
  }

  private NotificationCompat.Builder buildNormal(Context ctxt) {
    NotificationCompat.Builder b=new NotificationCompat.Builder(ctxt);

    b.setAutoCancel(true)
        .setDefaults(Notification.DEFAULT_ALL)
        .setContentTitle(ctxt.getString(R.string.download_complete))
        .setContentText(ctxt.getString(R.string.fun))
        .setContentIntent(buildPendingIntent(ctxt, Settings.ACTION_SECURITY_SETTINGS))
        .setSmallIcon(android.R.drawable.stat_sys_download_done)
        .setTicker(ctxt.getString(R.string.download_complete))
        .addAction(android.R.drawable.ic_media_play,
            ctxt.getString(R.string.play),
            buildPendingIntent(ctxt, Settings.ACTION_SETTINGS));

    return(b);
  }

  private NotificationCompat.Builder buildPublic(Context ctxt) {
    NotificationCompat.Builder b=new NotificationCompat.Builder(ctxt);

    b.setAutoCancel(true)
        .setDefaults(Notification.DEFAULT_ALL)
        .setContentTitle(ctxt.getString(R.string.public_title))
        .setContentText(ctxt.getString(R.string.public_text))
        .setContentIntent(buildPendingIntent(ctxt, Settings.ACTION_SECURITY_SETTINGS))
        .setSmallIcon(android.R.drawable.stat_sys_download_done)
        .addAction(android.R.drawable.ic_media_play,
            ctxt.getString(R.string.play),
            buildPendingIntent(ctxt, Settings.ACTION_SETTINGS));

    return(b);
  }

  private PendingIntent buildPendingIntent(Context ctxt, String action) {
    Intent i=new Intent(action);

    return(PendingIntent.getActivity(ctxt, 0, i, 0));
  }
}

EXTRA_TYPE 的值是从活动中的 Spinner 中设置的。该逻辑似乎没问题,因为悬浮通知场景可以正常工作。并且如果我通过代码进行步进(例如,在 onReceive() 中设置断点),我可以看到它沿着正确的路径(例如,在我选择发送机密 Notification 时,在 notifySecret() 中调用 setVisibility(NotificationCompat.VISIBILITY_SECRET))。

因此,我有点不知道为什么在 Android 5.0 锁屏界面上没有得到可见性效果。

有什么建议吗?

3个回答

10
您所描述的行为与我设置锁屏通知偏好为“显示所有通知内容”时遇到的行为一致。
此设置有三个选项:
- “显示所有通知内容”使所有通知(无论可见性如何)实际上都是公开的。 - “隐藏敏感通知内容”尊重新的可见性类型。 - “根本不显示通知”将使所有通知实际上都是秘密的。
更改锁屏通知可见性的选项在设备设置中的声音和通知下,“当设备被锁定”下,如下所示。
正如Selvin在他的答案中指出,仅当您设置了某种设备锁(例如PIN码或图案锁)时,才可以选择隐藏敏感内容。如果您可以轻松地滑动锁屏即可解锁设备,则无法使用此选项。


虽然我没有“隐藏敏感通知内容”这个选项,但这很有趣。当我点击“设备锁定时”偏好设置时,我只有“显示所有通知内容”和“根本不显示通知”这两个选择。 - CommonsWare
正如Selvin的回答所述,“隐藏敏感通知内容”只会在您设置了PIN码、密码或图案锁时出现。 - CommonsWare
嘿嘿,我只是想知道文档/手册中是否有说明 :) - Selvin
啊,有趣。肯定感觉应该有更好的文档记录,但这确实有道理。当你几乎没有解锁设备的障碍时,私人通知并不会非常有效地隐藏内容。 - Bryan Herbst
是的,我进行了实验,当“隐藏敏感通知内容”遵守新的可见性类型时,可见性将产生影响。http://android.stackexchange.com/questions/88303/i-dont-see-the-app-notification-sensitive-option - NitZRobotKoder
有没有办法获取该设置的值?我正在构建一个锁屏界面,希望通知能够遵循该设置。 - Mario Lenci

0

设置 NotificationBuilder#setPriority(Notification.PRIORITY_MIN); 还能防止通知出现在锁屏界面上。

虽然令人惊讶,但至少有很好的文档说明。


1
不,据我所知,您仍然可以在锁定屏幕上向下滑动并查看所有PRIORITY_MIN通知。 - EyesClear

-3
除了Tanis.7x的回答之外:您必须选择除了滑动之外的任何锁屏保护,才能在“声音和通知”下出现“隐藏敏感通知内容”的选项。

如果您有PIN码或密码,才会出现“隐藏敏感通知内容”选项。但是,如果只是滑动解锁,则用户可以选择在锁屏界面上显示“全部”或“无”,但不包括“隐藏敏感”的中间选项。 - CommonsWare

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接