在“设置->通知”中 选择“显示系统进程” 的话,会在应用列表中看到“蓝牙共享”应用,点击进入,打开“显示时不发出提示音”。这样,当有蓝牙设备发送文件过来时,就不再有提示了。
接下来分析一下代码,当打开这个开关时,都做了什么。
首先我们可以根据这个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 是如何处理的呢?下一篇以蓝牙接收文件通知为例进行分析。