From b19460f4a1125513f0f97b58475713b1f5919e3d Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Wed, 26 Mar 2014 19:09:21 -0400 Subject: [PATCH] List apps that advertise notification settings. Apps that have a CATEGORY_NOTIFICATION_PREFERENCES + CATEGORY_DEFAULT activity will be listed in notification settings, with a convenient link to that activity so the user can tweak those settings. Change-Id: Idc97b2aee3f070225822ebee1ecbeab79e7b9c2d --- res/layout/notification_app.xml | 84 ++++++++++ res/values/strings.xml | 4 + res/xml/notification_settings.xml | 9 +- .../settings/NotificationSettings.java | 157 ++++++++++++++++++ 4 files changed, 248 insertions(+), 6 deletions(-) create mode 100644 res/layout/notification_app.xml diff --git a/res/layout/notification_app.xml b/res/layout/notification_app.xml new file mode 100644 index 00000000000..4f61c132993 --- /dev/null +++ b/res/layout/notification_app.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 1d6c7511027..5376bb44cf5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5041,4 +5041,8 @@ Apps + + + Notification settings diff --git a/res/xml/notification_settings.xml b/res/xml/notification_settings.xml index edea08ffdee..49794225e73 100644 --- a/res/xml/notification_settings.xml +++ b/res/xml/notification_settings.xml @@ -75,14 +75,11 @@ +--> - - ---> + android:title="@string/notification_settings_apps"> + diff --git a/src/com/android/settings/NotificationSettings.java b/src/com/android/settings/NotificationSettings.java index c8ba39a00a7..303ec240f71 100644 --- a/src/com/android/settings/NotificationSettings.java +++ b/src/com/android/settings/NotificationSettings.java @@ -17,9 +17,16 @@ package com.android.settings; import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.database.ContentObserver; +import android.graphics.drawable.Drawable; import android.media.RingtoneManager; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -30,12 +37,26 @@ import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.provider.Settings; +import android.util.AttributeSet; import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; public class NotificationSettings extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener, OnPreferenceClickListener { private static final String TAG = "NotificationSettings"; + private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT + = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_NOTIFICATION_PREFERENCES); + private static final String KEY_NOTIFICATION_SOUND = "notification_sound"; private static final String KEY_ZEN_MODE = "zen_mode"; private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access"; @@ -44,6 +65,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements private static final String KEY_NOTIFICATION_PULSE = "notification_pulse"; private static final String KEY_SECURITY_CATEGORY = "category_security"; + private static final String KEY_APPS_CATEGORY = "category_apps"; private static final String KEY_TWEAKS_CATEGORY = "category_tweaks"; // power toys, eng only private static final int MSG_UPDATE_SOUND_SUMMARY = 2; @@ -81,6 +103,84 @@ public class NotificationSettings extends SettingsPreferenceFragment implements } }; + private final ArrayList mAppNotificationInfo + = new ArrayList(); + private final HashSet mAppNotificationInfoPackages = new HashSet(); + private final Comparator mAppComparator = new Comparator() { + private final Collator sCollator = Collator.getInstance(); + @Override + public int compare(AppNotificationInfo lhs, AppNotificationInfo rhs) { + return sCollator.compare(lhs.label, rhs.label); + } + }; + + private final Runnable mCollectAppsRunnable = new Runnable() { + @Override + public void run() { + synchronized (mAppNotificationInfo) { + mAppNotificationInfo.clear(); + mAppNotificationInfoPackages.clear(); + + final PackageManager pm = getPackageManager(); + + final List resolveInfos = pm.queryIntentActivities(APP_NOTIFICATION_PREFS_CATEGORY_INTENT, + PackageManager.MATCH_DEFAULT_ONLY); + + for (ResolveInfo ri : resolveInfos) { + final ActivityInfo activityInfo = ri.activityInfo; + final ApplicationInfo appInfo = activityInfo.applicationInfo; + if (mAppNotificationInfoPackages.contains(activityInfo.packageName)) { + Log.v(TAG, "Ignoring duplicate notification preference activity (" + + activityInfo.name + ") for package " + + activityInfo.packageName); + continue; + } + final AppNotificationInfo info = new AppNotificationInfo(); + mAppNotificationInfoPackages.add(activityInfo.packageName); + + info.label = appInfo.loadLabel(pm); + info.icon = appInfo.loadIcon(pm); + info.name = activityInfo.name; + info.pkg = activityInfo.packageName; + mAppNotificationInfo.add(info); + } + + Collections.sort(mAppNotificationInfo, mAppComparator); + mHandler.post(mRefreshAppsListRunnable); + } + } + }; + + private final Runnable mRefreshAppsListRunnable = new Runnable() { + @Override + public void run() { + final PreferenceScreen root = getPreferenceScreen(); + final PreferenceGroup appsCategory = (PreferenceGroup) + root.findPreference(KEY_APPS_CATEGORY); + + appsCategory.removeAll(); + + synchronized (mAppNotificationInfo) { + if (mAppNotificationInfo.size() == 0) { + root.removePreference(appsCategory); + return; + } + + final int N = mAppNotificationInfo.size(); + for (int i = 0; i < N; i++) { + final AppNotificationInfo info = mAppNotificationInfo.get(i); + Preference pref = new AppNotificationPreference(root.getContext()); + pref.setTitle(info.label); + pref.setIcon(info.icon); + pref.setIntent(new Intent(Intent.ACTION_MAIN) + .setClassName(info.pkg, info.name)); + appsCategory.addPreference(pref); + } + } + } + }; + + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -156,6 +256,11 @@ public class NotificationSettings extends SettingsPreferenceFragment implements refreshNotificationListeners(); lookupRingtoneNames(); + loadAppsList(); + } + + private void loadAppsList() { + AsyncTask.execute(mCollectAppsRunnable); } @Override @@ -252,4 +357,56 @@ public class NotificationSettings extends SettingsPreferenceFragment implements private void lookupRingtoneNames() { new Thread(mRingtoneLookupRunnable).start(); } + + // === Per-app notification settings row == + + private static class AppNotificationPreference extends Preference { + private Intent mIntent; + + public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + setLayoutResource(R.layout.notification_app); + } + + public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public AppNotificationPreference(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public AppNotificationPreference(Context context) { + this(context, null); + } + + public void setIntent(Intent intent) { + mIntent = intent; + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + + ImageView icon = (ImageView) view.findViewById(android.R.id.icon); + icon.setImageDrawable(getIcon()); + TextView title = (TextView) view.findViewById(android.R.id.title); + title.setText(getTitle()); + ImageView settingsButton = (ImageView) view.findViewById(android.R.id.button2); + settingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getContext().startActivity(mIntent); + } + }); + } + } + + private static class AppNotificationInfo { + public Drawable icon; + public CharSequence label; + public String name; + public String pkg; + } }