Android上有个通知使用权,给相关应用开启后,应用可以收到其他应用发送的通知,也可以移除相关通知
通知服务类
class NotificationListener : NotificationListenerService() {
companion object {
val TAG = NotificationListener::class.java.simpleName
}
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
super.onNotificationRemoved(sbn)
LogUtil.d("NotificationListener-onNotificationRemoved: " + sbn.toString());
}
override fun onNotificationPosted(sbn: StatusBarNotification?) {
super.onNotificationPosted(sbn)
LogUtil.d("NotificationListener-onNotificationPosted: " + sbn.toString())
}
}
manifest中声明
<service
android:name=".service.NotificationListener"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
代码判断是否开启通知使用权,并跳转设置页面打开权限
override fun onResume() {
super.onResume()
if (startSettin) {
checkNotificationPermission()
}
}
private fun checkNotificationPermission() {
startSettin = false
if (notificationListenerEnable()) {
//有通知使用权,跳出逻辑
startMainActivity()
} else {
if (gotoNotificationAccessSetting()) {
startSettin = true
}
}
}
private fun gotoNotificationAccessSetting(): Boolean {
try {
var intent = Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent)
return true;
} catch (e: Exception) {
try {
var intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
val cn = ComponentName(
"com.android.settings",
"com.android.settings.Settings\$NotificationAccessSettingsActivity"
);
intent.setComponent(cn)
intent.putExtra(":settings:show_fragment", "NotificationAccessSettings");
startActivity(intent)
return true;
} catch (ex: Exception) {
ex.printStackTrace()
}
return false
}
}
private fun notificationListenerEnable(): Boolean {
var enable = false
val packageName = AppContext.getPackageName()
val flat = Settings.Secure.getString(
AppContext.getContentResolver(),
"enabled_notification_listeners"
)
if (flat != null) {
enable = flat.contains(packageName)
}
return enable
}
权限开通后就能看到通知添加或移除时的日志
2022-06-21 16:44:12.850 7726-7726/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationPosted: StatusBarNotification(pkg=com.hihonor.hieduservice user=UserHandle{0} id=10001 tag=null key=0|com.hihonor.hieduservice|10001|null|10107: Notification(channel=notification_channel_edu_kit pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x62 color=0x00000000 groupKey=ranker_group10001 vis=PRIVATE))
2022-06-21 16:44:28.413 7726-7726/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationRemoved: StatusBarNotification(pkg=com.hihonor.hieduservice user=UserHandle{0} id=10001 tag=null key=0|com.hihonor.hieduservice|10001|null|10107: Notification(channel=notification_channel_edu_kit pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x62 color=0x00000000 groupKey=ranker_group10001 vis=PRIVATE))
2022-06-21 16:44:28.647 7726-7726/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationPosted: StatusBarNotification(pkg=android user=UserHandle{-1} id=26 tag=null key=-1|android|26|null|1000: Notification(channel=DEVELOPER pri=0 contentView=null vibrate=null sound=null tick defaults=0x0 flags=0x2 color=0xff607d8b groupKey=ranker_group26 vis=PUBLIC))
2022-06-21 16:44:29.611 7726-7726/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationPosted: StatusBarNotification(pkg=com.android.settings user=UserHandle{0} id=1000002 tag=null key=0|com.android.settings|1000002|null|1000: Notification(channel=SETTINGS_USB pri=1 contentView=null vibrate=null sound=null tick defaults=0x0 flags=0x2 color=0x00000000 groupKey=ranker_group1000002 vis=PRIVATE))
2022-06-21 17:00:39.247 7726-7726/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationPosted: StatusBarNotification(pkg=com.huawei.trustspace user=UserHandle{0} id=2131099660 tag=null key=0|com.huawei.trustspace|2131099660|null|1000: Notification(channel=trustspace_channel_id pri=1 contentView=null vibrate=null sound=default defaults=0x1 flags=0x10 color=0x00000000 actions=2 vis=PRIVATE))
2022-06-21 17:04:09.562 7726-7726/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationPosted: StatusBarNotification(pkg=com.huawei.music user=UserHandle{0} id=1 tag=null key=0|com.huawei.music|1|null|10027: Notification(channel=music_notify_channel_id_play pri=0 contentView=com.huawei.music/0x7f0d03fe vibrate=null sound=null defaults=0x0 flags=0x62 color=0x00000000 category=transport groupKey=music_notify_channel_id_play vis=PUBLIC))
能看到通知是属于哪一个应用发出的,这样我们就可以在onNotificationPosted中接收我们自己的通知然后使用cancelAllNotifications进行删除所有通知
发送通知
private fun sendNotification(){
val pi = PendingIntent.getActivity(context, 0, Intent(), 0)
val channel: String
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) channel = createChannel() else {
channel = ""
}
val notification =
context?.let {
NotificationCompat.Builder(it, channel)
.setContentTitle(context!!.getString(R.string.app_name))
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.icon_logo)
.setContentIntent(pi)
.build()
}
val mNotificationManager =
context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mNotificationManager.notify(TAG,ID,notification)
}
@TargetApi(26)
@Synchronized
private fun createChannel(): String {
val mNotificationManager =
context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val importance = NotificationManager.IMPORTANCE_LOW
val mChannel =
NotificationChannel(TAG, TAG, importance)
mChannel.enableLights(false)
mChannel.enableVibration(false)
mChannel.setSound(null, null)
if (mNotificationManager != null) {
mNotificationManager.createNotificationChannel(mChannel)
}
return TAG
}
接收到通知时,删除所有通知
override fun onNotificationPosted(sbn: StatusBarNotification?) {
super.onNotificationPosted(sbn)
LogUtil.d("NotificationListener-onNotificationPosted: " + sbn.toString())
if (sbn != null && sbn.tag == TAG) {
cancelAllNotifications()
}
}
测试日志
2022-06-21 17:12:53.928 22742-22742/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationPosted: StatusBarNotification(pkg=com.****.**** user=UserHandle{0} id=272 tag=com.****.****.provider.DeviceControlProvider key=0|com.****.****|272|com.****.****.provider.DeviceControlProvider|10132: Notification(channel=com.****.****.provider.DeviceControlProvider pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x0 color=0x00000000 vis=PRIVATE))
2022-06-21 17:12:53.944 22742-22742/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationRemoved: StatusBarNotification(pkg=com.****.**** user=UserHandle{0} id=272 tag=com.****.****.provider.DeviceControlProvider key=0|com.****.****|272|com.****.****.provider.DeviceControlProvider|10132: Notification(channel=com.****.****.provider.DeviceControlProvider pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x0 color=0x00000000 vis=PRIVATE))
2022-06-21 17:12:53.948 22742-22742/com.****.**** D/MdmOfflineApp: [MDMOffline-->]/MDMOffline-->NotificationListener-onNotificationRemoved: StatusBarNotification(pkg=com.huawei.trustspace user=UserHandle{0} id=2131099660 tag=null key=0|com.huawei.trustspace|2131099660|null|1000: Notification(channel=trustspace_channel_id pri=1 contentView=null vibrate=null sound=default defaults=0x1 flags=0x10 color=0x00000000 actions=2 vis=PRIVATE))
可以看到收到我们发的通知后,移除了我们的通知和com.huawei.trustspace的通知
| | | | ———————————————————— | ———————————————————— |
可以看到只少了一条通知,因为系统和设置的通知因为usb的原因不能被移除,而音乐的通知因为多媒体的原因需要手动交互才能被移除
因为MDM的原因,可以通过kill掉进程来删除通知
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
super.onNotificationRemoved(sbn)
LogUtil.d("NotificationListener-onNotificationRemoved: " + sbn.toString());
if (sbn != null && sbn.tag == TAG) {
val activeNotifications = activeNotifications
if (activeNotifications.isNotEmpty()) {
for (activeNotification in activeNotifications) {
if (activeNotification.packageName != "com.android.settings" &&
activeNotification.packageName != "android"
) {
if (activeNotification.notification.contentView != null) {
LogUtil.d("NotificationListener-onNotificationPosted: activeNotification ${activeNotification.toString()}")
CtrlProxy.get().killApplicationProcess(activeNotification.packageName)
}
}
}
}
}
}
可以看到实在我们的通知被移除的时候获取一下还存在的通知,然后过滤掉系统和设置的,再获取需要交互才能关闭的通知,通过killApplicationProcess杀掉进程来删除通知
这样就只保留了系统相关不能被移除的通知了。