勿扰模式代码结构简析
来源:互联网 发布:黑色玫瑰是什么软件 编辑:程序博客网 时间:2024/06/14 17:56
勿扰模式是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 勿扰模式代码结构简析
- 开发模式、代码分层结构
- Extjs MVC模式前台代码组织结构
- Android 开发 代码结构规范 MVC模式
- 结构型模式——装饰器模式 示例代码
- 代码结构
- 代码结构
- 代码结构
- 结构模式
- 【JS 设计模式 】用组合模式来实现树形导航--代码结构思路分析(一)
- 代码结构-可维护性代码
- 结构模式:Composite模式
- 组合模式 - 结构模式
- 设计模式-结构模式
- 结构模式->外观模式
- 结构模式->组合模式
- 结构模式->适配器模式
- python opencv入门 直方图计算、绘制、分析(22)
- Angular2 VS Angular4 深度对比:特性、性能
- List one 75 个词按原书顺序男哥的free style
- oracle一次插入多条记录
- 全文检索:分词,索引
- 勿扰模式代码结构简析
- mysql主从复制(超简单)
- 电商系统中的商品模型的分析与设计
- Mysql实现数据的不重复写入(insert if not exists)以及新问题:ID自增不连续的解答
- InfluxDB+Grafana整合及metrics没有显示问题
- hdu1293(dp大整数)
- IO流——File类
- 二叉树
- js来读写cookie操作