android 勿扰模式代码,android 勿扰模式代码结构简析

勿扰模式是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方法就可以了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值