勿扰模式代码结构简析
勿扰模式是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
private boolean shouldRingForContact(Uri contactUri) {final NotificationManager manager =(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);final Bundle extras = new Bundle();if (contactUri != null) {extras.putStringArray(Notification.EXTRA_PEOPLE, new String[] {contactUri.toString()});}return manager.matchesCallFilter(extras);}
使用matchesCallFilter来决定是否响铃。
4.matchesCallFilter流程分析
frameworks/base/core/java/android/app/NotificationManager.java
public boolean matchesCallFilter(Bundle extras) {INotificationManager service = getService();try {return service.matchesCallFilter(extras);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
public boolean matchesCallFilter(Bundle extras) {enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");return mZenModeHelper.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
public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {synchronized (mConfig) {return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,extras, validator, contactsTimeoutMs, timeoutAffinity);}}
android/frameworks/base/services/core/java/com/android/server/notification/ZenModeFiltering.java
public static boolean matchesCallFilter(Context context, int zen, ZenModeConfig config,UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator,int contactsTimeoutMs, float timeoutAffinity) {if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through //勿扰模式判断if (zen == Global.ZEN_MODE_ALARMS) return false; // not an alarmif (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {if (config.allowRepeatCallers && REPEAT_CALLERS.isRepeat(context, extras)) { //短时间内第二次来电放行return true;}if (!config.allowCalls) return false; // no other calls get through //是否禁止全部来电if (validator != null) {final float contactAffinity = validator.getContactAffinity(userHandle, extras,contactsTimeoutMs, timeoutAffinity);return audienceMatches(config.allowCallsFrom, contactAffinity); //依据联系人判断}}return true;}
先来看返回结果调用的方法:
private static boolean audienceMatches(int source, float contactAffinity) {switch (source) {case ZenModeConfig.SOURCE_ANYONE: //所有人return true;case ZenModeConfig.SOURCE_CONTACT:return contactAffinity >= ValidateNotificationPeople.VALID_CONTACT; //联系人case ZenModeConfig.SOURCE_STAR:return contactAffinity >= ValidateNotificationPeople.STARRED_CONTACT; //星标联系人default:Slog.w(TAG, "Encountered unknown source: " + source);return true;}}
很简单,就是依据配置走不同的分支。接下来继续看核心的getContactAffinity方法
frameworks/base/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
public float getContactAffinity(UserHandle userHandle, Bundle extras, int timeoutMs,float timeoutAffinity) {...final PeopleRankingReconsideration prr = validatePeople(context, key, extras, affinityOut); //从缓存中读取值float affinity = affinityOut[0];if (prr != null) {// Perform the heavy work on a background thread so we can abort when we hit the// timeout.final Semaphore s = new Semaphore(0);AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {@Overridepublic void run() {prr.work(); //开线程查询数据库s.release();}});try {if (!s.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {Slog.w(TAG, "Timeout while waiting for affinity: " + key + ". "+ "Returning timeoutAffinity=" + timeoutAffinity);return timeoutAffinity; //超时后直接返回}} catch (InterruptedException e) {Slog.w(TAG, "InterruptedException while waiting for affinity: " + key + ". "+ "Returning affinity=" + affinity, e);return affinity; //线程被中断后返回缓存结果}affinity = Math.max(prr.getContactAffinity(), affinity); //正常情况下返回的结果}return affinity;}
线程工作方法work如下:
public void work() {long start = SystemClock.elapsedRealtime();if (VERBOSE) Slog.i(TAG, "Executing: validation for: " + mKey);long timeStartMs = System.currentTimeMillis();for (final String handle: mPendingLookups) {LookupResult lookupResult = null;final Uri uri = Uri.parse(handle);if ("tel".equals(uri.getScheme())) { //处理电话号码类型的uriif (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);lookupResult = resolvePhoneContact(mContext, uri.getSchemeSpecificPart());} else if ("mailto".equals(uri.getScheme())) { //处理电子邮件类型的uriif (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);lookupResult = resolveEmailContact(mContext, uri.getSchemeSpecificPart());} else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) { //处理联系人lookup_uriif (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);lookupResult = searchContacts(mContext, uri);} else { //非法的uri,生成默认的结果lookupResult = new LookupResult(); // invalid person for the cacheSlog.w(TAG, "unsupported URI " + handle);}if (lookupResult != null) {synchronized (mPeopleCache) {final String 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");}}...}
以电话号码分支为例:
private LookupResult resolvePhoneContact(Context context, final String number) {Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,Uri.encode(number));return searchContacts(context, phoneUri);}
private LookupResult searchContacts(Context context, Uri lookupUri) {LookupResult lookupResult = new LookupResult();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.");return lookupResult;}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();}}return lookupResult;}
上述两个方法就是查询联系人数据库,其中生成结果的方法mergeContact如下:
public void mergeContact(Cursor cursor) {mAffinity = Math.max(mAffinity, VALID_CONTACT);// Contact IDint id;final int idIdx = 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");}// Starredfinal int starIdx = cursor.getColumnIndex(Contacts.STARRED);if (starIdx >= 0) {boolean isStarred = 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 勿扰模式代码结构简析
勿扰模式代码结构简析 标签: 勿扰模式 2017-08-08 11:05 60人阅读 评论(0) 收藏 举报 分类: android(59) 版权声明:本文为博主原创文章,未经博主允许不 ...
- android 勿扰模式代码,勿扰模式代码结构简析
勿扰模式是Android 7.0开始加入的功能.它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/ ...
- android 勿扰模式代码,android 勿扰模式代码结构简析
勿扰模式是Android 7.0开始加入的功能.它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/ ...
- android 勿扰模式代码,Android N Zen Mode (勿扰模式)设置流程
Android N去除了情景模式,取而代之的是勿扰模式.勿扰模式的入口有两处,下拉栏和设置声音里面.下面我们就从设置声音入口,看看勿扰模式的设置流程. 首先,勿扰模式的首页有三种选项,分别是仅允许优先 ...
- android 勿扰模式代码,android Lollipop勿扰模式
android的L新版本中增加了"打扰"的新功能,相信很多同学搞不明白.找了一篇介绍勿扰模式很好的文章,可惜是英文的,现翻译如下,相信读完此问,你会理解android对勿扰模式的设 ...
- android 勿扰模式代码,android机勿扰模式代码是什么
手机格式化代码!!!!!!!!!! BEGBEGIN:IMELODY VERSION:1.2 FORMAT:CLASS1.0 COMPOSER:MIK(23)Fomat BEAT:180 MELODY ...
- Android Zenmode/DND(勿扰模式) 实现原理剖析
引言 Android手机越来越多的向着用户体验提升方面靠近,那么Zenmode就会变得越来越重要. 近年来,也有很多的新功能依赖于ZenMode去实现,也有很多专利在这个方面申请成功. 举两个简单的例 ...
- Android系统设置之勿扰模式
项目场景: 智能车载机 问题描述: 车载机使用4G流量,但客户接入的是带通话功能的sim卡,客户测试过程中遇到有人拨号,来电音量不是静音情况下,居然通了.客户提出禁止来电功能. 原因分析: 尽管系统进 ...
- RK3568平台开发系列讲解(安卓篇)勿扰模式系统流程
文章目录 一.勿扰模式 一.勿扰模式 它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/apps/ ...
最新文章
- ubuntu20.04安裝迅雷
- 互联网日报 | 苹果首款自研芯片M1亮相;酷派主动终止与小米专利侵权诉讼;橙心优选日订单破700万...
- 【项目合作】瓷砖表面打印缺陷识别
- shell 当中的比较运算
- nginx 开启gzip压缩--字符串压缩比率很牛叉
- jquery自适应宽度轮播图
- android otg dac,随身HiFi 安卓OTG功能在音频上的妙用
- matlab中gui对话框,Matlab GUI之通用对话框
- 经典算法题:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号。
- 华为认证HCIE的含金量高吗,考试费用是多少?
- 远程FPGA虚拟实验平台用SystemVerilog HDL实现硬布线控制器
- samba共享盘简单配置共享空间
- Windows XP注册表与驱动程序优化全集
- 【211南京理工大学】新增网络空间安全学院,学硕专硕都招!
- 考研逻辑-逻辑4主讲人:王超-2020-05-16
- 综合评价与决策方法01——理想解法
- 食物与体质 营养食谱
- ADAS落地与突围——客运场景如何破解AEB困境?
- 南邮汇编 Homework3.8 拼装字节
- 2022爱分析·低代码厂商全景报告