Updates to automatic rule pages in Settings

- Re-added metrics for zen behavior preference controllers
- Dialogs in zen mode settings are rotate-friendly
- Automatic rules are refreshed on update state
- User-created (and default) automatic rules are always priority only and user cannot change this
- Automatic rules redesigned to have headers

Test: make ROBOTEST_FILTER=ZenModeAutomaticRulesPreferenceControllerTest RunSettingsRoboTests -j40
Bug: 63077372
Fixes: 68324465
Fixes: 69057696
Change-Id: I163acef2715dd4e60bfc08207f0e22352c4c0e28
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c38c86b..7331d72 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6741,6 +6741,9 @@
     <!--  Do not disturb: Title for the zen mode automatic rules page in settings. [CHAR LIMIT=30] -->
     <string name="zen_mode_automation_settings_page_title">Automatic rules</string>
 
+    <!--  Do not disturb: Title for a specific zen mode automatic rule in settings. [CHAR LIMIT=30] -->
+    <string name="zen_mode_automatic_rule_settings_page_title">Automatic rule</string>
+
     <!--  Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=50] -->
     <string name="zen_mode_automation_suggestion_title">Set Do Not Disturb rules</string>
 
diff --git a/res/xml/zen_mode_event_rule_settings.xml b/res/xml/zen_mode_event_rule_settings.xml
index 102d2a2..159dbe0 100644
--- a/res/xml/zen_mode_event_rule_settings.xml
+++ b/res/xml/zen_mode_event_rule_settings.xml
@@ -15,8 +15,18 @@
      limitations under the License.
 -->
 
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-    android:key="zen_mode_event_rule_settings" >
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="zen_mode_event_rule_settings"
+    android:title="@string/zen_mode_automatic_rule_settings_page_title">
+
+    <com.android.settings.applications.LayoutPreference
+        android:key="pref_app_header"
+        android:layout="@layout/settings_entity_header" />
+
+    <com.android.settings.applications.LayoutPreference
+        android:key="zen_automatic_rule_switch"
+        android:layout="@layout/styled_switch_bar" />
 
     <!-- Rule name -->
     <Preference
@@ -36,10 +46,4 @@
         android:title="@string/zen_mode_event_rule_reply"
         android:summary="%s" />
 
-    <!-- Zen mode -->
-    <DropDownPreference
-        android:key="zen_mode"
-        android:title="@string/zen_mode_settings_title"
-        android:summary="%s" />
-
 </PreferenceScreen>
diff --git a/res/xml/zen_mode_schedule_rule_settings.xml b/res/xml/zen_mode_schedule_rule_settings.xml
index 6224ce1..a0c52c0 100644
--- a/res/xml/zen_mode_schedule_rule_settings.xml
+++ b/res/xml/zen_mode_schedule_rule_settings.xml
@@ -15,8 +15,18 @@
      limitations under the License.
 -->
 
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-    android:key="zen_mode_schedule_rule_settings" >
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="zen_mode_schedule_rule_settings"
+    android:title="@string/zen_mode_automatic_rule_settings_page_title">
+
+    <com.android.settings.applications.LayoutPreference
+        android:key="pref_app_header"
+        android:layout="@layout/settings_entity_header" />
+
+    <com.android.settings.applications.LayoutPreference
+        android:key="zen_automatic_rule_switch"
+        android:layout="@layout/styled_switch_bar" />
 
     <!-- Rule name -->
     <Preference
@@ -39,11 +49,4 @@
         android:summary="@string/zen_mode_schedule_alarm_summary"
         android:order="99" />
 
-    <!-- Zen mode -->
-    <DropDownPreference
-            android:key="zen_mode"
-            android:title="@string/zen_mode_settings_title"
-            android:order="100"
-            android:summary="%s" />
-
 </PreferenceScreen>
diff --git a/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java b/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
index ec9cf2a..cc70a6f 100644
--- a/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
+++ b/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
@@ -29,8 +29,9 @@
 import android.service.notification.ZenModeConfig;
 import android.support.v7.preference.Preference;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import java.util.Arrays;
 import java.util.Comparator;
@@ -38,19 +39,19 @@
 import java.util.Set;
 
 abstract public class AbstractZenModeAutomaticRulePreferenceController extends
