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:
Julia Reynolds
2015-09-18 09:00:15 -04:00
parent dbb2c3bd4d
commit cf92ef10a5
4 changed files with 150 additions and 122 deletions

View 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>

View File

@@ -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>

View File

@@ -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);
}
}
}
} }

View File

@@ -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();
} }