Settings: An update on Downtime.

 - Migrate settings to the new zen mode state model.
 - Remove downtime settings.
 - Add automatic rule management page (add/remove)
 - Bind new automatic schedule rules to detail editor.
 - Clean up a few found miscapitalized string captions.
 - Migrate zen switch to report the shared summary string.

Bug: 20064962
Change-Id: Ia561e7f77c90c962729240b4d51ba1915297f64a
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 98516ed..2484831 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -709,6 +709,26 @@
                 android:value="true" />
         </activity>
 
+        <activity android:name="Settings$ZenModeScheduleRuleSettingsActivity"
+                android:exported="true"
+                android:taskAffinity="">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="com.android.settings.SHORTCUT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                android:value="com.android.settings.notification.ZenModeScheduleRuleSettings" />
+            <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
+                android:resource="@id/notification_settings" />
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                android:value="true" />
+        </activity>
+
         <activity android:name="Settings$HomeSettingsActivity"
                 android:label="@string/home_settings"
                 android:taskAffinity="">
diff --git a/res/drawable/ic_delete.xml b/res/drawable/ic_delete.xml
new file mode 100644
index 0000000..d4f79e3
--- /dev/null
+++ b/res/drawable/ic_delete.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:tint="?android:attr/colorControlNormal"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12.0,38.0c0.0,2.21 1.79,4.0 4.0,4.0l16.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L36.0,14.0L12.0,14.0l0.0,24.0zM38.0,8.0l-7.0,0.0l-2.0,-2.0L19.0,6.0l-2.0,2.0l-7.0,0.0l0.0,4.0l28.0,0.0L38.0,8.0z"/>
+</vector>
diff --git a/res/layout/zen_rule_name.xml b/res/layout/zen_rule_name.xml
new file mode 100755
index 0000000..62f51ea
--- /dev/null
+++ b/res/layout/zen_rule_name.xml
@@ -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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" >
+
+    <EditText
+        android:id="@+id/rule_name"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:layout_marginLeft="22dp"
+        android:layout_marginRight="22dp" >
+
+        <requestFocus />
+
+    </EditText>
+
+</FrameLayout>
diff --git a/res/layout/zen_downtime_day.xml b/res/layout/zen_schedule_rule_day.xml
similarity index 92%
rename from res/layout/zen_downtime_day.xml
rename to res/layout/zen_schedule_rule_day.xml
index 8d2fa73..1d300d2 100755
--- a/res/layout/zen_downtime_day.xml
+++ b/res/layout/zen_schedule_rule_day.xml
@@ -20,4 +20,4 @@
     android:minHeight="?android:attr/listPreferredItemHeightSmall"
     android:textAppearance="?android:attr/textAppearanceMedium"
     android:gravity="center_vertical"
-    android:paddingStart="@dimen/zen_downtime_checkbox_padding" />
+    android:paddingStart="@dimen/zen_schedule_rule_checkbox_padding" />
diff --git a/res/menu/zen_mode_automation.xml b/res/menu/zen_mode_automation.xml
new file mode 100644
index 0000000..02ec41f
--- /dev/null
+++ b/res/menu/zen_mode_automation.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/add"
+        android:title="@string/zen_mode_time_add_rule"
+        android:icon="@drawable/ic_menu_add_white"
+        android:visible="true"
+        android:showAsAction="collapseActionView|ifRoom" />
+</menu>
diff --git a/res/menu/zen_mode_rule.xml b/res/menu/zen_mode_rule.xml
new file mode 100644
index 0000000..eea30a8
--- /dev/null
+++ b/res/menu/zen_mode_rule.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/delete"
+        android:title="@string/zen_mode_delete_rule"
+        android:icon="@drawable/ic_delete"
+        android:visible="true"
+        android:showAsAction="collapseActionView|ifRoom" />
+</menu>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 22c351c..4f1eb97 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1210,20 +1210,6 @@
         <item>3</item>
     </string-array>
 
-    <!-- Setting display values for zen mode -->
-    <string-array name="entries_zen_mode">
-        <item>Off</item>
-        <item>Limited interruptions</item>
-        <item>Zero interruptions</item>
-    </string-array>
-
-    <!-- Setting values for zen mode, must match the Settings.Global.ZEN_MODE_ constants -->
-    <string-array name="entryvalues_zen_mode" translatable="false">
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-    </string-array>
-
     <!-- Battery saver mode: allowable trigger threshold levels. -->
     <integer-array name="battery_saver_trigger_values" translatable="false" >
         <item>0</item>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 580ae22..1fd22e0 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -90,8 +90,8 @@
     <dimen name="notification_app_icon_size">64dp</dimen>
     <dimen name="notification_app_icon_badge_size">20dp</dimen>
     <dimen name="notification_app_icon_badge_margin">4dp</dimen>
-    <dimen name="zen_downtime_checkbox_padding">7dp</dimen>
-    <dimen name="zen_downtime_margin">17dp</dimen>
+    <dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
+    <dimen name="zen_schedule_day_margin">17dp</dimen>
 
     <!-- Default text size for caption preview samples. Uses dp rather than sp because captions are not scaled. -->
     <dimen name="caption_preview_text_size">48dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 635b4650b..b6ec685 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -587,23 +587,11 @@
     <!-- Button label for generic cancel action [CHAR LIMIT=20] -->
     <string name="cancel">Cancel</string>
 
-    <!-- Button label for generic cancel action in all caps [CHAR LIMIT=20] -->
-    <string name="cancel_all_caps">CANCEL</string>
-
-    <!-- Button label for generic continue action in all caps [CHAR LIMIT=20] -->
-    <string name="continue_all_caps">CONTINUE</string>
-
     <!-- Button label for generic OK action [CHAR LIMIT=20] -->
     <string name="okay">OK</string>
 
-    <!-- Button label for generic YES action [CHAR LIMIT=20] -->
-    <string name="yes_all_caps">YES</string>
-
-    <!-- Button label for generic NO action [CHAR LIMIT=20] -->
-    <string name="no_all_caps">NO</string>
-
-    <!-- Button label for generic FORGET action [CHAR LIMIT=20] -->
-    <string name="forget">FORGET</string>
+    <!-- Button label for generic forget action [CHAR LIMIT=20] -->
+    <string name="forget">Forget</string>
 
     <!-- Title of the Settings activity shown within the application itself. -->
     <string name="settings_label">Settings</string>
@@ -5699,7 +5687,7 @@
     <string name="notification_volume_option_title">Notification volume</string>
 
     <!-- Sound & notification > Sound section: Title for the Interruptions option and associated settings page. [CHAR LIMIT=30] -->
-    <string name="zen_mode_settings_title">Block interruptions</string>
+    <string name="zen_mode_settings_title">@*android:string/zen_mode_feature_name</string>
 
     <!-- Sound & notification > Sound section: Title for the Priority interruptions option and associated settings page. [CHAR LIMIT=30] -->
     <string name="zen_mode_priority_settings_title">Priority only allows</string>
@@ -5717,7 +5705,7 @@
     <string name="zen_mode_option_no_interruptions">No interruptions</string>
 
     <!-- Sound & notification > Sound section: Zen mode combined summary + condition line [CHAR LIMIT=60] -->
-    <string name="zen_mode_summary_combination"><xliff:g id="mode" example="Priority only">%1$s</xliff:g> <xliff:g id="exit condition" example="until you turn this off">%2$s</xliff:g></string>
+    <string name="zen_mode_summary_combination"><xliff:g id="mode" example="Priority only">%1$s</xliff:g>: <xliff:g id="exit condition" example="Until you turn this off">%2$s</xliff:g></string>
 
     <!-- Sound & notification > Sound section: Title for the option defining the phone ringtone. [CHAR LIMIT=30] -->
     <string name="ringtone_title">Phone ringtone</string>
@@ -5822,32 +5810,6 @@
         to dismiss these notifications or touch action buttons within them.
     </string>
 