-        AbstractPreferenceController implements PreferenceControllerMixin {
+        AbstractZenModePreferenceController implements PreferenceControllerMixin {
 
-    private static final String TAG = "ZenModeAutomaticRule";
     protected ZenModeBackend mBackend;
     protected Fragment mParent;
     protected Set<Map.Entry<String, AutomaticZenRule>> mRules;
     protected PackageManager mPm;
 
-    public AbstractZenModeAutomaticRulePreferenceController(Context context, Fragment parent) {
-        super(context);
+    public AbstractZenModeAutomaticRulePreferenceController(Context context, String key, Fragment
+            parent, Lifecycle lifecycle) {
+        super(context, key, lifecycle);
         mBackend = ZenModeBackend.getInstance(context);
-        mParent = parent;
         mPm = mContext.getPackageManager();
+        mParent = parent;
     }
 
     @Override
@@ -65,19 +66,9 @@
         return ruleMap.entrySet();
     }
 
-    protected void showNameRuleDialog(final ZenRuleInfo ri) {
-        new ZenRuleNameDialog(mContext, null, ri.defaultConditionId) {
-            @Override
-            public void onOk(String ruleName) {
-                AutomaticZenRule rule = new AutomaticZenRule(ruleName, ri.serviceComponent,
-                        ri.defaultConditionId, NotificationManager.INTERRUPTION_FILTER_PRIORITY,
-                        true);
-                String savedRuleId = mBackend.addZenRule(rule);
-                if (savedRuleId != null) {
-                    mParent.startActivity(getRuleIntent(ri.settingsAction, null, savedRuleId));
-                }
-            }
-        }.show();
+    protected void showNameRuleDialog(final ZenRuleInfo ri, Fragment parent) {
+        ZenRuleNameDialog.show(parent, null, ri.defaultConditionId, new
+                RuleNameChangeListener(ri));
     }
 
     protected Map.Entry<String, AutomaticZenRule>[] sortedRules() {
@@ -157,4 +148,26 @@
         }
         return null;
     }
+
+    public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener {
+        ZenRuleInfo mRuleInfo;
+
+        public RuleNameChangeListener(ZenRuleInfo ruleInfo) {
+            mRuleInfo = ruleInfo;
+        }
+
+        @Override
+        public void onOk(String ruleName, Fragment parent) {
+            mMetricsFeatureProvider.action(mContext,
+                    MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
+            AutomaticZenRule rule = new AutomaticZenRule(ruleName, mRuleInfo.serviceComponent,
+                    mRuleInfo.defaultConditionId,
+                    NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+            String savedRuleId = mBackend.addZenRule(rule);
+            if (savedRuleId != null) {
+                parent.startActivity(getRuleIntent(mRuleInfo.settingsAction, null,
+                        savedRuleId));
+            }
+        }
+    }
 }
diff --git a/src/com/android/settings/notification/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/AbstractZenModePreferenceController.java
index 2642f81..33c027c 100644
--- a/src/com/android/settings/notification/AbstractZenModePreferenceController.java
+++ b/src/com/android/settings/notification/AbstractZenModePreferenceController.java
@@ -35,6 +35,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -51,6 +53,7 @@
     private final String KEY;
     final private NotificationManager mNotificationManager;
     protected static ZenModeConfigWrapper mZenModeConfigWrapper;
+    protected MetricsFeatureProvider mMetricsFeatureProvider;
 
     public AbstractZenModePreferenceController(Context context, String key,
             Lifecycle lifecycle) {
@@ -62,6 +65,9 @@
         KEY = key;
         mNotificationManager = (NotificationManager) context.getSystemService(
                 Context.NOTIFICATION_SERVICE);
+
+        final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
+        mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
     }
 
     @Override
diff --git a/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
new file mode 100644
index 0000000..8494998
--- /dev/null
+++ b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 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.widget.EntityHeaderController.PREF_KEY_APP_HEADER;
+
+import android.app.AutomaticZenRule;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.util.Slog;
+import android.view.View;
+
+import com.android.settings.R;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenAutomaticRuleHeaderPreferenceController extends AbstractZenModePreferenceController
+        implements PreferenceControllerMixin {
+
+    private final String KEY = PREF_KEY_APP_HEADER;
+    private final PreferenceFragment mFragment;
+    private AutomaticZenRule mRule;
+    private EntityHeaderController mController;
+
+    public ZenAutomaticRuleHeaderPreferenceController(Context context, PreferenceFragment fragment,
+            Lifecycle lifecycle) {
+        super(context, PREF_KEY_APP_HEADER, lifecycle);
+        mFragment = fragment;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mRule != null;
+    }
+
+    public void updateState(Preference preference) {
+        if (mRule == null) {
+            return;
+        }
+
+        if (mFragment != null) {
+            LayoutPreference pref = (LayoutPreference) preference;
+
+            if (mController == null) {
+                mController = EntityHeaderController
+                        .newInstance(mFragment.getActivity(), mFragment,
+                                pref.findViewById(R.id.entity_header));
+            }
+
+            pref = mController.setIcon(getIcon())
+                    .setLabel(mRule.getName())
+                    .setPackageName(mRule.getOwner().getPackageName())
+                    .setUid(mContext.getUserId())
+                    .setHasAppInfoLink(false)
+                    .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
+                            EntityHeaderController.ActionType.ACTION_NONE)
+                    .done(mFragment.getActivity(), mContext);
+
+            pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
+        }
+    }
+
+    private Drawable getIcon() {
+        try {
+            PackageManager packageManager =  mContext.getPackageManager();
+            ApplicationInfo info = packageManager.getApplicationInfo(
+                    mRule.getOwner().getPackageName(), 0);
+            return info.loadIcon(packageManager);
+        } catch (PackageManager.NameNotFoundException e) {
+           Slog.w(TAG, "Unable to load icon - PackageManager.NameNotFoundException");
+        }
+
+        return null;
+    }
+
+    protected void onResume(AutomaticZenRule rule) {
+        mRule = rule;
+    }
+}
diff --git a/src/com/android/settings/notification/ZenAutomaticRuleSwitchPreferenceController.java b/src/com/android/settings/notification/ZenAutomaticRuleSwitchPreferenceController.java
new file mode 100644
index 0000000..bc3fa25
--- /dev/null
+++ b/src/com/android/settings/notification/ZenAutomaticRuleSwitchPreferenceController.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 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.AutomaticZenRule;
+import android.app.Fragment;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.widget.Switch;
+import android.widget.Toast;
+
+import com.android.settings.R;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.widget.SwitchBar;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenAutomaticRuleSwitchPreferenceController extends
+        AbstractZenModeAutomaticRulePreferenceController implements
+        SwitchBar.OnSwitchChangeListener {
+
+    private static final String KEY = "zen_automatic_rule_switch";
+    private AutomaticZenRule mRule;
+    private String mId;
+    private Toast mEnabledToast;
+    private int mToastTextResource;
+
+    public ZenAutomaticRuleSwitchPreferenceController(Context context, Fragment parent,
+            int toastTextResource, Lifecycle lifecycle) {
+        super(context, KEY, parent, lifecycle);
+        mToastTextResource = toastTextResource;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mRule != null && mId != null;
+    }
+
+    public void onResume(AutomaticZenRule rule, String id) {
+        mRule = rule;
+        mId = id;
+    }
+
+    public void updateState(Preference preference) {
+        LayoutPreference pref = (LayoutPreference) preference;
+        SwitchBar bar = pref.findViewById(R.id.switch_bar);
+        if (mRule != null) {
+            bar.setChecked(mRule.isEnabled());
+        }
+        if (bar != null) {
+            bar.show();
+            try {
+                bar.addOnSwitchChangeListener(this);
+            } catch (IllegalStateException e) {
+                // an exception is thrown if you try to add the listener twice
+            }
+        }
+        bar.show();
+    }
+
+    @Override
+    public void onSwitchChanged(Switch switchView, boolean isChecked) {
+        final boolean enabled = isChecked;
+        if (enabled == mRule.isEnabled()) return;
+        mRule.setEnabled(enabled);
+        mBackend.setZenRule(mId, mRule);
+        if (enabled) {
+            final int toastText = mToastTextResource;
+            if (toastText != 0) {
+                mEnabledToast = Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT);
+                mEnabledToast.show();
+            }
+        } else {
+            if (mEnabledToast != null) {
+                mEnabledToast.cancel();
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/ZenDeleteRuleDialog.java b/src/com/android/settings/notification/ZenDeleteRuleDialog.java
new file mode 100644
index 0000000..d9061d3
--- /dev/null
+++ b/src/com/android/settings/notification/ZenDeleteRuleDialog.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Fragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class ZenDeleteRuleDialog extends InstrumentedDialogFragment {
+    protected static final String TAG = "ZenDeleteRuleDialog";
+    private static final String EXTRA_ZEN_RULE_NAME = "zen_rule_name";
+    private static final String EXTRA_ZEN_RULE_ID = "zen_rule_id";
+    protected static PositiveClickListener mPositiveClickListener;
+
+    /**
+     * The interface we expect a listener to implement.
+     */
+    public interface PositiveClickListener {
+        void onOk(String id);
+    }
+
+    public static void show(Fragment parent, String ruleName, String id, PositiveClickListener
+            listener) {
+        final Bundle args = new Bundle();
+        args.putString(EXTRA_ZEN_RULE_NAME, ruleName);
+        args.putString(EXTRA_ZEN_RULE_ID, id);
+        mPositiveClickListener = listener;
+
+        ZenDeleteRuleDialog dialog = new ZenDeleteRuleDialog();
+        dialog.setArguments(args);
+        dialog.setTargetFragment(parent, 0);
+        dialog.show(parent.getFragmentManager(), TAG);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Bundle arguments = getArguments();
+        String ruleName = arguments.getString(EXTRA_ZEN_RULE_NAME);
+        String id = arguments.getString(EXTRA_ZEN_RULE_ID);
+
+        final AlertDialog dialog = new AlertDialog.Builder(getContext())
+                .setMessage(getString(R.string.zen_mode_delete_rule_confirmation, ruleName))
+                .setNegativeButton(R.string.cancel, null)
+                .setPositiveButton(R.string.zen_mode_delete_rule_button,
+                        new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        if (arguments != null) {
+                            mPositiveClickListener.onOk(id);
+                        }
+                    }
+                }).create();
+        final View messageView = dialog.findViewById(android.R.id.message);
+        if (messageView != null) {
+            messageView.setTextDirection(View.TEXT_DIRECTION_LOCALE);
+        }
+        return dialog;
+    }
+
+}
diff --git a/src/com/android/settings/notification/ZenModeAddAutomaticRulePreferenceController.java b/src/com/android/settings/notification/ZenModeAddAutomaticRulePreferenceController.java
index a15536c..b2e69d8 100644
--- a/src/com/android/settings/notification/ZenModeAddAutomaticRulePreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeAddAutomaticRulePreferenceController.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
+import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import com.android.settings.utils.ZenServiceListing;
 
@@ -28,19 +29,18 @@
         AbstractZenModeAutomaticRulePreferenceController implements
         Preference.OnPreferenceClickListener {
 
-    private final String KEY_ADD_RULE;
+    protected static final String KEY = "zen_mode_add_automatic_rule";
     private final ZenServiceListing mZenServiceListing;
 
-    public ZenModeAddAutomaticRulePreferenceController(Context context, String key,
-            Fragment parent, ZenServiceListing serviceListing) {
-        super(context, parent);
-        KEY_ADD_RULE = key;
+    public ZenModeAddAutomaticRulePreferenceController(Context context, Fragment parent,
+            ZenServiceListing serviceListing, Lifecycle lifecycle) {
+        super(context, KEY, parent, lifecycle);
         mZenServiceListing = serviceListing;
     }
 
     @Override
     public String getPreferenceKey() {
-        return KEY_ADD_RULE;
+        return KEY;
     }
 
     @Override
@@ -51,25 +51,30 @@
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-        Preference pref = screen.findPreference(KEY_ADD_RULE);
+        Preference pref = screen.findPreference(KEY);
         pref.setPersistent(false);
         pref.setOnPreferenceClickListener(this);
     }
 
     @Override
     public boolean onPreferenceClick(Preference preference) {
-        new ZenRuleSelectionDialog(mContext, mZenServiceListing) {
-            @Override
-            public void onSystemRuleSelected(ZenRuleInfo ri) {
-                showNameRuleDialog(ri);
-            }
-
-            @Override
-            public void onExternalRuleSelected(ZenRuleInfo ri) {
-                Intent intent = new Intent().setComponent(ri.configurationActivity);
-                mParent.startActivity(intent);
-            }
-        }.show();
+        ZenRuleSelectionDialog.show(mContext, mParent, new RuleSelectionListener(),
+                mZenServiceListing);
         return true;
     }
+
+    public class RuleSelectionListener implements ZenRuleSelectionDialog.PositiveClickListener {
+        public RuleSelectionListener() {}
+
+        @Override
+        public void onSystemRuleSelected(ZenRuleInfo ri, Fragment parent) {
+            showNameRuleDialog(ri, parent);
+        }
+
+        @Override
+        public void onExternalRuleSelected(ZenRuleInfo ri, Fragment parent) {
+            Intent intent = new Intent().setComponent(ri.configurationActivity);
+            parent.startActivity(intent);
+        }
+    }
 }
diff --git a/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java b/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java
index ef8d026..a15f7fc 100644
--- a/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java
@@ -23,6 +23,7 @@
 import android.support.v7.preference.Preference;
 import android.util.Log;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 public class ZenModeAlarmsPreferenceController extends
@@ -73,6 +74,9 @@
         if (ZenModeSettingsBase.DEBUG) {
             Log.d(TAG, "onPrefChange allowAlarms=" + allowAlarms);
         }
+
+        mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_ALARMS,
+                allowAlarms);
         mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_ALARMS, allowAlarms);
         return true;
     }
