Fix links to notification settings activities.

Additionally, we now show the user a list of "app-like"
things (packages with launchable activities) instead of only
non-system things. This way you can make (some) changes to
system package notifications while not having to page
through reams of random non-app packages.

Bug: 17277023
Change-Id: I920d6b941070efb75a816e6ad38b798b09a83d08
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 4fb166a..47ff6af 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -30,9 +30,11 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -839,4 +841,34 @@
 
         return tm.getSimCount() > 0;
     }
+
+    /**
+     * Determine whether a package is a "system package", in which case certain things (like
+     * disabling notifications or disabling the package altogether) should be disallowed.
+     */
+    public static boolean isSystemPackage(PackageManager pm, PackageInfo pkg) {
+        if (sSystemSignature == null) {
+            sSystemSignature = new Signature[]{ getSystemSignature(pm) };
+        }
+        return sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg));
+    }
+
+    private static Signature[] sSystemSignature;
+
+    private static Signature getFirstSignature(PackageInfo pkg) {
+        if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
+            return pkg.signatures[0];
+        }
+        return null;
+    }
+
+    private static Signature getSystemSignature(PackageManager pm) {
+        try {
+            final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
+            return getFirstSignature(sys);
+        } catch (NameNotFoundException e) {
+        }
+        return null;
+    }
+
 }
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index adec63a..4b1bc10 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -316,22 +316,13 @@
         }
     }
 
-    private boolean isThisASystemPackage() {
-        try {
-            PackageInfo sys = mPm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
-            return (mPackageInfo != null && mPackageInfo.signatures != null &&
-                    sys.signatures[0].equals(mPackageInfo.signatures[0]));
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-    }
-
     private boolean handleDisableable(Button button) {
         boolean disableable = false;
         // Try to prevent the user from bricking their phone
         // by not allowing disabling of apps signed with the
         // system cert and any launcher app in the system.
-        if (mHomePackages.contains(mAppEntry.info.packageName) || isThisASystemPackage()) {
+        if (mHomePackages.contains(mAppEntry.info.packageName)
+                || Utils.isSystemPackage(mPm, mPackageInfo)) {
             // Disable button for core system applications.
             button.setText(R.string.disable_text);
         } else if (mAppEntry.info.enabled) {
@@ -427,7 +418,7 @@
             // this does not bode well
         }
         mNotificationSwitch.setChecked(enabled);
-        if (isThisASystemPackage()) {
+        if (Utils.isSystemPackage(mPm, mPackageInfo)) {
             mNotificationSwitch.setEnabled(false);
         } else {
             mNotificationSwitch.setEnabled(true);
diff --git a/src/com/android/settings/notification/NotificationAppList.java b/src/com/android/settings/notification/NotificationAppList.java
index 3879bef..7ca4b18 100644
--- a/src/com/android/settings/notification/NotificationAppList.java
+++ b/src/com/android/settings/notification/NotificationAppList.java
@@ -193,30 +193,6 @@
                 parent.getPaddingEnd() - eat, parent.getPaddingBottom());
     }
 
-    private boolean isSystemApp(PackageInfo pkg) {
-        if (mSystemSignature == null) {
-            mSystemSignature = new Signature[]{ getSystemSignature() };
-        }
-        return mSystemSignature[0] != null && mSystemSignature[0].equals(getFirstSignature(pkg));
-    }
-
-    private static Signature getFirstSignature(PackageInfo pkg) {
-        if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
-            return pkg.signatures[0];
-        }
-        return null;
-    }
-
-    private Signature getSystemSignature() {
-        final PackageManager pm = mContext.getPackageManager();
-        try {
-            final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
-            return getFirstSignature(sys);
-        } catch (NameNotFoundException e) {
-        }
-        return null;
-    }
-
     private static class ViewHolder {
         ViewGroup row;
         ImageView icon;
@@ -375,6 +351,7 @@
         public boolean priority;
         public boolean sensitive;
         public boolean first;  // first app in section
+        public boolean isSystem;
     }
 
     private static final Comparator<AppRow> mRowComparator = new Comparator<AppRow>() {
@@ -385,6 +362,7 @@
         }
     };
 
+
     public static AppRow loadAppRow(PackageManager pm, PackageInfo pkg, Backend backend) {
         final AppRow row = new AppRow();
         row.pkg = pkg.packageName;
@@ -399,16 +377,28 @@
         row.banned = backend.getNotificationsBanned(row.pkg, row.uid);
         row.priority = backend.getHighPriority(row.pkg, row.uid);
         row.sensitive = backend.getSensitive(row.pkg, row.uid);
+        row.isSystem = Utils.isSystemPackage(pm, pkg);
         return row;
     }
 
-    public static void collectConfigActivities(PackageManager pm, ArrayMap<String, AppRow> rows) {
+    public static List<ResolveInfo> queryNotificationConfigActivities(PackageManager pm) {
         if (DEBUG) Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is "
                 + APP_NOTIFICATION_PREFS_CATEGORY_INTENT);
         final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
                 APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
-                PackageManager.MATCH_DEFAULT_ONLY);
-        if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities");
+                0 //PackageManager.MATCH_DEFAULT_ONLY
+        );
+        return resolveInfos;
+    }
+    public static void collectConfigActivities(PackageManager pm, ArrayMap<String, AppRow> rows) {
+        final List<ResolveInfo> resolveInfos = queryNotificationConfigActivities(pm);
+        applyConfigActivities(pm, rows, resolveInfos);
+    }
+
+    public static void applyConfigActivities(PackageManager pm, ArrayMap<String, AppRow> rows,
+            List<ResolveInfo> resolveInfos) {
+        if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities"
+                + (resolveInfos.size() == 0 ? " ;_;" : ""));
         for (ResolveInfo ri : resolveInfos) {
             final ActivityInfo activityInfo = ri.activityInfo;
             final ApplicationInfo appInfo = activityInfo.applicationInfo;
@@ -425,7 +415,7 @@
                         + activityInfo.packageName);
                 continue;
             }
