Move automatic rules to main DND settings page.

Change-Id: I32b103714d4864ab32e2c85d86106dc118f9c338
Fixes: 31050255
Test: manual
This commit is contained in:
Julia Reynolds
2017-03-22 14:05:46 -04:00
parent 0ba5805455
commit e17590271f
9 changed files with 366 additions and 416 deletions

View File

@@ -727,6 +727,14 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.settings.SHORTCUT" /> <category android:name="com.android.settings.SHORTCUT" />
</intent-filter> </intent-filter>
<intent-filter android:priority="1">
<action android:name="android.settings.ZEN_MODE_AUTOMATION_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.settings.ACTION_CONDITION_PROVIDER_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS" <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.ZenModeSettings" /> android:value="com.android.settings.notification.ZenModeSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
@@ -759,25 +767,6 @@
android:value="true" /> android:value="true" />
</activity> </activity>
<activity android:name="Settings$ZenModeAutomationSettingsActivity"
android:label="@string/zen_mode_automation_settings_title"
android:icon="@drawable/ic_settings_notifications"
android:exported="true"
android:taskAffinity="">
<intent-filter android:priority="1">
<action android:name="android.settings.ZEN_MODE_AUTOMATION_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.settings.ACTION_CONDITION_PROVIDER_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.ZenModeAutomationSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
<activity android:name="Settings$ZenModeAutomationSuggestionActivity" <activity android:name="Settings$ZenModeAutomationSuggestionActivity"
android:label="@string/zen_mode_automation_settings_title" android:label="@string/zen_mode_automation_settings_title"
android:icon="@drawable/ic_settings_notifications" android:icon="@drawable/ic_settings_notifications"

View File

@@ -6418,7 +6418,7 @@
<!-- Do not disturb: Title for the Priority interruptions option and associated settings page. [CHAR LIMIT=30] --> <!-- Do not disturb: Title for the Priority interruptions option and associated settings page. [CHAR LIMIT=30] -->
<string name="zen_mode_priority_settings_title">Priority only allows</string> <string name="zen_mode_priority_settings_title">Priority only allows</string>
<!-- Do not disturb: Title for the zen mode automation option and associated settings page. [CHAR LIMIT=30] --> <!-- Do not disturb: Title for the zen mode automation listing. [CHAR LIMIT=30] -->
<string name="zen_mode_automation_settings_title">Automatic rules</string> <string name="zen_mode_automation_settings_title">Automatic rules</string>
<!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=30] --> <!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=30] -->

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_settings"
android:title="@string/zen_mode_automation_settings_title" >
<!-- Rules added at runtime -->
</PreferenceScreen>

View File

@@ -25,15 +25,14 @@
android:title="@string/zen_mode_priority_settings_title" android:title="@string/zen_mode_priority_settings_title"
android:fragment="com.android.settings.notification.ZenModePrioritySettings" /> android:fragment="com.android.settings.notification.ZenModePrioritySettings" />
<!-- Automated rules -->
<Preference
android:key="automation_settings"
android:title="@string/zen_mode_automation_settings_title"
android:fragment="com.android.settings.notification.ZenModeAutomationSettings" />
<!-- Visual interruptions --> <!-- Visual interruptions -->
<Preference <Preference
android:key="visual_interruptions_settings" android:key="visual_interruptions_settings"
android:title="@string/zen_mode_visual_interruptions_settings_title" android:title="@string/zen_mode_visual_interruptions_settings_title"
android:fragment="com.android.settings.notification.ZenModeVisualInterruptionSettings" /> android:fragment="com.android.settings.notification.ZenModeVisualInterruptionSettings" />
<!-- Automatic rules -->
<PreferenceCategory
android:key="automatic_rules"
android:title="@string/zen_mode_automation_settings_title" />
</PreferenceScreen> </PreferenceScreen>

View File

