标签: android源码
2017-02-08 11:04 1257人阅读 收藏 举报
Android系统在5.1系统开始增加勿扰模式,渐渐的有着取代静音模式的趋势,最新的系统已经更新到7.1.1,我们来看一下最新的原生勿扰有哪些功能。
首先在屏幕下滑出来的快捷开关界面中,我们可以看到勿扰模式。在这里如果我们点击开启勿扰模式,会出现三种勿扰模式供选择。
(1)完全静音:这会阻止所有声音和振动(包括闹钟、音乐、视频和游戏)打扰您。您仍然可以拨打电话。这里面也同事可以选择定时或者直到自己将其关闭。
(2)仅限闹钟:这里面除了闹钟之外,别的都会阻止通知。
(3)仅限优先打扰:您不会受声音和振动的打扰,但闹钟、提醒、活动和您指定的来电者除外。
勿扰模式在设置中的位置,在声音设置下。进入勿扰的设置中,我们可以看到有如下三项设置:
(1)仅允许优先打扰内容:设置在勿扰处于仅限优先打扰的时候,这种情况下,哪些联系人或者提醒等可以通知您。
(2)自动规则:可以自定义多个自动规则,这些规则指哪些活动或者时间内自动开启勿扰模式。同时可以开启闹钟响铃时结束勿扰模式。
(3)屏蔽视觉打扰:处于勿扰模式时的两种更优化方案的开关
- 屏幕开启时屏蔽:禁止在勿扰模式下被静音的通知在屏幕上短暂显示或弹出
- 屏幕关闭时屏蔽:禁止在勿扰模式下被静音的通知开启屏幕
以上都是从手机上直接可以看出的原生系统的勿扰模式的功能。接下来从代码层面简单分析一下:首先勿扰模式的功能入口在SoundSettings.java中,布局文件局部如下:Settings\res\xml\sound_settings.xml
-
- <com.android.settingslib.RestrictedPreference
- android:key="zen_mode"
- android:title="@string/zen_mode_settings_title"
- settings:useAdminDisabledSummary="true"
- settings:keywords="@string/keywords_sounds_and_notifications_interruptions"
- android:fragment="com.android.settings.notification.ZenModeSettings" />
点击勿扰选项进入ZenModeSettings中。ZenModeSettings中的布局文件为zen_mode_settings,如下:
Settings\res\xml\zen_mode_settings.xml
- <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:key="zen_mode_settings"
- android:title="@string/zen_mode_settings_title" >
-
-
- <PreferenceScreen
- android:key="priority_settings"
- android:title="@string/zen_mode_priority_settings_title"
- android:fragment="com.android.settings.notification.ZenModePrioritySettings" />
-
-
- <PreferenceScreen
- android:key="automation_settings"
- android:title="@string/zen_mode_automation_settings_title"
- android:fragment="com.android.settings.notification.ZenModeAutomationSettings" />
-
-
- <PreferenceScreen
- android:key="visual_interruptions_settings"
- android:title="@string/zen_mode_visual_interruptions_settings_title"
- android:fragment="com.android.settings.notification.ZenModeVisualInterruptionSettings" />
- </PreferenceScreen>
上面的布局文件和我们从手机上看到的勿扰设置界面一样。我们可以看出ZenModePrioritySettings 、ZenModeAutomationSettings 、ZenModeVisualInterruptionSettings分别对应着仅允许优先打扰内容、自动规则、屏蔽视觉打扰三种页面。
ZenModeSettings、ZenModePrioritySettings、ZenModeAutomationSettings 、ZenModeVisualInterruptionSettings都继承于ZenModeSettingsBase。我们来分别看一下这些类。
ZenModeSettings这个类,我们从代码中可以看出它只是三项设置界面的入口,以及对勿扰的更新做一些界面的显示工作。如下代码:
Settings/src/com/android/settings/notification/ZenModeSettings.java
- @Override
- protected void onZenModeChanged() {
- updateControls();
- }
-
- @Override
- protected void onZenModeConfigChanged() {
- mPolicy = NotificationManager.from(mContext).getNotificationPolicy();
- updateControls();
- }
-
- private void updateControls() {
- updatePrioritySettingsSummary();
- updateVisualSettingsSummary();
- }
-
- private void updatePrioritySettingsSummary() {
- String s = getResources().getString(R.string.zen_mode_alarms);
- s = appendLowercase(s, isCategoryEnabled(mPolicy, Policy.PRIORITY_CATEGORY_REMINDERS),
- R.string.zen_mode_reminders);
- s = appendLowercase(s, isCategoryEnabled(mPolicy, Policy.PRIORITY_CATEGORY_EVENTS),
- R.string.zen_mode_events);
- if (isCategoryEnabled(mPolicy, Policy.PRIORITY_CATEGORY_MESSAGES)) {
- if (mPolicy.priorityMessageSenders == Policy.PRIORITY_SENDERS_ANY) {
- s = appendLowercase(s, true, R.string.zen_mode_all_messages);
- } else {
- s = appendLowercase(s, true, R.string.zen_mode_selected_messages);
- }
- }
- if (isCategoryEnabled(mPolicy, Policy.PRIORITY_CATEGORY_CALLS)) {
- if (mPolicy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) {
- s = appendLowercase(s, true, R.string.zen_mode_all_callers);
- } else {
- s = appendLowercase(s, true, R.string.zen_mode_selected_callers);
- }
- } else if (isCategoryEnabled(mPolicy, Policy.PRIORITY_CATEGORY_REPEAT_CALLERS)) {
- s = appendLowercase(s, true, R.string.zen_mode_repeat_callers);
- }
- mPrioritySettings.setSummary(s);
- }
-
- private void updateVisualSettingsSummary() {
- String s = getString(R.string.zen_mode_all_visual_interruptions);
- if (isEffectSuppressed(Policy.SUPPRESSED_EFFECT_SCREEN_ON)
- && isEffectSuppressed(Policy.SUPPRESSED_EFFECT_SCREEN_OFF)) {
- s = getString(R.string.zen_mode_no_visual_interruptions);
- } else if (isEffectSuppressed(Policy.SUPPRESSED_EFFECT_SCREEN_ON)) {
- s = getString(R.string.zen_mode_screen_on_visual_interruptions);
- } else if (isEffectSuppressed(Policy.SUPPRESSED_EFFECT_SCREEN_OFF)) {
- s = getString(R.string.zen_mode_screen_off_visual_interruptions);
- }
- mVisualSettings.setSummary(s);
- }
我们再看ZenModePrioritySettings类,首先它负责自定义优先打扰的内容,其中包括闹钟、提醒、活动、消息、通话(仅限来自联系人)、重复来电者(如果同一个人在15分钟内第二次来电,则允许显示通知)。这面也仅是一些开关,将最后的更改用NotificationManager.from(mContext).setNotificationPolicy(mPolicy);进行保存,其中也只有消息和通话需要选择,我们来看一下通话的设置以及保存,其余的类似:Settings/src/com/android/settings/notification/ZenModePrioritySettings.java
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.zen_mode_priority_settings);
- final PreferenceScreen root = getPreferenceScreen();
-
- mPolicy = NotificationManager.from(mContext).getNotificationPolicy();
-
- ...
-
- mCalls = (DropDownPreference) root.findPreference(KEY_CALLS);
- addSources(mCalls);
- mCalls.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (mDisableListeners) return false;
- final int val = Integer.parseInt((String) newValue);
- final boolean allowCalls = val != SOURCE_NONE;
- final int allowCallsFrom = val == SOURCE_NONE ? mPolicy.priorityCallSenders : val;
- MetricsLogger.action(mContext, MetricsEvent.ACTION_ZEN_ALLOW_CALLS, val);
- if (DEBUG) Log.d(TAG, "onPrefChange allowCalls=" + allowCalls
- + " allowCallsFrom=" + ZenModeConfig.sourceToString(allowCallsFrom));
- savePolicy(getNewPriorityCategories(allowCalls, Policy.PRIORITY_CATEGORY_CALLS),
- allowCallsFrom, mPolicy.priorityMessageSenders,
- mPolicy.suppressedVisualEffects);
- return true;
- }
- });
-
- ...
-
- updateControls();
- }
-
- private void updateControls() {
- mDisableListeners = true;
- if (mCalls != null) {
- mCalls.setValue(Integer.toString(
- isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS)
- ? mPolicy.priorityCallSenders : SOURCE_NONE));
- }
- mMessages.setValue(Integer.toString(
- isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MESSAGES)
- ? mPolicy.priorityMessageSenders : SOURCE_NONE));
- mReminders.setChecked(isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REMINDERS));
- mEvents.setChecked(isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_EVENTS));
- mRepeatCallers.setChecked(
- isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS));
- mRepeatCallers.setVisible(!isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS)
- || mPolicy.priorityCallSenders != Policy.PRIORITY_SENDERS_ANY);
- mDisableListeners = false;
- }
-
- private void savePolicy(int priorityCategories, int priorityCallSenders,
- int priorityMessageSenders, int suppressedVisualEffects) {
- mPolicy = new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
- suppressedVisualEffects);
- NotificationManager.from(mContext).setNotificationPolicy(mPolicy);
- }
ZenModeVisualInterruptionSettings和ZenModePrioritySettings类似,只是换成了屏幕开启时屏蔽和屏幕关闭时屏蔽两个开关,所以就不分析了。我们看ZenModeAutomationSettings这个稍微不同的类。
在ZenModeSettingsBase中有一个mRules的集合,存储着用户自己定义的AutomaticZenRule,而mRules的值是NotificationManager中获取的的。也就是这里规则的维护存储也还是在NotificationManager中,如下代码。
Settings/src/com/android/settings/notification/ZenModeSettingsBase.java
- abstract public class ZenModeSettingsBase extends RestrictedSettingsFragment {
- ...
-
- protected Context mContext;
- protected Set<Map.Entry<String, AutomaticZenRule>> mRules;
-
- ...
-
- private void updateZenMode(boolean fireChanged) {
- final int zenMode = Settings.Global.getInt(getContentResolver(), Global.ZEN_MODE, mZenMode);
- if (zenMode == mZenMode) return;
- mZenMode = zenMode;
- if (DEBUG) Log.d(TAG, "updateZenMode mZenMode=" + mZenMode);
- if (fireChanged) {
- onZenModeChanged();
- }
- }
-
- protected String addZenRule(AutomaticZenRule rule) {
- try {
- String id = NotificationManager.from(mContext).addAutomaticZenRule(rule);
- final AutomaticZenRule savedRule =
- NotificationManager.from(mContext).getAutomaticZenRule(id);
- maybeRefreshRules(savedRule != null, true);
- return id;
- } catch (Exception e) {
- return null;
- }
- }
-
- protected boolean setZenRule(String id, AutomaticZenRule rule) {
- final boolean success =
- NotificationManager.from(mContext).updateAutomaticZenRule(id, rule);
- maybeRefreshRules(success, true);
- return success;
- }
-
- protected boolean removeZenRule(String id) {
- final boolean success =
- NotificationManager.from(mContext).removeAutomaticZenRule(id);
- maybeRefreshRules(success, true);
- return success;
- }
-
- protected void maybeRefreshRules(boolean success, boolean fireChanged) {
- if (success) {
- mRules = getZenModeRules();
- if (DEBUG) Log.d(TAG, "Refreshed mRules=" + mRules);
- if (fireChanged) {
- onZenModeConfigChanged();
- }
- }
- }
-
- protected void setZenMode(int zenMode, Uri conditionId) {
- NotificationManager.from(mContext).setZenMode(zenMode, conditionId, TAG);
- }
-
- private Set<Map.Entry<String, AutomaticZenRule>> getZenModeRules() {
- Map<String, AutomaticZenRule> ruleMap
- = NotificationManager.from(mContext).getAutomaticZenRules();
- return ruleMap.entrySet();
- }
-
- ...
- }
知道上面的东西,ZenModeAutomationSettings就简单多了,就是mRules列表的展示,以及添加删除等操作。只是这里面添加可以选择两种模式,分别是活动规则和时间规则。分别对应的类是ZenModeEventRuleSettings和ZenModeScheduleRuleSettings,他们都继承自ZenModeRuleSettingsBase。这里ZenModeAutomationSettings虽然代码很多,但都是各种弹出框的操作,就不分析了。主要看看活动规则和时间规则这两个里面分别又有哪些操作吧。
时间规则的列表,分别有规则名称、星期几、开始时间、结束时间、勿扰、闹钟响铃时间可覆盖结束时间(在所设结束时间或下一次闹钟响铃时(两者选其先)停止)。由private ScheduleInfo mSchedule;中来存储着时间规则的一些数据。
活动规则的页面的列表,分别是名字、在以下日历活动期间、回复内容如下的活动、勿扰。由private EventInfo mEvent;中来存储着时间规则的一些数据。以上两个规则里面其余都只是进行一些修改操作。这些操作最后的修改的数据都会通过调用ZenModeRuleSettingsBase里面的updateRule()方法保存到NotificationManager里。代码如下:
Settings/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
- mStart = new TimePickerPreference(getPrefContext(), mgr);
- mStart.setKey(KEY_START_TIME);
- mStart.setTitle(R.string.zen_mode_start_time);
- mStart.setCallback(new TimePickerPreference.Callback() {
- @Override
- public boolean onSetTime(final int hour, final int minute) {
- if (mDisableListeners) return true;
- if (!ZenModeConfig.isValidHour(hour)) return false;
- if (!ZenModeConfig.isValidMinute(minute)) return false;
- if (hour == mSchedule.startHour && minute == mSchedule.startMinute) {
- return true;
- }
- if (DEBUG) Log.d(TAG, "onPrefChange start h=" + hour + " m=" + minute);
- mSchedule.startHour = hour;
- mSchedule.startMinute = minute;
- updateRule(ZenModeConfig.toScheduleConditionId(mSchedule));
- return true;
- }
- });
Settings/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
- protected void updateRule(Uri newConditionId) {
- mRule.setConditionId(newConditionId);
- setZenRule(mId, mRule);
- }
-
- protected boolean setZenRule(String id, AutomaticZenRule rule) {
- final boolean success =
- NotificationManager.from(mContext).updateAutomaticZenRule(id, rule);
- maybeRefreshRules(success, true);
- return success;
- }
自此所有在Setting里面的勿扰模式的代码分析结束了,综上可知,Settings模块中勿扰只是一个界面的展示,其数据都放在NotificationManager进行管理操作。