-    <!-- Title of preference to manage condition providers -->
-    <string name="manage_condition_providers">Condition providers</string>
-
-    <!-- Summary of preference to manage condition providers, when none are enabled -->
-    <string name="manage_condition_providers_summary_zero">No apps provide conditions</string>
-
-    <!-- Summary of preference to manage condition providers, when one or more are enabled -->
-    <plurals name="manage_condition_providers_summary_nonzero">
-        <item quantity="one">%d app provides conditions</item>
-        <item quantity="other">%d apps provide conditions</item>
-    </plurals>
-
-    <!-- String to show in the list of condition providers, when none is installed -->
-    <string name="no_condition_providers">No condition providers are installed.</string>
-
-    <!-- Title for a warning message about security implications of enabling a condition
-          provider, displayed as a dialog message. [CHAR LIMIT=NONE] -->
-    <string name="condition_provider_security_warning_title">Enable
-         <xliff:g id="service" example="ConditionProvider">%1$s</xliff:g>?</string>
-    <!-- Summary for a warning message about security implications of enabling a condition
-          provider, displayed as a dialog message. [CHAR LIMIT=NONE] -->
-    <string name="condition_provider_security_warning_summary">
-        <xliff:g id="condition_provider_name">%1$s</xliff:g> will be able to
-        add exit conditions to Do not disturb mode.
-    </string>
-
     <!-- [CHAR LIMIT=NONE] Text when loading app list in notification settings -->
     <string name="loading_notification_apps">Loading apps...</string>
 
@@ -5887,29 +5849,29 @@
     <!-- [CHAR LIMIT=20] Notification settings: App notifications dialog dismiss button caption -->
     <string name="app_notifications_dialog_done">Done</string>
 
-    <!-- [CHAR LIMIT=60] Zen mode settings: Downtime category text -->
-    <string name="zen_mode_downtime_category">Downtime</string>
+    <!-- [CHAR LIMIT=40] Zen mode settings: Rule name option and edit dialog title -->
+    <string name="zen_mode_rule_name">Rule name</string>
 
-    <!-- [CHAR LIMIT=40] Zen mode settings: Downtime days option title -->
-    <string name="zen_mode_downtime_days">Days</string>
+    <!-- [CHAR LIMIT=40] Zen mode settings: Add rule menu option name -->
+    <string name="zen_mode_time_add_rule">Add rule</string>
+
+    <!-- [CHAR LIMIT=40] Zen mode settings: Delete rule menu option name -->
+    <string name="zen_mode_delete_rule">Delete rule</string>
+
+    <!-- [CHAR LIMIT=40] Zen mode settings: Delete rule dialog confirmation message -->
+    <string name="zen_mode_delete_rule_confirmation">Delete \"<xliff:g id="rule" example="Weekends">%1$s</xliff:g>\" rule?</string>
+
+    <!-- [CHAR LIMIT=40] Zen mode settings: Delete rule dialog button caption -->
+    <string name="zen_mode_delete_rule_button">Delete</string>
+
+    <!-- [CHAR LIMIT=40] Zen mode settings: Text to display if rule isn't found  -->
+    <string name="zen_mode_rule_not_found_text">Rule not found.</string>
+
+    <!-- [CHAR LIMIT=40] Zen mode settings: Timebased rule days option title -->
+    <string name="zen_mode_schedule_rule_days">Days</string>
 
     <!-- [CHAR LIMIT=40] Zen mode settings: Downtime days option value, no days set -->
-    <string name="zen_mode_downtime_days_none">None</string>
-
-    <!-- [CHAR LIMIT=60] Zen mode settings: Downtime mode option title -->
-    <string name="zen_mode_downtime_mode_title">Interruptions allowed</string>
-
-    <!-- [CHAR LIMIT=40] Zen mode settings: Downtime mode option value, priority only -->
-    <string name="zen_mode_downtime_mode_priority">Priority only</string>
-
-    <!-- [CHAR LIMIT=40] Zen mode settings: Downtime mode option value, none -->
-    <string name="zen_mode_downtime_mode_none">None</string>
-
-    <!-- [CHAR LIMIT=40] Zen mode settings: Automation category text -->
-    <string name="zen_mode_automation_category">Automation</string>
-
-    <!-- [CHAR LIMIT=40] Zen mode settings: Entry conditions option: title -->
-    <string name="zen_mode_entry_conditions_title">Automatically turn on</string>
+    <string name="zen_mode_schedule_rule_days_none">None</string>
 
     <!-- [CHAR LIMIT=40] General divider text when concatenating multiple items in a text summary -->
     <string name="summary_divider_text">,\u0020</string>
@@ -5962,14 +5924,8 @@
     <!-- [CHAR LIMIT=20] Zen mode settings: End time option -->
     <string name="zen_mode_end_time">End time</string>
 
-    <!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when downtime mode = priority and end time = next day -->
-    <string name="zen_mode_end_time_priority_next_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> next day</string>
-
-    <!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when downtime mode = none and end time = same day -->
-    <string name="zen_mode_end_time_none_same_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> or any alarm before</string>
-
-    <!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when downtime mode = none and end time = next day -->
-    <string name="zen_mode_end_time_none_next_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> next day or any alarm before</string>
+    <!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when end time = next day -->
+    <string name="zen_mode_end_time_next_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> next day</string>
 
     <!-- [CHAR LIMIT=20] Notifications settings: Apps section header -->
     <string name="notification_settings_apps_title">App notifications</string>
diff --git a/res/xml/zen_mode_automation_settings.xml b/res/xml/zen_mode_automation_settings.xml
index 3098630..7cfffd4 100644
--- a/res/xml/zen_mode_automation_settings.xml
+++ b/res/xml/zen_mode_automation_settings.xml
@@ -19,43 +19,5 @@
     android:key="zen_mode_settings"
     android:title="@string/zen_mode_automation_settings_title" >
 
-    <!-- Downtime -->
-    <PreferenceCategory
-        android:key="downtime"
-        android:title="@string/zen_mode_downtime_category" >
-
-        <!-- Days -->
-        <Preference
-            android:key="days"
-            android:title="@string/zen_mode_downtime_days"
-            android:persistent="false" />
-
-        <!-- Start time/End time added and removed here! :-) -->
-
-        <!-- Interruptions allowed -->
-        <com.android.settings.DropDownPreference
-                android:key="downtime_mode"
-                android:title="@string/zen_mode_downtime_mode_title"
-                android:order="100"
-                android:persistent="false" />
-
-    </PreferenceCategory>
-
-    <PreferenceCategory
-        android:key="automation"
-        android:title="@string/zen_mode_automation_category" >
-
-        <Preference
-            android:key="entry"
-            android:title="@string/zen_mode_entry_conditions_title"
-            android:persistent="false" />
-
-        <Preference
-                android:key="manage_condition_providers"
-                android:title="@string/manage_condition_providers"
-                android:persistent="false"
-                android:fragment="com.android.settings.notification.ConditionProviderSettings" />
-
-    </PreferenceCategory>
-
+    <!-- Rules added at runtime -->
 </PreferenceScreen>
diff --git a/res/xml/zen_mode_priority_settings.xml b/res/xml/zen_mode_priority_settings.xml
index e8bab66..6cdbe95 100644
--- a/res/xml/zen_mode_priority_settings.xml
+++ b/res/xml/zen_mode_priority_settings.xml
@@ -16,7 +16,7 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-    android:key="zen_mode_settings"
+    android:key="zen_mode_priority_settings"
     android:title="@string/zen_mode_priority_settings_title" >
 
     <!-- Alarms -->
