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

勿扰模式代码结构简析相关推荐

  1. android 勿扰模式代码结构简析

    勿扰模式代码结构简析 标签: 勿扰模式 2017-08-08 11:05  60人阅读  评论(0)  收藏  举报   分类: android(59)  版权声明:本文为博主原创文章,未经博主允许不 ...

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

    勿扰模式是Android 7.0开始加入的功能.它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/ ...

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

    勿扰模式是Android 7.0开始加入的功能.它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/ ...

  4. android 勿扰模式代码,Android N Zen Mode (勿扰模式)设置流程

    Android N去除了情景模式,取而代之的是勿扰模式.勿扰模式的入口有两处,下拉栏和设置声音里面.下面我们就从设置声音入口,看看勿扰模式的设置流程. 首先,勿扰模式的首页有三种选项,分别是仅允许优先 ...

  5. android 勿扰模式代码,android Lollipop勿扰模式

    android的L新版本中增加了"打扰"的新功能,相信很多同学搞不明白.找了一篇介绍勿扰模式很好的文章,可惜是英文的,现翻译如下,相信读完此问,你会理解android对勿扰模式的设 ...

  6. android 勿扰模式代码,android机勿扰模式代码是什么

    手机格式化代码!!!!!!!!!! BEGBEGIN:IMELODY VERSION:1.2 FORMAT:CLASS1.0 COMPOSER:MIK(23)Fomat BEAT:180 MELODY ...

  7. Android Zenmode/DND(勿扰模式) 实现原理剖析

    引言 Android手机越来越多的向着用户体验提升方面靠近,那么Zenmode就会变得越来越重要. 近年来,也有很多的新功能依赖于ZenMode去实现,也有很多专利在这个方面申请成功. 举两个简单的例 ...

  8. Android系统设置之勿扰模式

    项目场景: 智能车载机 问题描述: 车载机使用4G流量,但客户接入的是带通话功能的sim卡,客户测试过程中遇到有人拨号,来电音量不是静音情况下,居然通了.客户提出禁止来电功能. 原因分析: 尽管系统进 ...

  9. RK3568平台开发系列讲解(安卓篇)勿扰模式系统流程

    文章目录 一.勿扰模式 一.勿扰模式 它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/apps/ ...

最新文章

  1. ubuntu20.04安裝迅雷
  2. 互联网日报 | 苹果首款自研芯片M1亮相;酷派主动终止与小米专利侵权诉讼;橙心优选日订单破700万...
  3. 【项目合作】瓷砖表面打印缺陷识别
  4. shell 当中的比较运算
  5. nginx 开启gzip压缩--字符串压缩比率很牛叉
  6. jquery自适应宽度轮播图
  7. android otg dac,随身HiFi 安卓OTG功能在音频上的妙用
  8. matlab中gui对话框,Matlab GUI之通用对话框
  9. 经典算法题:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号。
  10. 华为认证HCIE的含金量高吗,考试费用是多少?
  11. 远程FPGA虚拟实验平台用SystemVerilog HDL实现硬布线控制器
  12. samba共享盘简单配置共享空间
  13. Windows XP注册表与驱动程序优化全集
  14. 【211南京理工大学】新增网络空间安全学院,学硕专硕都招!
  15. 考研逻辑-逻辑4主讲人:王超-2020-05-16
  16. 综合评价与决策方法01——理想解法
  17. 食物与体质 营养食谱
  18. ADAS落地与突围——客运场景如何破解AEB困境?
  19. 南邮汇编 Homework3.8 拼装字节
  20. 2022爱分析·低代码厂商全景报告

热门文章

  1. html jq页面跳转页面,JS和JQ定时跳转页面
  2. NVIDIA CUDA驱动安装
  3. 2022年发布jar到Maven公共仓库最全攻略
  4. Maven问题总结及配置私服或公共仓库
  5. 上传jar包到maven公共远程中央仓库
  6. 语音识别关键词,如何获取房产成交信息?
  7. HTML(网站搭建,标签,元素)
  8. html5 语音输入小话筒,科技常识:HTML5为输入框添加语音输入功能的实现方法
  9. FL水果编曲20.8中文版下载 flstudio语言修改中文教程
  10. 随机存取存储器SRAM