Add condition provider access to settings.

Pull NotificationAccessSettings out into a reusable base class
and reuse all of it for a new condition providers settings page.

As with notification listeners, the entire section is hidden if
no apps provide conditions.

Change-Id: Ib5273f3362e392d99647347c23a514e4590f7ac9
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 0d5839b..25378086 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -80,6 +80,7 @@
     public static class NotificationStationActivity extends SettingsActivity { /* empty */ }
     public static class UserSettingsActivity extends SettingsActivity { /* empty */ }
     public static class NotificationAccessSettingsActivity extends SettingsActivity { /* empty */ }
+    public static class ConditionProviderSettingsActivity extends SettingsActivity { /* empty */ }
     public static class UsbSettingsActivity extends SettingsActivity { /* empty */ }
     public static class TrustedCredentialsSettingsActivity extends SettingsActivity { /* empty */ }
     public static class PaymentSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 1bc0501..2465a47 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -92,6 +92,7 @@
 import com.android.settings.location.LocationSettings;
 import com.android.settings.nfc.AndroidBeam;
 import com.android.settings.nfc.PaymentSettings;
+import com.android.settings.notification.ConditionProviderSettings;
 import com.android.settings.notification.NotificationAccessSettings;
 import com.android.settings.notification.NotificationSettings;
 import com.android.settings.notification.NotificationStation;
@@ -270,6 +271,7 @@
             DreamSettings.class.getName(),
             UserSettings.class.getName(),
             NotificationAccessSettings.class.getName(),
+            ConditionProviderSettings.class.getName(),
             ManageAccountsSettings.class.getName(),
             PrintSettingsFragment.class.getName(),
             PrintJobSettingsFragment.class.getName(),
