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
- 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 alarm
- if (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() {
- @Override
- public 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())) { //处理电话号码类型的uri
- if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
- lookupResult = resolvePhoneContact(mContext, uri.getSchemeSpecificPart());
- } else if ("mailto".equals(uri.getScheme())) { //处理电子邮件类型的uri
- if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);
- lookupResult = resolveEmailContact(mContext, uri.getSchemeSpecificPart());
- } else if (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 = new LookupResult(); // invalid person for the cache
- Slog.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 ID
- int 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");
- }
- // Starred
- final 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 勿扰模式代码结构简析相关推荐
- android 勿扰模式代码,android 勿扰模式代码结构简析
勿扰模式是Android 7.0开始加入的功能.它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/ ...
- android 勿扰模式代码,勿扰模式代码结构简析
勿扰模式是Android 7.0开始加入的功能.它的核心思想是屏蔽了通知的铃声.振动和展示. 代码分散在几部分. 1.设置代码在Settings中,ZenMode开头的一系列文件 /packages/ ...
- 勿扰模式代码结构简析
勿扰模式是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 勿扰代码,Android7.1勿扰功能简析
Android系统在5.1系统开始增加勿扰模式,渐渐的有着取代静音模式的趋势,最新的系统已经更新到7.1.1,我们来看一下最新的原生勿扰有哪些功能. 首先在屏幕下滑出来的快捷开关界面中,我们可以看到勿 ...
- Android Zenmode/DND(勿扰模式) 实现原理剖析
引言 Android手机越来越多的向着用户体验提升方面靠近,那么Zenmode就会变得越来越重要. 近年来,也有很多的新功能依赖于ZenMode去实现,也有很多专利在这个方面申请成功. 举两个简单的例 ...
- Android系统设置之勿扰模式
项目场景: 智能车载机 问题描述: 车载机使用4G流量,但客户接入的是带通话功能的sim卡,客户测试过程中遇到有人拨号,来电音量不是静音情况下,居然通了.客户提出禁止来电功能. 原因分析: 尽管系统进 ...
最新文章
- java myeclipse jar 导出问题
- R使用pROC和ggplot2包绘制ROC曲线
- 港府拟修例禁止电子烟入口及销售 保障市民健康
- centos 防火墙位置
- vue中v-for循环如何将变量带入class的属性名中
- 区块链项目开发区块链应用场景需满足3个
- oracle数据库sql查询,oracle数据库中常用经典SQL查询
- Linux下gcc与g++用法以及编写makefile
- 【C语言入门教程】4.7 指针的地址分配 - mallocl(), free()
- 报错:[Microsoft][ODBC 驱动程序管理器] 无效的字符串或缓冲区长度
- 计算机网络自顶向下方法 【第一章 计算机网络及因特网】
- BF算法及KMP算法
- python画结构图_【实战案例】五分钟!用python绘制系统架构图
- 西门子实数转整数_怎样将实数转换成整数
- 游戏原画和3D游戏建模,哪个更胜一筹?
- 当clipper遇到重复裁剪框
- int3断点指令的原理和示例
- 创新药、大协同,科天云助力信达生物全球创新研发
- 电脑没有声音怎么办?
- 记一次robotframework-ride快捷方式打不开的坑!!