From c9afadb04b00598f5988101681089290cf14f79c Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Tue, 29 Apr 2014 18:07:23 -0400 Subject: [PATCH] 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 --- AndroidManifest.xml | 15 + ...ener_item.xml => managed_service_item.xml} | 0 ...tings.xml => managed_service_settings.xml} | 1 - res/values/strings.xml | 33 +- res/xml/zen_mode_settings.xml | 12 + src/com/android/settings/Settings.java | 1 + .../android/settings/SettingsActivity.java | 2 + .../ConditionProviderSettings.java | 55 +++ .../notification/ManagedServiceSettings.java | 345 ++++++++++++++++++ .../NotificationAccessSettings.java | 310 +--------------- .../notification/NotificationSettings.java | 10 +- .../notification/ZenModeSettings.java | 37 +- 12 files changed, 518 insertions(+), 303 deletions(-) rename res/layout/{notification_listener_item.xml => managed_service_item.xml} (100%) rename res/layout/{notification_access_settings.xml => managed_service_settings.xml} (96%) create mode 100644 src/com/android/settings/notification/ConditionProviderSettings.java create mode 100644 src/com/android/settings/notification/ManagedServiceSettings.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index faa20b4c087..aa47916ebf1 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1705,6 +1705,21 @@ android:resource="@id/security_settings" /> + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 1eae3aec5c4..0f3547d39c0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1059,6 +1059,32 @@ to dismiss these notifications or touch action buttons within them. + + Condition providers + + + No apps provide conditions + + + + %d app provides conditions + %d apps provide conditions + + + + No condition providers are installed. + + + Enable + %1$s? + + + %1$s will be able to + add exit conditions to Do not disturb mode. + + Bluetooth @@ -5156,7 +5182,7 @@ On - + Until you turn this off @@ -5165,7 +5191,10 @@ At night - + + Security + + Phone calls diff --git a/res/xml/zen_mode_settings.xml b/res/xml/zen_mode_settings.xml index 19316af3191..75f01d874bc 100644 --- a/res/xml/zen_mode_settings.xml +++ b/res/xml/zen_mode_settings.xml @@ -42,9 +42,21 @@ android:switchTextOn="" android:title="@string/zen_mode_messages" /> + + + + + \ No newline at end of file diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 0d5839b2de7..25378086d1c 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -80,6 +80,7 @@ public class Settings extends SettingsActivity { 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 1bc0501ab3d..2465a4708f4 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -92,6 +92,7 @@ import com.android.settings.inputmethod.UserDictionaryList; 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 @@ public class SettingsActivity extends Activity 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 00000000000..259e53cb031 --- /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 00000000000..1144cb9b978 --- /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 mEnabledServices = new HashSet(); + 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 adapter, PackageManager pm) { + int services = 0; + if (adapter != null) { + adapter.clear(); + } + final int user = ActivityManager.getCurrentUser(); + + List installedServices = pm.queryIntentServicesAsUser( + new Intent(c.intentAction), + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, + user); + + for (int i = 0, count = installedServices.size(); i < count; i++) { + ResolveInfo resolveInfo = installedServices.get(i); + ServiceInfo info = resolveInfo.serviceInfo; + + if (!c.permission.equals(info.permission)) { + Slog.w(c.tag, "Skipping " + c.noun + " service " + + info.packageName + "/" + info.name + + ": it does not require the permission " + + c.permission); + continue; + } + if (adapter != null) { + adapter.add(info); + } + services++; + } + return services; + } + + private boolean isServiceEnabled(ServiceInfo info) { + final ComponentName cn = new ComponentName(info.packageName, info.name); + return mEnabledServices.contains(cn); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + ServiceInfo info = 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 { + 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 78ea2d8907a..ced71a4463c 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 mEnabledListeners = new HashSet(); - 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 adapter, PackageManager pm) { - int listeners = 0; - if (adapter != null) { - adapter.clear(); - } - final int user = ActivityManager.getCurrentUser(); - - List 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 { - 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 2d613e4d248..f2ed64cdc9e 100644 --- a/src/com/android/settings/notification/NotificationSettings.java +++ b/src/com/android/settings/notification/NotificationSettings.java @@ -225,21 +225,13 @@ public class NotificationSettings extends SettingsPreferenceFragment implements // === 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 a5c720f14b2..7f7dafab31c 100644 --- a/src/com/android/settings/notification/ZenModeSettings.java +++ b/src/com/android/settings/notification/ZenModeSettings.java @@ -24,6 +24,7 @@ import android.app.INotificationManager; 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.Preference.OnPreferenceChangeListener; 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 @@ public class ZenModeSettings extends SettingsPreferenceFragment implements Index 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 @@ public class ZenModeSettings extends SettingsPreferenceFragment implements Index 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 @@ public class ZenModeSettings extends SettingsPreferenceFragment implements Index 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 @@ public class ZenModeSettings extends SettingsPreferenceFragment implements Index 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 class ZenModeSettings extends SettingsPreferenceFragment implements Index 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;