Android 取消蓝牙消息通知流程分析(一)

设置通知

在“设置->通知”中 选择“显示系统进程” 的话,会在应用列表中看到“蓝牙共享”应用,点击进入,打开“显示时不发出提示音”。这样,当有蓝牙设备发送文件过来时,就不再有提示了。
接下来分析一下代码,当打开这个开关时,都做了什么。
首先我们可以根据这个preferece的title,找到这个preference。是在packages/apps/Settings/src/com/android/settings/notification/AppNotificationSettings.java中的mSilent,mSilent的OnPreferenceChangeListener是在AppNotificationSettings的父类NotificationSettingsBase中设置的:

...
mSilent.setChecked(silenced);
mSilent.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
   @Override
   public boolean onPreferenceChange(Preference preference, Object newValue) {
       final boolean silenced = (Boolean) newValue;
       final int importance =
               silenced ? Ranking.IMPORTANCE_LOW : Ranking.IMPORTANCE_UNSPECIFIED;
       mBackend.setImportance(mPkgInfo.packageName, mUid, importance);//1
       updateDependents(importance);
       return true;
   }
});
...

最重要的处理是标记1处,开关打开,importance=Ranking.IMPORTANCE_LOW(2);开关关闭,importance=Ranking.IMPORTANCE_UNSPECIFIED(-1000);此处调用了NotificationBackend.setImportance:

public boolean setImportance(String pkg, int uid, int importance) {
        try {
            sINM.setImportance(pkg, uid, importance);
            return true;
        } catch (Exception e) {
            Log.w(TAG, "Error calling NoMan", e);
            return false;
        }
    }

该方法最终调用的是NotificationManagerService.setImportance:

@Override
        public void setImportance(String pkg, int uid, int importance) {
            enforceSystemOrSystemUI("Caller not system or systemui");
            setNotificationsEnabledForPackageImpl(pkg, uid,
                    importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);//1
            mRankingHelper.setImportance(pkg, uid, importance);//2
            savePolicyFile();//3
        }

标记1处的setNotificationsEnabledForPackageImpl 调用了AppOpsService.setMode,该方法主要是设置了pkg的AppOpsManager.OP_POST_NOTIFICATION Op,可以暂时先不关注;标记2处调用了RankingHelper.setImportance,该方法设置了pkg的importance:

@Override
    public void setImportance(String pkgName, int uid, int importance) {
        getOrCreateRecord(pkgName, uid).importance = importance;
        updateConfig();
    }
private Record getOrCreateRecord(String pkg, int uid) {
        final String key = recordKey(pkg, uid);
        Record r = mRecords.get(key);
        if (r == null) {
            r = new Record();
            r.pkg = pkg;
            r.uid = uid;
            mRecords.put(key, r);
        }
        return r;
    }

可以看到通过获取getOrCreateRecord 是把mRecords中pkg 对应的key 的Record, 然后更新importance。这样importance就保存在了mRecord中pkg对应的条目中。
回到NotificationManagerService.setImportance中继续看标记3,调用了savePolicyFile:

public void savePolicyFile() {
        mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
        mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
    }

继续看一下mHandler 对MESSAGE_SAVE_POLICY_FILE消息的处理:

 private final class WorkerHandler extends Handler
    {
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what)
            {
                case MESSAGE_TIMEOUT:
                    handleTimeout((ToastRecord)msg.obj);
                    break;
                case MESSAGE_SAVE_POLICY_FILE:
                    handleSavePolicyFile();//1
                    break;
               ...
            }
        }

    }

标记1处调用了handleSavePolicyFile:

private void handleSavePolicyFile() {
        if (DBG) Slog.d(TAG, "handleSavePolicyFile");
        synchronized (mPolicyFile) {
            final FileOutputStream stream;
            try {
                stream = mPolicyFile.startWrite();
            } catch (IOException e) {
                Slog.w(TAG, "Failed to save policy file", e);
                return;
            }

            try {
                writePolicyXml(stream, false /*forBackup*/);//1
                mPolicyFile.finishWrite(stream);
            } catch (IOException e) {
                Slog.w(TAG, "Failed to save policy file, restoring backup", e);
                mPolicyFile.failWrite(stream);
            }
        }
        BackupManager.dataChanged(getContext().getPackageName());
    }

该方法是写mPolicyFile,mPolicyFile的初始化是在NotificationManagerService.onStar中:

final File systemDir = new File(Environment.getDataDirectory(), "system");
        mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));

路径是 /data/system/notification_policy.xml。这样一来,设置的值就保存在文件中,重启机器也不会丢失。具体看一下标记1处的writePolicyXml:

private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
        final XmlSerializer out = new FastXmlSerializer();
        out.setOutput(stream, StandardCharsets.UTF_8.name());
        out.startDocument(null, true);
        out.startTag(null, TAG_NOTIFICATION_POLICY);
        out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
        mZenModeHelper.writeXml(out, forBackup);
        mRankingHelper.writeXml(out, forBackup);//1
        out.endTag(null, TAG_NOTIFICATION_POLICY);
        out.endDocument();
    }

标记1处调用了RankingHelper.writeXml:

public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
        out.startTag(null, TAG_RANKING);
        out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));

        final int N = mRecords.size();
        for (int i = 0; i < N; i++) {
            final Record r = mRecords.valueAt(i);
            //TODO: http://b/22388012
            if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
                continue;
            }
            final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE
                    || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY;
            if (hasNonDefaultSettings) {
                out.startTag(null, TAG_PACKAGE);
                out.attribute(null, ATT_NAME, r.pkg);
                if (r.importance != DEFAULT_IMPORTANCE) {
                    out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
                }
                if (r.priority != DEFAULT_PRIORITY) {
                    out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
                }
                if (r.visibility != DEFAULT_VISIBILITY) {
                    out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
                }

                if (!forBackup) {
                    out.attribute(null, ATT_UID, Integer.toString(r.uid));
                }

                out.endTag(null, TAG_PACKAGE);
            }
        }
        out.endTag(null, TAG_RANKING);
    }

可以看到是把mRecords的中的所有Record写进xml文件中。
到此为止,设置通知后发生的动作已经分析完了,那么有通知发送时,NotificationManagerService 是如何处理的呢?下一篇以蓝牙接收文件通知为例进行分析。

你可能感兴趣的:(Android 取消蓝牙消息通知流程分析(一))