概述
根据产品需求,产品定位不需要通知栏,所以需要屏蔽掉通知栏,同时也必须把悬浮通知去掉。
问题分析
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>