@@ -103,7 +103,6 @@ import com.android.settings.notification.NotificationAccessSettings;
import com.android.settings.notification.NotificationStation; import com.android.settings.notification.NotificationStation;
import com.android.settings.notification.SoundSettings; import com.android.settings.notification.SoundSettings;
import com.android.settings.notification.ZenAccessSettings; import com.android.settings.notification.ZenAccessSettings;
import com.android.settings.notification.ZenModeAutomationSettings;
import com.android.settings.notification.ZenModeEventRuleSettings; import com.android.settings.notification.ZenModeEventRuleSettings;
import com.android.settings.notification.ZenModePrioritySettings; import com.android.settings.notification.ZenModePrioritySettings;
import com.android.settings.notification.ZenModeScheduleRuleSettings; import com.android.settings.notification.ZenModeScheduleRuleSettings;
@@ -207,7 +206,6 @@ public class SettingsGateway {
ApnEditor.class.getName(), ApnEditor.class.getName(),
WifiCallingSettings.class.getName(), WifiCallingSettings.class.getName(),
ZenModePrioritySettings.class.getName(), ZenModePrioritySettings.class.getName(),
ZenModeAutomationSettings.class.getName(),
ZenModeScheduleRuleSettings.class.getName(), ZenModeScheduleRuleSettings.class.getName(),
ZenModeEventRuleSettings.class.getName(), ZenModeEventRuleSettings.class.getName(),
ZenModeVisualInterruptionSettings.class.getName(), ZenModeVisualInterruptionSettings.class.getName(),

View File

@@ -1,362 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.notification;
import android.app.AlertDialog;
import android.app.AutomaticZenRule;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
import android.service.notification.ConditionProviderService;
import android.service.notification.ZenModeConfig;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.PreferenceViewHolder;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.utils.ManagedServiceSettings.Config;
import com.android.settings.utils.ZenServiceListing;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
public class ZenModeAutomationSettings extends ZenModeSettingsBase {
static final Config CONFIG = getConditionProviderConfig();
private PackageManager mPm;
private ZenServiceListing mServiceListing;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.zen_mode_automation_settings);
mPm = mContext.getPackageManager();
mServiceListing = new ZenServiceListing(mContext, CONFIG);
mServiceListing.reloadApprovedServices();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
protected void onZenModeChanged() {
// don't care
}
@Override
protected void onZenModeConfigChanged() {
updateControls();
}
@Override
public void onResume() {
super.onResume();
if (isUiRestricted()) {
return;
}
updateControls();
}
private void showAddRuleDialog() {
new ZenRuleSelectionDialog(mContext, mServiceListing) {
@Override
public void onSystemRuleSelected(ZenRuleInfo ri) {
showNameRuleDialog(ri);
}
@Override
public void onExternalRuleSelected(ZenRuleInfo ri) {
Intent intent = new Intent().setComponent(ri.configurationActivity);
startActivity(intent);
}
}.show();
}
private void showNameRuleDialog(final ZenRuleInfo ri) {
new ZenRuleNameDialog(mContext, null) {
@Override
public void onOk(String ruleName) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE_OK);
AutomaticZenRule rule = new AutomaticZenRule(ruleName, ri.serviceComponent,
ri.defaultConditionId, NotificationManager.INTERRUPTION_FILTER_PRIORITY,
true);
String savedRuleId = addZenRule(rule);
if (savedRuleId != null) {
startActivity(getRuleIntent(ri.settingsAction, null, savedRuleId));
}
}
}.show();
}
private void showDeleteRuleDialog(final String ruleId, final CharSequence ruleName) {
new AlertDialog.Builder(mContext)
.setMessage(getString(R.string.zen_mode_delete_rule_confirmation, ruleName))
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_delete_rule_button,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
removeZenRule(ruleId);
}
})
.show();
}
private Intent getRuleIntent(String settingsAction, ComponentName configurationActivity,
String ruleId) {
Intent intent = new Intent()
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(ConditionProviderService.EXTRA_RULE_ID, ruleId);
if (configurationActivity != null) {
intent.setComponent(configurationActivity);
} else {
intent.setAction(settingsAction);
}
return intent;
}
private Map.Entry<String,AutomaticZenRule>[] sortedRules() {
final Map.Entry<String,AutomaticZenRule>[] rt =
mRules.toArray(new Map.Entry[mRules.size()]);
Arrays.sort(rt, RULE_COMPARATOR);
return rt;
}
private void updateControls() {
final PreferenceScreen root = getPreferenceScreen();
root.removeAll();
final Map.Entry<String,AutomaticZenRule>[] sortedRules = sortedRules();
for (Map.Entry<String,AutomaticZenRule> sortedRule : sortedRules) {
ZenRulePreference pref = new ZenRulePreference(getPrefContext(), sortedRule);
if (pref.appExists) {
root.addPreference(pref);
}
}
final Preference p = new Preference(getPrefContext());
p.setIcon(R.drawable.ic_add);
p.setTitle(R.string.zen_mode_add_rule);
p.setPersistent(false);
p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE);
showAddRuleDialog();
return true;
}
});
root.addPreference(p);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.NOTIFICATION_ZEN_MODE_AUTOMATION;
}
private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
CharSequence providerLabel) {
final String mode = computeZenModeCaption(getResources(), rule.getInterruptionFilter());
final String ruleState = (rule == null || !rule.isEnabled())
? getString(R.string.switch_off_text)
: getString(R.string.zen_mode_rule_summary_enabled_combination, mode);
return isSystemRule ? ruleState
: getString(R.string.zen_mode_rule_summary_provider_combination,
providerLabel, ruleState);
}
private static Config getConditionProviderConfig() {
final Config c = new Config();
c.tag = TAG;
c.setting = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
c.secondarySetting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
c.intentAction = ConditionProviderService.SERVICE_INTERFACE;
c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
c.noun = "condition provider";
return c;
}
private static String computeZenModeCaption(Resources res, int zenMode) {
switch (zenMode) {
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
return res.getString(R.string.zen_mode_option_alarms);
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
return res.getString(R.string.zen_mode_option_important_interruptions);
case NotificationManager.INTERRUPTION_FILTER_NONE:
return res.getString(R.string.zen_mode_option_no_interruptions);
default:
return null;
}
}
public static ZenRuleInfo getRuleInfo(PackageManager pm, ServiceInfo si) {
if (si == null || si.metaData == null) return null;
final String ruleType = si.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE);
final ComponentName configurationActivity = getSettingsActivity(si);
if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) {
final ZenRuleInfo ri = new ZenRuleInfo();
ri.serviceComponent = new ComponentName(si.packageName, si.name);
ri.settingsAction = Settings.ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS;
ri.title = ruleType;
ri.packageName = si.packageName;
ri.configurationActivity = getSettingsActivity(si);
ri.packageLabel = si.applicationInfo.loadLabel(pm);
ri.ruleInstanceLimit =
si.metaData.getInt(ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
return ri;
}
return null;
}
private static ComponentName getSettingsActivity(ServiceInfo si) {
if (si == null || si.metaData == null) return null;
final String configurationActivity =
si.metaData.getString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY);
if (configurationActivity != null) {
return ComponentName.unflattenFromString(configurationActivity);
}
return null;
}
private static final Comparator<Map.Entry<String,AutomaticZenRule>> RULE_COMPARATOR =
new Comparator<Map.Entry<String,AutomaticZenRule>>() {
@Override
public int compare(Map.Entry<String,AutomaticZenRule> lhs,
Map.Entry<String,AutomaticZenRule> rhs) {
int byDate = Long.compare(lhs.getValue().getCreationTime(),
rhs.getValue().getCreationTime());
if (byDate != 0) {
return byDate;
} else {
return key(lhs.getValue()).compareTo(key(rhs.getValue()));
}
}
private String key(AutomaticZenRule rule) {
final int type = ZenModeConfig.isValidScheduleConditionId(rule.getConditionId()) ? 1
: ZenModeConfig.isValidEventConditionId(rule.getConditionId()) ? 2
: 3;
return type + rule.getName().toString();
}
};
private class ZenRulePreference extends Preference {
final CharSequence mName;
final String mId;
final boolean appExists;
public ZenRulePreference(Context context,
final Map.Entry<String, AutomaticZenRule> ruleEntry) {
super(context);
final AutomaticZenRule rule = ruleEntry.getValue();
mName = rule.getName();
mId = ruleEntry.getKey();
final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(
rule.getConditionId());
final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.getConditionId());
final boolean isSystemRule = isSchedule || isEvent;
try {
ApplicationInfo info = mPm.getApplicationInfo(rule.getOwner().getPackageName(), 0);
LoadIconTask task = new LoadIconTask(this);
task.execute(info);
setSummary(computeRuleSummary(rule, isSystemRule, info.loadLabel(mPm)));
} catch (PackageManager.NameNotFoundException e) {
setIcon(R.drawable.ic_label);
appExists = false;
return;
}
appExists = true;
setTitle(rule.getName());
setPersistent(false);
final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
: isEvent ? ZenModeEventRuleSettings.ACTION : "";
ServiceInfo si = mServiceListing.findService(rule.getOwner());
ComponentName settingsActivity = getSettingsActivity(si);
setIntent(getRuleIntent(action, settingsActivity, mId));
setSelectable(settingsActivity != null || isSystemRule);
setWidgetLayoutResource(R.layout.zen_rule_widget);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
View v = view.findViewById(R.id.delete_zen_rule);
if (v != null) {
v.setOnClickListener(mDeleteListener);
}
view.setDividerAllowedAbove(true);
view.setDividerAllowedBelow(true);
}
private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
showDeleteRuleDialog(mId, mName);
}
};
}
private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> {
private final WeakReference<Preference> prefReference;
public LoadIconTask(Preference pref) {
prefReference = new WeakReference<>(pref);
}
@Override
protected Drawable doInBackground(ApplicationInfo... params) {
return params[0].loadIcon(mPm);
}
@Override
protected void onPostExecute(Drawable icon) {
if (icon != null) {
final Preference pref = prefReference.get();
if (pref != null) {
pref.setIcon(icon);
}
}
}
}
}

