SystemUI 悬浮通知

通知概览https://developer.android.google.cn/guide/topics/ui/notifiers/notifications

一、悬浮通知创建

简单通知创建代码

    public void showAlarmNotification() {
        //IMPORTANCE_HIGH 重要通知,弹出悬浮通知
        NotificationChannel channel = new NotificationChannel("123", "测试 channel_name", NotificationManager.IMPORTANCE_HIGH);
        //led灯
        channel.enableLights(true);
        //锁屏显示通知
        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
        //led灯颜色
        channel.setLightColor(Color.BLUE);

        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notificationManager.createNotificationChannel(channel);

        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.baidu.com"));
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

        // Get the layouts to use in the custom notification
        RemoteViews notificationLayout = new RemoteViews(getPackageName(), R.layout.notification_layout);
        notificationLayout.setTextViewText(R.id.text, "contentView");

        RemoteViews notificationLayoutExpanded = new RemoteViews(getPackageName(), R.layout.notification_layout_big);
        notificationLayoutExpanded.setTextViewText(R.id.text, "bigContentView");

        // Apply the layouts to the notification
        Notification customNotification = new NotificationCompat.Builder(this, "123")
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setContentTitle("imageTitle")
                .setContentText("imageDescription")
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_android_black_24dp))
                .setStyle(new NotificationCompat.BigPictureStyle()
                        .bigPicture(BitmapFactory.decodeResource(getResources(),R.drawable.ic_android_black_24dp))
                        .bigLargeIcon(null))
                .setFullScreenIntent(pendingIntent, false)
                .build();

        notificationManager.notify(0, customNotification);
    }

悬浮通知,就是在创建 NotificationChannel 时指定等级为 IMPORTANCE_HIGH 。系统对通知定义等级六级:

// 效果等于无通知
public static final int IMPORTANCE_NONE = 0;

// 通知被折叠起来,不在状态栏显示
public static final int IMPORTANCE_MIN = 1;

// 在状态栏显示,但是没有提示音等
public static final int IMPORTANCE_LOW = 2;

// 在状态栏显示,有提示音等,但没有弹出悬浮框
public static final int IMPORTANCE_DEFAULT = 3;

// 在状态栏显示,有提示音等,有弹出悬浮框
public static final int IMPORTANCE_HIGH = 4;

// 效果等同于 IMPORTANCE_HIGH
public static final int IMPORTANCE_MAX = 5;

二、悬浮通知上滑后再次创建不弹出问题

调试时候会遇到,点击APP希望弹出悬浮通知时,没有弹出场景。这个可能是在之前一分钟内,有过弹出悬浮通知,且被我们自己上滑取消。如此,接下来一分钟内,不再弹出通知。

这是系统的默认设计,系统在用户手动上滑时,会认为用户此时有其他活动,弹出的通知栏可能干扰了用户,所以用户上滑隐藏通知,故短时间内可能我们不应该再弹出相同通道的通知。

这部分控制在 NotificationInterruptStateProviderImpl.java

    public boolean shouldHeadsUp(NotificationEntry entry) {
        if (mStatusBarStateController.isDozing()) {
            return shouldHeadsUpWhenDozing(entry);
        } else {
            return shouldHeadsUpWhenAwake(entry);
        }
    }

... ... 

    private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
        StatusBarNotification sbn = entry.getSbn();

        // 与 Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED 值相关
        if (!mUseHeadsUp) {
            if (DEBUG_HEADS_UP) {
                Log.d(TAG, "No heads up: no huns");
            }
            return false;
        }

        if (!canAlertCommon(entry)) {
            return false;
        }

        if (!canAlertAwakeCommon(entry)) {
            return false;
        }

        if (isSnoozedPackage(sbn)) {
            if (DEBUG_HEADS_UP) {
                Log.d(TAG, "No alerting: snoozed package: " + sbn.getKey());
            }
            return false;
        }

... ...

    private boolean isSnoozedPackage(StatusBarNotification sbn) {
        return mHeadsUpManager.isSnoozed(sbn.getPackageName());
    }
shouldHeadsUp

此函数判断是否有悬浮通知,正常状态下执行。

shouldHeadsUpWhenAwake

在这里对即将执行的应用通知的各种状态进行检查。上滑后,会触发通知进入 Snooze 状态,会被return false ,判断不可弹出悬浮框。判断条件如下:

isSnoozedPackage(sbn) -> mHeadsUpManager.isSnoozed(sbn.getPackageName())

mHeadsUpManager 对象类 HeadsUpManager.java 主要用于管理悬浮通知状态的,管理

    /**
     * 判断通知是否处于 Snoozes 状态
     */
    public boolean isSnoozed(@NonNull String packageName) {
        final String key = snoozeKey(packageName, mUser);
        Long snoozedUntil = mSnoozedPackages.get(key);
        if (snoozedUntil != null) {
            if (snoozedUntil > mClock.currentTimeMillis()) {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, key + " snoozed");
                }
                return true;
            }
            mSnoozedPackages.remove(packageName);
        }
        return false;
    }

    /**
     * 增加 Snoozes 状态通知
     */
    public void snooze() {
        for (String key : mAlertEntries.keySet()) {
            AlertEntry entry = getHeadsUpEntry(key);
            String packageName = entry.mEntry.getSbn().getPackageName();
            mSnoozedPackages.put(snoozeKey(packageName, mUser),
                    mClock.currentTimeMillis() + mSnoozeLengthMs);
        }
    }

 通知上滑会执行 snooze() ,将当前通知包名添加到 mSnoozedPackages 中。后续该包名通知发出时,isSnoozed 中检查 mSnoozedPackages 是否存在此发出通知应用的包名。存在时,判断 snoozedUntil 是否已经到达当前时间。

snoozedUntil == mClock.currentTimeMillis() + mSnoozeLengthMs

mSnoozeLengthMs 默认是1分钟,所以一般设备上,通知上滑1分钟后,才有悬浮通知效果。

int defaultSnoozeLengthMs =
        resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
mSnoozeLengthMs = Settings.Global.getInt(context.getContentResolver(),
        SETTING_HEADS_UP_SNOOZE_LENGTH_MS, defaultSnoozeLengthMs);

修改 mSnoozeLengthMs 默认值,只要修改 heads_up_default_snooze_length_ms 即可,或者动态修改,修改 SETTING_HEADS_UP_SNOOZE_LENGTH_MS 属性。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值