Add a better app filtering mechanism and filter widgets

The old one didn't use the app filter when packages
were added or updated, only in the initial load.

The app filter is now also used for appwidget providers.

Bug: 10895858
Bug: 10898990
Change-Id: Id29bbc3cf7bdb0c360edd92f768b86684bd338ed
diff --git a/res/values/config.xml b/res/values/config.xml
index 8718f15..0766d76 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -81,4 +81,9 @@
 
     <!-- Memory debugging, including a memory dump icon -->
     <bool name="debug_memory_enabled">false</bool>
+
+    <!-- Name of a subclass of com.android.launcher3.AppFilter used to
+         filter the activities shown in the launcher. Can be empty. -->
+    <string name="app_filter_class" translatable="false"></string>
+
 </resources>
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 5d3aa3a..d955e4e 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -46,11 +46,14 @@
 
     private IconCache mIconCache;
 
+    private AppFilter mAppFilter;
+
     /**
      * Boring constructor.
      */
-    public AllAppsList(IconCache iconCache) {
+    public AllAppsList(IconCache iconCache, AppFilter appFilter) {
         mIconCache = iconCache;
+        mAppFilter = appFilter;
     }
 
     /**
@@ -60,13 +63,16 @@
      * If the app is already in the list, doesn't add it.
      */
     public void add(AppInfo info) {
+        if (mAppFilter != null && !mAppFilter.shouldShowApp(info.componentName)) {
+            return;
+        }
         if (findActivity(data, info.componentName)) {
             return;
         }
         data.add(info);
         added.add(info);
     }
-    
+
     public void clear() {
         data.clear();
         // TODO: do we clear these too?
diff --git a/src/com/android/launcher3/AppFilter.java b/src/com/android/launcher3/AppFilter.java
new file mode 100644
index 0000000..e01436d
--- /dev/null
+++ b/src/com/android/launcher3/AppFilter.java
@@ -0,0 +1,35 @@
+package com.android.launcher3;
+
+import android.content.ComponentName;
+import android.text.TextUtils;
+import android.util.Log;
+
+public abstract class AppFilter {
+
+    private static final boolean DBG = false;
+    private static final String TAG = "AppFilter";
+
+    public abstract boolean shouldShowApp(ComponentName app);
+
+    public static AppFilter loadByName(String className) {
+        if (TextUtils.isEmpty(className)) return null;
+        if (DBG) Log.d(TAG, "Loading AppFilter: " + className);
+        try {
+            Class<?> cls = Class.forName(className);
+            return (AppFilter) cls.newInstance();
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "Bad AppFilter class", e);
+            return null;
+        } catch (InstantiationException e) {
+            Log.e(TAG, "Bad AppFilter class", e);
+            return null;
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Bad AppFilter class", e);
+            return null;
+        } catch (ClassCastException e) {
+            Log.e(TAG, "Bad AppFilter class", e);
+            return null;
+        }
+    }
+
+}
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index 4e9d68b..9b35bb5 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -438,6 +438,9 @@
         for (Object o : widgetsAndShortcuts) {
             if (o instanceof AppWidgetProviderInfo) {
                 AppWidgetProviderInfo widget = (AppWidgetProviderInfo) o;
+                if (!app.shouldShowAppOrWidgetProvider(widget.provider)) {
+                    continue;
+                }
                 widget.label = widget.label.trim();
                 if (widget.minWidth > 0 && widget.minHeight > 0) {
                     // Ensure that all widgets we show can be added on a workspace of this size
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5e10e8b..d04f7ed 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3933,11 +3933,6 @@
         }
     }
 
-    @Override
-    public boolean shouldShowApp(ResolveInfo app) {
-        return true;
-    }
-
     /**
      * A package was updated.
      *
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index ed96310..7da1c2a 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -34,6 +34,7 @@
 
     private LauncherModel mModel;
     private IconCache mIconCache;
+    private AppFilter mAppFilter;
     private WidgetPreviewLoader.CacheDb mWidgetPreviewCacheDb;
     private boolean mIsScreenLarge;
     private float mScreenDensity;
@@ -81,7 +82,9 @@
 
         mWidgetPreviewCacheDb = new WidgetPreviewLoader.CacheDb(sContext);
         mIconCache = new IconCache(sContext);
-        mModel = new LauncherModel(this, mIconCache);
+
+        mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class));
+        mModel = new LauncherModel(this, mIconCache, mAppFilter);
 
         // Register intent receivers
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
@@ -147,6 +150,10 @@
         return mModel;
     }
 
+    boolean shouldShowAppOrWidgetProvider(ComponentName componentName) {
+        return mAppFilter == null || mAppFilter.shouldShowApp(componentName);
+    }
+
     WidgetPreviewLoader.CacheDb getWidgetPreviewCacheDb() {
         return mWidgetPreviewCacheDb;
     }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index cc89d01..edfc070 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -158,7 +158,6 @@
         public void bindFolders(HashMap<Long,FolderInfo> folders);
         public void finishBindingItems(boolean upgradePath);
         public void bindAppWidget(LauncherAppWidgetInfo info);
-        public boolean shouldShowApp(ResolveInfo app);
         public void bindAllApplications(ArrayList<AppInfo> apps);
         public void bindAppsAdded(ArrayList<Long> newScreens,
                                   ArrayList<ItemInfo> addNotAnimated,
@@ -179,12 +178,12 @@
         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);
     }
 
-    LauncherModel(LauncherAppState app, IconCache iconCache) {
+    LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
         final Context context = app.getContext();
 
         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();
         mApp = app;
-        mBgAllAppsList = new AllAppsList(iconCache);
+        mBgAllAppsList = new AllAppsList(iconCache, appFilter);
         mIconCache = iconCache;
 
         mDefaultIcon = Utilities.createIconBitmap(
@@ -2397,11 +2396,9 @@
             // Create the ApplicationInfos
             for (int i = 0; i < apps.size(); i++) {
                 ResolveInfo app = apps.get(i);
-                if (oldCallbacks.shouldShowApp(app)) {
-                    // This builds the icon bitmaps.
-                    mBgAllAppsList.add(new AppInfo(packageManager, app,
-                            mIconCache, mLabelCache));
-                }
+                // This builds the icon bitmaps.
+                mBgAllAppsList.add(new AppInfo(packageManager, app,
+                        mIconCache, mLabelCache));
             }
 
             // Huh? Shouldn't this be inside the Runnable below?