View File

@@ -16,29 +16,56 @@
package com.android.settings.notification; package com.android.settings.notification;
import android.app.AlertDialog;
import android.app.AutomaticZenRule; import android.app.AutomaticZenRule;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.NotificationManager.Policy; import android.app.NotificationManager.Policy;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.provider.Settings;
import android.service.notification.ConditionProviderService;
import android.service.notification.ZenModeConfig;
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.PreferenceViewHolder;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
public class ZenModeSettings extends ZenModeSettingsBase { public class ZenModeSettings extends ZenModeSettingsBase {
private static final String KEY_PRIORITY_SETTINGS = "priority_settings"; private static final String KEY_PRIORITY_SETTINGS = "priority_settings";
private static final String KEY_VISUAL_SETTINGS = "visual_interruptions_settings"; private static final String KEY_VISUAL_SETTINGS = "visual_interruptions_settings";
private static final String KEY_AUTOMATIC_RULES = "automatic_rules";
static final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
private PreferenceCategory mAutomaticRules;
private Preference mPrioritySettings; private Preference mPrioritySettings;
private Preference mVisualSettings; private Preference mVisualSettings;
private Policy mPolicy; private Policy mPolicy;
private SummaryBuilder mSummaryBuilder; private SummaryBuilder mSummaryBuilder;
private PackageManager mPm;
private ZenServiceListing mServiceListing;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@@ -47,10 +74,14 @@ public class ZenModeSettings extends ZenModeSettingsBase {
addPreferencesFromResource(R.xml.zen_mode_settings); addPreferencesFromResource(R.xml.zen_mode_settings);
final PreferenceScreen root = getPreferenceScreen(); final PreferenceScreen root = getPreferenceScreen();
mAutomaticRules = (PreferenceCategory) root.findPreference(KEY_AUTOMATIC_RULES);
mPrioritySettings = root.findPreference(KEY_PRIORITY_SETTINGS); mPrioritySettings = root.findPreference(KEY_PRIORITY_SETTINGS);
mVisualSettings = root.findPreference(KEY_VISUAL_SETTINGS); mVisualSettings = root.findPreference(KEY_VISUAL_SETTINGS);
mPolicy = NotificationManager.from(mContext).getNotificationPolicy(); mPolicy = NotificationManager.from(mContext).getNotificationPolicy();
mSummaryBuilder = new SummaryBuilder(getContext()); mSummaryBuilder = new SummaryBuilder(getContext());
mPm = mContext.getPackageManager();
mServiceListing = new ZenServiceListing(mContext, CONFIG);
mServiceListing.reloadApprovedServices();
} }
@Override @Override
@@ -59,6 +90,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
if (isUiRestricted()) { if (isUiRestricted()) {
return; return;
} }
updateControls();
} }
@Override @Override
@@ -80,6 +112,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
private void updateControls() { private void updateControls() {
updatePrioritySettingsSummary(); updatePrioritySettingsSummary();
updateVisualSettingsSummary(); updateVisualSettingsSummary();
updateAutomaticRules();
} }
private void updatePrioritySettingsSummary() { private void updatePrioritySettingsSummary() {
@@ -90,11 +123,251 @@ public class ZenModeSettings extends ZenModeSettingsBase {
mVisualSettings.setSummary(mSummaryBuilder.getVisualSettingSummary(mPolicy)); mVisualSettings.setSummary(mSummaryBuilder.getVisualSettingSummary(mPolicy));
} }
private void updateAutomaticRules() {
mAutomaticRules.removeAll();
final Map.Entry<String,AutomaticZenRule>[] sortedRules = sortedRules();
for (Map.Entry<String,AutomaticZenRule> sortedRule : sortedRules) {
ZenRulePreference pref = new ZenRulePreference(getPrefContext(), sortedRule);
if (pref.appExists) {
mAutomaticRules.addPreference(pref);
}
}
final Preference p = new Preference(getPrefContext());
p.setIcon(R.drawable.ic_add);
p.setTitle(R.string.zen_mode_add_rule);
p.setPersistent(false);
p.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE);
showAddRuleDialog();
return true;
}
});
mAutomaticRules.addPreference(p);
}
private void showAddRuleDialog() {
new ZenRuleSelectionDialog(mContext, mServiceListing) {
@Override
public void onSystemRuleSelected(ZenRuleInfo ri) {
showNameRuleDialog(ri);
}
@Override
public void onExternalRuleSelected(ZenRuleInfo ri) {
Intent intent = new Intent().setComponent(ri.configurationActivity);
startActivity(intent);
}
}.show();
}
private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
CharSequence providerLabel) {
final String mode = computeZenModeCaption(getResources(), rule.getInterruptionFilter());
final String ruleState = (rule == null || !rule.isEnabled())
? getString(R.string.switch_off_text)
: getString(R.string.zen_mode_rule_summary_enabled_combination, mode);
return isSystemRule ? ruleState
: getString(R.string.zen_mode_rule_summary_provider_combination,
providerLabel, ruleState);
}
private static ManagedServiceSettings.Config getConditionProviderConfig() {
final ManagedServiceSettings.Config c = new ManagedServiceSettings.Config();
c.tag = TAG;
c.setting = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
c.secondarySetting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
c.intentAction = ConditionProviderService.SERVICE_INTERFACE;
c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
c.noun = "condition provider";
return c;
}
private static String computeZenModeCaption(Resources res, int zenMode) {
switch (zenMode) {
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
return res.getString(R.string.zen_mode_option_alarms);
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
return res.getString(R.string.zen_mode_option_important_interruptions);
case NotificationManager.INTERRUPTION_FILTER_NONE:
return res.getString(R.string.zen_mode_option_no_interruptions);
default:
return null;
}
}
public static ZenRuleInfo getRuleInfo(PackageManager pm, ServiceInfo si) {
if (si == null || si.metaData == null) return null;
final String ruleType = si.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE);
final ComponentName configurationActivity = getSettingsActivity(si);
if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) {
final ZenRuleInfo ri = new ZenRuleInfo();
ri.serviceComponent = new ComponentName(si.packageName, si.name);
ri.settingsAction = Settings.ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS;
ri.title = ruleType;
ri.packageName = si.packageName;
ri.configurationActivity = getSettingsActivity(si);
ri.packageLabel = si.applicationInfo.loadLabel(pm);
ri.ruleInstanceLimit =
si.metaData.getInt(ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
return ri;
}
return null;
}
private static ComponentName getSettingsActivity(ServiceInfo si) {
if (si == null || si.metaData == null) return null;
final String configurationActivity =
si.metaData.getString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY);
if (configurationActivity != null) {
return ComponentName.unflattenFromString(configurationActivity);
}
return null;
}
private void showNameRuleDialog(final ZenRuleInfo ri) {
new ZenRuleNameDialog(mContext, null) {
@Override
public void onOk(String ruleName) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ADD_RULE_OK);
AutomaticZenRule rule = new AutomaticZenRule(ruleName, ri.serviceComponent,
ri.defaultConditionId, NotificationManager.INTERRUPTION_FILTER_PRIORITY,
true);
String savedRuleId = addZenRule(rule);
if (savedRuleId != null) {
startActivity(getRuleIntent(ri.settingsAction, null, savedRuleId));
}
}
}.show();
}
private void showDeleteRuleDialog(final String ruleId, final CharSequence ruleName) {
new AlertDialog.Builder(mContext)
.setMessage(getString(R.string.zen_mode_delete_rule_confirmation, ruleName))
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_delete_rule_button,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
removeZenRule(ruleId);
}
})
.show();
}
private Intent getRuleIntent(String settingsAction, ComponentName configurationActivity,
String ruleId) {
Intent intent = new Intent()
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(ConditionProviderService.EXTRA_RULE_ID, ruleId);
if (configurationActivity != null) {
intent.setComponent(configurationActivity);
} else {
intent.setAction(settingsAction);
}
return intent;
}
private Map.Entry<String,AutomaticZenRule>[] sortedRules() {
final Map.Entry<String,AutomaticZenRule>[] rt =
mRules.toArray(new Map.Entry[mRules.size()]);
Arrays.sort(rt, RULE_COMPARATOR);
return rt;
}
@Override @Override
protected int getHelpResource() { protected int getHelpResource() {
return R.string.help_uri_interruptions; return R.string.help_uri_interruptions;
} }
private class ZenRulePreference extends Preference {
final CharSequence mName;
final String mId;
final boolean appExists;
public ZenRulePreference(Context context,
final Map.Entry<String, AutomaticZenRule> ruleEntry) {
super(context);
final AutomaticZenRule rule = ruleEntry.getValue();
mName = rule.getName();
mId = ruleEntry.getKey();
final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(
rule.getConditionId());
final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.getConditionId());
final boolean isSystemRule = isSchedule || isEvent;
try {
ApplicationInfo info = mPm.getApplicationInfo(rule.getOwner().getPackageName(), 0);
LoadIconTask task = new LoadIconTask(this);
task.execute(info);
setSummary(computeRuleSummary(rule, isSystemRule, info.loadLabel(mPm)));
} catch (PackageManager.NameNotFoundException e) {
setIcon(R.drawable.ic_label);
appExists = false;
return;
}
appExists = true;
setTitle(rule.getName());
setPersistent(false);
final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
: isEvent ? ZenModeEventRuleSettings.ACTION : "";
ServiceInfo si = mServiceListing.findService(rule.getOwner());
ComponentName settingsActivity = getSettingsActivity(si);
setIntent(getRuleIntent(action, settingsActivity, mId));
setSelectable(settingsActivity != null || isSystemRule);
setWidgetLayoutResource(R.layout.zen_rule_widget);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
View v = view.findViewById(R.id.delete_zen_rule);
if (v != null) {
v.setOnClickListener(mDeleteListener);
}
}
private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
showDeleteRuleDialog(mId, mName);
}
};
}
private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> {
private final WeakReference<Preference> prefReference;
public LoadIconTask(Preference pref) {
prefReference = new WeakReference<>(pref);
}
@Override
protected Drawable doInBackground(ApplicationInfo... params) {
return params[0].loadIcon(mPm);
}
@Override
protected void onPostExecute(Drawable icon) {
if (icon != null) {
final Preference pref = prefReference.get();
if (pref != null) {
pref.setIcon(icon);
}
}
}
}
public static class SummaryBuilder { public static class SummaryBuilder {
private Context mContext; private Context mContext;
@@ -180,6 +453,29 @@ public class ZenModeSettings extends ZenModeSettingsBase {
private boolean isEffectSuppressed(Policy policy, int effect) { private boolean isEffectSuppressed(Policy policy, int effect) {
return (policy.suppressedVisualEffects & effect) != 0; return (policy.suppressedVisualEffects & effect) != 0;
} }
}
private static final Comparator<Map.Entry<String,AutomaticZenRule>> RULE_COMPARATOR =
new Comparator<Map.Entry<String,AutomaticZenRule>>() {
@Override
public int compare(Map.Entry<String,AutomaticZenRule> lhs,
Map.Entry<String,AutomaticZenRule> rhs) {
int byDate = Long.compare(lhs.getValue().getCreationTime(),
rhs.getValue().getCreationTime());
if (byDate != 0) {
return byDate;
} else {
return key(lhs.getValue()).compareTo(key(rhs.getValue()));
} }
} }
private String key(AutomaticZenRule rule) {
final int type = ZenModeConfig.isValidScheduleConditionId(rule.getConditionId())
? 1
: ZenModeConfig.isValidEventConditionId(rule.getConditionId())
? 2
: 3;
return type + rule.getName().toString();
}
};
}