diff --git a/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java b/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
index f91bdd6..55fe927 100644
--- a/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
@@ -19,28 +19,31 @@
 import android.app.AutomaticZenRule;
 import android.app.Fragment;
 import android.content.Context;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceCategory;
 import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
 import java.util.Map;
 
 public class ZenModeAutomaticRulesPreferenceController extends
         AbstractZenModeAutomaticRulePreferenceController {
 
-    private final String KEY_AUTOMATIC_RULES;
-    private PreferenceCategory mPreferenceCategory;
-    Map.Entry<String, AutomaticZenRule>[] mSortedRules;
+    protected static final String KEY = "zen_mode_automatic_rules";
 
-    public ZenModeAutomaticRulesPreferenceController(Context context, String key,
-            Fragment parent) {
-        super(context, parent);
-        KEY_AUTOMATIC_RULES = key;
-        mSortedRules = sortedRules();
+    @VisibleForTesting
+    protected PreferenceCategory mPreferenceCategory;
+
+    public ZenModeAutomaticRulesPreferenceController(Context context, Fragment parent, Lifecycle
+            lifecycle) {
+        super(context, KEY, parent, lifecycle);
     }
 
     @Override
     public String getPreferenceKey() {
-        return KEY_AUTOMATIC_RULES;
+        return KEY;
     }
 
     @Override
@@ -59,40 +62,14 @@
     public void updateState(Preference preference) {
         super.updateState(preference);
 
-        // no need to update AutomaticRule if a rule was deleted
-        // (on rule deletion, the preference removes itself from its parent)
-        int oldRuleLength = mSortedRules.length;
-        mSortedRules = sortedRules();
-        if  (!wasRuleDeleted(oldRuleLength)) {
-            updateAutomaticRules();
+        mPreferenceCategory.removeAll();
+        Map.Entry<String, AutomaticZenRule>[] sortedRules = sortedRules();
+        for (Map.Entry<String, AutomaticZenRule> sortedRule : sortedRules) {
+            ZenRulePreference pref = new ZenRulePreference(mPreferenceCategory.getContext(),
+                    sortedRule, mParent, mMetricsFeatureProvider);
+            mPreferenceCategory.addPreference(pref);
         }
     }
-
-    private boolean wasRuleDeleted(int oldRuleLength) {
-        int newRuleLength = mSortedRules.length;
-        int prefCount =  mPreferenceCategory.getPreferenceCount();
-
-        return (prefCount == oldRuleLength -1) && (prefCount == newRuleLength);
-    }
-
-    private void updateAutomaticRules() {
-        for (Map.Entry<String, AutomaticZenRule> sortedRule : mSortedRules) {
-            ZenRulePreference currPref = (ZenRulePreference)
-                    mPreferenceCategory.findPreference(sortedRule.getKey());
-            if (currPref != null && currPref.appExists) {
-                // rule already exists in preferences, update it
-                currPref.setAttributes(sortedRule.getValue());
-            } else {
-                // rule doesn't exist in preferences, add it
-                ZenRulePreference pref = new ZenRulePreference(mPreferenceCategory.getContext(),
-                        sortedRule, mPreferenceCategory);
-                if (pref.appExists) {
-                    mPreferenceCategory.addPreference(pref);
-                }
-            }
-        }
-
-    }
 }
 
 
diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java
index 582fb03..55d0fca 100644
--- a/src/com/android/settings/notification/ZenModeAutomationSettings.java
+++ b/src/com/android/settings/notification/ZenModeAutomationSettings.java
@@ -28,29 +28,27 @@
 import com.android.settings.utils.ManagedServiceSettings;
 import com.android.settings.utils.ZenServiceListing;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class ZenModeAutomationSettings extends ZenModeSettingsBase {
-    private static final String KEY_ADD_RULE = "zen_mode_add_automatic_rule";
-    private static final String KEY_AUTOMATIC_RULES = "zen_mode_automatic_rules";
-    protected static final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
+    protected final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
 
     @Override
     protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
         ZenServiceListing serviceListing = new ZenServiceListing(getContext(), CONFIG);
         serviceListing.reloadApprovedServices();
-        return buildPreferenceControllers(context, this, serviceListing);
+        return buildPreferenceControllers(context, this, serviceListing, getLifecycle());
     }
 
     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
-            Fragment parent, ZenServiceListing serviceListing) {
+            Fragment parent, ZenServiceListing serviceListing, Lifecycle lifecycle) {
         List<AbstractPreferenceController> controllers = new ArrayList<>();
-        controllers.add(new ZenModeAddAutomaticRulePreferenceController(context, KEY_ADD_RULE,
-                parent, serviceListing));
-        controllers.add(new ZenModeAutomaticRulesPreferenceController(context,
-                KEY_AUTOMATIC_RULES, parent));
+        controllers.add(new ZenModeAddAutomaticRulePreferenceController(context, parent,
+                serviceListing, lifecycle));
+        controllers.add(new ZenModeAutomaticRulesPreferenceController(context, parent, lifecycle));
 
         return controllers;
     }
@@ -94,15 +92,15 @@
                 @Override
                 public List<String> getNonIndexableKeys(Context context) {
                     final List<String> keys = super.getNonIndexableKeys(context);
-                    keys.add(KEY_ADD_RULE);
-                    keys.add(KEY_AUTOMATIC_RULES);
+                    keys.add(ZenModeAddAutomaticRulePreferenceController.KEY);
+                    keys.add(ZenModeAutomaticRulesPreferenceController.KEY);
                     return keys;
                 }
 
                 @Override
                 public List<AbstractPreferenceController> getPreferenceControllers(
                         Context context) {
-                    return buildPreferenceControllers(context, null, null);
+                    return buildPreferenceControllers(context, null, null, null);
                 }
             };
 }