diff --git a/res/xml/zen_mode_schedule_rule_settings.xml b/res/xml/zen_mode_schedule_rule_settings.xml
new file mode 100644
index 0000000..d808b10
--- /dev/null
+++ b/res/xml/zen_mode_schedule_rule_settings.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="zen_mode_schedule_rule_settings" >
+
+    <!-- Rule name -->
+    <Preference
+        android:key="rule_name"
+        android:title="@string/zen_mode_rule_name"
+        android:persistent="false" />
+
+    <!-- Days -->
+    <Preference
+        android:key="days"
+        android:title="@string/zen_mode_schedule_rule_days"
+        android:persistent="false" />
+
+    <!-- Start time/End time added and removed here! :-) -->
+
+    <!-- Zen mode -->
+    <com.android.settings.DropDownPreference
+            android:key="zen_mode"
+            android:title="@string/zen_mode_settings_title"
+            android:order="100"
+            android:persistent="false" />
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 70455a4..b58159e 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -96,6 +96,7 @@
     public static class ZenModeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class ZenModePrioritySettingsActivity extends SettingsActivity { /* empty */ }
     public static class ZenModeAutomationSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class ZenModeScheduleRuleSettingsActivity 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 0973b14..24209b0 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -100,6 +100,7 @@
 import com.android.settings.notification.NotificationStation;
 import com.android.settings.notification.OtherSoundSettings;
 import com.android.settings.notification.ZenModeSettings;
+import com.android.settings.notification.ZenModeScheduleRuleSettings;
 import com.android.settings.print.PrintJobSettingsFragment;
 import com.android.settings.print.PrintSettingsFragment;
 import com.android.settings.search.DynamicIndexableContentMonitor;
@@ -332,7 +333,8 @@
             AppNotificationSettings.class.getName(),
             OtherSoundSettings.class.getName(),
             ApnSettings.class.getName(),
-            WifiCallingSettings.class.getName()
+            WifiCallingSettings.class.getName(),
+            ZenModeScheduleRuleSettings.class.getName(),
     };
 
 
diff --git a/src/com/android/settings/notification/ZenModeAutomaticConditionSelection.java b/src/com/android/settings/notification/ZenModeAutomaticConditionSelection.java
deleted file mode 100644
index 0e77632..0000000
--- a/src/com/android/settings/notification/ZenModeAutomaticConditionSelection.java
+++ /dev/null
@@ -1,157 +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.animation.LayoutTransition;
-import android.app.INotificationManager;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
-import android.util.ArraySet;
-import android.util.Log;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.LinearLayout;
-
-import com.android.settings.R;
-
-public class ZenModeAutomaticConditionSelection extends LinearLayout {
-    private static final String TAG = "ZenModeAutomaticConditionSelection";
-    private static final boolean DEBUG = true;
-
-    private final INotificationManager mNoMan;
-    private final H mHandler = new H();
-    private final Context mContext;
-    private final ArraySet<Uri> mSelectedConditions = new ArraySet<Uri>();
-
-    public ZenModeAutomaticConditionSelection(Context context) {
-        super(context);
-        mContext = context;
-        setOrientation(VERTICAL);
-        setLayoutTransition(new LayoutTransition());
-        final int p = mContext.getResources().getDimensionPixelSize(R.dimen.content_margin_left);
-        setPadding(p, p, p, 0);
-        mNoMan = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        refreshSelectedConditions();
-    }
-
-    private void refreshSelectedConditions() {
-        try {
-            final Condition[] automatic = mNoMan.getAutomaticZenModeConditions();
-            mSelectedConditions.clear();
-            if (automatic != null) {
-                for (Condition c : automatic) {
-                    mSelectedConditions.add(c.id);
-                }
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error calling getAutomaticZenModeConditions", e);
-        }
-    }
-
-    private CheckBox newCheckBox(Object tag) {
-        final CheckBox button = new CheckBox(mContext);
-        button.setTag(tag);
-        button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                 setSelectedCondition((Uri)button.getTag(), isChecked);
-            }
-        });
-        addView(button);
-        return button;
-    }
-
-    private void setSelectedCondition(Uri conditionId, boolean selected) {
-        if (DEBUG) Log.d(TAG, "setSelectedCondition conditionId=" + conditionId
-                + " selected=" + selected);
-        if (selected) {
-            mSelectedConditions.add(conditionId);
-        } else {
-            mSelectedConditions.remove(conditionId);
-        }
-        final Uri[] automatic = new Uri[mSelectedConditions.size()];
-        for (int i = 0; i < automatic.length; i++) {
-            automatic[i] = mSelectedConditions.valueAt(i);
-        }
-        try {
-            mNoMan.setAutomaticZenModeConditions(automatic);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error calling setAutomaticZenModeConditions", e);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        requestZenModeConditions(Condition.FLAG_RELEVANT_ALWAYS);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        requestZenModeConditions(0 /*none*/);
-    }
-
-    protected void requestZenModeConditions(int relevance) {
-        if (DEBUG) Log.d(TAG, "requestZenModeConditions " + Condition.relevanceToString(relevance));
-        try {
-            mNoMan.requestZenModeConditions(mListener, relevance);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error calling requestZenModeConditions", e);
-        }
-    }
-
-    protected void handleConditions(Condition[] conditions) {
-        for (final Condition c : conditions) {
-            CheckBox v = (CheckBox) findViewWithTag(c.id);
-            if (c.state != Condition.STATE_ERROR) {
-                if (v == null) {
-                    v = newCheckBox(c.id);
-                }
-            }
-            if (v != null) {
-                v.setText(c.summary);
-                v.setEnabled(c.state != Condition.STATE_ERROR);
-                v.setChecked(mSelectedConditions.contains(c.id));
-            }
-        }
-    }
-
-    private final IConditionListener mListener = new IConditionListener.Stub() {
-        @Override
-        public void onConditionsReceived(Condition[] conditions) {
-            if (conditions == null || conditions.length == 0) return;
-            mHandler.obtainMessage(H.CONDITIONS, conditions).sendToTarget();
-        }
-    };
-
-    private final class H extends Handler {
-        private static final int CONDITIONS = 1;
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == CONDITIONS) handleConditions((Condition[])msg.obj);
-        }
-    }
-}
diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java
index 378643e..09de7d1 100644
--- a/src/com/android/settings/notification/ZenModeAutomationSettings.java
+++ b/src/com/android/settings/notification/ZenModeAutomationSettings.java
@@ -16,248 +16,76 @@
 
 package com.android.settings.notification;
 
-import static com.android.settings.notification.ZenModeDowntimeDaysSelection.DAYS;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.app.INotificationManager;
-import android.app.TimePickerDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
+import android.content.Intent;
 import android.os.Bundle;
-import android.os.ServiceManager;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
-import android.service.notification.Condition;
+import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
-import android.text.format.DateFormat;
+import android.service.notification.ZenModeConfig.ScheduleInfo;
+import android.service.notification.ZenModeConfig.ZenRule;
 import android.util.Log;
-import android.util.SparseArray;
-import android.widget.TimePicker;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.settings.DropDownPreference;
 import com.android.settings.R;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.search.Indexable;
