Android12 (S) 去掉悬浮通知消息及通知创建流程分析

概述

根据产品需求,产品定位不需要通知栏,所以需要屏蔽掉通知栏,同时也必须把悬浮通知去掉。

问题分析

1.通知创建的流程

应用发送通知
->NotificationManager.notify()
–>NotificationManager.notifyAsUser()
—>NotificationManagerService.enqueueNotificationWithTag()
---->NotificationManagerService.enqueueNotificationInternal()
----->NotificationManagerService.EnqueueNotificationRunnable()
------>NotificationManagerService.PostNotificationRunnable()
------->NotificationManagerService.notifyPostedLocked()
-------->NotificationManagerService.notifyPosted()
--------->INotificationListener.onNotificationPosted()
---------->NotificationListenerService.onNotificationPosted()
----------->com.android.systemui.statusbar.phone.NotificationListenerWithPlugins
------------>com.android.systemui.statusbar.phone.NotificationListener.onNotificationPosted()
------------->com.android.systemui.statusbar.notification.NotificationEntryManager.onNotificationPosted()
-------------->com.android.systemui.statusbar.notification.NotificationEntryManager.addNotificationInternal()
-------------->com.android.systemui.statusbar.notification.collection.notifcollection.onEntryAdded()
--------------->com.android.systemui.statusbar.notification.interruption.HeadsUpController.onEntryAdded()
--------------->com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder.bindHeadsUpView()
--------------->com.android.systemui.statusbar.notification.row.BindRequester.requestRebind()
--------------->com.android.systemui.statusbar.notification.row.NotifBindPipeline.onBindRequested()
---------------->com.android.systemui.statusbar.notification.row.NotifBindPipeline.requestPipelineRun()
----------------->com.android.systemui.statusbar.notification.row.NotifBindPipeline.startPipeline()
------------------>com.android.systemui.statusbar.notification.row.RowContentBindStage.executeStage()
------------------->com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.bindContent()
-------------------->com.android.systemui.statusbar.notification.row.NotificationContentInflater.bindContent()
-------------------->com.android.systemui.statusbar.notification.row.NotificationContentInflater.AsyncInflationTask.doInBackground()
--------------------->com.android.systemui.statusbar.notification.row.NotificationContentInflater.createRemoteViews()

经过以上流程通知就创建成功了,在流程中我们发现系统对通知消息的view进行了分类,而我们正是需要去去掉悬浮消息这一类型的通知,
所以继续分析:

2.通知view的不同类型

path:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
     frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
     
     @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true,
            prefix = {"FLAG_CONTENT_VIEW_"},
            value = {
                    FLAG_CONTENT_VIEW_CONTRACTED,
                    FLAG_CONTENT_VIEW_EXPANDED,
                    FLAG_CONTENT_VIEW_HEADS_UP,
                    FLAG_CONTENT_VIEW_PUBLIC,
                    FLAG_CONTENT_VIEW_ALL})
    @interface InflationFlag {}
    /**
     * The default, contracted view.  Seen when the shade is pulled down and in the lock screen
     * if there is no worry about content sensitivity.
     * 默认通知消息类型,显示在下拉通知栏中的缩略通知消息
     */
    int FLAG_CONTENT_VIEW_CONTRACTED = 1;
    /**
     * The expanded view.  Seen when the user expands a notification.
     *显示在通知栏中被用户展开的通知消息
     */
    int FLAG_CONTENT_VIEW_EXPANDED = 1 << 1;
    /**
     * The heads up view.  Seen when a high priority notification peeks in from the top.
     *悬浮通知消息,高重要性的通知,在全屏状态下会在屏幕顶部悬浮出消息
     */
    int FLAG_CONTENT_VIEW_HEADS_UP = 1 << 2;
    /**
     * The public view.  This is a version of the contracted view that hides sensitive
     * information and is used on the lock screen if we determine that the notification's
     * content should be hidden.
     */
    int FLAG_CONTENT_VIEW_PUBLIC = 1 << 3;

    int FLAG_CONTENT_VIEW_ALL = (1 << 4) - 1;

从上面代码可以看出在创建通知消息时根据flag不同会创建不同类型的消息,悬浮通知是其中之一

3.HeadsUpView创建入口

当HeadsUpController中当监听到有新的Entry添加的时候就会去创建headsupView,代码如下:

//path:com.android.systemui.statusbar.notification.interruption.HeadsUpController
@SysUISingleton
public class HeadsUpController {
    
    
   ...
 private NotifCollectionListener mCollectionListener = new NotifCollectionListener() {
    
    
        @Override
        public void onEntryAdded(NotificationEntry entry) {
    
    
            if (mInterruptStateProvider.shouldHeadsUp(entry)) {
    
    
            	//此处开始创建headsUpView
                mHeadsUpViewBinder.bindHeadsUpView(
                        entry, HeadsUpController.this::showAlertingView);
            }
        }

        @Override
        public void onEntryUpdated(NotificationEntry entry) {
    
    
            updateHunState(entry);
        }

        @Override
        public void onEntryRemoved(NotificationEntry entry, int reason) {
    
    
            stopAlerting(entry);
        }

        @Override
        public void onEntryCleanUp(NotificationEntry entry) {
    
    
            mHeadsUpViewBinder.abortBindCallback(entry);
        }
    };

在此处我们发现是有判断条件,当shouldHeadsUp()为true时才会去创建消息通知,由此我们找到了屏蔽掉悬浮通知的方法,我们只需要将shouldHeadsUp默认为false即可。
继续看代码:

4.shouldHeadsUp方法的实现

shouldHeadsUp() 是由NotificationInterruptStateProviderImpl 实现的

//path:com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl
@SysUISingleton
public class NotificationInterruptStateProviderImpl implements NotificationInterruptStateProvider {
    
    


