在上一节我们说到了ZenModeConditions里面的evaluateConfig()方法 。
调到了另一个类ZenModeConditions里面的evaluateConfig()方法 。这个文件的目录:\framework\base\services\core\java\com\android\server\notification\ZenModeConditions.java,具体方法实现的代码如下,
public
void
evaluateConfig(ZenModeConfig
config, boolean
processSubscriptions) {
if (config
==
null)
return;
if (config.manualRule
!= null
&&
config.manualRule.condition !=
null
&&
!config.manualRule.isTrueOrUnknown()) {
if (DEBUG)
Log.d(TAG, "evaluateConfig: clearing
manual rule");
config.manualRule =
null;
}
final ArraySet current
= new
ArraySet<>();
evaluateRule(config.manualRule, current,
processSubscriptions);
for (ZenRule
automaticRule : config.automaticRules.values()) {
evaluateRule(automaticRule, current,
processSubscriptions);
updateSnoozing(automaticRule);
}
final
int N =
mSubscriptions.size();
for
(int
i = N - 1; i >= 0; i--)
{
final Uri id =
mSubscriptions.keyAt(i);
final ComponentName
component = mSubscriptions.valueAt(i);
if
(processSubscriptions) {
if
(!current.contains(id)) {
mConditionProviders.unsubscribeIfNecessary(component,
id);
mSubscriptions.removeAt(i);
}
}
}
mFirstEvaluation =
false;
}
而这个方法,其实在处理的时候,又调到另一个方法evaluateRule(),该方法的具体实现如下,所以看代码跟流程就需要这样一个一个方法调用往里面跟,好,继续看代码。
private
void
evaluateRule(ZenRule rule, ArraySet
current, boolean
processSubscriptions) {
if (rule
== null
|| rule.conditionId ==
null)
return;
final Uri id =
rule.conditionId;
boolean
isSystemCondition =
false;
for
(SystemConditionProviderService sp :
mConditionProviders.getSystemProviders()) {
if
(sp.isValidConditionId(id)) {
mConditionProviders.ensureRecordExists(sp.getComponent(), id,
sp.asInterface());
rule.component = sp.getComponent();
isSystemCondition =
true;
}
}
if
(!isSystemCondition) {
final
IConditionProvider cp =
mConditionProviders.findConditionProvider(rule.component);
if (DEBUG)
Log.d(TAG, "Ensure external rule exists:
" + (cp !=
null) +
" for " +
id);
if (cp
!= null)
{
mConditionProviders.ensureRecordExists(rule.component, id,
cp);
}
}
if (rule.component
== null)
{
Log.w(TAG, "No component found for
automatic rule: " +
rule.conditionId);
rule.enabled =
false;
return;
}
if (current
!= null)
{
current.add(id);
}
if
(processSubscriptions)
{
if
(mConditionProviders.subscribeIfNecessary(rule.component,
rule.conditionId)) {
mSubscriptions.put(rule.conditionId,
rule.component);
} else
{
if (DEBUG)
Log.d(TAG, "zmc failed to
subscribe");
}
}
if (rule.condition
== null)
{
rule.condition = mConditionProviders.findCondition(rule.component,
rule.conditionId);
if (rule.condition
!= null
&& DEBUG)
Log.d(TAG, "Found existing condition for:
"
+ rule.conditionId);
}
}
那上面的这个方法主要的处理又调到了另一个文件里面了,ConditionProviders,这个类中的ensureRecordExists 和subscribeIfNecessary
方法,最后将数据记录到HashMap中,这个文件的目录:\framework\base\services\core\java\com\android\server\notification\ConditionProviders
.java。那我们所要说的ZenMode的设置过程就是如此,通过NotificationManager调到了NotificationManagerService ,然后调到了ZenModeHelper,主要的处理在ZenModeHelper,设置完成后,相关注册的Callback会进行相关消息的通知,最后数据库的mode值被改写,到此设置模式结束。那勿扰模式是怎么生效的,我们需要继续查看代码了,我们在之前也说过,勿扰模式和通知有关系,那我们就看下NotificationManagerService是如何通过勿扰模式,来屏蔽通知提醒的,首先我们找到文件NotificationManagerService,对应的目录:\framework\base\services\core\java\com\android\server\notification\NotificationManagerService.java。我们知道Notification的数据结构封装成了3个类,Notification,NotificationRecord和StatusBarNotification,具体的Notification流程,我们在此就不详细分析。而NotificationRecord有定义一个属性:mIntercept,看注释也就是这个通知是否需要被ZenMode影响的属性。
// is this
notification currently being intercepted by Zen
Mode?
private
boolean
mIntercept;
而这个属性被设置的位置我们在NotificationManagerService可以看到如下方法的处理,其中ZenModeHelper对象调用的shouldIntercept()方法就是在我们之前讲的类,这个方法最后其实调用到了ZenModeFiltering中的方法shouldIntercept(),这个方法也就是根据当前的模式和配置ZenModeConfig来判断这个NotificationRecord是否需要被intercept(阻截)。如果是true表示这条通知就会被屏蔽阻截掉。然后这个返回结果最后是记录在NotificationRecord的mIntercept属性中,然后我们继续看代码。NotificationRecord还有一个取这个值的方法isIntercepted(),我们继续看这个方法在NotificationManagerService调用的处理。
// let zen mode evaluate this record
private
void
applyZenModeLocked(NotificationRecord
record) {
record.setIntercepted(mZenModeHelper.shouldIntercept(record));
}
主要的处理就在NotificationManagerService 这个类的buzzBeepBlinkLocked()方法中处理,由于方法代码有点多少,所以只是贴上了前面一部分,我们的前面说的NotificationRecord 这个通知是否需要被屏蔽阻截掉的属性调用的方法isIntercepted() ,最后的值就这个地方被调用,canInterrupt
= aboveThreshold &&
!record.isIntercepted();所以canInterrupt最后其实就是这个是否需要屏蔽阻截的值取反。当aboveThreshold为true的时候,canInterrupt 的值就取决于isIntercepted() 的结果,这个值被使用的地方,也就是下面的那个if条件。这个if后面的处理就包括播放声音、振动的提醒具体的代码这里就不贴出来了。所以我们看这个if条件,当canInterrupt为true,这个时候才会去播放声音和振动,也就是不是勿扰模式,那么isIntercepted()取到的值应该为false,所以这样的逻辑就走通了。具体返回的值,可查阅ZenModeFiltering中方法shouldIntercept()的处理。这个文件对应的目录为:\framework\base\services\core\java\com\android\server\notification\ZenModeFiltering.java
private
void
buzzBeepBlinkLocked(NotificationRecord
record) {
boolean buzz
=
false;
boolean beep
=
false;
boolean blink
=
false;
final Notification
notification = record.sbn.getNotification();
// Should this notification make noise, vibe, or use
the LED?
final
boolean aboveThreshold
= record.score >=
SCORE_INTERRUPTION_THRESHOLD;
final
boolean canInterrupt =
aboveThreshold &&
!record.isIntercepted();
if (DBG ||
record.isIntercepted())
Slog.v(TAG,
"pkg=" +
record.sbn.getPackageName() + "
canInterrupt=" + canInterrupt
+
" intercept=" +
record.isIntercepted()
);
final
int
currentUser;
final
long token =
Binder.clearCallingIdentity();
try
{
currentUser = ActivityManager.getCurrentUser();
} finally
{
Binder.restoreCallingIdentity(token);
}
// If we're not supposed to beep, vibrate, etc. then
don't.
final String
disableEffects =
disableNotificationEffects(record);
if (disableEffects
!= null)
{
ZenLog.traceDisableEffects(record,
disableEffects);
}
/// M: Determine if we should play
alerts
final
boolean enableAlerts =
(((mDisabledNotifications
& StatusBarManager.DISABLE_NOTIFICATION_ALERTS) ==
0)
// Phone app will disable alerts but we need the alert
of mms
||
record.sbn.getPackageName().equals("com.android.mms"))
&& !mDmLock
&& !mPplLock;
// Never play alerts when DM/PPL lock
// if (disableEffects == null
if (enableAlerts
&& disableEffects ==
null
&&
(!(record.isUpdate
&& (notification.flags
& Notification.FLAG_ONLY_ALERT_ONCE) != 0
))
&& (record.getUserId() ==
UserHandle.USER_ALL ||
record.getUserId() == currentUser ||
mUserProfiles.isCurrentProfile(record.getUserId()))
&& canInterrupt
&& mSystemReady
&& mAudioManager !=
null)
{
if (DBG)
Slog.v(TAG,
"Interrupting!");
sendAccessibilityEvent(notification,
record.sbn.getPackageName());
//省略部分代码 ···
}
本次ZenMode(禅模式)勿扰模式的设置和生效的流程分析就到此了,那下一次我们将介绍定时勿扰的实现流程和机制。本次介绍到此结束,祝你工作学习愉快!