diff --git a/src/com/android/settings/notification/ConditionProviderSettings.java b/src/com/android/settings/notification/ConditionProviderSettings.java
new file mode 100644
index 0000000..259e53c
--- /dev/null
+++ b/src/com/android/settings/notification/ConditionProviderSettings.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.service.notification.ConditionProviderService;
+
+import com.android.settings.R;
+
+public class ConditionProviderSettings extends ManagedServiceSettings {
+    private static final String TAG = ConditionProviderSettings.class.getSimpleName();
+    private static final Config CONFIG = getConditionProviderConfig();
+
+    private static Config getConditionProviderConfig() {
+        final Config c = new Config();
+        c.tag = TAG;
+        c.setting = Settings.Secure.ENABLED_CONDITION_PROVIDERS;
+        c.intentAction = ConditionProviderService.SERVICE_INTERFACE;
+        c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
+        c.noun = "condition provider";
+        c.warningDialogTitle = R.string.condition_provider_security_warning_title;
+        c.warningDialogSummary = R.string.condition_provider_security_warning_summary;
+        c.emptyText = R.string.no_condition_providers;
+        return c;
+    }
+
+    @Override
+    protected Config getConfig() {
+        return CONFIG;
+    }
+
+    public static int getProviderCount(PackageManager pm) {
+        return getServicesCount(CONFIG, pm);
+    }
+
+    public static int getEnabledProviderCount(Context context) {
+        return getEnabledServicesCount(CONFIG, context);
+    }
+}
diff --git a/src/com/android/settings/notification/ManagedServiceSettings.java b/src/com/android/settings/notification/ManagedServiceSettings.java
new file mode 100644
index 0000000..1144cb9
--- /dev/null
+++ b/src/com/android/settings/notification/ManagedServiceSettings.java
@@ -0,0 +1,345 @@
+/*
+ * 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.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.ListFragment;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+import java.util.HashSet;
+import java.util.List;
+
+public abstract class ManagedServiceSettings extends ListFragment {
+    private static final boolean SHOW_PACKAGE_NAME = false;
+
+    private final Config mConfig;
+    private PackageManager mPM;
+    private ContentResolver mCR;
+
+    private final HashSet<ComponentName> mEnabledServices = new HashSet<ComponentName>();
+    private ServiceListAdapter mList;
+
+    abstract protected Config getConfig();
+
+    public ManagedServiceSettings() {
+        mConfig = getConfig();
+    }
+
+    private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateList();
+        }
+    };
+
+    private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            updateList();
+        }
+    };
+
+    public class ScaryWarningDialogFragment extends DialogFragment {
+        static final String KEY_COMPONENT = "c";
+        static final String KEY_LABEL = "l";
+
+        public ScaryWarningDialogFragment setServiceInfo(ComponentName cn, String label) {
+            Bundle args = new Bundle();
+            args.putString(KEY_COMPONENT, cn.flattenToString());
+            args.putString(KEY_LABEL, label);
+            setArguments(args);
+            return this;
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            final Bundle args = getArguments();
+            final String label = args.getString(KEY_LABEL);
+            final ComponentName cn = ComponentName.unflattenFromString(args.getString(KEY_COMPONENT));
+
+            final String title = getResources().getString(mConfig.warningDialogTitle, label);
+            final String summary = getResources().getString(mConfig.warningDialogSummary, label);
+            return new AlertDialog.Builder(getActivity())
+                    .setMessage(summary)
+                    .setTitle(title)
+                    .setIconAttribute(android.R.attr.alertDialogIcon)
+                    .setCancelable(true)
+                    .setPositiveButton(android.R.string.ok,
+                            new DialogInterface.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int id) {
+                                    mEnabledServices.add(cn);
+                                    saveEnabledServices();
+                                }
+                            })
+                    .setNegativeButton(android.R.string.cancel,
+                            new DialogInterface.OnClickListener() {
+                                public void onClick(DialogInterface dialog, int id) {
+                                    // pass
+                                }
+                            })
+                    .create();
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mPM = getActivity().getPackageManager();
+        mCR = getActivity().getContentResolver();
+        mList = new ServiceListAdapter(getActivity());
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        View v =  inflater.inflate(R.layout.managed_service_settings, container, false);
+        TextView empty = (TextView) v.findViewById(android.R.id.empty);
+        empty.setText(mConfig.emptyText);
+        return v;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateList();
+
+        // listen for package changes
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        filter.addDataScheme("package");
+        getActivity().registerReceiver(mPackageReceiver, filter);
+
+        mCR.registerContentObserver(Settings.Secure.getUriFor(mConfig.setting),
+                false, mSettingsObserver);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        getActivity().unregisterReceiver(mPackageReceiver);
+        mCR.unregisterContentObserver(mSettingsObserver);
+    }
+
+    private void loadEnabledServices() {
+        mEnabledServices.clear();
+        final String flat = Settings.Secure.getString(mCR, mConfig.setting);
+        if (flat != null && !"".equals(flat)) {
+            final String[] names = flat.split(":");
+            for (int i = 0; i < names.length; i++) {
+                final ComponentName cn = ComponentName.unflattenFromString(names[i]);
+                if (cn != null) {
+                    mEnabledServices.add(cn);
+                }
+            }
+        }
+    }
+
+    private void saveEnabledServices() {
+        StringBuilder sb = null;
+        for (ComponentName cn : mEnabledServices) {
+            if (sb == null) {
+                sb = new StringBuilder();
+            } else {
+                sb.append(':');
+            }
+            sb.append(cn.flattenToString());
+        }
+        Settings.Secure.putString(mCR,
+                mConfig.setting,
+                sb != null ? sb.toString() : "");
+    }
+
+    private void updateList() {
+        loadEnabledServices();
+
+        getServices(mConfig, mList, mPM);
+        mList.sort(new PackageItemInfo.DisplayNameComparator(mPM));
+
+        getListView().setAdapter(mList);
+    }
+
+    protected static int getEnabledServicesCount(Config config, Context context) {
+        final String flat = Settings.Secure.getString(context.getContentResolver(), config.setting);
+        if (flat == null || "".equals(flat)) return 0;
+        final String[] components = flat.split(":");
+        return components.length;
+    }
+
+    protected static int getServicesCount(Config c, PackageManager pm) {
+        return getServices(c, null, pm);
+    }
+
+    private static int getServices(Config c, ArrayAdapter<ServiceInfo> adapter, PackageManager pm) {
+        int services = 0;
+        if (adapter != null) {
+            adapter.clear();
+        }
+        final int user = ActivityManager.getCurrentUser();
+
+        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
+                new Intent(c.intentAction),
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+                user);
+
+        for (int i = 0, count = installedServices.size(); i < count; i++) {
+            ResolveInfo resolveInfo = installedServices.get(i);
+            ServiceInfo info = resolveInfo.serviceInfo;
+
+            if (!c.permission.equals(info.permission)) {
+                Slog.w(c.tag, "Skipping " + c.noun + " service "
+                        + info.packageName + "/" + info.name
+                        + ": it does not require the permission "
+                        + c.permission);
+                continue;
+            }
+            if (adapter != null) {
+                adapter.add(info);
+            }
+            services++;
+        }
+        return services;
+    }
+
+    private boolean isServiceEnabled(ServiceInfo info) {
+        final ComponentName cn = new ComponentName(info.packageName, info.name);
+        return mEnabledServices.contains(cn);
+    }
+
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        ServiceInfo info = mList.getItem(position);
+        final ComponentName cn = new ComponentName(info.packageName, info.name);
+        if (mEnabledServices.contains(cn)) {
+            // the simple version: disabling
+            mEnabledServices.remove(cn);
+            saveEnabledServices();
+        } else {
+            // show a scary dialog
+            new ScaryWarningDialogFragment()
+                .setServiceInfo(cn, info.loadLabel(mPM).toString())
+                .show(getFragmentManager(), "dialog");
+        }
+    }
+
+    private static class ViewHolder {
+        ImageView icon;
+        TextView name;
+        CheckBox checkbox;
+        TextView description;
+    }
+
+    private class ServiceListAdapter extends ArrayAdapter<ServiceInfo> {
+        final LayoutInflater mInflater;
+
+        ServiceListAdapter(Context context) {
+            super(context, 0, 0);
+            mInflater = (LayoutInflater)
+                    getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        }
+
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View v;
+            if (convertView == null) {
+                v = newView(parent);
+            } else {
+                v = convertView;
+            }
+            bindView(v, position);
+            return v;
+        }
+
+        public View newView(ViewGroup parent) {
+            View v = mInflater.inflate(R.layout.managed_service_item, parent, false);
+            ViewHolder h = new ViewHolder();
+            h.icon = (ImageView) v.findViewById(R.id.icon);
+            h.name = (TextView) v.findViewById(R.id.name);
+            h.checkbox = (CheckBox) v.findViewById(R.id.checkbox);
+            h.description = (TextView) v.findViewById(R.id.description);
+            v.setTag(h);
+            return v;
+        }
+
+        public void bindView(View view, int position) {
+            ViewHolder vh = (ViewHolder) view.getTag();
+            ServiceInfo info = getItem(position);
+
+            vh.icon.setImageDrawable(info.loadIcon(mPM));
+            vh.name.setText(info.loadLabel(mPM));
+            if (SHOW_PACKAGE_NAME) {
+                vh.description.setText(info.packageName);
+                vh.description.setVisibility(View.VISIBLE);
+            } else {
+                vh.description.setVisibility(View.GONE);
+            }
+            vh.checkbox.setChecked(isServiceEnabled(info));
+        }
+    }
+
+    protected static class Config {
+        String tag;
+        String setting;
+        String intentAction;
+        String permission;
+        String noun;
+        int warningDialogTitle;
+        int warningDialogSummary;
+        int emptyText;
+    }
+}
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 78ea2d8..ced71a4 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -16,310 +16,40 @@
 
 package com.android.settings.notification;
 
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.ListFragment;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
 
 import com.android.settings.R;
 
-import java.util.HashSet;
-import java.util.List;
+public class NotificationAccessSettings extends ManagedServiceSettings {
+    private static final String TAG = NotificationAccessSettings.class.getSimpleName();
+    private static final Config CONFIG = getNotificationListenerConfig();
 
-public class NotificationAccessSettings extends ListFragment {
-    static final String TAG = NotificationAccessSettings.class.getSimpleName();
-    private static final boolean SHOW_PACKAGE_NAME = false;
-
-    private PackageManager mPM;
-    private ContentResolver mCR;
-
-    private final HashSet<ComponentName> mEnabledListeners = new HashSet<ComponentName>();
-    private ListenerListAdapter mList;
-
-    private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
-            = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
-    private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            updateList();
-        }
-    };
-
-    private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            updateList();
-        }
-    };
-
-    public class ListenerWarningDialogFragment extends DialogFragment {
-        static final String KEY_COMPONENT = "c";
-        static final String KEY_LABEL = "l";
-
-        public ListenerWarningDialogFragment setListenerInfo(ComponentName cn, String label) {
-            Bundle args = new Bundle();
-            args.putString(KEY_COMPONENT, cn.flattenToString());
-            args.putString(KEY_LABEL, label);
-            setArguments(args);
-
-            return this;
-        }
-        @Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            final Bundle args = getArguments();
-            final String label = args.getString(KEY_LABEL);
-            final ComponentName cn = ComponentName.unflattenFromString(args.getString(KEY_COMPONENT));
-
-            final String title = getResources().getString(
-                    R.string.notification_listener_security_warning_title, label);
-            final String summary = getResources().getString(
-                    R.string.notification_listener_security_warning_summary, label);
-            return new AlertDialog.Builder(getActivity())
-                    .setMessage(summary)
-                    .setTitle(title)
-                    .setIconAttribute(android.R.attr.alertDialogIcon)
-                    .setCancelable(true)
-                    .setPositiveButton(android.R.string.ok,
-                            new DialogInterface.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int id) {
-                                    mEnabledListeners.add(cn);
-                                    saveEnabledListeners();
-                                }
-                            })
-                    .setNegativeButton(android.R.string.cancel,
-                            new DialogInterface.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int id) {
-                                    // pass
-                                }
-                            })
-                    .create();
-        }
+    private static Config getNotificationListenerConfig() {
+        final Config c = new Config();
+        c.tag = TAG;
+        c.setting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
+        c.intentAction = NotificationListenerService.SERVICE_INTERFACE;
+        c.permission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
+        c.noun = "notification listener";
+        c.warningDialogTitle = R.string.notification_listener_security_warning_title;
+        c.warningDialogSummary = R.string.notification_listener_security_warning_summary;
+        c.emptyText = R.string.no_notification_listeners;
+        return c;
     }
 
     @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mPM = getActivity().getPackageManager();
-        mCR = getActivity().getContentResolver();
-        mList = new ListenerListAdapter(getActivity());
+    protected Config getConfig() {
+        return CONFIG;
     }
 
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        return inflater.inflate(R.layout.notification_access_settings, container, false);
+    public static int getListenersCount(PackageManager pm) {
+        return getServicesCount(CONFIG, pm);
     }
 
-    @Override
-    public void onResume() {
-        super.onResume();
-        updateList();
-
-        // listen for package changes
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
-        filter.addDataScheme("package");
-        getActivity().registerReceiver(mPackageReceiver, filter);
-
-        mCR.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI, false, mSettingsObserver);
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-
-        getActivity().unregisterReceiver(mPackageReceiver);
-        mCR.unregisterContentObserver(mSettingsObserver);
-    }
-
-    void loadEnabledListeners() {
-        mEnabledListeners.clear();
-        final String flat = Settings.Secure.getString(mCR,
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-        if (flat != null && !"".equals(flat)) {
-            final String[] names = flat.split(":");
-            for (int i = 0; i < names.length; i++) {
-                final ComponentName cn = ComponentName.unflattenFromString(names[i]);
-                if (cn != null) {
-                    mEnabledListeners.add(cn);
-                }
-            }
-        }
-    }
-
-    void saveEnabledListeners() {
-        StringBuilder sb = null;
-        for (ComponentName cn : mEnabledListeners) {
-            if (sb == null) {
-                sb = new StringBuilder();
-            } else {
-                sb.append(':');
-            }
-            sb.append(cn.flattenToString());
-        }
-        Settings.Secure.putString(mCR,
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-                sb != null ? sb.toString() : "");
-    }
-
-    void updateList() {
-        loadEnabledListeners();
-
-        getListeners(mList, mPM);
-        mList.sort(new PackageItemInfo.DisplayNameComparator(mPM));
-
-        getListView().setAdapter(mList);
-    }
-
-    static int getListenersCount(PackageManager pm) {
-        return getListeners(null, pm);
-    }
-
-    private static int getListeners(ArrayAdapter<ServiceInfo> adapter, PackageManager pm) {
-        int listeners = 0;
-        if (adapter != null) {
-            adapter.clear();
-        }
-        final int user = ActivityManager.getCurrentUser();
-
-        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
-                new Intent(NotificationListenerService.SERVICE_INTERFACE),
-                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
-                user);
-
-        for (int i = 0, count = installedServices.size(); i < count; i++) {
-            ResolveInfo resolveInfo = installedServices.get(i);
-            ServiceInfo info = resolveInfo.serviceInfo;
-
-            if (!android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE.equals(
-                    info.permission)) {
-                Slog.w(TAG, "Skipping notification listener service "
-                        + info.packageName + "/" + info.name
-                        + ": it does not require the permission "
-                        + android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
-                continue;
-            }
-            if (adapter != null) {
-                adapter.add(info);
-            }
-            listeners++;
-        }
-        return listeners;
-    }
-
-    boolean isListenerEnabled(ServiceInfo info) {
-        final ComponentName cn = new ComponentName(info.packageName, info.name);
-        return mEnabledListeners.contains(cn);
-    }
-
-    @Override
-    public void onListItemClick(ListView l, View v, int position, long id) {
-        ServiceInfo info = mList.getItem(position);
-        final ComponentName cn = new ComponentName(info.packageName, info.name);
-        if (mEnabledListeners.contains(cn)) {
-            // the simple version: disabling
-            mEnabledListeners.remove(cn);
-            saveEnabledListeners();
-        } else {
-            // show a scary dialog
-            new ListenerWarningDialogFragment()
-                .setListenerInfo(cn, info.loadLabel(mPM).toString())
-                .show(getFragmentManager(), "dialog");
-        }
-    }
-
-    static class ViewHolder {
-        ImageView icon;
-        TextView name;
-        CheckBox checkbox;
-        TextView description;
-    }
-
-    class ListenerListAdapter extends ArrayAdapter<ServiceInfo> {
-        final LayoutInflater mInflater;
-
-        ListenerListAdapter(Context context) {
-            super(context, 0, 0);
-            mInflater = (LayoutInflater)
-                    getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        }
-
-        public boolean hasStableIds() {
-            return true;
-        }
-
-        public long getItemId(int position) {
-            return position;
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            View v;
-            if (convertView == null) {
-                v = newView(parent);
-            } else {
-                v = convertView;
-            }
-            bindView(v, position);
-            return v;
-        }
-
-        public View newView(ViewGroup parent) {
-            View v = mInflater.inflate(R.layout.notification_listener_item, parent, false);
-            ViewHolder h = new ViewHolder();
-            h.icon = (ImageView) v.findViewById(R.id.icon);
-            h.name = (TextView) v.findViewById(R.id.name);
-            h.checkbox = (CheckBox) v.findViewById(R.id.checkbox);
-            h.description = (TextView) v.findViewById(R.id.description);
-            v.setTag(h);
-            return v;
-        }
-
-        public void bindView(View view, int position) {
-            ViewHolder vh = (ViewHolder) view.getTag();
-            ServiceInfo info = getItem(position);
-
-            vh.icon.setImageDrawable(info.loadIcon(mPM));
-            vh.name.setText(info.loadLabel(mPM));
-            if (SHOW_PACKAGE_NAME) {
-                vh.description.setText(info.packageName);
-                vh.description.setVisibility(View.VISIBLE);
-            } else {
-                vh.description.setVisibility(View.GONE);
-            }
-            vh.checkbox.setChecked(isListenerEnabled(info));
-        }
+    public static int getEnabledListenersCount(Context context) {
+        return getEnabledServicesCount(CONFIG, context);
     }
 }
diff --git a/src/com/android/settings/notification/NotificationSettings.java b/src/com/android/settings/notification/NotificationSettings.java
index 2d613e4..f2ed64c 100644
--- a/src/com/android/settings/notification/NotificationSettings.java
+++ b/src/com/android/settings/notification/NotificationSettings.java
@@ -225,21 +225,13 @@
 
     // === Notification listeners ===
 
-    private int getNumEnabledNotificationListeners() {
-        final String flat = Settings.Secure.getString(getContentResolver(),
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-        if (flat == null || "".equals(flat)) return 0;
-        final String[] components = flat.split(":");
-        return components.length;
-    }
-
     private void refreshNotificationListeners() {
         if (mNotificationAccess != null) {
             final int total = NotificationAccessSettings.getListenersCount(mPM);
             if (total == 0) {
                 getPreferenceScreen().removePreference(mNotificationAccess);
             } else {
-                final int n = getNumEnabledNotificationListeners();
+                final int n = NotificationAccessSettings.getEnabledListenersCount(mContext);
                 if (n == 0) {
                     mNotificationAccess.setSummary(getResources().getString(
                             R.string.manage_notification_access_summary_zero));
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index a5c720f..7f7dafa 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -24,6 +24,7 @@
 import android.app.TimePickerDialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Typeface;
@@ -37,6 +38,7 @@
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
 import android.preference.SwitchPreference;
+import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
 import android.text.format.DateFormat;
@@ -69,11 +71,15 @@
     private static final String KEY_AUTOMATIC = "automatic";
     private static final String KEY_WHEN = "when";
 
+    private static final String KEY_SECURITY = "security";
+    private static final String KEY_CONDITION_PROVIDERS = "manage_condition_providers";
+
     private final Handler mHandler = new Handler();
     private final SettingsObserver mSettingsObserver = new SettingsObserver();
 
     private SwitchPreference mSwitch;
     private Context mContext;
+    private PackageManager mPM;
     private ZenModeConfig mConfig;
     private boolean mDisableListeners;
     private SwitchPreference mCalls;
@@ -82,12 +88,15 @@
     private DropDownPreference mWhen;
     private TimePickerPreference mStart;
     private TimePickerPreference mEnd;
+    private PreferenceCategory mSecurityCategory;
+    private Preference mConditionProviders;
     private AlertDialog mDialog;
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         mContext = getActivity();
+        mPM = mContext.getPackageManager();
         final Resources res = mContext.getResources();
         final int p = res.getDimensionPixelSize(R.dimen.content_margin_left);
 
@@ -222,6 +231,10 @@
         mStart.setDependency(mWhen.getKey());
         mEnd.setDependency(mWhen.getKey());
 
+        mSecurityCategory = (PreferenceCategory) findPreference(KEY_SECURITY);
+        mConditionProviders = findPreference(KEY_CONDITION_PROVIDERS);
+        refreshConditionProviders();
+
         updateZenMode();
         updateControls();
     }
@@ -239,9 +252,28 @@
         mDisableListeners = false;
     }
 
+    private void refreshConditionProviders() {
+        if (mConditionProviders != null) {
+            final int total = ConditionProviderSettings.getProviderCount(mPM);
+            if (total == 0) {
+                getPreferenceScreen().removePreference(mSecurityCategory);
+            } 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)));
+                }
+            }
+        }
+    }
     @Override
     public void onResume() {
         super.onResume();
+        refreshConditionProviders();
         updateZenMode();
         mSettingsObserver.register();
     }
@@ -344,7 +376,10 @@
                 public void run() {
                     final int v = isChecked ? Global.ZEN_MODE_ON : Global.ZEN_MODE_OFF;
                     putZenModeSetting(v);
-                    mHandler.post(isChecked ? mShowDialog : mHideDialog);
+                    final int n = ConditionProviderSettings.getEnabledProviderCount(mContext);
+                    if (n > 0) {
+                        mHandler.post(isChecked ? mShowDialog : mHideDialog);
+                    }
                 }
             });
             return true;