Move automatic rules to main DND settings page.
Change-Id: I32b103714d4864ab32e2c85d86106dc118f9c338 Fixes: 31050255 Test: manual
This commit is contained in:
@@ -727,6 +727,14 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="com.android.settings.SHORTCUT" />
|
||||
</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"
|
||||
android:value="com.android.settings.notification.ZenModeSettings" />
|
||||
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
|
||||
@@ -759,25 +767,6 @@
|
||||
android:value="true" />
|
||||
</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"
|
||||
android:label="@string/zen_mode_automation_settings_title"
|
||||
android:icon="@drawable/ic_settings_notifications"
|
||||
|
@@ -6418,7 +6418,7 @@
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=30] -->
|
||||
|
@@ -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>
|
@@ -25,15 +25,14 @@
|
||||
android:title="@string/zen_mode_priority_settings_title"
|
||||
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 -->
|
||||
<Preference
|
||||
android:key="visual_interruptions_settings"
|
||||
android:title="@string/zen_mode_visual_interruptions_settings_title"
|
||||
android:fragment="com.android.settings.notification.ZenModeVisualInterruptionSettings" />
|
||||
|
||||
<!-- Automatic rules -->
|
||||
<PreferenceCategory
|
||||
android:key="automatic_rules"
|
||||
android:title="@string/zen_mode_automation_settings_title" />
|
||||
</PreferenceScreen>
|
||||
|
@@ -103,7 +103,6 @@ import com.android.settings.notification.NotificationAccessSettings;
|
||||
import com.android.settings.notification.NotificationStation;
|
||||
import com.android.settings.notification.SoundSettings;
|
||||
import com.android.settings.notification.ZenAccessSettings;
|
||||
import com.android.settings.notification.ZenModeAutomationSettings;
|
||||
import com.android.settings.notification.ZenModeEventRuleSettings;
|
||||
import com.android.settings.notification.ZenModePrioritySettings;
|
||||
import com.android.settings.notification.ZenModeScheduleRuleSettings;
|
||||
@@ -207,7 +206,6 @@ public class SettingsGateway {
|
||||
ApnEditor.class.getName(),
|
||||
WifiCallingSettings.class.getName(),
|
||||
ZenModePrioritySettings.class.getName(),
|
||||
ZenModeAutomationSettings.class.getName(),
|
||||
ZenModeScheduleRuleSettings.class.getName(),
|
||||
ZenModeEventRuleSettings.class.getName(),
|
||||
ZenModeVisualInterruptionSettings.class.getName(),
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -16,29 +16,56 @@
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AutomaticZenRule;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.NotificationManager.Policy;
|
||||
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 com.android.settings.utils.ManagedServiceSettings;
|
||||
import com.android.settings.utils.ZenServiceListing;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceCategory;
|
||||
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 java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
private static final String KEY_PRIORITY_SETTINGS = "priority_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 mVisualSettings;
|
||||
private Policy mPolicy;
|
||||
private SummaryBuilder mSummaryBuilder;
|
||||
private PackageManager mPm;
|
||||
private ZenServiceListing mServiceListing;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -47,10 +74,14 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
addPreferencesFromResource(R.xml.zen_mode_settings);
|
||||
final PreferenceScreen root = getPreferenceScreen();
|
||||
|
||||
mAutomaticRules = (PreferenceCategory) root.findPreference(KEY_AUTOMATIC_RULES);
|
||||
mPrioritySettings = root.findPreference(KEY_PRIORITY_SETTINGS);
|
||||
mVisualSettings = root.findPreference(KEY_VISUAL_SETTINGS);
|
||||
mPolicy = NotificationManager.from(mContext).getNotificationPolicy();
|
||||
mSummaryBuilder = new SummaryBuilder(getContext());
|
||||
mPm = mContext.getPackageManager();
|
||||
mServiceListing = new ZenServiceListing(mContext, CONFIG);
|
||||
mServiceListing.reloadApprovedServices();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,6 +90,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
if (isUiRestricted()) {
|
||||
return;
|
||||
}
|
||||
updateControls();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,6 +112,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
private void updateControls() {
|
||||
updatePrioritySettingsSummary();
|
||||
updateVisualSettingsSummary();
|
||||
updateAutomaticRules();
|
||||
}
|
||||
|
||||
private void updatePrioritySettingsSummary() {
|
||||
@@ -90,11 +123,251 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
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
|
||||
protected int getHelpResource() {
|
||||
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 {
|
||||
|
||||
private Context mContext;
|
||||
@@ -180,6 +453,29 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
private boolean isEffectSuppressed(Policy policy, int effect) {
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -169,7 +169,7 @@ public abstract class ZenRuleSelectionDialog {
|
||||
if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size());
|
||||
Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR);
|
||||
for (ServiceInfo serviceInfo : services) {
|
||||
final ZenRuleInfo ri = ZenModeAutomationSettings.getRuleInfo(mPm, serviceInfo);
|
||||
final ZenRuleInfo ri = ZenModeSettings.getRuleInfo(mPm, serviceInfo);
|
||||
if (ri != null && ri.configurationActivity != null
|
||||
&& mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName)
|
||||
&& (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user