diff --git a/src/com/android/settings/notification/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
index 79115f2..1886dab 100644
--- a/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
@@ -22,6 +22,7 @@
 import android.view.View;
 import android.widget.Button;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.applications.LayoutPreference;
 import com.android.settings.core.PreferenceControllerMixin;
@@ -57,15 +58,21 @@
         if (null == mZenButtonOn) {
             mZenButtonOn = (Button) ((LayoutPreference) preference)
                     .findViewById(R.id.zen_mode_settings_turn_on_button);
-            mZenButtonOn.setOnClickListener(v ->
-                    mBackend.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS));
+            mZenButtonOn.setOnClickListener(v -> {
+                mMetricsFeatureProvider.action(mContext,
+                        MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, true);
+                mBackend.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+            });
         }
 
         if (null == mZenButtonOff) {
             mZenButtonOff = (Button) ((LayoutPreference) preference)
                     .findViewById(R.id.zen_mode_settings_turn_off_button);
-            mZenButtonOff.setOnClickListener(v ->
-                    mBackend.setZenMode(Settings.Global.ZEN_MODE_OFF));
+            mZenButtonOff.setOnClickListener(v -> {
+                mMetricsFeatureProvider.action(mContext,
+                        MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, false);
+                mBackend.setZenMode(Settings.Global.ZEN_MODE_OFF);
+            });
         }
 
         updateButtons();
diff --git a/src/com/android/settings/notification/ZenModeEventRuleSettings.java b/src/com/android/settings/notification/ZenModeEventRuleSettings.java
index aa2cc3f..bb66768 100644
--- a/src/com/android/settings/notification/ZenModeEventRuleSettings.java
+++ b/src/com/android/settings/notification/ZenModeEventRuleSettings.java
@@ -61,16 +61,6 @@
     }
 
     @Override
-    protected String getZenModeDependency() {
-        return null;
-    }
-
-    @Override
-    protected int getEnabledToastText() {
-        return R.string.zen_event_rule_enabled_toast;
-    }
-
-    @Override
     public void onResume() {
         super.onResume();
         if (isUiRestricted()) {
@@ -89,7 +79,14 @@
 
     @Override
     protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
-        return null;
+        List<AbstractPreferenceController> controllers = new ArrayList<>();
+        mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
+                getLifecycle());
+        mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
+                R.string.zen_event_rule_enabled_toast, getLifecycle());
+        controllers.add(mHeader);
+        controllers.add(mSwitch);
+        return controllers;
     }
 
     private void reloadCalendar() {
diff --git a/src/com/android/settings/notification/ZenModeEventsPreferenceController.java b/src/com/android/settings/notification/ZenModeEventsPreferenceController.java
index 3763fed..be5e6d6 100644
--- a/src/com/android/settings/notification/ZenModeEventsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeEventsPreferenceController.java
@@ -24,6 +24,7 @@
 import android.util.Log;
 
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 public class ZenModeEventsPreferenceController extends AbstractZenModePreferenceController
@@ -71,6 +72,8 @@
         if (ZenModeSettingsBase.DEBUG) {
             Log.d(TAG, "onPrefChange allowEvents=" + allowEvents);
         }
+        mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_EVENTS,
+                allowEvents);
         mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_EVENTS, allowEvents);
         return true;
     }
diff --git a/src/com/android/settings/notification/ZenModeRemindersPreferenceController.java b/src/com/android/settings/notification/ZenModeRemindersPreferenceController.java
index edc7cf9..99a4f0d7 100644
--- a/src/com/android/settings/notification/ZenModeRemindersPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeRemindersPreferenceController.java
@@ -23,6 +23,7 @@
 import android.support.v7.preference.Preference;
 import android.util.Log;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 public class ZenModeRemindersPreferenceController extends AbstractZenModePreferenceController
@@ -67,7 +68,11 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean allowReminders = (Boolean) newValue;
-        if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowReminders=" + allowReminders);
+        if (ZenModeSettingsBase.DEBUG) {
+            Log.d(TAG, "onPrefChange allowReminders=" + allowReminders);
+        }
+        mMetricsFeatureProvider.action(mContext,
+                MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_REMINDERS, allowReminders);
         mBackend.saveSoundPolicy(NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS,
                 allowReminders);
         return true;
diff --git a/src/com/android/settings/notification/ZenModeRepeatCallersPreferenceController.java b/src/com/android/settings/notification/ZenModeRepeatCallersPreferenceController.java
index 1d18409..82fe865 100644
--- a/src/com/android/settings/notification/ZenModeRepeatCallersPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeRepeatCallersPreferenceController.java
@@ -23,6 +23,7 @@
 import android.support.v7.preference.Preference;
 import android.util.Log;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 public class ZenModeRepeatCallersPreferenceController extends AbstractZenModePreferenceController
@@ -77,8 +78,11 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean allowRepeatCallers = (Boolean) newValue;
-        if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowRepeatCallers="
-                + allowRepeatCallers);
+        if (ZenModeSettingsBase.DEBUG) {
+            Log.d(TAG, "onPrefChange allowRepeatCallers=" + allowRepeatCallers);
+        }
+        mMetricsFeatureProvider.action(mContext,
+                MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_REPEAT_CALLS, allowRepeatCallers);
         mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, allowRepeatCallers);
         return true;
     }
diff --git a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
index 069d38b..0234c8e 100644
--- a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
@@ -16,62 +16,43 @@
 
 package com.android.settings.notification;
 
