概述
勿扰模式是Android 7.0开始加入的功能。它的核心思想是屏蔽了通知的铃声、振动和展示。
代码分散在几部分。
1.设置代码在Settings中,ZenMode开头的一系列文件
/packages/apps/Settings/src/com/android/settings/notification/ZenModeSettings.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeSettingsBase.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeVoiceActivity.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModePrioritySettings.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeEventRuleSettings.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeAutomationSettings.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeScheduleDaysSelection.java
/packages/apps/Settings/src/com/android/settings/notification/ZenModeVisualInterruptionSettings.java
2.framework中关于勿扰的文件
2.1 勿扰模式设置,可以在进程间传递
/frameworks/base/core/java/android/service/notification/ZenModeConfig.aidl
/frameworks/base/core/java/android/service/notification/ZenModeConfig.java
2.2 勿扰模式使用相关文件
/frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java
/frameworks/base/services/core/java/com/android/server/notification/ZenModeFiltering.java
/frameworks/base/services/core/java/com/android/server/notification/ZenModeConditions.java
2.3 systemUI中,有勿扰模式UI和功能两个部分构成。因为最终的目的是处理通知,所以实现是在systemUI中。
/frameworks/base/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
/frameworks/base/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
3.各个apk对勿扰模式的处理,以来电铃声为例
/packages/services/Telecomm/src/com/android/server/telecom/Ringer.java
privatebooleanshouldRingForContact(Uri contactUri) {
finalNotificationManager manager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
finalBundle extras =newBundle();
if(contactUri !=null) {
extras.putStringArray(Notification.EXTRA_PEOPLE, newString[] {contactUri.toString()});
}
returnmanager.matchesCallFilter(extras);
}
使用matchesCallFilter来决定是否响铃。
4.matchesCallFilter流程分析
frameworks/base/core/java/android/app/NotificationManager.java
publicbooleanmatchesCallFilter(Bundle extras) {
INotificationManager service = getService();
try{
returnservice.matchesCallFilter(extras);
} catch(RemoteException e) {
throwe.rethrowFromSystemServer();
}
}
frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
publicbooleanmatchesCallFilter(Bundle extras) {
enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
returnmZenModeHelper.matchesCallFilter(
Binder.getCallingUserHandle(),
extras,
mRankingHelper.findExtractor(ValidateNotificationPeople.class),
MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
}
android/frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java
publicbooleanmatchesCallFilter(UserHandle userHandle, Bundle extras,
ValidateNotificationPeople validator, intcontactsTimeoutMs,floattimeoutAffinity) {
synchronized(mConfig) {
returnZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
extras, validator, contactsTimeoutMs, timeoutAffinity);
}
}
android/frameworks/base/services/core/java/com/android/server/notification/ZenModeFiltering.java
publicstaticbooleanmatchesCallFilter(Context context,intzen, ZenModeConfig config,
UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator,
intcontactsTimeoutMs,floattimeoutAffinity) {
if(zen == Global.ZEN_MODE_NO_INTERRUPTIONS)returnfalse;// nothing gets through //勿扰模式判断
if(zen == Global.ZEN_MODE_ALARMS)returnfalse;// not an alarm
if(zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
if(config.allowRepeatCallers && REPEAT_CALLERS.isRepeat(context, extras)) {//短时间内第二次来电放行
returntrue;
}
if(!config.allowCalls)returnfalse;// no other calls get through //是否禁止全部来电
if(validator !=null) {
finalfloatcontactAffinity = validator.getContactAffinity(userHandle, extras,
contactsTimeoutMs, timeoutAffinity);
returnaudienceMatches(config.allowCallsFrom, contactAffinity);//依据联系人判断
}
}
returntrue;
}
先来看返回结果调用的方法:
privatestaticbooleanaudienceMatches(intsource,floatcontactAffinity) {
switch(source) {
caseZenModeConfig.SOURCE_ANYONE://所有人
returntrue;
caseZenModeConfig.SOURCE_CONTACT:
returncontactAffinity >= ValidateNotificationPeople.VALID_CONTACT;//联系人
caseZenModeConfig.SOURCE_STAR:
returncontactAffinity >= ValidateNotificationPeople.STARRED_CONTACT;//星标联系人
default:
Slog.w(TAG, "Encountered unknown source: "+ source);
returntrue;
}
} 很简单,就是依据配置走不同的分支。接下来继续看核心的getContactAffinity方法
frameworks/base/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
publicfloatgetContactAffinity(UserHandle userHandle, Bundle extras,inttimeoutMs,
floattimeoutAffinity) {
...
finalPeopleRankingReconsideration prr = validatePeople(context, key, extras, affinityOut);//从缓存中读取值
floataffinity = affinityOut[0];
if(prr !=null) {
// Perform the heavy work on a background thread so we can abort when we hit the
// timeout.
finalSemaphore s =newSemaphore(0);
AsyncTask.THREAD_POOL_EXECUTOR.execute(newRunnable() {
@Override
publicvoidrun() {
prr.work(); //开线程查询数据库
s.release();
}
});
try{
if(!s.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
Slog.w(TAG, "Timeout while waiting for affinity: "+ key +". "
+ "Returning timeoutAffinity="+ timeoutAffinity);
returntimeoutAffinity;//超时后直接返回
}
} catch(InterruptedException e) {
Slog.w(TAG, "InterruptedException while waiting for affinity: "+ key +". "
+ "Returning affinity="+ affinity, e);
returnaffinity;//线程被中断后返回缓存结果
}
affinity = Math.max(prr.getContactAffinity(), affinity); //正常情况下返回的结果
}
returnaffinity;
} 线程工作方法work如下:
publicvoidwork() {
longstart = SystemClock.elapsedRealtime();
if(VERBOSE) Slog.i(TAG,"Executing: validation for: "+ mKey);
longtimeStartMs = System.currentTimeMillis();
for(finalString handle: mPendingLookups) {
LookupResult lookupResult = null;
finalUri uri = Uri.parse(handle);
if("tel".equals(uri.getScheme())) {//处理电话号码类型的uri
if(DEBUG) Slog.d(TAG,"checking telephone URI: "+ handle);
lookupResult = resolvePhoneContact(mContext, uri.getSchemeSpecificPart());
} elseif("mailto".equals(uri.getScheme())) {//处理电子邮件类型的uri
if(DEBUG) Slog.d(TAG,"checking mailto URI: "+ handle);
lookupResult = resolveEmailContact(mContext, uri.getSchemeSpecificPart());
} elseif(handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {//处理联系人lookup_uri
if(DEBUG) Slog.d(TAG,"checking lookup URI: "+ handle);
lookupResult = searchContacts(mContext, uri);
} else{//非法的uri,生成默认的结果
lookupResult = newLookupResult();// invalid person for the cache
Slog.w(TAG, "unsupported URI "+ handle);
}
if(lookupResult !=null) {
synchronized(mPeopleCache) {
finalString cacheKey = getCacheKey(mContext.getUserId(), handle);
mPeopleCache.put(cacheKey, lookupResult); //查询存储到缓存
}
if(DEBUG) Slog.d(TAG,"lookup contactAffinity is "+ lookupResult.getAffinity());
mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity()); //保存结果值
} else{
if(DEBUG) Slog.d(TAG,"lookupResult is null");
}
}
...
} 以电话号码分支为例:
privateLookupResult resolvePhoneContact(Context context,finalString number) {
Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
returnsearchContacts(context, phoneUri);
}
privateLookupResult searchContacts(Context context, Uri lookupUri) {
LookupResult lookupResult = newLookupResult();
Cursor c = null;
try{
c = context.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null,null,null);
if(c ==null) {
Slog.w(TAG, "Null cursor from contacts query.");
returnlookupResult;
}
while(c.moveToNext()) {
lookupResult.mergeContact(c);
}
} catch(Throwable t) {
Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
} finally{
if(c !=null) {
c.close();
}
}
returnlookupResult;
} 上述两个方法就是查询联系人数据库,其中生成结果的方法mergeContact如下:
publicvoidmergeContact(Cursor cursor) {
mAffinity = Math.max(mAffinity, VALID_CONTACT);
// Contact ID
intid;
finalintidIdx = cursor.getColumnIndex(Contacts._ID);
if(idIdx >=0) {
id = cursor.getInt(idIdx);
if(DEBUG) Slog.d(TAG,"contact _ID is: "+ id);
} else{
id = -1;
Slog.i(TAG, "invalid cursor: no _ID");
}
// Starred
finalintstarIdx = cursor.getColumnIndex(Contacts.STARRED);
if(starIdx >=0) {
booleanisStarred = cursor.getInt(starIdx) !=0;
if(isStarred) {
mAffinity = Math.max(mAffinity, STARRED_CONTACT);
}
if(DEBUG) Slog.d(TAG,"contact STARRED is: "+ isStarred);
} else{
if(DEBUG) Slog.d(TAG,"invalid cursor: no STARRED");
}
} 实际上就是给mAffinity赋值,标记为普通联系人或者星标联系人。
如果要加入指定联系人在勿扰模式中优先,从流程分析看只要修改searchContacts方法就可以了。
最后
以上就是踏实柚子为你收集整理的android 勿扰模式代码,android 勿扰模式代码结构简析的全部内容,希望文章能够帮你解决android 勿扰模式代码,android 勿扰模式代码结构简析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复