Merge "Introduce IconProvider." into ub-launcher3-calgary
diff --git a/res/values/config.xml b/res/values/config.xml
index 90df997..8d69f9a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -68,6 +68,9 @@
          filter the activities shown in the launcher. Can be empty. -->
     <string name="app_filter_class" translatable="false"></string>
 
+    <!-- Name of an icon provider class. -->
+    <string name="icon_provider_class" translatable="false"></string>
+
     <!-- View ID to use for QSB widget -->
     <item type="id" name="qsb_widget" />
 
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 27e01c3..9ed42f7 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -55,7 +55,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Locale;
 import java.util.Set;
 import java.util.Stack;
 
@@ -89,6 +88,7 @@
 
     private final Context mContext;
     private final PackageManager mPackageManager;
+    private IconProvider mIconProvider;
     @Thunk final UserManagerCompat mUserManager;
     private final LauncherAppsCompat mLauncherApps;
     private final HashMap<ComponentKey, CacheEntry> mCache =
@@ -107,7 +107,6 @@
     private final int mPackageBgColor;
     private final BitmapFactory.Options mLowResOptions;
 
-    private String mSystemState;
     private Canvas mLowResCanvas;
     private Paint mLowResPaint;
 
@@ -121,6 +120,9 @@
         mLowResCanvas = new Canvas();
         mLowResPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
 
+        mIconProvider = IconProvider.loadByName(context.getString(R.string.icon_provider_class),
+                context);
+
         mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
 
         mActivityBgColor = context.getResources().getColor(R.color.quantum_panel_bg_color);
@@ -129,7 +131,6 @@
         // Always prefer RGB_565 config for low res. If the bitmap has transparency, it will
         // automatically be loaded as ALPHA_8888.
         mLowResOptions.inPreferredConfig = Bitmap.Config.RGB_565;
-        updateSystemStateString();
     }
 
     private Drawable getFullResDefaultActivityIcon() {
@@ -241,7 +242,7 @@
         // Remove all active icon update tasks.
         mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
 
-        updateSystemStateString();
+        mIconProvider.updateSystemStateString();
         for (UserHandleCompat user : mUserManager.getUserProfiles()) {
             // Query for the set of apps
             final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
@@ -315,7 +316,8 @@
                 int version = c.getInt(indexVersion);
                 LauncherActivityInfoCompat app = componentMap.remove(component);
                 if (version == info.versionCode && updateTime == info.lastUpdateTime &&
-                        TextUtils.equals(mSystemState, c.getString(systemStateIndex))) {
+                        TextUtils.equals(c.getString(systemStateIndex),
+                                mIconProvider.getIconSystemState(info.packageName))) {
                     continue;
                 }
                 if (app == null) {
@@ -382,14 +384,16 @@
         if (entry == null) {
             entry = new CacheEntry();
             entry.icon = Utilities.createBadgedIconBitmap(
-                    app.getIcon(mIconDpi), app.getUser(), mContext);
+                    mIconProvider.getIcon(app, mIconDpi), app.getUser(),
+                    mContext);
         }
         entry.title = app.getLabel();
         entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, app.getUser());
         mCache.put(new ComponentKey(app.getComponentName(), app.getUser()), entry);
 
         Bitmap lowResIcon = generateLowResIcon(entry.icon, mActivityBgColor);
-        return newContentValues(entry.icon, lowResIcon, entry.title.toString());
+        return newContentValues(entry.icon, lowResIcon, entry.title.toString(),
+                app.getApplicationInfo().packageName);
     }
 
     /**
@@ -546,7 +550,8 @@
             if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
                 if (info != null) {
                     entry.icon = Utilities.createBadgedIconBitmap(
-                            info.getIcon(mIconDpi), info.getUser(), mContext);
+                            mIconProvider.getIcon(info, mIconDpi), info.getUser(),
+                            mContext);
                 } else {
                     if (usePackageIcon) {
                         CacheEntry packageEntry = getEntryForPackageLocked(
@@ -641,7 +646,7 @@
                     // Add the icon in the DB here, since these do not get written during
                     // package updates.
                     ContentValues values =
-                            newContentValues(icon, lowResIcon, entry.title.toString());
+                            newContentValues(icon, lowResIcon, entry.title.toString(), packageName);
                     addIconToDB(values, cacheKey.componentName, info,
                             mUserManager.getSerialNumberForUser(user));
 
@@ -683,7 +688,8 @@
 
         icon = Bitmap.createScaledBitmap(icon, idp.iconBitmapSize, idp.iconBitmapSize, true);
         Bitmap lowResIcon = generateLowResIcon(icon, Color.TRANSPARENT);
-        ContentValues values = newContentValues(icon, lowResIcon, label);
+        ContentValues values = newContentValues(icon, lowResIcon, label,
+                componentName.getPackageName());
         values.put(IconDB.COLUMN_COMPONENT, componentName.flattenToString());
         values.put(IconDB.COLUMN_USER, userSerial);
         mIconDb.insertOrReplace(values);
@@ -795,10 +801,6 @@
         }
     }
 
-    private void updateSystemStateString() {
-        mSystemState = Locale.getDefault().toString();
-    }
-
     private static final class IconDB extends SQLiteCacheHelper {
         private final static int DB_VERSION = 8;
 
@@ -838,13 +840,15 @@
         }
     }
 
-    private ContentValues newContentValues(Bitmap icon, Bitmap lowResIcon, String label) {
+    private ContentValues newContentValues(Bitmap icon, Bitmap lowResIcon, String label,
+            String packageName) {
         ContentValues values = new ContentValues();
         values.put(IconDB.COLUMN_ICON, Utilities.flattenBitmap(icon));
         values.put(IconDB.COLUMN_ICON_LOW_RES, Utilities.flattenBitmap(lowResIcon));
 
         values.put(IconDB.COLUMN_LABEL, label);
-        values.put(IconDB.COLUMN_SYSTEM_STATE, mSystemState);
+        values.put(IconDB.COLUMN_SYSTEM_STATE,
+                mIconProvider.getIconSystemState(mIconProvider.getIconSystemState(packageName)));
 
         return values;
     }
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
new file mode 100644
index 0000000..0a273bb
--- /dev/null
+++ b/src/com/android/launcher3/IconProvider.java
@@ -0,0 +1,49 @@
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Locale;
+
+public class IconProvider {
+
+    private static final boolean DBG = false;
+    private static final String TAG = "IconProvider";
+
+    protected String mSystemState;
+
+    public IconProvider() {
+        updateSystemStateString();
+    }
+
+    public static IconProvider loadByName(String className, Context context) {
+        if (TextUtils.isEmpty(className)) return new IconProvider();
+        if (DBG) Log.d(TAG, "Loading IconProvider: " + className);
+        try {
+            Class<?> cls = Class.forName(className);
+            return (IconProvider) cls.getDeclaredConstructor(Context.class).newInstance(context);
+        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
+                | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
+            Log.e(TAG, "Bad IconProvider class", e);
+            return new IconProvider();
+        }
+    }
+
+    public void updateSystemStateString() {
+        mSystemState = Locale.getDefault().toString();
+    }
+
+    public String getIconSystemState(String packageName) {
+        return mSystemState;
+    }
+
+
+    public Drawable getIcon(LauncherActivityInfoCompat info, int iconDpi) {
+        return info.getIcon(iconDpi);
+    }
+}