View File

@@ -169,7 +169,7 @@ public abstract class ZenRuleSelectionDialog {
if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size()); if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size());
Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR); Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR);
for (ServiceInfo serviceInfo : services) { for (ServiceInfo serviceInfo : services) {
final ZenRuleInfo ri = ZenModeAutomationSettings.getRuleInfo(mPm, serviceInfo); final ZenRuleInfo ri = ZenModeSettings.getRuleInfo(mPm, serviceInfo);
if (ri != null && ri.configurationActivity != null if (ri != null && ri.configurationActivity != null
&& mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName) && mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName)
&& (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit && (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit

View File

@@ -0,0 +1,53 @@
package com.android.settings.notification;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ZenModeSettingsIntegrationTest {
private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
private Context mContext;
private UiDevice mUiDevice;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mUiDevice.wakeUp();
mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
}
@Test
public void testAutomaticRulesAppear() {
launchZenSettings();
onView(withText("Automatic rules")).check(matches(isDisplayed()));
onView(withText("Weekend")).check(matches(isDisplayed()));
onView(withText("Add more")).check(matches(isDisplayed())).perform(click());
onView(withText("Choose rule type")).check(matches(isDisplayed()));
}
private void launchZenSettings() {
Intent settingsIntent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS)
.setPackage(mContext.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(settingsIntent);
}
}