    @VisibleForTesting
    protected boolean mUseHeadsUp = false;

    @Inject
    public NotificationInterruptStateProviderImpl(
            ContentResolver contentResolver,
            PowerManager powerManager,
            IDreamManager dreamManager,
            AmbientDisplayConfiguration ambientDisplayConfiguration,
            NotificationFilter notificationFilter,
            BatteryController batteryController,
            StatusBarStateController statusBarStateController,
            HeadsUpManager headsUpManager,
            @Main Handler mainHandler) {
    
    
        mContentResolver = contentResolver;
        mPowerManager = powerManager;
        mDreamManager = dreamManager;
        mBatteryController = batteryController;
        mAmbientDisplayConfiguration = ambientDisplayConfiguration;
        mNotificationFilter = notificationFilter;
        mStatusBarStateController = statusBarStateController;
        mHeadsUpManager = headsUpManager;
        mHeadsUpObserver = new ContentObserver(mainHandler) {
    
    
            @Override
            public void onChange(boolean selfChange) {
    
    
                boolean wasUsing = mUseHeadsUp;
                //mUseHeadsUp赋值 由Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED决定
                mUseHeadsUp = ENABLE_HEADS_UP
                        && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
                        mContentResolver,
                        Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
                        Settings.Global.HEADS_UP_OFF);
                Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
                if (wasUsing != mUseHeadsUp) {
    
    
                    if (!mUseHeadsUp) {
    
    
                        Log.d(TAG, "dismissing any existing heads up notification on "
                                + "disable event");
                        mHeadsUpManager.releaseAllImmediately();
                    }
                }
            }
        };

        if (ENABLE_HEADS_UP) {
    
    
            mContentResolver.registerContentObserver(
                    Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED),
                    true,
                    mHeadsUpObserver);
            mContentResolver.registerContentObserver(
                    Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
                    mHeadsUpObserver);
        }
        mHeadsUpObserver.onChange(true); // set up
    }

...
	//判断是否使用悬浮通知的方法
     @Override
    public boolean shouldHeadsUp(NotificationEntry entry) {
    
    
        if (mStatusBarStateController.isDozing()) {
    
    
            return shouldHeadsUpWhenDozing(entry);
        } else {
    
    
            return shouldHeadsUpWhenAwake(entry);
        }
    }

    /**
     * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
     * incoming calls.
     * 由shouldHeadsUp调用判断是否使用悬浮通知
     */
    @Override
    public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
    
    
        return entry.getSbn().getNotification().fullScreenIntent != null
                && (!shouldHeadsUp(entry)
                || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
    }

    private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
    
    
        StatusBarNotification sbn = entry.getSbn();
		//mUseHeadsUp变量可以控制是否使用悬浮通知
        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;
        }

        boolean inShade = mStatusBarStateController.getState() == SHADE;
        if (entry.isBubble() && inShade) {
    
    
            if (DEBUG_HEADS_UP) {
    
    
                Log.d(TAG, "No heads up: in unlocked shade where notification is shown as a "
                        + "bubble: " + sbn.getKey());
            }
            return false;
        }

        if (entry.shouldSuppressPeek()) {
    
    
            if (DEBUG_HEADS_UP) {
    
    
                Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
            }
            return false;
        }

        if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) {
    
    
            if (DEBUG_HEADS_UP) {
    
    
                Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
            }
            return false;
        }

        boolean isDreaming = false;
        try {
    
    
            isDreaming = mDreamManager.isDreaming();
        } catch (RemoteException e) {
    
    
            Log.e(TAG, "Failed to query dream manager.", e);
        }
        boolean inUse = mPowerManager.isScreenOn() && !isDreaming;

        if (!inUse) {
    
    
            if (DEBUG_HEADS_UP) {
    
    
                Log.d(TAG, "No heads up: not in use: " + sbn.getKey());
            }
            return false;
        }

        for (int i = 0; i < mSuppressors.size(); i++) {
    
    
            if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
    
    
                if (DEBUG_HEADS_UP) {
    
    
                    Log.d(TAG, "No heads up: aborted by suppressor: "
                            + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
                }
                return false;
            }
        }
        return true;
    }

解决方案

由上分析可知 只需要把Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED默认置为OFF即可去掉悬浮通知栏
可以通过overlay设置

//path:device/xxx/xx/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml
+<resources>
+    <!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on -->
+    <integer name="def_heads_up_enabled">0</integer>
+</resources>

猜你喜欢

转载自blog.csdn.net/weixin_40774418/article/details/127090195