Updates to automatic rule listing page for 3P rules.
Show the provider app icon and name; allow deletion from listing page; remove the rule summary for consistency. Bug: 22977552 Change-Id: Ib71832fa4ff64b7321ade39f9964ac52cee6c643
This commit is contained in:
32
res/layout/zen_rule_widget.xml
Normal file
32
res/layout/zen_rule_widget.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/delete_zen_rule"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:paddingStart="16dip"
|
||||||
|
android:paddingEnd="16dip"
|
||||||
|
android:src="@drawable/ic_menu_delete"
|
||||||
|
android:contentDescription="@string/zen_mode_delete_rule"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="?android:attr/selectableItemBackground" />
|
||||||
|
</LinearLayout>
|
@@ -6272,7 +6272,10 @@
|
|||||||
<string name="zen_mode_rule_not_found_text">Rule not found.</string>
|
<string name="zen_mode_rule_not_found_text">Rule not found.</string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=40] Zen mode settings: Rule summary template (when enabled) -->
|
<!-- [CHAR LIMIT=40] Zen mode settings: Rule summary template (when enabled) -->
|
||||||
<string name="zen_mode_rule_summary_combination"><xliff:g id="description" example="Sun - Thu">%1$s</xliff:g> / <xliff:g id="mode" example="Alarms only">%2$s</xliff:g></string>
|
<string name="zen_mode_rule_summary_enabled_combination">On / <xliff:g id="mode" example="Alarms only">%1$s</xliff:g></string>
|
||||||
|
|
||||||
|
<!-- [CHAR LIMIT=40] Zen mode settings: Third party Rule summary template -->
|
||||||
|
<string name="zen_mode_rule_summary_provider_combination"><xliff:g id="package" example="Condition Provider App">%1$s</xliff:g>\n<xliff:g id="summary" example="On / Alarms only">%2$s</xliff:g></string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=40] Zen mode settings: Time-based rule days option title -->
|
<!-- [CHAR LIMIT=40] Zen mode settings: Time-based rule days option title -->
|
||||||
<string name="zen_mode_schedule_rule_days">Days</string>
|
<string name="zen_mode_schedule_rule_days">Days</string>
|
||||||
|
@@ -16,14 +16,18 @@
|
|||||||
|
|
||||||
package com.android.settings.notification;
|
package com.android.settings.notification;
|
||||||
|
|
||||||
import static android.service.notification.ZenModeConfig.ALL_DAYS;
|
import android.app.AlertDialog;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.Preference.OnPreferenceClickListener;
|
import android.preference.Preference.OnPreferenceClickListener;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
@@ -31,33 +35,27 @@ import android.provider.Settings;
|
|||||||
import android.provider.Settings.Global;
|
import android.provider.Settings.Global;
|
||||||
import android.service.notification.ConditionProviderService;
|
import android.service.notification.ConditionProviderService;
|
||||||
import android.service.notification.ZenModeConfig;
|
import android.service.notification.ZenModeConfig;
|
||||||
import android.service.notification.ZenModeConfig.EventInfo;
|
|
||||||
import android.service.notification.ZenModeConfig.ScheduleInfo;
|
|
||||||
import android.service.notification.ZenModeConfig.ZenRule;
|
import android.service.notification.ZenModeConfig.ZenRule;
|
||||||
import android.text.format.DateFormat;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.notification.ManagedServiceSettings.Config;
|
import com.android.settings.notification.ManagedServiceSettings.Config;
|
||||||
import com.android.settings.notification.ZenModeEventRuleSettings.CalendarInfo;
|
|
||||||
import com.android.settings.notification.ZenRuleNameDialog.RuleInfo;
|
import com.android.settings.notification.ZenRuleNameDialog.RuleInfo;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
||||||
|
|
||||||
static final Config CONFIG = getConditionProviderConfig();
|
static final Config CONFIG = getConditionProviderConfig();
|
||||||
|
|
||||||
// per-instance to ensure we're always using the current locale
|
private PackageManager mPm;
|
||||||
private final SimpleDateFormat mDayFormat = new SimpleDateFormat("EEE");
|
|
||||||
private final Calendar mCalendar = Calendar.getInstance();
|
|
||||||
|
|
||||||
private ServiceListing mServiceListing;
|
private ServiceListing mServiceListing;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,6 +66,7 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
|||||||
mServiceListing.addCallback(mServiceListingCallback);
|
mServiceListing.addCallback(mServiceListingCallback);
|
||||||
mServiceListing.reload();
|
mServiceListing.reload();
|
||||||
mServiceListing.setListening(true);
|
mServiceListing.setListening(true);
|
||||||
|
mPm = mContext.getPackageManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -114,6 +113,22 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
|||||||
}.show();
|
}.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showDeleteRuleDialog(final String ruleName, final String ruleId) {
|
||||||
|
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) {
|
||||||
|
MetricsLogger.action(mContext, MetricsLogger.ACTION_ZEN_DELETE_RULE_OK);
|
||||||
|
mConfig.automaticRules.remove(ruleId);
|
||||||
|
setZenModeConfig(mConfig);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
private void showRule(String settingsAction, ComponentName configurationActivity,
|
private void showRule(String settingsAction, ComponentName configurationActivity,
|
||||||
String ruleId, String ruleName) {
|
String ruleId, String ruleName) {
|
||||||
if (DEBUG) Log.d(TAG, "showRule " + ruleId + " name=" + ruleName);
|
if (DEBUG) Log.d(TAG, "showRule " + ruleId + " name=" + ruleName);
|
||||||
@@ -142,26 +157,7 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
|||||||
for (int i = 0; i < sortedRules.length; i++) {
|
for (int i = 0; i < sortedRules.length; i++) {
|
||||||
final String id = sortedRules[i].id;
|
final String id = sortedRules[i].id;
|
||||||
final ZenRule rule = sortedRules[i].rule;
|
final ZenRule rule = sortedRules[i].rule;
|
||||||
final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(rule.conditionId);
|
root.addPreference(new ZenRulePreference(mContext, rule, id));
|
||||||
final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.conditionId);
|
|
||||||
final Preference p = new Preference(mContext);
|
|
||||||
p.setIcon(isSchedule ? R.drawable.ic_schedule
|
|
||||||
: isEvent ? R.drawable.ic_event
|
|
||||||
: R.drawable.ic_label);
|
|
||||||
p.setTitle(rule.name);
|
|
||||||
p.setSummary(computeRuleSummary(rule));
|
|
||||||
p.setPersistent(false);
|
|
||||||
p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
|
||||||
final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
|
|
||||||
: isEvent ? ZenModeEventRuleSettings.ACTION
|
|
||||||
: ZenModeExternalRuleSettings.ACTION;
|
|
||||||
showRule(action, null, id, rule.name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
root.addPreference(p);
|
|
||||||
}
|
}
|
||||||
final Preference p = new Preference(mContext);
|
final Preference p = new Preference(mContext);
|
||||||
p.setIcon(R.drawable.ic_add);
|
p.setIcon(R.drawable.ic_add);
|
||||||
@@ -183,96 +179,16 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
|||||||
return MetricsLogger.NOTIFICATION_ZEN_MODE_AUTOMATION;
|
return MetricsLogger.NOTIFICATION_ZEN_MODE_AUTOMATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String computeRuleSummary(ZenRule rule) {
|
private String computeRuleSummary(ZenRule rule, boolean isSystemRule,
|
||||||
if (rule == null || !rule.enabled) return getString(R.string.switch_off_text);
|
CharSequence providerLabel) {
|
||||||
final String mode = computeZenModeCaption(getResources(), rule.zenMode);
|
final String mode = computeZenModeCaption(getResources(), rule.zenMode);
|
||||||
String summary = getString(R.string.switch_on_text);
|
final String ruleState = (rule == null || !rule.enabled)
|
||||||
final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(rule.conditionId);
|
? getString(R.string.switch_off_text)
|
||||||
final EventInfo event = ZenModeConfig.tryParseEventConditionId(rule.conditionId);
|
: getString(R.string.zen_mode_rule_summary_enabled_combination, mode);
|
||||||
if (schedule != null) {
|
|
||||||
summary = computeScheduleRuleSummary(schedule);
|
|
||||||
} else if (event != null) {
|
|
||||||
summary = computeEventRuleSummary(event);
|
|
||||||
}
|
|
||||||
return getString(R.string.zen_mode_rule_summary_combination, summary, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String computeScheduleRuleSummary(ScheduleInfo schedule) {
|
return isSystemRule ? ruleState
|
||||||
final String days = computeContiguousDayRanges(schedule.days);
|
: getString(R.string.zen_mode_rule_summary_provider_combination,
|
||||||
final String start = getTime(schedule.startHour, schedule.startMinute);
|
providerLabel, ruleState);
|
||||||
final String end = getTime(schedule.endHour, schedule.endMinute);
|
|
||||||
final String time = getString(R.string.summary_range_verbal_combination, start, end);
|
|
||||||
return getString(R.string.zen_mode_rule_summary_combination, days, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String computeEventRuleSummary(EventInfo event) {
|
|
||||||
final String calendar = getString(R.string.zen_mode_event_rule_summary_calendar_template,
|
|
||||||
computeCalendarName(event));
|
|
||||||
final String reply = getString(R.string.zen_mode_event_rule_summary_reply_template,
|
|
||||||
getString(computeReply(event)));
|
|
||||||
return getString(R.string.zen_mode_rule_summary_combination, calendar, reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String computeCalendarName(EventInfo event) {
|
|
||||||
return event.calendar != null ? event.calendar
|
|
||||||
: getString(R.string.zen_mode_event_rule_summary_any_calendar);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int computeReply(EventInfo event) {
|
|
||||||
switch (event.reply) {
|
|
||||||
case EventInfo.REPLY_ANY_EXCEPT_NO:
|
|
||||||
return R.string.zen_mode_event_rule_reply_any_except_no;
|
|
||||||
case EventInfo.REPLY_YES:
|
|
||||||
return R.string.zen_mode_event_rule_reply_yes;
|
|
||||||
case EventInfo.REPLY_YES_OR_MAYBE:
|
|
||||||
return R.string.zen_mode_event_rule_reply_yes_or_maybe;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Bad reply: " + event.reply);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTime(int hour, int minute) {
|
|
||||||
mCalendar.set(Calendar.HOUR_OF_DAY, hour);
|
|
||||||
mCalendar.set(Calendar.MINUTE, minute);
|
|
||||||
return DateFormat.getTimeFormat(mContext).format(mCalendar.getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String computeContiguousDayRanges(int[] days) {
|
|
||||||
final TreeSet<Integer> daySet = new TreeSet<>();
|
|
||||||
for (int i = 0; days != null && i < days.length; i++) {
|
|
||||||
daySet.add(days[i]);
|
|
||||||
}
|
|
||||||
if (daySet.isEmpty()) {
|
|
||||||
return getString(R.string.zen_mode_schedule_rule_days_none);
|
|
||||||
}
|
|
||||||
final int N = ALL_DAYS.length;
|
|
||||||
if (daySet.size() == N) {
|
|
||||||
return getString(R.string.zen_mode_schedule_rule_days_all);
|
|
||||||
}
|
|
||||||
String rt = null;
|
|
||||||
for (int i = 0; i < N; i++) {
|
|
||||||
final int startDay = ALL_DAYS[i];
|
|
||||||
final boolean active = daySet.contains(startDay);
|
|
||||||
if (!active) continue;
|
|
||||||
int end = 0;
|
|
||||||
while (daySet.contains(ALL_DAYS[(i + end + 1) % N])) {
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
if (!(i == 0 && daySet.contains(ALL_DAYS[N - 1]))) {
|
|
||||||
final String v = end == 0 ? dayString(startDay)
|
|
||||||
: getString(R.string.summary_range_symbol_combination,
|
|
||||||
dayString(startDay),
|
|
||||||
dayString(ALL_DAYS[(i + end) % N]));
|
|
||||||
rt = rt == null ? v : getString(R.string.summary_divider_text, rt, v);
|
|
||||||
}
|
|
||||||
i += end;
|
|
||||||
}
|
|
||||||
return rt;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String dayString(int day) {
|
|
||||||
mCalendar.set(Calendar.DAY_OF_WEEK, day);
|
|
||||||
return mDayFormat.format(mCalendar.getTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Config getConditionProviderConfig() {
|
private static Config getConditionProviderConfig() {
|
||||||
@@ -314,6 +230,7 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Sort by creation date, once that data is available.
|
||||||
private static final Comparator<ZenRuleInfo> RULE_COMPARATOR = new Comparator<ZenRuleInfo>() {
|
private static final Comparator<ZenRuleInfo> RULE_COMPARATOR = new Comparator<ZenRuleInfo>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(ZenRuleInfo lhs, ZenRuleInfo rhs) {
|
public int compare(ZenRuleInfo lhs, ZenRuleInfo rhs) {
|
||||||
@@ -334,4 +251,80 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
|
|||||||
ZenRule rule;
|
ZenRule rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ZenRulePreference extends Preference {
|
||||||
|
final String mName;
|
||||||
|
final String mId;
|
||||||
|
|
||||||
|
public ZenRulePreference(Context context, final ZenRule rule, final String id) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
mName = rule.name;
|
||||||
|
this.mId = id;
|
||||||
|
|
||||||
|
final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(rule.conditionId);
|
||||||
|
final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.conditionId);
|
||||||
|
final boolean isSystemRule = isSchedule || isEvent;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ApplicationInfo info = mPm.getApplicationInfo(
|
||||||
|
rule.component.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTitle(rule.name);
|
||||||
|
setPersistent(false);
|
||||||
|
setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
|
||||||
|
: isEvent ? ZenModeEventRuleSettings.ACTION
|
||||||
|
: ZenModeExternalRuleSettings.ACTION;
|
||||||
|
showRule(action, null, id, rule.name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setWidgetLayoutResource(R.layout.zen_rule_widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBindView(View view) {
|
||||||
|
super.onBindView(view);
|
||||||
|
|
||||||
|
View v = view.findViewById(R.id.delete_zen_rule);
|
||||||
|
v.setOnClickListener(mDeleteListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
showDeleteRuleDialog(mName, mId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> {
|
||||||
|
private final WeakReference<Preference> prefReference;
|
||||||
|
|
||||||
|
public LoadIconTask(Preference pref) {
|
||||||
|
prefReference = new WeakReference<Preference>(pref);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Drawable doInBackground(ApplicationInfo... params) {
|
||||||
|
return params[0].loadIcon(mPm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Drawable icon) {
|
||||||
|
if (prefReference != null && icon != null) {
|
||||||
|
final Preference pref = prefReference.get();
|
||||||
|
pref.setIcon(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -100,7 +100,7 @@ abstract public class ZenModeSettingsBase extends RestrictedSettingsFragment {
|
|||||||
final String reason = getClass().getSimpleName();
|
final String reason = getClass().getSimpleName();
|
||||||
final boolean success = NotificationManager.from(mContext).setZenModeConfig(config, reason);
|
final boolean success = NotificationManager.from(mContext).setZenModeConfig(config, reason);
|
||||||
if (success) {
|
if (success) {
|
||||||
mConfig = config;
|
mConfig = getZenModeConfig();
|
||||||
if (DEBUG) Log.d(TAG, "Saved mConfig=" + mConfig);
|
if (DEBUG) Log.d(TAG, "Saved mConfig=" + mConfig);
|
||||||
onZenModeConfigChanged();
|
onZenModeConfigChanged();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user