一. 前言
[定制需求描述]:在插入SD后, 锁屏状态下, 去掉提示“SD卡可用于传输照片和媒体文件”
需求拆解: 要求正常显示在SystemUI下拉状态栏, 只需要屏蔽在锁屏状态下的通知.
二. 发送通知
首先来找找这个字符串"可用于传输照片和媒体文件"
是在/frameworks/base/core/res/res/values-zh-rCN.xml 中
在源码中搜索引用该字符串的文件为:StorageNotification.java 路径为:
frameworks/base/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
当插入SD后的逻辑代码为:
private void onVolumeStateChangedInternal(VolumeInfo vol) {
switch (vol.getType()) {
case VolumeInfo.TYPE_PRIVATE:
onPrivateVolumeStateChangedInternal(vol);
break;
//SD卡
case VolumeInfo.TYPE_PUBLIC:
onPublicVolumeStateChangedInternal(vol);
break;
}
}
接下来, 待SD卡挂载成功后,就会走 onVolumeMounted(vol)方法
private Notification onVolumeMounted(VolumeInfo vol) {
....
Notification.Builder builder = buildNotificationBuilder(vol, title, text)
....
}
方法中,会创建通知builder对象
private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
CharSequence text) {
Notification.Builder builder =
new Notification.Builder(mContext, NotificationChannels.STORAGE)
.setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
.extend(new Notification.TvExtender());
overrideNotificationAppName(mContext, builder, false);
return builder;
}
接下来回到 onPublicVolumeStateChangedInternal中, 当builder创建成功后,接下来就是发送通知
private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
....
mNotificationManager.notifyAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC,
notif, UserHandle.of(vol.getMountUserId()));
....
}
三. 显示通知
熟悉SystemUI模块的开发人员, 可以直接看管理锁屏状态下通知显示的文件:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java 它是一个接口文件, 里面有这两个方法:
一个是通过userId 来过滤, 一个是字符串String key 来过滤隐藏通信
boolean shouldHideNotifications(int userId);
boolean shouldHideNotifications(String key);
具体的实现文件为NotificationLockscreenUserManagerImpl.java文件
我是通过用key这个方法来过滤的
public boolean shouldHideNotifications(String key) {
if (getEntryManager() == null) {
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
return true;
}
return isLockscreenPublicMode(mCurrentUserId)
&& getEntryManager().getNotificationData().getVisibilityOverride(key) ==
Notification.VISIBILITY_SECRET;
}
通过全局搜索这个方法被调用的地方
在NotificationFilter.java文件中的shouldFilterOut 方法中
/**
* @return true if the provided notification should NOT be shown right now.
*/
public boolean shouldFilterOut(NotificationEntry entry) {
final StatusBarNotification sbn = entry.notification;
if (!(getEnvironment().isDeviceProvisioned()
|| showNotificationEvenIfUnprovisioned(sbn))) {
return true;
}
if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
return true;
}
if (getUserManager().isLockscreenPublicMode(sbn.getUserId())
&& (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
|| getUserManager().shouldHideNotifications(sbn.getUserId())
|| getUserManager().shouldHideNotifications(sbn.getKey()))) {
return true;
}
....
}
这个方法表达的意思就是 在特定条件下过滤掉通知, 所以这样子就有解决方法了, 我们在这个方法中根据特定的判断条件,返回true,表示需要在锁屏界面上过滤掉这个通知显示.
四. 解决方案
既然是通过key作为判断条件, 在发送通知的地方加上一个key相关的方法
private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
CharSequence text) {
Notification.Builder builder =
new Notification.Builder(mContext, NotificationChannels.STORAGE)
.setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
//加上这个自定义的key 不需要显示在锁屏界面
.setGroup("not_show_on_lockscreen")
.extend(new Notification.TvExtender());
overrideNotificationAppName(mContext, builder, false);
return builder;
}
然后在显示通知的过滤方法中,加入判断条件并返回true
public boolean shouldFilterOut(NotificationEntry entry) {
final StatusBarNotification sbn = entry.notification;
if (!(getEnvironment().isDeviceProvisioned()
|| showNotificationEvenIfUnprovisioned(sbn))) {
return true;
}
//在锁屏界面不显示SD卡的通知
if ("not_show_on_lockscreen".equals(sbn.getGroupKey())) {
return true;
}
//
....
}