-import com.android.settings.search.SearchIndexableRaw;
 
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Objects;
-
-public class ZenModeAutomationSettings extends ZenModeSettingsBase implements Indexable {
-    private static final String KEY_DOWNTIME = "downtime";
-    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_DOWNTIME_MODE = "downtime_mode";
-
-    private static final String KEY_AUTOMATION = "automation";
-    private static final String KEY_ENTRY = "entry";
-    private static final String KEY_CONDITION_PROVIDERS = "manage_condition_providers";
-
-    private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEE");
-
-    private PackageManager mPM;
-    private boolean mDisableListeners;
-    private boolean mDowntimeSupported;
-
-    private Preference mDays;
-    private TimePickerPreference mStart;
-    private TimePickerPreference mEnd;
-    private DropDownPreference mDowntimeMode;
-    private PreferenceCategory mAutomationCategory;
-    private Preference mEntry;
-    private Preference mConditionProviders;
+public class ZenModeAutomationSettings extends ZenModeSettingsBase {
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        mPM = mContext.getPackageManager();
+
+        setHasOptionsMenu(true);
 
         addPreferencesFromResource(R.xml.zen_mode_automation_settings);
-        final PreferenceScreen root = getPreferenceScreen();
-
-        onCreateDowntimeSettings(root);
-
-        mAutomationCategory = (PreferenceCategory) findPreference(KEY_AUTOMATION);
-        mEntry = findPreference(KEY_ENTRY);
-        mEntry.setOnPreferenceClickListener(new OnPreferenceClickListener() {
-            @Override
-            public boolean onPreferenceClick(Preference preference) {
-                new AlertDialog.Builder(mContext)
-                    .setTitle(R.string.zen_mode_entry_conditions_title)
-                    .setView(new ZenModeAutomaticConditionSelection(mContext))
-                    .setOnDismissListener(new OnDismissListener() {
-                        @Override
-                        public void onDismiss(DialogInterface dialog) {
-                            refreshAutomationSection();
-                        }
-                    })
-                    .setPositiveButton(R.string.dlg_ok, null)
-                    .show();
-                return true;
-            }
-        });
-        mConditionProviders = findPreference(KEY_CONDITION_PROVIDERS);
     }
 
-    private void onCreateDowntimeSettings(PreferenceScreen root) {
-        mDowntimeSupported = isDowntimeSupported(mContext);
-        if (!mDowntimeSupported) {
-            removePreference(KEY_DOWNTIME);
-            return;
-        }
-        final PreferenceCategory downtime = (PreferenceCategory) findPreference(KEY_DOWNTIME);
-        mDays = downtime.findPreference(KEY_DAYS);
-        mDays.setOnPreferenceClickListener(new OnPreferenceClickListener() {
-            @Override
-            public boolean onPreferenceClick(Preference preference) {
-                new AlertDialog.Builder(mContext)
-                        .setTitle(R.string.zen_mode_downtime_days)
-                        .setView(new ZenModeDowntimeDaysSelection(mContext, mConfig.sleepMode) {
-                              @Override
-                              protected void onChanged(String mode) {
-                                  if (mDisableListeners) return;
-                                  if (Objects.equals(mode, mConfig.sleepMode)) return;
-                                  if (DEBUG) Log.d(TAG, "days.onChanged sleepMode=" + mode);
-                                  final ZenModeConfig newConfig = mConfig.copy();
-                                  newConfig.sleepMode = mode;
-                                  setZenModeConfig(newConfig);
-                              }
-                        })
-                        .setOnDismissListener(new OnDismissListener() {
-                            @Override
-                            public void onDismiss(DialogInterface dialog) {
-                                updateDays();
-                            }
-                        })
-                        .setPositiveButton(R.string.done_button, null)
-                        .show();
-                return true;
-            }
-        });
-
-        final FragmentManager mgr = getFragmentManager();
-
-        mStart = new TimePickerPreference(mContext, mgr);
-        mStart.setKey(KEY_START_TIME);
-        mStart.setTitle(R.string.zen_mode_start_time);
-        mStart.setCallback(new TimePickerPreference.Callback() {
-            @Override
-            public boolean onSetTime(int hour, int minute) {
-                if (mDisableListeners) return true;
-                if (!ZenModeConfig.isValidHour(hour)) return false;
-                if (!ZenModeConfig.isValidMinute(minute)) return false;
-                if (hour == mConfig.sleepStartHour && minute == mConfig.sleepStartMinute) {
-                    return true;
-                }
-                if (DEBUG) Log.d(TAG, "onPrefChange sleepStart h=" + hour + " m=" + minute);
-                final ZenModeConfig newConfig = mConfig.copy();
-                newConfig.sleepStartHour = hour;
-                newConfig.sleepStartMinute = minute;
-                return setZenModeConfig(newConfig);
-            }
-        });
-        downtime.addPreference(mStart);
-        mStart.setDependency(mDays.getKey());
-
-        mEnd = new TimePickerPreference(mContext, mgr);
-        mEnd.setKey(KEY_END_TIME);
-        mEnd.setTitle(R.string.zen_mode_end_time);
-        mEnd.setCallback(new TimePickerPreference.Callback() {
-            @Override
-            public boolean onSetTime(int hour, int minute) {
-                if (mDisableListeners) return true;
-                if (!ZenModeConfig.isValidHour(hour)) return false;
-                if (!ZenModeConfig.isValidMinute(minute)) return false;
-                if (hour == mConfig.sleepEndHour && minute == mConfig.sleepEndMinute) {
-                    return true;
-                }
-                if (DEBUG) Log.d(TAG, "onPrefChange sleepEnd h=" + hour + " m=" + minute);
-                final ZenModeConfig newConfig = mConfig.copy();
-                newConfig.sleepEndHour = hour;
-                newConfig.sleepEndMinute = minute;
-                return setZenModeConfig(newConfig);
-            }
-        });
-        downtime.addPreference(mEnd);
-        mEnd.setDependency(mDays.getKey());
-
-        mDowntimeMode = (DropDownPreference) downtime.findPreference(KEY_DOWNTIME_MODE);
-        mDowntimeMode.addItem(R.string.zen_mode_downtime_mode_priority, false);
-        mDowntimeMode.addItem(R.string.zen_mode_downtime_mode_none, true);
-        mDowntimeMode.setCallback(new DropDownPreference.Callback() {
-            @Override
-            public boolean onItemSelected(int pos, Object value) {
-                if (mDisableListeners) return true;
-                final boolean sleepNone = value instanceof Boolean ? ((Boolean) value) : false;
-                if (mConfig == null || mConfig.sleepNone == sleepNone) return false;
-                final ZenModeConfig newConfig = mConfig.copy();
-                newConfig.sleepNone = sleepNone;
-                if (DEBUG) Log.d(TAG, "onPrefChange sleepNone=" + sleepNone);
-                return setZenModeConfig(newConfig);
-            }
-        });
-        mDowntimeMode.setOrder(10);  // sort at the bottom of the category
-        mDowntimeMode.setDependency(mDays.getKey());
+    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));
     }
 
-    private void updateDays() {
-        // Compute an ordered, delimited list of day names based on the persisted user config.
-        if (mConfig != null) {
-            final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
-            if (days != null && days.length != 0) {
-                final StringBuilder sb = new StringBuilder();
-                final Calendar c = Calendar.getInstance();
-                for (int i = 0; i < DAYS.length; i++) {
-                    final int day = DAYS[i];
-                    for (int j = 0; j < days.length; j++) {
-                        if (day == days[j]) {
-                            c.set(Calendar.DAY_OF_WEEK, day);
-                            if (sb.length() > 0) {
-                                sb.append(mContext.getString(R.string.summary_divider_text));
-                            }
-                            sb.append(DAY_FORMAT.format(c.getTime()));
-                            break;
-                        }
-                    }
-                }
-                if (sb.length() > 0) {
-                    mDays.setSummary(sb);
-                    mDays.notifyDependencyChange(false);
-                    return;
-                }
-            }
-        }
-        mDays.setSummary(R.string.zen_mode_downtime_days_none);
-        mDays.notifyDependencyChange(true);
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.zen_mode_automation, menu);
     }
 
