美文网首页
Android 清除所有Notification的一些探究

Android 清除所有Notification的一些探究

作者: 铁皮阿童木 | 来源:发表于2017-06-05 15:03 被阅读0次

    最近在开发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<View> viewsToHide = new ArrayList<View>(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的一些探究

          本文链接:https://www.haomeiwen.com/subject/xlcifxtx.html