-import android.app.Activity;
-import android.app.AlertDialog;
 import android.app.AutomaticZenRule;
+import android.app.Fragment;
 import android.app.NotificationManager;
 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.service.notification.ConditionProviderService;
-import android.support.v7.preference.DropDownPreference;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.support.v7.preference.Preference.OnPreferenceClickListener;
 import android.support.v7.preference.PreferenceScreen;
 import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Switch;
 import android.widget.Toast;
 
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.widget.SwitchBar;
 import com.android.settingslib.core.AbstractPreferenceController;
 
-import java.util.List;
+public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase {
 
-public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
-        implements SwitchBar.OnSwitchChangeListener {
     protected static final String TAG = ZenModeSettingsBase.TAG;
     protected static final boolean DEBUG = ZenModeSettingsBase.DEBUG;
 
     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 AutomaticZenRule mRule;
     protected String mId;
 
-    private boolean mDeleting;
     private Preference mRuleName;
-    private SwitchBar mSwitchBar;
-    private DropDownPreference mZenMode;
-    private Toast mEnabledToast;
+    protected ZenAutomaticRuleHeaderPreferenceController mHeader;
+    protected ZenAutomaticRuleSwitchPreferenceController mSwitch;
 
     abstract protected void onCreateInternal();
     abstract protected boolean setRule(AutomaticZenRule rule);
-    abstract protected String getZenModeDependency();
     abstract protected void updateControlsInternal();
-    abstract protected int getEnabledToastText();
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -99,8 +80,6 @@
 
         super.onCreate(icicle);
 
-        setHasOptionsMenu(true);
-
         onCreateInternal();
 
         final PreferenceScreen root = getPreferenceScreen();
@@ -112,37 +91,6 @@
                 return true;
             }
         });
-
-        mZenMode = (DropDownPreference) root.findPreference(KEY_ZEN_MODE);
-        mZenMode.setEntries(new CharSequence[] {
-                getString(R.string.zen_mode_option_important_interruptions),
-                getString(R.string.zen_mode_option_alarms),
-                getString(R.string.zen_mode_option_no_interruptions),
-        });
-        mZenMode.setEntryValues(new CharSequence[] {
-                Integer.toString(NotificationManager.INTERRUPTION_FILTER_PRIORITY),
-                Integer.toString(NotificationManager.INTERRUPTION_FILTER_ALARMS),
-                Integer.toString(NotificationManager.INTERRUPTION_FILTER_NONE),
-        });
-        mZenMode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
-            @Override
-            public boolean onPreferenceChange(Preference preference, Object newValue) {
-                if (mDisableListeners) return false;
-                final int zenMode = Integer.parseInt((String) newValue);
-                if (zenMode == mRule.getInterruptionFilter()) return false;
-                if (DEBUG) Log.d(TAG, "onPrefChange zenMode=" + zenMode);
-                mRule.setInterruptionFilter(zenMode);
-                mBackend.setZenRule(mId, mRule);
-                return true;
-            }
-        });
-        mZenMode.setOrder(10);  // sort at the bottom of the category
-        mZenMode.setDependency(getZenModeDependency());
-    }
-
-    @Override
-    protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
-        return null;
     }
 
     @Override
@@ -155,43 +103,39 @@
     }
 
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-
-        final SettingsActivity activity = (SettingsActivity) getActivity();
-        mSwitchBar = activity.getSwitchBar();
-        mSwitchBar.addOnSwitchChangeListener(this);
-        mSwitchBar.show();
+    public int getHelpResource() {
+        return R.string.help_uri_interruptions;
     }
 
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-        mSwitchBar.removeOnSwitchChangeListener(this);
-        mSwitchBar.hide();
+    /**
+     * Update state of header preference managed by PreferenceController.
+     */
+    protected void updateHeader() {
+        final PreferenceScreen screen = getPreferenceScreen();
+
+        mSwitch.onResume(mRule,mId);
+        mSwitch.displayPreference(screen);
+        updatePreference(mSwitch);
+
+        mHeader.onResume(mRule);
+        mHeader.displayPreference(screen);
+        updatePreference(mHeader);
     }
 
-    @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.isEnabled()) return;
-        mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ENABLE_RULE, enabled);
-        if (DEBUG) Log.d(TAG, "onSwitchChanged enabled=" + enabled);
-        mRule.setEnabled(enabled);
-        mBackend.setZenRule(mId, mRule);
-        if (enabled) {
-            final int toastText = getEnabledToastText();
-            if (toastText != 0) {
-                mEnabledToast = Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT);
-                mEnabledToast.show();
-            }
-        } else {
-            if (mEnabledToast != null) {
-                mEnabledToast.cancel();
-            }
+    private void updatePreference(AbstractPreferenceController controller) {
+        final PreferenceScreen screen = getPreferenceScreen();
+        if (!controller.isAvailable()) {
+            return;
         }
+        final String key = controller.getPreferenceKey();
+
+        final Preference preference = screen.findPreference(key);
+        if (preference == null) {
+            Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
+                    key, controller.getClass().getSimpleName()));
+            return;
+        }
+        controller.updateState(preference);
     }
 
     protected void updateRule(Uri newConditionId) {
@@ -207,33 +151,6 @@
         }
     }
 
-    @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) {
-            mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_DELETE_RULE);
-            showDeleteRuleDialog();
-            return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    private void showRuleNameDialog() {
-        new ZenRuleNameDialog(mContext, mRule.getName(), null) {
-            @Override
-            public void onOk(String ruleName) {
-                mRule.setName(ruleName);
-                mBackend.setZenRule(mId, mRule);
-            }
-        }.show();
-    }
-
     private boolean refreshRuleOrFinish() {
         mRule = getZenRule();
         if (DEBUG) Log.d(TAG, "mRule=" + mRule);
@@ -244,42 +161,22 @@
         return false;
     }
 
-    private void showDeleteRuleDialog() {
-        final AlertDialog dialog = new AlertDialog.Builder(mContext)
-                .setMessage(getString(R.string.zen_mode_delete_rule_confirmation, mRule.getName()))
-                .setNegativeButton(R.string.cancel, null)
-                .setPositiveButton(R.string.zen_mode_delete_rule_button, new OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        mMetricsFeatureProvider.action(mContext,
-                                MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
-                        mDeleting = true;
-                        mBackend.removeZenRule(mId);
-                    }
-                })
-                .show();
-        final View messageView = dialog.findViewById(android.R.id.message);
-        if (messageView != null) {
-            messageView.setTextDirection(View.TEXT_DIRECTION_LOCALE);
-        }
+    private void showRuleNameDialog() {
+        ZenRuleNameDialog.show(this, mRule.getName(), null, new RuleNameChangeListener());
     }
 
     private void toastAndFinish() {
-        if (!mDeleting) {
-            Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT)
+        Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT)
                     .show();
-        }
         getActivity().finish();
     }
 
     private void updateRuleName() {
-        Activity activity = getActivity();
-        if (activity != null) {
-            activity.setTitle(mRule.getName());
+        if (mRule != null) {
             mRuleName.setSummary(mRule.getName());
         } else {
-            if (DEBUG) Log.d(TAG, "updateRuleName - activity title and mRuleName "
-                    + "not updated; getActivity() returned null");
+            if (DEBUG) Log.d(TAG, "updateRuleName - mRuleName "
+                    + "not updated; mRuleName returned null");
         }
     }
 
@@ -291,10 +188,19 @@
         mDisableListeners = true;
         updateRuleName();
         updateControlsInternal();
-        mZenMode.setValue(Integer.toString(mRule.getInterruptionFilter()));
-        if (mSwitchBar != null) {
-            mSwitchBar.setChecked(mRule.isEnabled());
-        }
+        updateHeader();
         mDisableListeners = false;
     }
