SystemUI 悬浮通知

Posted 虫师魁拔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 属性。

以上是关于SystemUI 悬浮通知的主要内容,如果未能解决你的问题,请参考以下文章

Android定制透明悬浮StatusBar 多分辨率适配

Notifications通知到SystemUI(“Notifications 通知”拆解)

Android 10.0 原生SystemUI下拉通知栏UI背景设置为圆角背景的定制

系统方向学习8--Android 10.0 SystemUI 状态栏屏蔽弹出的 提醒式通知

系统方向学习8--Android 10.0 SystemUI 状态栏屏蔽弹出的 提醒式通知

系统方向学习8--Android 10.0 SystemUI 状态栏屏蔽弹出的 提醒式通知