Android(安卓)清除所有Notification的一些探究
最近在开发xposed模块中想要实现一个清除所有通知的功能,但是发现cancelAll只能清除单个应用的所有通知。
查看NotificationManager源码可知
http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/android/app/NotificationManager.java
28 /**229 * Cancel all previously shown notifications. See {@link #cancel} for the230 * detailed behavior.231 */232 public void cancelAll()233 {234 INotificationManager service = getService(); //此处获取了包名,导致只能关闭该包下的消息235 String pkg = mContext.getPackageName();236 if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");237 try {238 service.cancelAllNotifications(pkg, UserHandle.myUserId());239 } catch (RemoteException e) {240 }241 }
再次查看UserHandle.myUserId的源码
/**233 * Returns the user id of the current process234 * @return user id of the current process235 * @hide 这个方法是隐藏的236 */237 @SystemApi238 public static final int myUserId() { //获取进程对应的UID239 return getUserId(Process.myUid());240 }
cancelAll中关闭通知使用了uid和包名,可以看出来其实是只关闭一个应用里所有的通知
但是通知栏上面明明是有一个清除所有通知的按钮,通过源码来看一下它的实现
在源码中找到一个这样的布局
http://androidxref.com/5.1.0_r1/xref/frameworks/base/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
该布局里面只有一个DismissViewButton控件,通过调用它的ID,找到了这样一个类:
http://androidxref.com/5.1.0_r1/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
通过里面的setOnButtonClickListener,在源码中查找调用类这个方法的类
http://androidxref.com/5.1.0_r1/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
在PhoneStatusBar中,有这样一段代码:
744 mDismissView.setOnButtonClickListener(new View.OnClickListener() {745 @Override746 public void onClick(View v) {747 clearAllNotifications();748 }749 });
clearAllNotifications() 这个方法应该就是我们想要的那个清除所有通知的方法
我们来看一下它的具体实现
943 private void clearAllNotifications() {944945 // animate-swipe all dismissable notifications, then animate the shade closed946 int numChildren = mStackScroller.getChildCount();947948 final ArrayList viewsToHide = new ArrayList(numChildren);949 for (int i = 0; i < numChildren; i++) {950 final View child = mStackScroller.getChildAt(i);951 if (mStackScroller.canChildBeDismissed(child)) {952 if (child.getVisibility() == View.VISIBLE) {953 viewsToHide.add(child);954 }955 }956 }957 if (viewsToHide.isEmpty()) {958 animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);959 return;960 }961962 addPostCollapseAction(new Runnable() {963 @Override964 public void run() {965 try {966 mBarService.onClearAllNotifications(mCurrentUserId);967 } catch (Exception ex) { }968 }969 });970971 performDismissAllAnimations(viewsToHide);972973 }
通过Xposed Hook后调用该方法,成功实现清除所有通知栏的内容,但是仍然有一改问题:在通知栏收起的情况下,清除通知后,状态栏仍然有图标存在,而在下拉状态栏后才清除。
这个问题应该是由于该方法中
952 if (child.getVisibility() == View.VISIBLE) {953 viewsToHide.add(child);954 }
这一段代码造成的。
解决方法:
1.使用xposed hook替换整个清除通知栏的方法,去掉这一部分。比较麻烦,而且可能会造成某些问题,但是效果好。
2.在调用hook出来的clearAllNotificatons的时候,执行一下拉通知栏和收起通知栏的方法。效果稍微差一些,但是不至于出现太大问题。
更多相关文章
- android 使用InstanceState保存和恢复数据
- android 系统定制之编译方法总结
- Android(安卓)4.0 ICS SystemUI浅析——StatusBar加载流程分析
- Android(安卓)限制显示小数点位数
- Android与H5页面的互调
- android OpenGLES开发第三课 绘制一个可以翻转的Polygon
- java化改造--xml布局文件转成java——学习整理
- Android(安卓)上网流量监控方法
- [安卓开发Android] RecyclerView 类型与点击事件的用法