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 the
230     * 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 process
234     * @return user id of the current process
235     * @hide  这个方法是隐藏的
236     */
237    @SystemApi
238    public static final int myUserId() {
          //获取进程对应的UID
239        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            @Override
746            public void onClick(View v) {
747                clearAllNotifications();
748            }
749        });

clearAllNotifications() 这个方法应该就是我们想要的那个清除所有通知的方法
我们来看一下它的具体实现

943    private void clearAllNotifications() {
944
945        // animate-swipe all dismissable notifications, then animate the shade closed
946        int numChildren = mStackScroller.getChildCount();
947
948        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        }
961
962        addPostCollapseAction(new Runnable() {
963            @Override
964            public void run() {
965                try {
966                    mBarService.onClearAllNotifications(mCurrentUserId);
967                } catch (Exception ex) { }
968            }
969        });
970
971        performDismissAllAnimations(viewsToHide);
972
973    }

通过Xposed Hook后调用该方法,成功实现清除所有通知栏的内容,但是仍然有一改问题:在通知栏收起的情况下,清除通知后,状态栏仍然有图标存在,而在下拉状态栏后才清除。
这个问题应该是由于该方法中

952                if (child.getVisibility() == View.VISIBLE) {
953                    viewsToHide.add(child);
954                }

这一段代码造成的。
解决方法:
1.使用xposed hook替换整个清除通知栏的方法,去掉这一部分。比较麻烦,而且可能会造成某些问题,但是效果好。
2.在调用hook出来的clearAllNotificatons的时候,执行一下拉通知栏和收起通知栏的方法。效果稍微差一些,但是不至于出现太大问题。

你可能感兴趣的:(Android 清除所有Notification的一些探究)