-            row.settingsIntent = new Intent(Intent.ACTION_MAIN)
+            row.settingsIntent = new Intent(APP_NOTIFICATION_PREFS_CATEGORY_INTENT)
                     .setClassName(activityInfo.packageName, activityInfo.name);
         }
     }
@@ -439,18 +429,41 @@
                 mRows.clear();
                 mSortedRows.clear();
 
-                // collect all non-system apps
+                // collect all launchable apps, plus any packages that have notification settings
                 final PackageManager pm = mContext.getPackageManager();
-                for (PackageInfo pkg : pm.getInstalledPackages(PackageManager.GET_SIGNATURES)) {
-                    if (pkg.applicationInfo == null || isSystemApp(pkg)) {
-                        if (DEBUG) Log.d(TAG, "Skipping " + pkg.packageName);
+                final List<ResolveInfo> resolvedApps = pm.queryIntentActivities(
+                        new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER),
+                        PackageManager.MATCH_DEFAULT_ONLY
+                );
+                final List<ResolveInfo> resolvedConfigActivities
+                        = queryNotificationConfigActivities(pm);
+                resolvedApps.addAll(resolvedConfigActivities);
+
+                for (ResolveInfo info : resolvedApps) {
+                    String pkgName = info.activityInfo.packageName;
+                    if (mRows.containsKey(pkgName)) {
+                        // we already have this app, thanks
+                        continue;
+                    }
+
+                    PackageInfo pkg = null;
+                    try {
+                        pkg = pm.getPackageInfo(pkgName,
+                                PackageManager.GET_SIGNATURES);
+                    } catch (NameNotFoundException e) {
+                        if (DEBUG) Log.d(TAG, "Skipping (NNFE): " + pkg.packageName);
+                        continue;
+                    }
+                    if (info.activityInfo.applicationInfo == null) {
+                        if (DEBUG) Log.d(TAG, "Skipping (no applicationInfo): " + pkg.packageName);
                         continue;
                     }
                     final AppRow row = loadAppRow(pm, pkg, mBackend);
-                    mRows.put(row.pkg, row);
+                    mRows.put(pkgName, row);
                 }
-                // collect config activities
-                collectConfigActivities(pm, mRows);
+
+                // add config activities to the list
+                applyConfigActivities(pm, mRows, resolvedConfigActivities);
                 // sort rows
                 mSortedRows.addAll(mRows.values());
                 Collections.sort(mSortedRows, mRowComparator);