-    private void updateEndSummary() {
-        if (!mDowntimeSupported) return;
-        final int startMin = 60 * mConfig.sleepStartHour + mConfig.sleepStartMinute;
-        final int endMin = 60 * mConfig.sleepEndHour + mConfig.sleepEndMinute;
-        final boolean nextDay = startMin >= endMin;
-        final int summaryFormat;
-        if (mConfig.sleepNone) {
-            summaryFormat = nextDay ? R.string.zen_mode_end_time_none_next_day_summary_format
-                    : R.string.zen_mode_end_time_none_same_day_summary_format;
-        } else {
-            summaryFormat = nextDay ? R.string.zen_mode_end_time_priority_next_day_summary_format
-                    : 0;
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.add) {
+            showAddRuleDialog();
+            return true;
         }
-        mEnd.setSummaryFormat(summaryFormat);
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void showAddRuleDialog() {
+        new ZenRuleNameDialog(mContext, "", mConfig.getAutomaticRuleNames()) {
+            @Override
+            public void onOk(String ruleName) {
+                final ScheduleInfo schedule = new ScheduleInfo();
+                schedule.days = ZenModeConfig.ALL_DAYS;
+                schedule.startHour = 22;
+                schedule.endHour = 7;
+                final ZenRule rule = new ZenRule();
+                rule.name = ruleName;
+                rule.enabled = true;
+                rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+                rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
+                final ZenModeConfig newConfig = mConfig.copy();
+                final String ruleId = newConfig.newRuleId();
+                newConfig.automaticRules.put(ruleId, rule);
+                if (setZenModeConfig(newConfig)) {
+                    showRule(ruleId, rule.name);
+                }
+            }
+        }.show();
     }
 
     @Override
@@ -277,16 +105,27 @@
     }
 
     private void updateControls() {
-        mDisableListeners = true;
-        if (mDowntimeSupported) {
-            updateDays();
-            mStart.setTime(mConfig.sleepStartHour, mConfig.sleepStartMinute);
-            mEnd.setTime(mConfig.sleepEndHour, mConfig.sleepEndMinute);
-            mDowntimeMode.setSelectedValue(mConfig.sleepNone);
+        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 Preference p = new Preference(mContext);
+            p.setTitle(rule.name);
+            p.setSummary(rule.enabled ? R.string.switch_on_text : R.string.switch_off_text);
+            p.setPersistent(false);
+            p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+                @Override
+                public boolean onPreferenceClick(Preference preference) {
+                    showRule(id, rule.name);
+                    return true;
+                }
+            });
+            root.addPreference(p);
         }
-        mDisableListeners = false;
-        refreshAutomationSection();
-        updateEndSummary();
     }
 
     @Override
@@ -294,171 +133,4 @@
         return MetricsLogger.NOTIFICATION_ZEN_MODE_AUTOMATION;
     }
 
-    private void refreshAutomationSection() {
-        if (mConditionProviders != null) {
-            final int total = ConditionProviderSettings.getProviderCount(mPM);
-            if (total == 0) {
-                getPreferenceScreen().removePreference(mAutomationCategory);
-            } else {
-                final int n = ConditionProviderSettings.getEnabledProviderCount(mContext);
-                if (n == 0) {
-                    mConditionProviders.setSummary(getResources().getString(
-                            R.string.manage_condition_providers_summary_zero));
-                } else {
-                    mConditionProviders.setSummary(String.format(getResources().getQuantityString(
-                            R.plurals.manage_condition_providers_summary_nonzero,
-                            n, n)));
-                }
-                final String entrySummary = getEntryConditionSummary();
-                if (n == 0 || entrySummary == null) {
-                    mEntry.setSummary(R.string.zen_mode_entry_conditions_summary_none);
-                } else {
-                    mEntry.setSummary(entrySummary);
-                }
-            }
-        }
-    }
-
-    private String getEntryConditionSummary() {
-        final INotificationManager nm = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        try {
-            final Condition[] automatic = nm.getAutomaticZenModeConditions();
-            if (automatic == null || automatic.length == 0) {
-                return null;
-            }
-            final String divider = getString(R.string.summary_divider_text);
-            final StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < automatic.length; i++) {
-                if (i > 0) sb.append(divider);
-                sb.append(automatic[i].summary);
-            }
-            return sb.toString();
-        } catch (Exception e) {
-            Log.w(TAG, "Error calling getAutomaticZenModeConditions", e);
-            return null;
-        }
-    }
-
-    private static SparseArray<String> allKeyTitles(Context context) {
-        final SparseArray<String> rt = new SparseArray<String>();
-        rt.put(R.string.zen_mode_downtime_category, KEY_DOWNTIME);
-        rt.put(R.string.zen_mode_downtime_days, KEY_DAYS);
-        rt.put(R.string.zen_mode_start_time, KEY_START_TIME);
-        rt.put(R.string.zen_mode_end_time, KEY_END_TIME);
-        rt.put(R.string.zen_mode_downtime_mode_title, KEY_DOWNTIME_MODE);
-        rt.put(R.string.zen_mode_automation_category, KEY_AUTOMATION);
-        rt.put(R.string.manage_condition_providers, KEY_CONDITION_PROVIDERS);
-        return rt;
-    }
-
-    // Enable indexing of searchable data
-    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-        new BaseSearchIndexProvider() {
-
-            @Override
-            public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
-                final SparseArray<String> keyTitles = allKeyTitles(context);
-                final int N = keyTitles.size();
-                final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>(N);
-                final Resources res = context.getResources();
-                for (int i = 0; i < N; i++) {
-                    final SearchIndexableRaw data = new SearchIndexableRaw(context);
-                    data.key = keyTitles.valueAt(i);
-                    data.title = res.getString(keyTitles.keyAt(i));
-                    data.screenTitle = res.getString(R.string.zen_mode_automation_settings_title);
-                    result.add(data);
-                }
-                return result;
-            }
-
-            @Override
-            public List<String> getNonIndexableKeys(Context context) {
-                final ArrayList<String> rt = new ArrayList<String>();
-                if (!isDowntimeSupported(context)) {
-                    rt.add(KEY_DOWNTIME);
-                    rt.add(KEY_DAYS);
-                    rt.add(KEY_START_TIME);
-                    rt.add(KEY_END_TIME);
-                    rt.add(KEY_DOWNTIME_MODE);
-                }
-                return rt;
-            }
-        };
-
-    private static class TimePickerPreference extends Preference {
-        private final Context mContext;
-
-        private int mSummaryFormat;
-        private int mHourOfDay;
-        private int mMinute;
-        private Callback mCallback;
-
-        public TimePickerPreference(Context context, final FragmentManager mgr) {
-            super(context);
-            mContext = context;
-            setPersistent(false);
-            setOnPreferenceClickListener(new OnPreferenceClickListener(){
-                @Override
-                public boolean onPreferenceClick(Preference preference) {
-                    final TimePickerFragment frag = new TimePickerFragment();
-                    frag.pref = TimePickerPreference.this;
-                    frag.show(mgr, TimePickerPreference.class.getName());
-                    return true;
-                }
-            });
-        }
-
-        public void setCallback(Callback callback) {
-            mCallback = callback;
-        }
-
-        public void setSummaryFormat(int resId) {
-            mSummaryFormat = resId;
-            updateSummary();
-        }
-
-        public void setTime(int hourOfDay, int minute) {
-            if (mCallback != null && !mCallback.onSetTime(hourOfDay, minute)) return;
-            mHourOfDay = hourOfDay;
-            mMinute = minute;
-            updateSummary();
-        }
-
-        private void updateSummary() {
-            final Calendar c = Calendar.getInstance();
-            c.set(Calendar.HOUR_OF_DAY, mHourOfDay);
-            c.set(Calendar.MINUTE, mMinute);
-            String time = DateFormat.getTimeFormat(mContext).format(c.getTime());
-            if (mSummaryFormat != 0) {
-                time = mContext.getResources().getString(mSummaryFormat, time);
-            }
-            setSummary(time);
-        }
-
-        public static class TimePickerFragment extends DialogFragment implements
-                TimePickerDialog.OnTimeSetListener {
-            public TimePickerPreference pref;
-
-            @Override
-            public Dialog onCreateDialog(Bundle savedInstanceState) {
-                final boolean usePref = pref != null && pref.mHourOfDay >= 0 && pref.mMinute >= 0;
-                final Calendar c = Calendar.getInstance();
-                final int hour = usePref ? pref.mHourOfDay : c.get(Calendar.HOUR_OF_DAY);
-                final int minute = usePref ? pref.mMinute : c.get(Calendar.MINUTE);
-                return new TimePickerDialog(getActivity(), this, hour, minute,
-                        DateFormat.is24HourFormat(getActivity()));
-            }
-
-            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
-                if (pref != null) {
-                    pref.setTime(hourOfDay, minute);
-                }
-            }
-        }
-
-        public interface Callback {
-            boolean onSetTime(int hour, int minute);
-        }
-    }
 }
