From c96a5dcbfc3f37f71e8b3e8b962f9571b1e7ceaf Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Fri, 10 Apr 2015 11:59:54 -0400 Subject: Settings: External automatic rule settings. - Add external automatic rule settings page with the common settings for all rules (enabled, name, zen mode). - Pull common rule-instance settings into settings base class, share with existing schedule rule settings. - New page not searchable since it is at the rule-instance level. - Obtain external rule information from existing conditions provider metadata. Includes rule type caption, sub-configuration activity, and default condition id. - If external condition providers exist with the appropriate metadata, display the external rule types as options in the new rule dialog. (max of 3 external types) - Pull common managed service listing code out of common settings base class and into a more reusable helper class. Bug: 20064962 Change-Id: Ibc13607490b7312a7d9f7f3bd61c3cfcf71a2794 --- src/com/android/settings/Settings.java | 1 + src/com/android/settings/SettingsActivity.java | 4 +- .../notification/ConditionProviderSettings.java | 50 ---- .../notification/ManagedServiceSettings.java | 233 +++++-------------- .../notification/NotificationAccessSettings.java | 4 +- .../settings/notification/ServiceListing.java | 206 +++++++++++++++++ .../notification/ZenModeAutomationSettings.java | 124 +++++++--- .../notification/ZenModeExternalRuleSettings.java | 133 +++++++++++ .../notification/ZenModeRuleSettingsBase.java | 256 +++++++++++++++++++++ .../notification/ZenModeScheduleRuleSettings.java | 216 +---------------- .../settings/notification/ZenRuleNameDialog.java | 119 +++++++++- 11 files changed, 870 insertions(+), 476 deletions(-) delete mode 100644 src/com/android/settings/notification/ConditionProviderSettings.java create mode 100644 src/com/android/settings/notification/ServiceListing.java create mode 100644 src/com/android/settings/notification/ZenModeExternalRuleSettings.java create mode 100644 src/com/android/settings/notification/ZenModeRuleSettingsBase.java (limited to 'src/com/android') diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index fe0df59..ba08036 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -98,6 +98,7 @@ public class Settings extends SettingsActivity { public static class ZenModePrioritySettingsActivity extends SettingsActivity { /* empty */ } public static class ZenModeAutomationSettingsActivity extends SettingsActivity { /* empty */ } public static class ZenModeScheduleRuleSettingsActivity extends SettingsActivity { /* empty */ } + public static class ZenModeExternalRuleSettingsActivity extends SettingsActivity { /* empty */ } public static class NotificationSettingsActivity extends SettingsActivity { /* empty */ } public static class NotificationAppListActivity extends SettingsActivity { /* empty */ } public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 7bfd249..0fdf04b 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -95,11 +95,11 @@ import com.android.settings.location.LocationSettings; import com.android.settings.nfc.AndroidBeam; import com.android.settings.nfc.PaymentSettings; import com.android.settings.notification.AppNotificationSettings; -import com.android.settings.notification.ConditionProviderSettings; import com.android.settings.notification.NotificationAccessSettings; import com.android.settings.notification.NotificationSettings; import com.android.settings.notification.NotificationStation; import com.android.settings.notification.OtherSoundSettings; +import com.android.settings.notification.ZenModeExternalRuleSettings; import com.android.settings.notification.ZenModeSettings; import com.android.settings.notification.ZenModeScheduleRuleSettings; import com.android.settings.print.PrintJobSettingsFragment; @@ -320,7 +320,6 @@ public class SettingsActivity extends Activity DreamSettings.class.getName(), UserSettings.class.getName(), NotificationAccessSettings.class.getName(), - ConditionProviderSettings.class.getName(), PrintSettingsFragment.class.getName(), PrintJobSettingsFragment.class.getName(), TrustedCredentialsSettings.class.getName(), @@ -337,6 +336,7 @@ public class SettingsActivity extends Activity ApnSettings.class.getName(), WifiCallingSettings.class.getName(), ZenModeScheduleRuleSettings.class.getName(), + ZenModeExternalRuleSettings.class.getName(), }; diff --git a/src/com/android/settings/notification/ConditionProviderSettings.java b/src/com/android/settings/notification/ConditionProviderSettings.java deleted file mode 100644 index 76576ab..0000000 --- a/src/com/android/settings/notification/ConditionProviderSettings.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2014 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.content.Context; -import android.content.pm.PackageManager; -import android.provider.Settings; -import android.service.notification.ConditionProviderService; - -public class ConditionProviderSettings extends ManagedServiceSettings { - private static final String TAG = ConditionProviderSettings.class.getSimpleName(); - private static final Config CONFIG = getConditionProviderConfig(); - - private static Config getConditionProviderConfig() { - final Config c = new Config(); - c.tag = TAG; - c.setting = Settings.Secure.ENABLED_CONDITION_PROVIDERS; - c.intentAction = ConditionProviderService.SERVICE_INTERFACE; - c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE; - c.noun = "condition provider"; - return c; - } - - @Override - protected Config getConfig() { - return CONFIG; - } - - public static int getProviderCount(PackageManager pm) { - return getServicesCount(CONFIG, pm); - } - - public static int getEnabledProviderCount(Context context) { - return getEnabledServicesCount(CONFIG, context); - } -} diff --git a/src/com/android/settings/notification/ManagedServiceSettings.java b/src/com/android/settings/notification/ManagedServiceSettings.java index 7be644e..cc9e734 100644 --- a/src/com/android/settings/notification/ManagedServiceSettings.java +++ b/src/com/android/settings/notification/ManagedServiceSettings.java @@ -16,28 +16,17 @@ package com.android.settings.notification; -import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.app.ListFragment; -import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.database.ContentObserver; -import android.net.Uri; import android.os.Bundle; -import android.os.Handler; -import android.provider.Settings; -import android.util.Slog; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -49,17 +38,15 @@ import android.widget.TextView; import com.android.settings.R; -import java.util.HashSet; import java.util.List; public abstract class ManagedServiceSettings extends ListFragment { private static final boolean SHOW_PACKAGE_NAME = false; private final Config mConfig; - private PackageManager mPM; - private ContentResolver mCR; - private final HashSet mEnabledServices = new HashSet(); + private PackageManager mPM; + private ServiceListing mServiceListing; private ServiceListAdapter mListAdapter; abstract protected Config getConfig(); @@ -68,68 +55,18 @@ public abstract class ManagedServiceSettings extends ListFragment { mConfig = getConfig(); } - private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange, Uri uri) { - updateList(); - } - }; - - private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - updateList(); - } - }; - - public class ScaryWarningDialogFragment extends DialogFragment { - static final String KEY_COMPONENT = "c"; - static final String KEY_LABEL = "l"; - - public ScaryWarningDialogFragment setServiceInfo(ComponentName cn, String label) { - Bundle args = new Bundle(); - args.putString(KEY_COMPONENT, cn.flattenToString()); - args.putString(KEY_LABEL, label); - setArguments(args); - return this; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final Bundle args = getArguments(); - final String label = args.getString(KEY_LABEL); - final ComponentName cn = ComponentName.unflattenFromString(args.getString(KEY_COMPONENT)); - - final String title = getResources().getString(mConfig.warningDialogTitle, label); - final String summary = getResources().getString(mConfig.warningDialogSummary, label); - return new AlertDialog.Builder(getActivity()) - .setMessage(summary) - .setTitle(title) - .setCancelable(true) - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - mEnabledServices.add(cn); - saveEnabledServices(); - } - }) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // pass - } - }) - .create(); - } - } - @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); mPM = getActivity().getPackageManager(); - mCR = getActivity().getContentResolver(); + mServiceListing = new ServiceListing(getActivity(), mConfig); + mServiceListing.addCallback(new ServiceListing.Callback() { + @Override + public void onServicesReloaded(List services) { + updateList(services); + } + }); mListAdapter = new ServiceListAdapter(getActivity()); } @@ -145,122 +82,31 @@ public abstract class ManagedServiceSettings extends ListFragment { @Override public void onResume() { super.onResume(); - updateList(); - - // listen for package changes - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_CHANGED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_REPLACED); - filter.addDataScheme("package"); - getActivity().registerReceiver(mPackageReceiver, filter); - - mCR.registerContentObserver(Settings.Secure.getUriFor(mConfig.setting), - false, mSettingsObserver); + mServiceListing.reload(); + mServiceListing.setListening(true); } @Override public void onPause() { super.onPause(); - - getActivity().unregisterReceiver(mPackageReceiver); - mCR.unregisterContentObserver(mSettingsObserver); - } - - private void loadEnabledServices() { - mEnabledServices.clear(); - final String flat = Settings.Secure.getString(mCR, mConfig.setting); - if (flat != null && !"".equals(flat)) { - final String[] names = flat.split(":"); - for (int i = 0; i < names.length; i++) { - final ComponentName cn = ComponentName.unflattenFromString(names[i]); - if (cn != null) { - mEnabledServices.add(cn); - } - } - } - } - - private void saveEnabledServices() { - StringBuilder sb = null; - for (ComponentName cn : mEnabledServices) { - if (sb == null) { - sb = new StringBuilder(); - } else { - sb.append(':'); - } - sb.append(cn.flattenToString()); - } - Settings.Secure.putString(mCR, - mConfig.setting, - sb != null ? sb.toString() : ""); + mServiceListing.setListening(false); } - private void updateList() { - loadEnabledServices(); - - getServices(mConfig, mListAdapter, mPM); + private void updateList(List services) { + mListAdapter.clear(); + mListAdapter.addAll(services); mListAdapter.sort(new PackageItemInfo.DisplayNameComparator(mPM)); getListView().setAdapter(mListAdapter); } - protected static int getEnabledServicesCount(Config config, Context context) { - final String flat = Settings.Secure.getString(context.getContentResolver(), config.setting); - if (flat == null || "".equals(flat)) return 0; - final String[] components = flat.split(":"); - return components.length; - } - - protected static int getServicesCount(Config c, PackageManager pm) { - return getServices(c, null, pm); - } - - private static int getServices(Config c, ArrayAdapter adapter, PackageManager pm) { - int services = 0; - if (adapter != null) { - adapter.clear(); - } - final int user = ActivityManager.getCurrentUser(); - - List installedServices = pm.queryIntentServicesAsUser( - new Intent(c.intentAction), - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, - user); - - for (int i = 0, count = installedServices.size(); i < count; i++) { - ResolveInfo resolveInfo = installedServices.get(i); - ServiceInfo info = resolveInfo.serviceInfo; - - if (!c.permission.equals(info.permission)) { - Slog.w(c.tag, "Skipping " + c.noun + " service " - + info.packageName + "/" + info.name - + ": it does not require the permission " - + c.permission); - continue; - } - if (adapter != null) { - adapter.add(info); - } - services++; - } - return services; - } - - private boolean isServiceEnabled(ServiceInfo info) { - final ComponentName cn = new ComponentName(info.packageName, info.name); - return mEnabledServices.contains(cn); - } - @Override public void onListItemClick(ListView l, View v, int position, long id) { ServiceInfo info = mListAdapter.getItem(position); final ComponentName cn = new ComponentName(info.packageName, info.name); - if (mEnabledServices.contains(cn)) { + if (mServiceListing.isEnabled(cn)) { // the simple version: disabling - mEnabledServices.remove(cn); - saveEnabledServices(); + mServiceListing.setEnabled(cn, false); } else { // show a scary dialog new ScaryWarningDialogFragment() @@ -269,6 +115,48 @@ public abstract class ManagedServiceSettings extends ListFragment { } } + public class ScaryWarningDialogFragment extends DialogFragment { + static final String KEY_COMPONENT = "c"; + static final String KEY_LABEL = "l"; + + public ScaryWarningDialogFragment setServiceInfo(ComponentName cn, String label) { + Bundle args = new Bundle(); + args.putString(KEY_COMPONENT, cn.flattenToString()); + args.putString(KEY_LABEL, label); + setArguments(args); + return this; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Bundle args = getArguments(); + final String label = args.getString(KEY_LABEL); + final ComponentName cn = ComponentName.unflattenFromString(args + .getString(KEY_COMPONENT)); + + final String title = getResources().getString(mConfig.warningDialogTitle, label); + final String summary = getResources().getString(mConfig.warningDialogSummary, label); + return new AlertDialog.Builder(getActivity()) + .setMessage(summary) + .setTitle(title) + .setCancelable(true) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + mServiceListing.setEnabled(cn, true); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // pass + } + }) + .create(); + } + } + private static class ViewHolder { ImageView icon; TextView name; @@ -327,7 +215,8 @@ public abstract class ManagedServiceSettings extends ListFragment { } else { vh.description.setVisibility(View.GONE); } - vh.checkbox.setChecked(isServiceEnabled(info)); + final ComponentName cn = new ComponentName(info.packageName, info.name); + vh.checkbox.setChecked(mServiceListing.isEnabled(cn)); } } diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java index ced71a4..5104d4a 100644 --- a/src/com/android/settings/notification/NotificationAccessSettings.java +++ b/src/com/android/settings/notification/NotificationAccessSettings.java @@ -46,10 +46,10 @@ public class NotificationAccessSettings extends ManagedServiceSettings { } public static int getListenersCount(PackageManager pm) { - return getServicesCount(CONFIG, pm); + return ServiceListing.getServicesCount(CONFIG, pm); } public static int getEnabledListenersCount(Context context) { - return getEnabledServicesCount(CONFIG, context); + return ServiceListing.getEnabledServicesCount(CONFIG, context); } } diff --git a/src/com/android/settings/notification/ServiceListing.java b/src/com/android/settings/notification/ServiceListing.java new file mode 100644 index 0000000..d296139 --- /dev/null +++ b/src/com/android/settings/notification/ServiceListing.java @@ -0,0 +1,206 @@ +/* + * 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.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.provider.Settings; +import android.util.Slog; + +import com.android.settings.notification.ManagedServiceSettings.Config; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class ServiceListing { + private final ContentResolver mContentResolver; + private final Context mContext; + private final Config mConfig; + private final HashSet mEnabledServices = new HashSet(); + private final List mServices = new ArrayList(); + private final List mCallbacks = new ArrayList(); + + private boolean mListening; + + public ServiceListing(Context context, Config config) { + mContext = context; + mConfig = config; + mContentResolver = context.getContentResolver(); + } + + public void addCallback(Callback callback) { + mCallbacks.add(callback); + } + + public void removeCallback(Callback callback) { + mCallbacks.remove(callback); + } + + public void setListening(boolean listening) { + if (mListening == listening) return; + mListening = listening; + if (mListening) { + // listen for package changes + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + filter.addDataScheme("package"); + mContext.registerReceiver(mPackageReceiver, filter); + mContentResolver.registerContentObserver(Settings.Secure.getUriFor(mConfig.setting), + false, mSettingsObserver); + } else { + mContext.unregisterReceiver(mPackageReceiver); + mContentResolver.unregisterContentObserver(mSettingsObserver); + } + } + + public static int getEnabledServicesCount(Config config, Context context) { + final String flat = Settings.Secure.getString(context.getContentResolver(), config.setting); + if (flat == null || "".equals(flat)) return 0; + final String[] components = flat.split(":"); + return components.length; + } + + public static int getServicesCount(Config c, PackageManager pm) { + return getServices(c, null, pm); + } + + public static ServiceInfo findService(Context context, Config config, final ComponentName cn) { + final ServiceListing listing = new ServiceListing(context, config); + final List services = listing.reload(); + for (ServiceInfo service : services) { + final ComponentName serviceCN = new ComponentName(service.packageName, service.name); + if (serviceCN.equals(cn)) { + return service; + } + } + return null; + } + + private static int getServices(Config c, List list, PackageManager pm) { + int services = 0; + if (list != null) { + list.clear(); + } + final int user = ActivityManager.getCurrentUser(); + + List installedServices = pm.queryIntentServicesAsUser( + new Intent(c.intentAction), + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, + user); + + for (int i = 0, count = installedServices.size(); i < count; i++) { + ResolveInfo resolveInfo = installedServices.get(i); + ServiceInfo info = resolveInfo.serviceInfo; + + if (!c.permission.equals(info.permission)) { + Slog.w(c.tag, "Skipping " + c.noun + " service " + + info.packageName + "/" + info.name + + ": it does not require the permission " + + c.permission); + continue; + } + if (list != null) { + list.add(info); + } + services++; + } + return services; + } + + private void saveEnabledServices() { + StringBuilder sb = null; + for (ComponentName cn : mEnabledServices) { + if (sb == null) { + sb = new StringBuilder(); + } else { + sb.append(':'); + } + sb.append(cn.flattenToString()); + } + Settings.Secure.putString(mContentResolver, mConfig.setting, + sb != null ? sb.toString() : ""); + } + + private void loadEnabledServices() { + mEnabledServices.clear(); + final String flat = Settings.Secure.getString(mContentResolver, mConfig.setting); + if (flat != null && !"".equals(flat)) { + final String[] names = flat.split(":"); + for (int i = 0; i < names.length; i++) { + final ComponentName cn = ComponentName.unflattenFromString(names[i]); + if (cn != null) { + mEnabledServices.add(cn); + } + } + } + } + + public List reload() { + loadEnabledServices(); + getServices(mConfig, mServices, mContext.getPackageManager()); + for (Callback callback : mCallbacks) { + callback.onServicesReloaded(mServices); + } + return mServices; + } + + public boolean isEnabled(ComponentName cn) { + return mEnabledServices.contains(cn); + } + + public void setEnabled(ComponentName cn, boolean enabled) { + if (enabled) { + mEnabledServices.add(cn); + } else { + mEnabledServices.remove(cn); + } + saveEnabledServices(); + } + + private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { + @Override + public void onChange(boolean selfChange, Uri uri) { + reload(); + } + }; + + private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + reload(); + } + }; + + public interface Callback { + void onServicesReloaded(List services); + } +} diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java index c43d99e..f2ee71d 100644 --- a/src/com/android/settings/notification/ZenModeAutomationSettings.java +++ b/src/com/android/settings/notification/ZenModeAutomationSettings.java @@ -18,12 +18,16 @@ package com.android.settings.notification; import static android.service.notification.ZenModeConfig.ALL_DAYS; +import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ServiceInfo; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceScreen; +import android.provider.Settings; import android.provider.Settings.Global; +import android.service.notification.ConditionProviderService; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.ScheduleInfo; import android.service.notification.ZenModeConfig.ZenRule; @@ -35,30 +39,39 @@ import android.view.MenuItem; import com.android.internal.logging.MetricsLogger; import com.android.settings.R; +import com.android.settings.notification.ManagedServiceSettings.Config; +import com.android.settings.notification.ZenRuleNameDialog.RuleInfo; import java.text.SimpleDateFormat; import java.util.Calendar; +import java.util.List; import java.util.TreeSet; public class ZenModeAutomationSettings extends ZenModeSettingsBase { private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEE"); + static final Config CONFIG = getConditionProviderConfig(); + private final Calendar mCalendar = Calendar.getInstance(); + private ServiceListing mServiceListing; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - setHasOptionsMenu(true); - addPreferencesFromResource(R.xml.zen_mode_automation_settings); + mServiceListing = new ServiceListing(mContext, CONFIG); + mServiceListing.addCallback(mServiceListingCallback); + mServiceListing.reload(); + mServiceListing.setListening(true); } - private void showRule(String ruleId, String ruleName) { - if (DEBUG) Log.d(TAG, "showRule " + ruleId + " name=" + ruleName); - mContext.startActivity(new Intent(ZenModeScheduleRuleSettings.ACTION) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - .putExtra(ZenModeScheduleRuleSettings.EXTRA_RULE_ID, ruleId)); + @Override + public void onDestroy() { + super.onDestroy(); + mServiceListing.setListening(false); + mServiceListing.removeCallback(mServiceListingCallback); } @Override @@ -75,54 +88,58 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase { return super.onOptionsItemSelected(item); } + @Override + protected void onZenModeChanged() { + // don't care + } + + @Override + protected void onZenModeConfigChanged() { + updateControls(); + } + + @Override + public void onResume() { + super.onResume(); + updateControls(); + } + private void showAddRuleDialog() { - new ZenRuleNameDialog(mContext, "", mConfig.getAutomaticRuleNames()) { + new ZenRuleNameDialog(mContext, mServiceListing, null, mConfig.getAutomaticRuleNames()) { @Override - public void onOk(String ruleName) { - final ScheduleInfo schedule = new ScheduleInfo(); - schedule.days = ZenModeConfig.ALL_DAYS; - schedule.startHour = 22; - schedule.endHour = 7; + public void onOk(String ruleName, RuleInfo ri) { final ZenRule rule = new ZenRule(); rule.name = ruleName; rule.enabled = true; rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; - rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule); + rule.conditionId = ri.defaultConditionId; + rule.component = ri.serviceComponent; final ZenModeConfig newConfig = mConfig.copy(); final String ruleId = newConfig.newRuleId(); newConfig.automaticRules.put(ruleId, rule); if (setZenModeConfig(newConfig)) { - showRule(ruleId, rule.name); + showRule(ri.settingsAction, ri.configurationActivity, ruleId, rule.name); } } }.show(); } - @Override - protected void onZenModeChanged() { - // don't care - } - - @Override - protected void onZenModeConfigChanged() { - updateControls(); - } - - @Override - public void onResume() { - super.onResume(); - updateControls(); + private void showRule(String settingsAction, ComponentName configurationActivity, + String ruleId, String ruleName) { + if (DEBUG) Log.d(TAG, "showRule " + ruleId + " name=" + ruleName); + mContext.startActivity(new Intent(settingsAction) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(ZenModeRuleSettingsBase.EXTRA_RULE_ID, ruleId)); } private void updateControls() { final PreferenceScreen root = getPreferenceScreen(); root.removeAll(); - if (mConfig == null) return; for (int i = 0; i < mConfig.automaticRules.size(); i++) { final String id = mConfig.automaticRules.keyAt(i); final ZenRule rule = mConfig.automaticRules.valueAt(i); - if (!ZenModeConfig.isValidScheduleConditionId(rule.conditionId)) continue; + final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(rule.conditionId); final Preference p = new Preference(mContext); p.setTitle(rule.name); p.setSummary(computeRuleSummary(rule)); @@ -130,7 +147,9 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase { p.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - showRule(id, rule.name); + final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION + : ZenModeExternalRuleSettings.ACTION; + showRule(action, null, id, rule.name); return true; } }); @@ -146,13 +165,16 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase { private String computeRuleSummary(ZenRule rule) { if (rule == null || !rule.enabled) return getString(R.string.switch_off_text); final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(rule.conditionId); - if (schedule == null) return getString(R.string.switch_on_text); - final String days = computeContiguousDayRanges(schedule.days); - final String start = getTime(schedule.startHour, schedule.startMinute); - final String end = getTime(schedule.endHour, schedule.endMinute); - final String time = getString(R.string.summary_range_verbal_combination, start, end); final String mode = ZenModeSettings.computeZenModeCaption(getResources(), rule.zenMode); - return getString(R.string.zen_mode_rule_summary_template, days, time, mode); + String summary = getString(R.string.switch_on_text); + if (schedule != null) { + final String days = computeContiguousDayRanges(schedule.days); + final String start = getTime(schedule.startHour, schedule.startMinute); + final String end = getTime(schedule.endHour, schedule.endMinute); + final String time = getString(R.string.summary_range_verbal_combination, start, end); + summary = getString(R.string.zen_mode_rule_summary_combination, days, time); + } + return getString(R.string.zen_mode_rule_summary_combination, summary, mode); } private String getTime(int hour, int minute) { @@ -199,4 +221,30 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase { return DAY_FORMAT.format(mCalendar.getTime()); } + private static Config getConditionProviderConfig() { + final Config c = new Config(); + c.tag = TAG; + c.setting = Settings.Secure.ENABLED_CONDITION_PROVIDERS; + c.intentAction = ConditionProviderService.SERVICE_INTERFACE; + c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE; + c.noun = "condition provider"; + return c; + } + + private final ServiceListing.Callback mServiceListingCallback = new ServiceListing.Callback() { + @Override + public void onServicesReloaded(List services) { + for (ServiceInfo service : services) { + final RuleInfo ri = ZenModeExternalRuleSettings.getRuleInfo(service); + if (ri != null && ri.serviceComponent != null + && ri.settingsAction == ZenModeExternalRuleSettings.ACTION) { + if (!mServiceListing.isEnabled(ri.serviceComponent)) { + Log.i(TAG, "Enabling external condition provider: " + ri.serviceComponent); + mServiceListing.setEnabled(ri.serviceComponent, true); + } + } + } + } + }; + } diff --git a/src/com/android/settings/notification/ZenModeExternalRuleSettings.java b/src/com/android/settings/notification/ZenModeExternalRuleSettings.java new file mode 100644 index 0000000..9f9dc8a --- /dev/null +++ b/src/com/android/settings/notification/ZenModeExternalRuleSettings.java @@ -0,0 +1,133 @@ +/* + * 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.Activity; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ServiceInfo; +import android.net.Uri; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceScreen; +import android.provider.Settings; +import android.service.notification.ZenModeConfig.ZenRule; +import android.util.Log; + +import com.android.internal.logging.MetricsLogger; +import com.android.settings.R; +import com.android.settings.notification.ZenRuleNameDialog.RuleInfo; + +public class ZenModeExternalRuleSettings extends ZenModeRuleSettingsBase { + private static final String KEY_TYPE = "type"; + private static final String KEY_CONFIGURE = "configure"; + + public static final String ACTION = Settings.ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS; + private static final int REQUEST_CODE_CONFIGURE = 1; + + private static final String MD_RULE_TYPE = "automatic.ruleType"; + private static final String MD_DEFAULT_CONDITION_ID = "automatic.defaultConditionId"; + private static final String MD_CONFIGURATION_ACTIVITY = "automatic.configurationActivity"; + private static final String EXTRA_CONDITION_ID = "automatic.conditionId"; + + private Preference mType; + private Preference mConfigure; + + @Override + protected boolean setRule(ZenRule rule) { + return rule != null; + } + + @Override + protected String getZenModeDependency() { + return null; + } + + @Override + protected void onCreateInternal() { + addPreferencesFromResource(R.xml.zen_mode_external_rule_settings); + final PreferenceScreen root = getPreferenceScreen(); + final ServiceInfo si = ServiceListing.findService(mContext, + ZenModeAutomationSettings.CONFIG, mRule.component); + if (DEBUG) Log.d(TAG, "ServiceInfo: " + si); + final RuleInfo ri = getRuleInfo(si); + if (DEBUG) Log.d(TAG, "RuleInfo: " + ri); + mType = root.findPreference(KEY_TYPE); + if (ri == null) { + mType.setSummary(R.string.zen_mode_rule_type_unknown); + } else { + mType.setSummary(ri.caption); + } + + mConfigure = root.findPreference(KEY_CONFIGURE); + if (ri == null || ri.configurationActivity == null) { + mConfigure.setEnabled(false); + } else { + mConfigure.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + startActivityForResult(new Intent().setComponent(ri.configurationActivity), + REQUEST_CODE_CONFIGURE); + return true; + } + }); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE_CONFIGURE) { + if (resultCode == Activity.RESULT_OK && data != null) { + final Uri conditionId = data.getParcelableExtra(EXTRA_CONDITION_ID); + if (conditionId != null && !conditionId.equals(mRule.conditionId)) { + updateRule(conditionId); + } + } + } + } + + public static RuleInfo getRuleInfo(ServiceInfo si) { + if (si == null || si.metaData == null) return null; + final String ruleType = si.metaData.getString(MD_RULE_TYPE); + final String defaultConditionId = si.metaData.getString(MD_DEFAULT_CONDITION_ID); + final String configurationActivity = si.metaData.getString(MD_CONFIGURATION_ACTIVITY); + if (ruleType != null && !ruleType.trim().isEmpty() && defaultConditionId != null) { + final RuleInfo ri = new RuleInfo(); + ri.serviceComponent = new ComponentName(si.packageName, si.name); + ri.settingsAction = ZenModeExternalRuleSettings.ACTION; + ri.caption = ruleType; + ri.defaultConditionId = Uri.parse(defaultConditionId); + if (configurationActivity != null) { + ri.configurationActivity = ComponentName.unflattenFromString(configurationActivity); + } + return ri; + } + return null; + } + + @Override + protected void updateControlsInternal() { + // everything done up front + } + + @Override + protected int getMetricsCategory() { + return MetricsLogger.NOTIFICATION_ZEN_MODE_EXTERNAL_RULE; + } + +} diff --git a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java new file mode 100644 index 0000000..f6bc75f --- /dev/null +++ b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java @@ -0,0 +1,256 @@ +/* + * 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.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceScreen; +import android.provider.Settings.Global; +import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeConfig.ZenRule; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.Switch; +import android.widget.Toast; + +import com.android.settings.DropDownPreference; +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.widget.SwitchBar; + +public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase + implements SwitchBar.OnSwitchChangeListener { + protected static final String TAG = ZenModeSettingsBase.TAG; + protected static final boolean DEBUG = ZenModeSettingsBase.DEBUG; + + public static final String EXTRA_RULE_ID = "rule_id"; + private static final String KEY_RULE_NAME = "rule_name"; + private static final String KEY_ZEN_MODE = "zen_mode"; + + protected Context mContext; + protected boolean mDisableListeners; + protected ZenRule mRule; + + private String mRuleId; + private boolean mDeleting; + private Preference mRuleName; + private SwitchBar mSwitchBar; + private DropDownPreference mZenMode; + + abstract protected void onCreateInternal(); + abstract protected boolean setRule(ZenRule rule); + abstract protected String getZenModeDependency(); + abstract protected void updateControlsInternal(); + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mContext = getActivity(); + + final Intent intent = getActivity().getIntent(); + if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent); + if (intent == null) { + Log.w(TAG, "No intent"); + toastAndFinish(); + return; + } + + mRuleId = intent.getStringExtra(EXTRA_RULE_ID); + if (DEBUG) Log.d(TAG, "mRuleId=" + mRuleId); + if (refreshRuleOrFinish()) { + return; + } + + setHasOptionsMenu(true); + + onCreateInternal(); + + final PreferenceScreen root = getPreferenceScreen(); + mRuleName = root.findPreference(KEY_RULE_NAME); + mRuleName.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + showRuleNameDialog(); + return true; + } + }); + + mZenMode = (DropDownPreference) root.findPreference(KEY_ZEN_MODE); + mZenMode.addItem(R.string.zen_mode_option_important_interruptions, + Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenMode.addItem(R.string.zen_mode_option_alarms, Global.ZEN_MODE_ALARMS); + mZenMode.addItem(R.string.zen_mode_option_no_interruptions, + Global.ZEN_MODE_NO_INTERRUPTIONS); + mZenMode.setCallback(new DropDownPreference.Callback() { + @Override + public boolean onItemSelected(int pos, Object value) { + if (mDisableListeners) return true; + final int zenMode = (Integer) value; + if (zenMode == mRule.zenMode) return true; + if (DEBUG) Log.d(TAG, "onPrefChange zenMode=" + zenMode); + mRule.zenMode = zenMode; + setZenModeConfig(mConfig); + return true; + } + }); + mZenMode.setOrder(10); // sort at the bottom of the category + mZenMode.setDependency(getZenModeDependency()); + } + + @Override + public void onResume() { + super.onResume(); + updateControls(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + final SettingsActivity activity = (SettingsActivity) getActivity(); + mSwitchBar = activity.getSwitchBar(); + mSwitchBar.addOnSwitchChangeListener(this); + mSwitchBar.show(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mSwitchBar.removeOnSwitchChangeListener(this); + mSwitchBar.hide(); + } + + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + if (DEBUG) Log.d(TAG, "onSwitchChanged " + isChecked); + if (mDisableListeners) return; + final boolean enabled = isChecked; + if (enabled == mRule.enabled) return; + if (DEBUG) Log.d(TAG, "onSwitchChanged enabled=" + enabled); + mRule.enabled = enabled; + mRule.snoozing = false; + setZenModeConfig(mConfig); + } + + protected void updateRule(Uri newConditionId) { + mRule.conditionId = newConditionId; + mRule.condition = null; + mRule.snoozing = false; + setZenModeConfig(mConfig); + } + + @Override + protected void onZenModeChanged() { + // noop + } + + @Override + protected void onZenModeConfigChanged() { + if (!refreshRuleOrFinish()) { + updateControls(); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + if (DEBUG) Log.d(TAG, "onCreateOptionsMenu"); + inflater.inflate(R.menu.zen_mode_rule, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (DEBUG) Log.d(TAG, "onOptionsItemSelected " + item.getItemId()); + if (item.getItemId() == R.id.delete) { + showDeleteRuleDialog(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void showRuleNameDialog() { + new ZenRuleNameDialog(mContext, null, mRule.name, mConfig.getAutomaticRuleNames()) { + @Override + public void onOk(String ruleName, RuleInfo type) { + final ZenModeConfig newConfig = mConfig.copy(); + final ZenRule rule = newConfig.automaticRules.get(mRuleId); + if (rule == null) return; + rule.name = ruleName; + setZenModeConfig(newConfig); + } + }.show(); + } + + private boolean refreshRuleOrFinish() { + mRule = mConfig.automaticRules.get(mRuleId); + if (DEBUG) Log.d(TAG, "mRule=" + mRule); + if (!setRule(mRule)) { + toastAndFinish(); + return true; + } + return false; + } + + private void showDeleteRuleDialog() { + new AlertDialog.Builder(mContext) + .setMessage(getString(R.string.zen_mode_delete_rule_confirmation, mRule.name)) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.zen_mode_delete_rule_button, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mDeleting = true; + mConfig.automaticRules.remove(mRuleId); + setZenModeConfig(mConfig); + } + }) + .show(); + } + + private void toastAndFinish() { + if (!mDeleting) { + Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT) + .show(); + } + getActivity().finish(); + } + + private void updateRuleName() { + getActivity().setTitle(mRule.name); + mRuleName.setSummary(mRule.name); + } + + private void updateControls() { + mDisableListeners = true; + updateRuleName(); + updateControlsInternal(); + mZenMode.setSelectedValue(mRule.zenMode); + mDisableListeners = false; + if (mSwitchBar != null) { + mSwitchBar.setChecked(mRule.enabled); + } + } + +} diff --git a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java index f0f0294..f7015d3 100644 --- a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java +++ b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java @@ -25,141 +25,58 @@ import android.app.FragmentManager; import android.app.TimePickerDialog; import android.content.Context; import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnDismissListener; -import android.content.Intent; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceScreen; import android.provider.Settings; -import android.provider.Settings.Global; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.ScheduleInfo; import android.service.notification.ZenModeConfig.ZenRule; import android.text.format.DateFormat; import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.widget.Switch; import android.widget.TimePicker; -import android.widget.Toast; import com.android.internal.logging.MetricsLogger; -import com.android.settings.DropDownPreference; import com.android.settings.R; -import com.android.settings.SettingsActivity; -import com.android.settings.widget.SwitchBar; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; -public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase - implements SwitchBar.OnSwitchChangeListener { - private static final String TAG = ZenModeSettingsBase.TAG; - private static final boolean DEBUG = ZenModeSettingsBase.DEBUG; - - private static final String KEY_RULE_NAME = "rule_name"; +public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase { private static final String KEY_DAYS = "days"; private static final String KEY_START_TIME = "start_time"; private static final String KEY_END_TIME = "end_time"; - private static final String KEY_ZEN_MODE = "zen_mode"; private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEE"); public static final String ACTION = Settings.ACTION_ZEN_MODE_SCHEDULE_RULE_SETTINGS; - public static final String EXTRA_RULE_ID = "rule_id"; - private Context mContext; - private boolean mDisableListeners; - private SwitchBar mSwitchBar; - private Preference mRuleName; private Preference mDays; private TimePickerPreference mStart; private TimePickerPreference mEnd; - private DropDownPreference mZenMode; - private String mRuleId; - private ZenRule mRule; private ScheduleInfo mSchedule; - private boolean mDeleting; - - @Override - protected void onZenModeChanged() { - // noop - } @Override - protected void onZenModeConfigChanged() { - if (!refreshRuleOrFinish()) { - updateControls(); - } - } - - private boolean refreshRuleOrFinish() { - mRule = mConfig.automaticRules.get(mRuleId); - if (DEBUG) Log.d(TAG, "mRule=" + mRule); - mSchedule = mRule != null ? ZenModeConfig.tryParseScheduleConditionId(mRule.conditionId) + protected boolean setRule(ZenRule rule) { + mSchedule = rule != null ? ZenModeConfig.tryParseScheduleConditionId(rule.conditionId) : null; - if (mSchedule == null) { - toastAndFinish(); - return true; - } - return false; + return mSchedule != null; } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - if (DEBUG) Log.d(TAG, "onCreateOptionsMenu"); - inflater.inflate(R.menu.zen_mode_rule, menu); + protected String getZenModeDependency() { + return mDays.getKey(); } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (DEBUG) Log.d(TAG, "onOptionsItemSelected " + item.getItemId()); - if (item.getItemId() == R.id.delete) { - showDeleteRuleDialog(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mContext = getActivity(); - - final Intent intent = getActivity().getIntent(); - if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent); - if (intent == null) { - Log.w(TAG, "No intent"); - toastAndFinish(); - return; - } - - mRuleId = intent.getStringExtra(EXTRA_RULE_ID); - if (DEBUG) Log.d(TAG, "mRuleId=" + mRuleId); - if (refreshRuleOrFinish()) { - return; - } - + protected void onCreateInternal() { addPreferencesFromResource(R.xml.zen_mode_schedule_rule_settings); final PreferenceScreen root = getPreferenceScreen(); - setHasOptionsMenu(true); - - mRuleName = root.findPreference(KEY_RULE_NAME); - mRuleName.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - showRuleNameDialog(); - return true; - } - }); - mDays = root.findPreference(KEY_DAYS); mDays.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override @@ -186,10 +103,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase if (DEBUG) Log.d(TAG, "onPrefChange start h=" + hour + " m=" + minute); mSchedule.startHour = hour; mSchedule.startMinute = minute; - mRule.conditionId = ZenModeConfig.toScheduleConditionId(mSchedule); - mRule.condition = null; - mRule.snoozing = false; - setZenModeConfig(mConfig); + updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); return true; } }); @@ -211,63 +125,12 @@ public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase if (DEBUG) Log.d(TAG, "onPrefChange end h=" + hour + " m=" + minute); mSchedule.endHour = hour; mSchedule.endMinute = minute; - mRule.conditionId = ZenModeConfig.toScheduleConditionId(mSchedule); - mRule.condition = null; - mRule.snoozing = false; - setZenModeConfig(mConfig); + updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); return true; } }); root.addPreference(mEnd); mEnd.setDependency(mDays.getKey()); - - mZenMode = (DropDownPreference) root.findPreference(KEY_ZEN_MODE); - mZenMode.addItem(R.string.zen_mode_option_important_interruptions, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); - mZenMode.addItem(R.string.zen_mode_option_alarms, Global.ZEN_MODE_ALARMS); - mZenMode.addItem(R.string.zen_mode_option_no_interruptions, Global.ZEN_MODE_NO_INTERRUPTIONS); - mZenMode.setCallback(new DropDownPreference.Callback() { - @Override - public boolean onItemSelected(int pos, Object value) { - if (mDisableListeners) return true; - final int zenMode = (Integer) value; - if (zenMode == mRule.zenMode) return true; - if (DEBUG) Log.d(TAG, "onPrefChange zenMode=" + zenMode); - mRule.zenMode = zenMode; - setZenModeConfig(mConfig); - return true; - } - }); - mZenMode.setOrder(10); // sort at the bottom of the category - mZenMode.setDependency(mDays.getKey()); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - final SettingsActivity activity = (SettingsActivity) getActivity(); - mSwitchBar = activity.getSwitchBar(); - mSwitchBar.addOnSwitchChangeListener(this); - mSwitchBar.show(); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - mSwitchBar.removeOnSwitchChangeListener(this); - mSwitchBar.hide(); - } - - @Override - public void onSwitchChanged(Switch switchView, boolean isChecked) { - if (DEBUG) Log.d(TAG, "onSwitchChanged " + isChecked); - if (mDisableListeners) return; - final boolean enabled = isChecked; - if (enabled == mRule.enabled) return; - if (DEBUG) Log.d(TAG, "onSwitchChanged enabled=" + enabled); - mRule.enabled = enabled; - mRule.snoozing = false; - setZenModeConfig(mConfig); } private void updateDays() { @@ -308,28 +171,11 @@ public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase } @Override - public void onResume() { - super.onResume(); - updateControls(); - } - - private void updateRuleName() { - getActivity().setTitle(mRule.name); - mRuleName.setSummary(mRule.name); - } - - private void updateControls() { - mDisableListeners = true; - updateRuleName(); + protected void updateControlsInternal() { updateDays(); mStart.setTime(mSchedule.startHour, mSchedule.startMinute); mEnd.setTime(mSchedule.endHour, mSchedule.endMinute); - mZenMode.setSelectedValue(mRule.zenMode); - mDisableListeners = false; updateEndSummary(); - if (mSwitchBar != null) { - mSwitchBar.setChecked(mRule.enabled); - } } @Override @@ -337,34 +183,6 @@ public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase return MetricsLogger.NOTIFICATION_ZEN_MODE_SCHEDULE_RULE; } - private void showDeleteRuleDialog() { - new AlertDialog.Builder(mContext) - .setMessage(getString(R.string.zen_mode_delete_rule_confirmation, mRule.name)) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.zen_mode_delete_rule_button, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mDeleting = true; - mConfig.automaticRules.remove(mRuleId); - setZenModeConfig(mConfig); - } - }) - .show(); - } - - private void showRuleNameDialog() { - new ZenRuleNameDialog(mContext, mRule.name, mConfig.getAutomaticRuleNames()) { - @Override - public void onOk(String ruleName) { - final ZenModeConfig newConfig = mConfig.copy(); - final ZenRule rule = newConfig.automaticRules.get(mRuleId); - if (rule == null) return; - rule.name = ruleName; - setZenModeConfig(newConfig); - } - }.show(); - } - private void showDaysDialog() { new AlertDialog.Builder(mContext) .setTitle(R.string.zen_mode_schedule_rule_days) @@ -375,10 +193,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase if (Arrays.equals(days, mSchedule.days)) return; if (DEBUG) Log.d(TAG, "days.onChanged days=" + Arrays.asList(days)); mSchedule.days = days; - mRule.conditionId = ZenModeConfig.toScheduleConditionId(mSchedule); - mRule.condition = null; - mRule.snoozing = false; - setZenModeConfig(mConfig); + updateRule(ZenModeConfig.toScheduleConditionId(mSchedule)); } }) .setOnDismissListener(new OnDismissListener() { @@ -391,14 +206,6 @@ public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase .show(); } - private void toastAndFinish() { - if (!mDeleting) { - Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT) - .show(); - } - getActivity().finish(); - } - private static class TimePickerPreference extends Preference { private final Context mContext; @@ -474,4 +281,5 @@ public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase boolean onSetTime(int hour, int minute); } } + } diff --git a/src/com/android/settings/notification/ZenRuleNameDialog.java b/src/com/android/settings/notification/ZenRuleNameDialog.java index b0eaaec..8b44e46 100644 --- a/src/com/android/settings/notification/ZenRuleNameDialog.java +++ b/src/com/android/settings/notification/ZenRuleNameDialog.java @@ -17,35 +17,71 @@ package com.android.settings.notification; import android.app.AlertDialog; +import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; +import android.content.DialogInterface.OnDismissListener; +import android.content.pm.ServiceInfo; +import android.net.Uri; +import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeConfig.ScheduleInfo; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.ArraySet; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; +import android.widget.RadioButton; +import android.widget.RadioGroup; import com.android.settings.R; +import java.util.List; + public abstract class ZenRuleNameDialog { + private static final String TAG = ZenModeSettings.TAG; + private static final boolean DEBUG = ZenModeSettings.DEBUG; + private final AlertDialog mDialog; private final EditText mEditText; + private final RadioGroup mTypes; private final ArraySet mExistingNames; + private final ServiceListing mServiceListing; + private final RuleInfo[] mExternalRules = new RuleInfo[3]; - public ZenRuleNameDialog(Context context, String ruleName, ArraySet existingNames) { + public ZenRuleNameDialog(Context context, ServiceListing serviceListing, String ruleName, + ArraySet existingNames) { + mServiceListing = serviceListing; final View v = LayoutInflater.from(context).inflate(R.layout.zen_rule_name, null, false); mEditText = (EditText) v.findViewById(R.id.rule_name); - mEditText.setText(ruleName); + if (ruleName != null) { + mEditText.setText(ruleName); + } mEditText.setSelectAllOnFocus(true); + mTypes = (RadioGroup) v.findViewById(R.id.rule_types); + if (mServiceListing != null) { + bindType(R.id.rule_type_schedule, defaultNewSchedule()); + bindExternalRules(); + mServiceListing.addCallback(mServiceListingCallback); + mServiceListing.reload(); + } mDialog = new AlertDialog.Builder(context) .setTitle(R.string.zen_mode_rule_name) .setView(v) .setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - onOk(trimmedText()); + onOk(trimmedText(), selectedRuleInfo()); + } + }) + .setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + if (mServiceListing != null) { + mServiceListing.removeCallback(mServiceListingCallback); + } } }) .setNegativeButton(R.string.cancel, null) @@ -72,17 +108,37 @@ public abstract class ZenRuleNameDialog { } } - abstract public void onOk(String ruleName); - - private String trimmedText() { - return mEditText.getText() == null ? null : mEditText.getText().toString().trim(); - } + abstract public void onOk(String ruleName, RuleInfo ruleInfo); public void show() { mDialog.show(); updatePositiveButton(); } + private void bindType(int id, RuleInfo ri) { + final RadioButton rb = (RadioButton) mTypes.findViewById(id); + if (ri == null) { + rb.setVisibility(View.GONE); + return; + } + rb.setVisibility(View.VISIBLE); + if (ri.caption != null) { + rb.setText(ri.caption); + } + rb.setTag(ri); + } + + private RuleInfo selectedRuleInfo() { + final int id = mTypes.getCheckedRadioButtonId(); + if (id == -1) return null; + final RadioButton rb = (RadioButton) mTypes.findViewById(id); + return (RuleInfo) rb.getTag(); + } + + private String trimmedText() { + return mEditText.getText() == null ? null : mEditText.getText().toString().trim(); + } + private void updatePositiveButton() { final String name = trimmedText(); final boolean validName = !TextUtils.isEmpty(name) @@ -90,4 +146,51 @@ public abstract class ZenRuleNameDialog { mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validName); } + private static RuleInfo defaultNewSchedule() { + final ScheduleInfo schedule = new ScheduleInfo(); + schedule.days = ZenModeConfig.ALL_DAYS; + schedule.startHour = 22; + schedule.endHour = 7; + final RuleInfo rt = new RuleInfo(); + rt.settingsAction = ZenModeScheduleRuleSettings.ACTION; + rt.defaultConditionId = ZenModeConfig.toScheduleConditionId(schedule); + return rt; + } + + private void bindExternalRules() { + bindType(R.id.rule_type_2, mExternalRules[0]); + bindType(R.id.rule_type_3, mExternalRules[1]); + bindType(R.id.rule_type_4, mExternalRules[2]); + // show radio group if we have at least one external rule type + mTypes.setVisibility(mExternalRules[0] != null ? View.VISIBLE : View.GONE); + } + + private final ServiceListing.Callback mServiceListingCallback = new ServiceListing.Callback() { + @Override + public void onServicesReloaded(List services) { + if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size()); + mExternalRules[0] = mExternalRules[1] = mExternalRules[2] = null; + int i = 0; + for (ServiceInfo si : services) { + final RuleInfo ri = ZenModeExternalRuleSettings.getRuleInfo(si); + if (ri != null) { + mExternalRules[i] = ri; + i++; + if (i == mExternalRules.length) { + break; + } + } + } + bindExternalRules(); + } + }; + + public static class RuleInfo { + public String caption; + public String settingsAction; + public Uri defaultConditionId; + public ComponentName serviceComponent; + public ComponentName configurationActivity; + } + } \ No newline at end of file -- cgit v1.1