+
+    public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener {
+        public RuleNameChangeListener() {}
+
+        @Override
+        public void onOk(String ruleName, Fragment parent) {
+            mMetricsFeatureProvider.action(mContext,
+                    MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
+            mRule.setName(ruleName);
+            mBackend.setZenRule(mId, mRule);
+        }
+    }
 }
diff --git a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
index ab0349e..ecfe91b 100644
--- a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
+++ b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
@@ -42,6 +42,7 @@
 import com.android.settingslib.core.AbstractPreferenceController;
 
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.List;
@@ -77,21 +78,6 @@
     }
 
     @Override
-    protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
-        return null;
-    }
-
-    @Override
-    protected String getZenModeDependency() {
-        return mDays.getKey();
-    }
-
-    @Override
-    protected int getEnabledToastText() {
-        return R.string.zen_schedule_rule_enabled_toast;
-    }
-
-    @Override
     protected void onCreateInternal() {
         final PreferenceScreen root = getPreferenceScreen();
 
@@ -208,6 +194,20 @@
         updateEndSummary();
     }
 
+
+    @Override
+    protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
+        List<AbstractPreferenceController> controllers = new ArrayList<>();
+        mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
+                getLifecycle());
+        mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
+                R.string.zen_schedule_rule_enabled_toast, getLifecycle());
+
+        controllers.add(mHeader);
+        controllers.add(mSwitch);
+        return controllers;
+    }
+
     @Override
     public int getMetricsCategory() {
         return MetricsEvent.NOTIFICATION_ZEN_MODE_SCHEDULE_RULE;
diff --git a/src/com/android/settings/notification/ZenModeScreenOffPreferenceController.java b/src/com/android/settings/notification/ZenModeScreenOffPreferenceController.java
index 2b70706..0ba24c0 100644
--- a/src/com/android/settings/notification/ZenModeScreenOffPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeScreenOffPreferenceController.java
@@ -22,6 +22,7 @@
 import android.support.v7.preference.Preference;
 import android.util.Log;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 public class ZenModeScreenOffPreferenceController extends
@@ -56,8 +57,11 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean bypass = (Boolean) newValue;
-        if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowWhenScreenOff="
-                + !bypass);
+        if (ZenModeSettingsBase.DEBUG) {
+            Log.d(TAG, "onPrefChange allowWhenScreenOff=" + bypass);
+        }
+        mMetricsFeatureProvider.action(mContext,
+                MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_WHEN_SCREEN_OFF, bypass);
         mBackend.saveVisualEffectsPolicy(Policy.SUPPRESSED_EFFECT_SCREEN_OFF, bypass);
         return true;
     }
diff --git a/src/com/android/settings/notification/ZenModeScreenOnPreferenceController.java b/src/com/android/settings/notification/ZenModeScreenOnPreferenceController.java
index 8e0b348..bcb1af8 100644
--- a/src/com/android/settings/notification/ZenModeScreenOnPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeScreenOnPreferenceController.java
@@ -22,6 +22,7 @@
 import android.support.v7.preference.Preference;
 import android.util.Log;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 
 public class ZenModeScreenOnPreferenceController extends
@@ -57,8 +58,9 @@
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean bypass = (Boolean) newValue;
         if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowWhenScreenOn="
-                + !bypass);
-
+                + bypass);
+        mMetricsFeatureProvider.action(mContext,
+                MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_WHEN_SCREEN_ON, bypass);
         mBackend.saveVisualEffectsPolicy(Policy.SUPPRESSED_EFFECT_SCREEN_ON, bypass);
         return true;
     }
diff --git a/src/com/android/settings/notification/ZenRuleNameDialog.java b/src/com/android/settings/notification/ZenRuleNameDialog.java
index eb85431..819ba5b 100644
--- a/src/com/android/settings/notification/ZenRuleNameDialog.java
+++ b/src/com/android/settings/notification/ZenRuleNameDialog.java
@@ -17,73 +17,103 @@
 package com.android.settings.notification;
 
 import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Fragment;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.net.Uri;
+import android.os.Bundle;
 import android.service.notification.ZenModeConfig;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.EditText;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 
-public abstract class ZenRuleNameDialog {
-    private static final String TAG = "ZenRuleNameDialog";
-    private static final boolean DEBUG = ZenModeSettings.DEBUG;
+public class ZenRuleNameDialog extends InstrumentedDialogFragment {
+    protected static final String TAG = "ZenRuleNameDialog";
+    private static final String EXTRA_ZEN_RULE_NAME = "zen_rule_name";
+    private static final String EXTRA_CONDITION_ID = "extra_zen_condition_id";
+    protected static PositiveClickListener mPositiveClickListener;
 
-    private final AlertDialog mDialog;
-    private final EditText mEditText;
-    private final CharSequence mOriginalRuleName;
-    private final boolean mIsNew;
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG;
+    }
 
-    public ZenRuleNameDialog(Context context, CharSequence ruleName, Uri conditionId) {
-        mIsNew = ruleName == null;
-        mOriginalRuleName = ruleName;
+    /**
+     * The interface we expect a listener to implement.
+     */
+    public interface PositiveClickListener {
+        void onOk(String newName, Fragment parent);
+    }
+
+    public static void show(Fragment parent, String ruleName, Uri conditionId, PositiveClickListener
+            listener) {
+        final Bundle args = new Bundle();
+        args.putString(EXTRA_ZEN_RULE_NAME, ruleName);
+        args.putParcelable(EXTRA_CONDITION_ID, conditionId);
+        mPositiveClickListener = listener;
+
+        ZenRuleNameDialog dialog = new ZenRuleNameDialog();
+        dialog.setArguments(args);
+        dialog.setTargetFragment(parent, 0);
+        dialog.show(parent.getFragmentManager(), TAG);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Bundle arguments = getArguments();
+        Uri conditionId = arguments.getParcelable(EXTRA_CONDITION_ID);
+        String ruleName = arguments.getString(EXTRA_ZEN_RULE_NAME);
+
+        boolean isNew = ruleName == null;
+        CharSequence originalRuleName = ruleName;
+        Context context = getContext();
         final View v = LayoutInflater.from(context).inflate(R.layout.zen_rule_name, null,
                 false);
-        mEditText = (EditText) v.findViewById(R.id.zen_mode_rule_name);
-        if (!mIsNew) {
-            mEditText.setText(ruleName);
+        EditText editText = (EditText) v.findViewById(R.id.zen_mode_rule_name);
+        if (!isNew) {
+            // set text to current rule name
+            editText.setText(ruleName);
+            // move cursor to end of text
+            editText.setSelection(editText.getText().length());
         }
-        mEditText.setSelectAllOnFocus(true);
-        mDialog = new AlertDialog.Builder(context)
-                .setTitle(getTitleResource(conditionId))
+        editText.setSelectAllOnFocus(true);
+        return new AlertDialog.Builder(context)
+                .setTitle(getTitleResource(conditionId, isNew))
                 .setView(v)
-                .setPositiveButton(mIsNew ? R.string.zen_mode_add : R.string.okay,
+                .setPositiveButton(isNew ? R.string.zen_mode_add : R.string.okay,
                         new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        final String newName = trimmedText();
-                        if (TextUtils.isEmpty(newName)) {
-                            return;
-                        }
-                        if (!mIsNew && mOriginalRuleName != null
-                                && mOriginalRuleName.equals(newName)) {
-                            return;  // no change to an existing rule, just dismiss
-                        }
-                        onOk(newName);
-                    }
-                })
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                final String newName = trimmedText(editText);
+                                if (TextUtils.isEmpty(newName)) {
+                                    return;
+                                }
+                                if (!isNew && originalRuleName != null
+                                        && originalRuleName.equals(newName)) {
+                                    return;  // no change to an existing rule, just dismiss
+                                }
+                               mPositiveClickListener.onOk(newName, getTargetFragment());
+                            }
+                        })
                 .setNegativeButton(R.string.cancel, null)
                 .create();
     }
 