diff --git a/src/com/android/settings/notification/ZenModeConditionSelection.java b/src/com/android/settings/notification/ZenModeConditionSelection.java
index 9beea0a..481bd88 100644
--- a/src/com/android/settings/notification/ZenModeConditionSelection.java
+++ b/src/com/android/settings/notification/ZenModeConditionSelection.java
@@ -45,11 +45,14 @@
     private final H mHandler = new H();
     private final Context mContext;
     private final List<Condition> mConditions;
+    private final int mZenMode;
+
     private Condition mCondition;
 
-    public ZenModeConditionSelection(Context context) {
+    public ZenModeConditionSelection(Context context, int zenMode) {
         super(context);
         mContext = context;
+        mZenMode = zenMode;
         mConditions = new ArrayList<Condition>();
         setLayoutTransition(new LayoutTransition());
         final int p = mContext.getResources().getDimensionPixelSize(R.dimen.content_margin_left);
@@ -130,7 +133,7 @@
     public void confirmCondition() {
         if (DEBUG) Log.d(TAG, "confirmCondition " + mCondition);
         try {
-            mNoMan.setZenModeCondition(mCondition);
+            mNoMan.setZenMode(mZenMode, mCondition != null ? mCondition.id : null, TAG);
         } catch (RemoteException e) {
             // noop
         }
diff --git a/src/com/android/settings/notification/ZenModeDowntimeDaysSelection.java b/src/com/android/settings/notification/ZenModeScheduleDaysSelection.java
similarity index 73%
rename from src/com/android/settings/notification/ZenModeDowntimeDaysSelection.java
rename to src/com/android/settings/notification/ZenModeScheduleDaysSelection.java
index 3361ad0..6d11ffb 100644
--- a/src/com/android/settings/notification/ZenModeDowntimeDaysSelection.java
+++ b/src/com/android/settings/notification/ZenModeScheduleDaysSelection.java
@@ -17,37 +17,42 @@
 package com.android.settings.notification;
 
 import android.content.Context;
-import android.service.notification.ZenModeConfig;
 import android.util.SparseBooleanArray;
 import android.view.LayoutInflater;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
-import android.widget.ScrollView;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.LinearLayout;
+import android.widget.ScrollView;
 
 import com.android.settings.R;
 
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Calendar;
 
-public class ZenModeDowntimeDaysSelection extends ScrollView {
+public class ZenModeScheduleDaysSelection extends ScrollView {
     public static final int[] DAYS = {
-        Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY,
-        Calendar.SATURDAY, Calendar.SUNDAY
+        Calendar.SUNDAY,
+        Calendar.MONDAY,
+        Calendar.TUESDAY,
+        Calendar.WEDNESDAY,
+        Calendar.THURSDAY,
+        Calendar.FRIDAY,
+        Calendar.SATURDAY,
     };
     private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEEE");
 
     private final SparseBooleanArray mDays = new SparseBooleanArray();
     private final LinearLayout mLayout;
 
-    public ZenModeDowntimeDaysSelection(Context context, String mode) {
+    public ZenModeScheduleDaysSelection(Context context, int[] days) {
         super(context);
         mLayout = new LinearLayout(mContext);
-        final int hPad = context.getResources().getDimensionPixelSize(R.dimen.zen_downtime_margin);
+        final int hPad = context.getResources()
+                .getDimensionPixelSize(R.dimen.zen_schedule_day_margin);
         mLayout.setPadding(hPad, 0, hPad, 0);
         addView(mLayout);
-        final int[] days = ZenModeConfig.tryParseDays(mode);
         if (days != null) {
             for (int i = 0; i < days.length; i++) {
                 mDays.put(days[i], true);
@@ -58,7 +63,7 @@
         final LayoutInflater inflater = LayoutInflater.from(context);
         for (int i = 0; i < DAYS.length; i++) {
             final int day = DAYS[i];
-            final CheckBox checkBox = (CheckBox) inflater.inflate(R.layout.zen_downtime_day,
+            final CheckBox checkBox = (CheckBox) inflater.inflate(R.layout.zen_schedule_rule_day,
                     this, false);
             c.set(Calendar.DAY_OF_WEEK, day);
             checkBox.setText(DAY_FORMAT.format(c.getTime()));
@@ -67,30 +72,29 @@
                 @Override
                 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                     mDays.put(day, isChecked);
-                    onChanged(getMode());
+                    onChanged(getDays());
                 }
             });
             mLayout.addView(checkBox);
         }
     }
 
-    private String getMode() {
-        final StringBuilder sb = new StringBuilder(ZenModeConfig.SLEEP_MODE_DAYS_PREFIX);
-        boolean empty = true;
+    private int[] getDays() {
+        final SparseBooleanArray rt = new SparseBooleanArray(mDays.size());
         for (int i = 0; i < mDays.size(); i++) {
             final int day = mDays.keyAt(i);
             if (!mDays.valueAt(i)) continue;
-            if (empty) {
-                empty = false;
-            } else {
-                sb.append(',');
-            }
-            sb.append(day);
+            rt.put(day, true);
         }
-        return empty ? null : sb.toString();
+        final int[] rta = new int[rt.size()];
+        for (int i = 0; i < rta.length; i++) {
+            rta[i] = rt.keyAt(i);
+        }
+        Arrays.sort(rta);
+        return rta;
     }
 
-    protected void onChanged(String mode) {
+    protected void onChanged(int[] days) {
         // event hook for subclasses
     }
 }
diff --git a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
new file mode 100644
index 0000000..7bec3c4
--- /dev/null
+++ b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
@@ -0,0 +1,477 @@
+/*
+ * 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 static com.android.settings.notification.ZenModeScheduleDaysSelection.DAYS;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+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";
+    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)
+                : null;
+        if (mSchedule == null) {
+            toastAndFinish();
+            return true;
+        }
+        return false;
+    }
+
+    @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);
+    }
+
+    @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;
+        }
+
+        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
+            public boolean onPreferenceClick(Preference preference) {
+                showDaysDialog();
+                return true;
+            }
+        });
+
+        final FragmentManager mgr = getFragmentManager();
+
+        mStart = new TimePickerPreference(mContext, mgr);
+        mStart.setKey(KEY_START_TIME);
+        mStart.setTitle(R.string.zen_mode_start_time);
+        mStart.setCallback(new TimePickerPreference.Callback() {
+            @Override
+            public boolean onSetTime(final int hour, final int minute) {
+                if (mDisableListeners) return true;
+                if (!ZenModeConfig.isValidHour(hour)) return false;
+                if (!ZenModeConfig.isValidMinute(minute)) return false;
+                if (hour == mSchedule.startHour && minute == mSchedule.startMinute) {
+                    return true;
+                }
+                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);
+                return true;
+            }
+        });
+        root.addPreference(mStart);
+        mStart.setDependency(mDays.getKey());
+
+        mEnd = new TimePickerPreference(mContext, mgr);
+        mEnd.setKey(KEY_END_TIME);
+        mEnd.setTitle(R.string.zen_mode_end_time);
+        mEnd.setCallback(new TimePickerPreference.Callback() {
+            @Override
+            public boolean onSetTime(final int hour, final int minute) {
+                if (mDisableListeners) return true;
+                if (!ZenModeConfig.isValidHour(hour)) return false;
+                if (!ZenModeConfig.isValidMinute(minute)) return false;
+                if (hour == mSchedule.endHour && minute == mSchedule.endMinute) {
+                    return true;
+                }
+                if (DEBUG) Log.d(TAG, "onPrefChange end h=" + hour + " m=" + minute);
+                mSchedule.startHour = hour;
+                mSchedule.startMinute = minute;
+                mRule.conditionId = ZenModeConfig.toScheduleConditionId(mSchedule);
+                mRule.condition = null;
+                mRule.snoozing = false;
+                setZenModeConfig(mConfig);
+                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() {
+        // Compute an ordered, delimited list of day names based on the persisted user config.
+        final int[] days = mSchedule.days;
+        if (days != null && days.length > 0) {
+            final StringBuilder sb = new StringBuilder();
+            final Calendar c = Calendar.getInstance();
+            for (int i = 0; i < DAYS.length; i++) {
+                final int day = DAYS[i];
+                for (int j = 0; j < days.length; j++) {
+                    if (day == days[j]) {
+                        c.set(Calendar.DAY_OF_WEEK, day);
+                        if (sb.length() > 0) {
+                            sb.append(mContext.getString(R.string.summary_divider_text));
+                        }
+                        sb.append(DAY_FORMAT.format(c.getTime()));
+                        break;
+                    }
+                }
+            }
+            if (sb.length() > 0) {
+                mDays.setSummary(sb);
+                mDays.notifyDependencyChange(false);
+                return;
+            }
+        }
+        mDays.setSummary(R.string.zen_mode_schedule_rule_days_none);
+        mDays.notifyDependencyChange(true);
+    }
+
+    private void updateEndSummary() {
+        final int startMin = 60 * mSchedule.startHour + mSchedule.startMinute;
+        final int endMin = 60 * mSchedule.endHour + mSchedule.endMinute;
+        final boolean nextDay = startMin >= endMin;
+        final int summaryFormat = nextDay ? R.string.zen_mode_end_time_next_day_summary_format : 0;
+        mEnd.setSummaryFormat(summaryFormat);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateControls();
+    }
+
+    private void updateRuleName() {
+        getActivity().setTitle(mRule.name);
+        mRuleName.setSummary(mRule.name);
+    }
+
+    private void updateControls() {
+        mDisableListeners = true;
+        updateRuleName();
+        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
+    protected int getMetricsCategory() {
+        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)
+                .setView(new ZenModeScheduleDaysSelection(mContext, mSchedule.days) {
+                      @Override
+                      protected void onChanged(final int[] days) {
+                          if (mDisableListeners) return;
+                          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);
+                      }
+                })
+                .setOnDismissListener(new OnDismissListener() {
+                    @Override
+                    public void onDismiss(DialogInterface dialog) {
+                        updateDays();
+                    }
+                })
+                .setPositiveButton(R.string.done_button, null)
+                .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;
+
+        private int mSummaryFormat;
+        private int mHourOfDay;
+        private int mMinute;
+        private Callback mCallback;
+
+        public TimePickerPreference(Context context, final FragmentManager mgr) {
+            super(context);
+            mContext = context;
+            setPersistent(false);
+            setOnPreferenceClickListener(new OnPreferenceClickListener(){
+                @Override
+                public boolean onPreferenceClick(Preference preference) {
+                    final TimePickerFragment frag = new TimePickerFragment();
+                    frag.pref = TimePickerPreference.this;
+                    frag.show(mgr, TimePickerPreference.class.getName());
+                    return true;
+                }
+            });
+        }
+
+        public void setCallback(Callback callback) {
+            mCallback = callback;
+        }
+
+        public void setSummaryFormat(int resId) {
+            mSummaryFormat = resId;
+            updateSummary();
+        }
+
+        public void setTime(int hourOfDay, int minute) {
+            if (mCallback != null && !mCallback.onSetTime(hourOfDay, minute)) return;
+            mHourOfDay = hourOfDay;
+            mMinute = minute;
+            updateSummary();
+        }
+
+        private void updateSummary() {
+            final Calendar c = Calendar.getInstance();
+            c.set(Calendar.HOUR_OF_DAY, mHourOfDay);
+            c.set(Calendar.MINUTE, mMinute);
+            String time = DateFormat.getTimeFormat(mContext).format(c.getTime());
+            if (mSummaryFormat != 0) {
+                time = mContext.getResources().getString(mSummaryFormat, time);
+            }
+            setSummary(time);
+        }
+
+        public static class TimePickerFragment extends DialogFragment implements
+                TimePickerDialog.OnTimeSetListener {
+            public TimePickerPreference pref;
+
+            @Override
+            public Dialog onCreateDialog(Bundle savedInstanceState) {
+                final boolean usePref = pref != null && pref.mHourOfDay >= 0 && pref.mMinute >= 0;
+                final Calendar c = Calendar.getInstance();
+                final int hour = usePref ? pref.mHourOfDay : c.get(Calendar.HOUR_OF_DAY);
+                final int minute = usePref ? pref.mMinute : c.get(Calendar.MINUTE);
+                return new TimePickerDialog(getActivity(), this, hour, minute,
+                        DateFormat.is24HourFormat(getActivity()));
+            }
+
+            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
+                if (pref != null) {
+                    pref.setTime(hourOfDay, minute);
+                }
+            }
+        }
+
+        public interface Callback {
+            boolean onSetTime(int hour, int minute);
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index f519796..4ff5e0f 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -21,10 +21,12 @@
 import android.content.DialogInterface;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -51,6 +53,7 @@
     private AlertDialog mDialog;
     private SwitchBar mSwitchBar;
     private boolean mShowing;
+    private boolean mUpdatingControls;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -60,7 +63,7 @@
         final PreferenceScreen root = getPreferenceScreen();
 
         mPrioritySettings = root.findPreference(KEY_PRIORITY_SETTINGS);
-        if (!isDowntimeSupported(mContext)) {
+        if (!isScheduleSupported(mContext)) {
             removePreference(KEY_AUTOMATION_SETTINGS);
         }
     }
@@ -97,13 +100,14 @@
 
     @Override
     public void onSwitchChanged(Switch switchView, boolean isChecked) {
-        if (DEBUG) Log.d(TAG, "onSwitchChanged " + isChecked + " mShowing=" + mShowing);
-        if (!mShowing) return; // not from the user
+        if (DEBUG) Log.d(TAG, "onSwitchChanged " + isChecked + " mShowing=" + mShowing
+                + " mUpdatingControls=" + mUpdatingControls);
+        if (!mShowing || mUpdatingControls) return; // not from the user
         if (isChecked) {
-            setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+            setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null);
             showConditionSelection(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
         } else {
-            setZenMode(Global.ZEN_MODE_OFF);
+            setZenMode(Global.ZEN_MODE_OFF, null);
         }
     }
 
@@ -135,29 +139,20 @@
         }
     }
 
-    private String computeExitConditionText() {
-        return mConfig == null || mConfig.exitCondition == null
-                ? getString(com.android.internal.R.string.zen_mode_forever)
-                : computeConditionText(mConfig.exitCondition);
-    }
-
-    public static String computeConditionText(Condition c) {
-        return !TextUtils.isEmpty(c.line1) ? c.line1
-                : !TextUtils.isEmpty(c.summary) ? c.summary
-                : "";
-    }
-
     private String computeZenModeSummaryLine() {
         final String caption = computeZenModeCaption(mZenMode);
-        if (caption == null) return null;
-        final String conditionText = computeExitConditionText().toLowerCase();
+        if (caption == null) return null;  // zen mode off
+        final String conditionText = ZenModeConfig.getConditionLine1(mContext, mConfig,
+                UserHandle.myUserId());
         return getString(R.string.zen_mode_summary_combination, caption, conditionText);
     }
 
     private void updateControls() {
         if (mSwitchBar != null) {
             final String summaryLine = computeZenModeSummaryLine();
+            mUpdatingControls = true;
             mSwitchBar.setChecked(summaryLine != null);
+            mUpdatingControls = false;
             mSwitchBar.setSummary(summaryLine);
         }
         updatePrioritySettingsSummary();
@@ -184,7 +179,7 @@
         if (mDialog != null) return;
 
         final ZenModeConditionSelection zenModeConditionSelection =
-                new ZenModeConditionSelection(mContext);
+                new ZenModeConditionSelection(mContext, zenMode);
         DialogInterface.OnClickListener positiveListener = new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
@@ -198,7 +193,7 @@
                 .setTitle(computeZenModeCaption(zenMode))
                 .setView(scrollView)
                 .setPositiveButton(R.string.okay, positiveListener)
-                .setNegativeButton(R.string.cancel_all_caps, new DialogInterface.OnClickListener() {
+                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         cancelDialog();
@@ -216,10 +211,16 @@
     private void cancelDialog() {
         if (DEBUG) Log.d(TAG, "cancelDialog");
         // If not making a decision, reset zen to off.
-        setZenMode(Global.ZEN_MODE_OFF);
+        setZenMode(Global.ZEN_MODE_OFF, null);
         mDialog = null;
     }
 
+    public static String computeConditionText(Condition c) {
+        return !TextUtils.isEmpty(c.line1) ? c.line1
+                : !TextUtils.isEmpty(c.summary) ? c.summary
+                : "";
+    }
+
     private static SparseArray<String> allKeyTitles(Context context) {
         final SparseArray<String> rt = new SparseArray<String>();
         rt.put(R.string.zen_mode_priority_settings_title, KEY_PRIORITY_SETTINGS);
@@ -250,7 +251,7 @@
             @Override
             public List<String> getNonIndexableKeys(Context context) {
                 final ArrayList<String> rt = new ArrayList<String>();
-                if (!isDowntimeSupported(context)) {
+                if (!isScheduleSupported(context)) {
                     rt.add(KEY_AUTOMATION_SETTINGS);
                 }
                 return rt;
diff --git a/src/com/android/settings/notification/ZenModeSettingsBase.java b/src/com/android/settings/notification/ZenModeSettingsBase.java
index 5ef0da4..9824dc7 100644
--- a/src/com/android/settings/notification/ZenModeSettingsBase.java
+++ b/src/com/android/settings/notification/ZenModeSettingsBase.java
@@ -16,14 +16,12 @@
 
 package com.android.settings.notification;
 
-import android.app.INotificationManager;
 import android.app.NotificationManager;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.ServiceManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
@@ -91,40 +89,27 @@
     }
 
     protected boolean setZenModeConfig(ZenModeConfig config) {
-        final INotificationManager nm = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        try {
-            final boolean success = nm.setZenModeConfig(config);
-            if (success) {
-                mConfig = config;
-                if (DEBUG) Log.d(TAG, "Saved mConfig=" + mConfig);
-                onZenModeConfigChanged();
-            }
-            return success;
-        } catch (Exception e) {
-           Log.w(TAG, "Error calling NoMan", e);
-           return false;
+        final String reason = getClass().getSimpleName();
+        final boolean success = NotificationManager.from(mContext).setZenModeConfig(config, reason);
+        if (success) {
+            mConfig = config;
+            if (DEBUG) Log.d(TAG, "Saved mConfig=" + mConfig);
+            onZenModeConfigChanged();
         }
+        return success;
     }
 
-    protected void setZenMode(int zenMode) {
-        Global.putInt(getContentResolver(), Global.ZEN_MODE, zenMode);
+    protected void setZenMode(int zenMode, Uri conditionId) {
+        NotificationManager.from(mContext).setZenMode(zenMode, conditionId, TAG);
     }
 
-    protected static boolean isDowntimeSupported(Context context) {
+    protected static boolean isScheduleSupported(Context context) {
         return NotificationManager.from(context)
-                .isSystemConditionProviderEnabled(ZenModeConfig.DOWNTIME_PATH);
+                .isSystemConditionProviderEnabled(ZenModeConfig.SCHEDULE_PATH);
     }
 
     private ZenModeConfig getZenModeConfig() {
-        final INotificationManager nm = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        try {
-            return nm.getZenModeConfig();
-        } catch (Exception e) {
-           Log.w(TAG, "Error calling NoMan", e);
-           return new ZenModeConfig();
-        }
+        return NotificationManager.from(mContext).getZenModeConfig();
     }
 
     private final class SettingsObserver extends ContentObserver {
diff --git a/src/com/android/settings/notification/ZenRuleNameDialog.java b/src/com/android/settings/notification/ZenRuleNameDialog.java
new file mode 100644
index 0000000..b0eaaec
--- /dev/null
+++ b/src/com/android/settings/notification/ZenRuleNameDialog.java
@@ -0,0 +1,93 @@
+/*
+ * 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.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.ArraySet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+
+import com.android.settings.R;
+
+public abstract class ZenRuleNameDialog {
+    private final AlertDialog mDialog;
+    private final EditText mEditText;
+    private final ArraySet<String> mExistingNames;
+
+    public ZenRuleNameDialog(Context context, String ruleName, ArraySet<String> existingNames) {
+        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);
+        mEditText.setSelectAllOnFocus(true);
+        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());
+                    }
+                })
+                .setNegativeButton(R.string.cancel, null)
+                .create();
+        mEditText.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+                // noop
+            }
+
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+                // noop
+            }
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                updatePositiveButton();
+            }
+        });
+        mExistingNames = new ArraySet<String>(existingNames.size());
+        for (String existingName : existingNames) {
+            mExistingNames.add(existingName.toLowerCase());
+        }
+    }
+
+    abstract public void onOk(String ruleName);
+
+    private String trimmedText() {
+        return mEditText.getText() == null ? null : mEditText.getText().toString().trim();
+    }
+
+    public void show() {
+        mDialog.show();
+        updatePositiveButton();
+    }
+
+    private void updatePositiveButton() {
+        final String name = trimmedText();
+        final boolean validName = !TextUtils.isEmpty(name)
+                && !mExistingNames.contains(name.toLowerCase());
+        mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validName);
+    }
+
+}
\ No newline at end of file
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 0ad9503..dae8860 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -24,11 +24,12 @@
 import com.android.settings.DeviceInfoSettings;
 import com.android.settings.DisplaySettings;
 import com.android.settings.HomeSettings;
-import com.android.settings.ScreenPinningSettings;
 import com.android.settings.PrivacySettings;
 import com.android.settings.R;
+import com.android.settings.ScreenPinningSettings;
 import com.android.settings.SecuritySettings;
 import com.android.settings.WallpaperTypeSettings;
+import com.android.settings.WifiCallingSettings;
 import com.android.settings.WirelessSettings;
 import com.android.settings.accessibility.AccessibilitySettings;
 import com.android.settings.applications.AdvancedAppSettings;
@@ -43,7 +44,6 @@
 import com.android.settings.net.DataUsageMeteredSettings;
 import com.android.settings.notification.NotificationSettings;
 import com.android.settings.notification.OtherSoundSettings;
-import com.android.settings.notification.ZenModeAutomationSettings;
 import com.android.settings.notification.ZenModePrioritySettings;
 import com.android.settings.notification.ZenModeSettings;
 import com.android.settings.print.PrintSettingsFragment;
@@ -53,7 +53,6 @@
 import com.android.settings.wifi.AdvancedWifiSettings;
 import com.android.settings.wifi.SavedAccessPointsWifiSettings;
 import com.android.settings.wifi.WifiSettings;
-import com.android.settings.WifiCallingSettings;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -171,13 +170,6 @@
                         ZenModePrioritySettings.class.getName(),
                         R.drawable.ic_settings_notifications));
 
-        sResMap.put(ZenModeAutomationSettings.class.getName(),
-                new SearchIndexableResource(
-                        Ranking.getRankForClassName(ZenModeAutomationSettings.class.getName()),
-                        NO_DATA_RES_ID,
-                        ZenModeAutomationSettings.class.getName(),
-                        R.drawable.ic_settings_notifications));
-
         sResMap.put(Memory.class.getName(),
                 new SearchIndexableResource(
                         Ranking.getRankForClassName(Memory.class.getName()),