-    abstract public void onOk(String ruleName);
-
-    public void show() {
-        mDialog.show();
+    private String trimmedText(EditText editText) {
+        return editText.getText() == null ? null : editText.getText().toString().trim();
     }
 
-    private String trimmedText() {
-        return mEditText.getText() == null ? null : mEditText.getText().toString().trim();
-    }
-
-    private int getTitleResource(Uri conditionId) {
+    private int getTitleResource(Uri conditionId, boolean isNew) {
         final boolean isEvent = ZenModeConfig.isValidEventConditionId(conditionId);
         final boolean isTime = ZenModeConfig.isValidScheduleConditionId(conditionId);
         int titleResource =  R.string.zen_mode_rule_name;
-        if (mIsNew) {
+        if (isNew) {
             if (isEvent) {
                 titleResource = R.string.zen_mode_add_event_rule;
             } else if (isTime) {
diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java
index 4d7181a..90f6a94 100644
--- a/src/com/android/settings/notification/ZenRulePreference.java
+++ b/src/com/android/settings/notification/ZenRulePreference.java
@@ -16,23 +16,21 @@
 
 package com.android.settings.notification;
 
-import android.app.AlertDialog;
 import android.app.AutomaticZenRule;
-import android.app.NotificationManager;
+import android.app.Fragment;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
 import android.service.notification.ZenModeConfig;
 import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceCategory;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.view.View;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
 import com.android.settings.utils.ManagedServiceSettings;
 import com.android.settings.utils.ZenServiceListing;
 import com.android.settingslib.TwoTargetPreference;
@@ -45,16 +43,17 @@
     final CharSequence mName;
     final String mId;
     boolean appExists;
-    final PreferenceCategory mParent;
+    final Fragment mParent;
     final Preference mPref;
     final Context mContext;
     final ZenModeBackend mBackend;
     final ZenServiceListing mServiceListing;
     final PackageManager mPm;
+    final MetricsFeatureProvider mMetricsFeatureProvider;
 
     public ZenRulePreference(Context context,
             final Map.Entry<String, AutomaticZenRule> ruleEntry,
-            PreferenceCategory prefCategory) {
+            Fragment parent, MetricsFeatureProvider metricsProvider) {
         super(context);
 
         mBackend = ZenModeBackend.getInstance(context);
@@ -62,11 +61,12 @@
         final AutomaticZenRule rule = ruleEntry.getValue();
         mName = rule.getName();
         mId = ruleEntry.getKey();
-        mParent = prefCategory;
+        mParent = parent;
         mPm = mContext.getPackageManager();
         mServiceListing = new ZenServiceListing(mContext, CONFIG);
         mServiceListing.reloadApprovedServices();
         mPref = this;
+        mMetricsFeatureProvider = metricsProvider;
 
         setAttributes(rule);
     }
@@ -89,25 +89,21 @@
     private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            showDeleteRuleDialog(mId, mName, mParent, mPref);
+            showDeleteRuleDialog(mParent, mId, mName.toString());
         }
     };
 
-    private void showDeleteRuleDialog(final String ruleId, final CharSequence ruleName,
-            PreferenceCategory parent, Preference pref) {
-        new AlertDialog.Builder(mContext)
-                .setMessage(mContext.getResources().getString(
-                        R.string.zen_mode_delete_rule_confirmation, ruleName))
-                .setNegativeButton(R.string.cancel, null)
-                .setPositiveButton(R.string.zen_mode_delete_rule_button,
-                        new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                mBackend.removeZenRule(ruleId);
-                                parent.removePreference(pref);
-                            }
-                        })
-                .show();
+    private void showDeleteRuleDialog(final Fragment parent, final String ruleId,
+            final String ruleName) {
+        ZenDeleteRuleDialog.show(parent, ruleName, ruleId,
+                new ZenDeleteRuleDialog.PositiveClickListener() {
+                    @Override
+                    public void onOk(String id) {
+                        mMetricsFeatureProvider.action(mContext,
+                                MetricsProto.MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
+                        mBackend.removeZenRule(id);
+                    }
+                });
     }
 
     protected void setAttributes(AutomaticZenRule rule) {
@@ -141,26 +137,8 @@
 
     private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
             CharSequence providerLabel) {
-        final String mode = computeZenModeCaption(mContext.getResources(),
-                rule.getInterruptionFilter());
-        final String ruleState = (rule == null || !rule.isEnabled())
+        return (rule == null || !rule.isEnabled())
                 ? mContext.getResources().getString(R.string.switch_off_text)
-                : mContext.getResources().getString(
-                        R.string.zen_mode_rule_summary_enabled_combination, mode);
-
-        return ruleState;
-    }
-
-    private static String computeZenModeCaption(Resources res, int zenMode) {
-        switch (zenMode) {
-            case NotificationManager.INTERRUPTION_FILTER_ALARMS:
-                return res.getString(R.string.zen_mode_option_alarms);
-            case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
-                return res.getString(R.string.zen_mode_option_important_interruptions);
-            case NotificationManager.INTERRUPTION_FILTER_NONE:
-                return res.getString(R.string.zen_mode_option_no_interruptions);
-            default:
-                return null;
-        }
+                : mContext.getResources().getString(R.string.switch_on_text);
     }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/notification/ZenRuleSelectionDialog.java b/src/com/android/settings/notification/ZenRuleSelectionDialog.java
index 0c725ed..0784d5a 100644
--- a/src/com/android/settings/notification/ZenRuleSelectionDialog.java
+++ b/src/com/android/settings/notification/ZenRuleSelectionDialog.java
@@ -16,16 +16,20 @@
 
 package com.android.settings.notification;
 
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
 import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Fragment;
 import android.app.NotificationManager;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
+import android.os.Bundle;
 import android.service.notification.ZenModeConfig;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -35,6 +39,7 @@
 import android.widget.TextView;
 
 import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.utils.ZenServiceListing;
 
 import java.lang.ref.WeakReference;
@@ -43,24 +48,48 @@
 import java.util.Set;
 import java.util.TreeSet;
 
-public abstract class ZenRuleSelectionDialog {
+public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
     private static final String TAG = "ZenRuleSelectionDialog";
     private static final boolean DEBUG = ZenModeSettings.DEBUG;
 
-    private final Context mContext;
-    private final PackageManager mPm;
-    private NotificationManager mNm;
-    private final AlertDialog mDialog;
-    private final LinearLayout mRuleContainer;
-    private final ZenServiceListing mServiceListing;
+    private static ZenServiceListing mServiceListing;
+    protected static PositiveClickListener mPositiveClickListener;
 
-    public ZenRuleSelectionDialog(Context context, ZenServiceListing serviceListing) {
+    private static Context mContext;
+    private static PackageManager mPm;
+    private static NotificationManager mNm;
+    private LinearLayout mRuleContainer;
+
+    /**
+     * The interface we expect a listener to implement.
+     */
+    public interface PositiveClickListener {
+        void onSystemRuleSelected(ZenRuleInfo ruleInfo, Fragment parent);
+        void onExternalRuleSelected(ZenRuleInfo ruleInfo, Fragment parent);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG;
+    }
+
+    public static void show(Context context, Fragment parent, PositiveClickListener
+            listener, ZenServiceListing serviceListing) {
+        mPositiveClickListener = listener;
         mContext = context;
-        mPm = context.getPackageManager();
-        mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        mPm = mContext.getPackageManager();
+        mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mServiceListing = serviceListing;
-        final View v =
-                LayoutInflater.from(context).inflate(R.layout.zen_rule_type_selection, null, false);
+
+        ZenRuleSelectionDialog dialog = new ZenRuleSelectionDialog();
+        dialog.setTargetFragment(parent, 0);
+        dialog.show(parent.getFragmentManager(), TAG);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        final View v = LayoutInflater.from(getContext()).inflate(R.layout.zen_rule_type_selection,
+                null, false);
 
         mRuleContainer = (LinearLayout) v.findViewById(R.id.rule_container);
         if (mServiceListing != null) {
@@ -69,28 +98,21 @@
             mServiceListing.addZenCallback(mServiceListingCallback);
             mServiceListing.reloadApprovedServices();
         }
-        mDialog = new AlertDialog.Builder(context)
+        return new AlertDialog.Builder(getContext())
                 .setTitle(R.string.zen_mode_choose_rule_type)
                 .setView(v)
-                .setOnDismissListener(new OnDismissListener() {
-                    @Override
-                    public void onDismiss(DialogInterface dialog) {
-                        if (mServiceListing != null) {
-                            mServiceListing.removeZenCallback(mServiceListingCallback);
-                        }
-                    }
-                })
                 .setNegativeButton(R.string.cancel, null)
                 .create();
     }
 
-    public void show() {
-        mDialog.show();
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        super.onDismiss(dialog);
+        if (mServiceListing != null) {
+            mServiceListing.removeZenCallback(mServiceListingCallback);
+        }
     }
 
-    abstract public void onSystemRuleSelected(ZenRuleInfo ruleInfo);
-    abstract public void onExternalRuleSelected(ZenRuleInfo ruleInfo);
-
     private void bindType(final ZenRuleInfo ri) {
         try {
             ApplicationInfo info = mPm.getApplicationInfo(ri.packageName, 0);
@@ -108,11 +130,11 @@
             v.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    mDialog.dismiss();
+                    dismiss();
                     if (ri.isSystem) {
-                        onSystemRuleSelected(ri);
+                        mPositiveClickListener.onSystemRuleSelected(ri, getTargetFragment());
                     } else {
-                        onExternalRuleSelected(ri);
+                        mPositiveClickListener.onExternalRuleSelected(ri, getTargetFragment());
                     }
                 }
             });
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
new file mode 100644
index 0000000..0dae923
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2017 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 junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.AutomaticZenRule;
+import android.app.Fragment;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ZenModeAutomaticRulesPreferenceControllerTest {
+    private ZenModeAutomaticRulesPreferenceController mController;
+    private final String GENERIC_RULE_NAME = "test";
+
+    @Mock
+    private ZenModeBackend mBackend;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private PreferenceCategory mockPref;
+    @Mock
+    private NotificationManager.Policy mPolicy;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+
+    private Context mContext;
+    private ContentResolver mContentResolver;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        ShadowApplication shadowApplication = ShadowApplication.getInstance();
+        shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
+
+        mContext = shadowApplication.getApplicationContext();
+        mContentResolver = RuntimeEnvironment.application.getContentResolver();
+        when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
+        mController = new ZenModeAutomaticRulesPreferenceController(mContext, mock(Fragment.class),
+                mock(Lifecycle.class));
+        ReflectionHelpers.setField(mController, "mBackend", mBackend);
+
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
+                mockPref);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void updateState_checkRuleOrderingDescending() {
+        final int NUM_RULES = 4;
+        when(mNotificationManager.getAutomaticZenRules()).thenReturn(
+                mockAutoZenRulesDecreasingCreationTime(NUM_RULES));
+
+        Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
+        assertEquals(NUM_RULES, rules.length);
+
+        // check ordering, most recent should be at the bottom/end (ie higher creation time)
+        for (int i = 0; i < NUM_RULES; i++) {
+            assertEquals(rules[i].getKey(), GENERIC_RULE_NAME + (NUM_RULES - 1 - i));
+        }
+    }
+
+    @Test
+    public void updateState_checkRuleOrderingAscending() {
+        final int NUM_RULES = 4;
+        when(mNotificationManager.getAutomaticZenRules()).thenReturn(
+                mockAutoZenRulesAscendingCreationTime(NUM_RULES));
+
+        Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
+        assertEquals(NUM_RULES, rules.length);
+
+        // check ordering, most recent should be at the bottom/end (ie higher creation time)
+        for (int i = 0; i < NUM_RULES; i++) {
+            assertEquals(rules[i].getKey(), GENERIC_RULE_NAME + i);
+        }
+    }
+
+    @Test
+    public void updateState_checkRuleOrderingMix() {
+        final int NUM_RULES = 4;
+        // map with creation times: 0, 2, 4, 6
+        Map<String,AutomaticZenRule> rMap = mockAutoZenRulesAscendingCreationTime(NUM_RULES);
+
+        final String insertedRule1 = "insertedRule1";
+        rMap.put(insertedRule1, new AutomaticZenRule(insertedRule1, null, null,
+                Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 5));
+
+        final String insertedRule2 = "insertedRule2";
+        rMap.put(insertedRule2, new AutomaticZenRule(insertedRule2, null, null,
+                Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 3));
+
+        // rule map with rule creation times, 0, 2, 4, 6, 5, 3
+        // sort should create ordering based on creation times: 0, 2, 3, 4, 5, 6
+        when(mNotificationManager.getAutomaticZenRules()).thenReturn(rMap);
+
+        Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
+        assertEquals(NUM_RULES + 2, rules.length); // inserted 2 rules
+
+        // check ordering of inserted rules
+        assertEquals(rules[4].getKey(), insertedRule1);
+        assertEquals(rules[2].getKey(), insertedRule2);
+    }
+
+    private Map<String, AutomaticZenRule> mockAutoZenRulesAscendingCreationTime(int numRules) {
+        Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
+
+        for (int i = 0; i < numRules; i++) {
+            ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
+                    null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, i * 2));
+        }
+
+        return ruleMap;
+    }
+
+    private Map<String, AutomaticZenRule> mockAutoZenRulesDecreasingCreationTime(int numRules) {
+        Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
+
+        for (int i = 0; i < numRules; i++) {
+            ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
+                    null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, numRules - i));
+        }
+
+        return ruleMap;
+    }
+}
\ No newline at end of file