Fixing different bitmap sizes in different orientations

> Using a single bitmap icon size
> Picking up appropriate density for satisfy the required icon size
> Fixing some icon size assumptions during icon animations

Bug: 19514688
Change-Id: Ia7a1d0d2c03a9d39ccc241fa4ae3eb8a0f374585
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 994c192..daa98ef 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -15,8 +15,6 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">64dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_container_inset">18dp</dimen>
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 89942f7..9d1e352 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -15,8 +15,6 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">72dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_search_bar_height">54dp</dimen>
     <dimen name="all_apps_icon_top_bottom_padding">16dp</dimen>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7950862..4fa997c 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -15,8 +15,6 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">48dp</dimen>
-
 <!-- Dynamic Grid -->
     <dimen name="dynamic_grid_edge_margin">6dp</dimen>
     <dimen name="dynamic_grid_search_bar_max_width">500dp</dimen>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 314c21f..f4e306a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -57,6 +57,7 @@
     private static final int DISPLAY_WORKSPACE = 0;
     private static final int DISPLAY_ALL_APPS = 1;
 
+    private final Launcher mLauncher;
     private Drawable mIcon;
     private final Drawable mBackground;
     private final CheckLongPressHelper mLongPressHelper;
@@ -91,8 +92,8 @@
 
     public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = ((Launcher) context).getDeviceProfile();
+        mLauncher = (Launcher) context;
+        DeviceProfile grid = mLauncher.getDeviceProfile();
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.BubbleTextView, defStyle, 0);
@@ -142,7 +143,7 @@
             boolean promiseStateChanged) {
         Bitmap b = info.getIcon(iconCache);
 
-        FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
+        FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(b);
         iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
 
         setIcon(iconDrawable, mIconSize);
@@ -158,7 +159,7 @@
     }
 
     public void applyFromApplicationInfo(AppInfo info) {
-        setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize);
+        setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
         setText(info.title);
         if (info.contentDescription != null) {
             setContentDescription(info.contentDescription);
@@ -171,7 +172,7 @@
     }
 
     public void applyFromPackageItemInfo(PackageItemInfo info) {
-        setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize);
+        setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
         setText(info.title);
         if (info.contentDescription != null) {
             setContentDescription(info.contentDescription);
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index a81e651..f1e9dc8 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -645,9 +645,10 @@
             final Runnable onCompleteRunnable) {
         final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
 
-        final float scale0 = 1.0f;
-        final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2;
-        final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2 + getPaddingTop();
+        float iconSize = mLauncher.getDeviceProfile().iconSizePx;
+        final float scale0 = iconSize / d.getIntrinsicWidth() ;
+        final float transX0 = (mAvailableSpaceInPreview - iconSize) / 2;
+        final float transY0 = (mAvailableSpaceInPreview - iconSize) / 2 + getPaddingTop();
         mAnimParams.drawable = d;
 
         ValueAnimator va = LauncherAnimUtils.ofFloat(this, 0f, 1.0f);
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6f09744..6e33d10 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -131,7 +131,7 @@
                 inflater.inflate(R.layout.all_apps_button, mContent, false);
         Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
 
-        Utilities.resizeIconDrawable(d);
+        mLauncher.resizeIconDrawable(d);
         allAppsButton.setCompoundDrawables(null, d, null, null);
 
         allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a16067d..fe25bb9 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
@@ -93,14 +92,11 @@
     @Thunk final Handler mWorkerHandler;
 
     public IconCache(Context context, InvariantDeviceProfile inv) {
-        ActivityManager activityManager =
-                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-
         mContext = context;
         mPackageManager = context.getPackageManager();
         mUserManager = UserManagerCompat.getInstance(mContext);
         mLauncherApps = LauncherAppsCompat.getInstance(mContext);
-        mIconDpi = activityManager.getLauncherLargeIconDensity();
+        mIconDpi = inv.fillResIconDpi;
         mIconDb = new IconDB(context);
 
         mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
@@ -136,10 +132,6 @@
         return getFullResDefaultActivityIcon();
     }
 
-    public int getFullResIconDpi() {
-        return mIconDpi;
-    }
-
     public Drawable getFullResIcon(ActivityInfo info) {
         Resources resources;
         try {
@@ -744,7 +736,7 @@
     }
 
     private static final class IconDB extends SQLiteOpenHelper {
-        private final static int DB_VERSION = 4;
+        private final static int DB_VERSION = 5;
 
         private final static String TABLE_NAME = "icons";
         private final static String COLUMN_ROWID = "rowid";
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 7f34593..fcaf834 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -35,6 +35,8 @@
     // This is a static that we use for the default icon size on a 4/5-inch phone
     private static float DEFAULT_ICON_SIZE_DP = 60;
 
+    private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
+
     // Constants that affects the interpolation curve between statically defined device profile
     // buckets.
     private static float KNEARESTNEIGHBOR = 3;
@@ -60,6 +62,8 @@
     public int numFolderRows;
     public int numFolderColumns;
     float iconSize;
+    int iconBitmapSize;
+    int fillResIconDpi;
     float iconTextSize;
 
     /**
@@ -135,8 +139,10 @@
         numFolderColumns = closestProfile.numFolderColumns;
 
         iconSize = interpolatedDeviceProfileOut.iconSize;
+        iconBitmapSize = Utilities.pxFromDp(iconSize, dm);
         iconTextSize = interpolatedDeviceProfileOut.iconTextSize;
         hotseatIconSize = interpolatedDeviceProfileOut.hotseatIconSize;
+        fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
 
         // If the partner customization apk contains any grid overrides, apply them
         // Supported overrides: numRows, numColumns, iconSize
@@ -187,6 +193,29 @@
         return predefinedDeviceProfiles;
     }
 
+    private int getLauncherIconDensity(int requiredSize) {
+        // Densities typically defined by an app.
+        int[] densityBuckets = new int[] {
+                DisplayMetrics.DENSITY_LOW,
+                DisplayMetrics.DENSITY_MEDIUM,
+                DisplayMetrics.DENSITY_TV,
+                DisplayMetrics.DENSITY_HIGH,
+                DisplayMetrics.DENSITY_XHIGH,
+                DisplayMetrics.DENSITY_XXHIGH,
+                DisplayMetrics.DENSITY_XXXHIGH
+        };
+
+        int density = DisplayMetrics.DENSITY_XXXHIGH;
+        for (int i = densityBuckets.length - 1; i >= 0; i--) {
+            float expectedSize = ICON_SIZE_DEFINED_IN_APP_DP * densityBuckets[i]
+                    / DisplayMetrics.DENSITY_DEFAULT;
+            if (expectedSize >= requiredSize) {
+                density = densityBuckets[i];
+            }
+        }
+
+        return density;
+    }
 
     /**
      * Apply any Partner customization grid overrides.
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 867a6e7..dc63a76 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -453,9 +453,6 @@
                         app.getInvariantDeviceProfile().landscapeProfile
                             : app.getInvariantDeviceProfile().portraitProfile;
 
-        // TODO: Move this to icon cache.
-        Utilities.setIconSize(mDeviceProfile.iconSizePx);
-
         // the LauncherApplication should call this, but in case of Instrumentation it might not be present yet
         mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(),
                 Context.MODE_PRIVATE);
@@ -4674,6 +4671,23 @@
     }
 
     /**
+     * Returns a FastBitmapDrawable with the icon, accurately sized.
+     */
+    public FastBitmapDrawable createIconDrawable(Bitmap icon) {
+        FastBitmapDrawable d = new FastBitmapDrawable(icon);
+        d.setFilterBitmap(true);
+        resizeIconDrawable(d);
+        return d;
+    }
+
+    /**
+     * Resizes an icon drawable to the correct icon size.
+     */
+    public void resizeIconDrawable(Drawable icon) {
+        icon.setBounds(0, 0, mDeviceProfile.iconSizePx, mDeviceProfile.iconSizePx);
+    }
+
+    /**
      * Prints out out state for debugging.
      */
     public void dumpState() {
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index 7ca4fe3..85af92f 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -67,7 +67,8 @@
         if (isCustomWidget) {
             return cache.getFullResIcon(provider.getPackageName(), icon);
         }
-        return super.loadIcon(context, cache.getFullResIconDpi());
+        return super.loadIcon(context,
+                LauncherAppState.getInstance().getInvariantDeviceProfile().fillResIconDpi);
     }
 
     public String toString(PackageManager pm) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 776c2bd..4974daf 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -3114,8 +3114,9 @@
                             // Update shortcuts which use iconResource.
                             if ((si.iconResource != null)
                                     && packageSet.contains(si.iconResource.packageName)) {
-                                Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,
-                                        si.iconResource.resourceName, mIconCache, context);
+                                Bitmap icon = Utilities.createIconBitmap(
+                                        si.iconResource.packageName,
+                                        si.iconResource.resourceName, context);
                                 if (icon != null) {
                                     si.setIcon(icon);
                                     si.usingFallbackIcon = false;
@@ -3558,7 +3559,7 @@
             String resourceName = c.getString(iconResourceIndex);
             info.customIcon = false;
             // the resource
-            icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);
+            icon = Utilities.createIconBitmap(packageName, resourceName, context);
             // the db
             if (icon == null) {
                 icon = Utilities.createIconBitmap(c, iconIndex, context);
@@ -3612,7 +3613,7 @@
             if (extra instanceof ShortcutIconResource) {
                 iconResource = (ShortcutIconResource) extra;
                 icon = Utilities.createIconBitmap(iconResource.packageName,
-                        iconResource.resourceName, mIconCache, context);
+                        iconResource.resourceName, context);
             }
         }
 
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index c8b27ef..08f8e56 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -121,7 +121,7 @@
             //   2) Preload icon in the center
             //   3) Setup icon in the center and app icon in the top right corner.
             if (mDisabledForSafeMode) {
-                FastBitmapDrawable disabledIcon = Utilities.createIconDrawable(mIcon);
+                FastBitmapDrawable disabledIcon = mLauncher.createIconDrawable(mIcon);
                 disabledIcon.setGhostModeEnabled(true);
                 mCenterDrawable = disabledIcon;
                 mTopCornerDrawable = null;
@@ -134,7 +134,7 @@
                     sPreloaderTheme.applyStyle(R.style.PreloadIcon, true);
                 }
 
-                FastBitmapDrawable drawable = Utilities.createIconDrawable(mIcon);
+                FastBitmapDrawable drawable = mLauncher.createIconDrawable(mIcon);
                 mCenterDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme);
                 mCenterDrawable.setCallback(this);
                 mTopCornerDrawable = null;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index a9cbf69..cffcd34 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -71,9 +71,6 @@
 
     private static final String TAG = "Launcher.Utilities";
 
-    private static int sIconWidth = -1;
-    private static int sIconHeight = -1;
-
     private static final Rect sOldBounds = new Rect();
     private static final Canvas sCanvas = new Canvas();
 
@@ -87,33 +84,16 @@
     static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
     static int sColorIndex = 0;
 
-    static int[] sLoc0 = new int[2];
-    static int[] sLoc1 = new int[2];
+    private static final int[] sLoc0 = new int[2];
+    private static final int[] sLoc1 = new int[2];
 
     // To turn on these properties, type
     // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
-    static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
-    public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
+    private static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
+    private static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
 
     public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
 
-    /**
-     * Returns a FastBitmapDrawable with the icon, accurately sized.
-     */
-    public static FastBitmapDrawable createIconDrawable(Bitmap icon) {
-        FastBitmapDrawable d = new FastBitmapDrawable(icon);
-        d.setFilterBitmap(true);
-        resizeIconDrawable(d);
-        return d;
-    }
-
-    /**
-     * Resizes an icon drawable to the correct icon size.
-     */
-    static void resizeIconDrawable(Drawable icon) {
-        icon.setBounds(0, 0, sIconWidth, sIconHeight);
-    }
-
     public static boolean isPropertyEnabled(String propertyName) {
         return Log.isLoggable(propertyName, Log.VERBOSE);
     }
@@ -141,7 +121,7 @@
         return Build.VERSION.SDK_INT >= 22;
     }
 
-    static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
+    public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
         byte[] data = c.getBlob(iconIndex);
         try {
             return createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), context);
@@ -154,7 +134,7 @@
      * Returns a bitmap suitable for the all apps view. If the package or the resource do not
      * exist, it returns null.
      */
-    static Bitmap createIconBitmap(String packageName, String resourceName, IconCache cache,
+    public static Bitmap createIconBitmap(String packageName, String resourceName,
             Context context) {
         PackageManager packageManager = context.getPackageManager();
         // the resource
@@ -163,7 +143,8 @@
             if (resources != null) {
                 final int id = resources.getIdentifier(resourceName, null, null);
                 return createIconBitmap(
-                        resources.getDrawableForDensity(id, cache.getFullResIconDpi()), context);
+                        resources.getDrawableForDensity(id, LauncherAppState.getInstance()
+                                .getInvariantDeviceProfile().fillResIconDpi), context);
             }
         } catch (Exception e) {
             // Icon not found.
@@ -171,16 +152,16 @@
         return null;
     }
 
+    private static int getIconBitmapSize() {
+        return LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
+    }
+
     /**
      * Returns a bitmap which is of the appropriate size to be displayed as an icon
      */
-    static Bitmap createIconBitmap(Bitmap icon, Context context) {
-        synchronized (sCanvas) { // we share the statics :-(
-            if (sIconWidth == -1) {
-                initStatics(context);
-            }
-        }
-        if (sIconWidth == icon.getWidth() && sIconHeight == icon.getHeight()) {
+    public static Bitmap createIconBitmap(Bitmap icon, Context context) {
+        final int iconBitmapSize = getIconBitmapSize();
+        if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) {
             return icon;
         }
         return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context);
@@ -190,13 +171,11 @@
      * Returns a bitmap suitable for the all apps view.
      */
     public static Bitmap createIconBitmap(Drawable icon, Context context) {
-        synchronized (sCanvas) { // we share the statics :-(
-            if (sIconWidth == -1) {
-                initStatics(context);
-            }
+        synchronized (sCanvas) {
+            final int iconBitmapSize = getIconBitmapSize();
 
-            int width = sIconWidth;
-            int height = sIconHeight;
+            int width = iconBitmapSize;
+            int height = iconBitmapSize;
 
             if (icon instanceof PaintDrawable) {
                 PaintDrawable painter = (PaintDrawable) icon;
@@ -223,8 +202,8 @@
             }
 
             // no intrinsic size --> use default size
-            int textureWidth = sIconWidth;
-            int textureHeight = sIconHeight;
+            int textureWidth = iconBitmapSize;
+            int textureHeight = iconBitmapSize;
 
             final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
                     Bitmap.Config.ARGB_8888);
@@ -354,15 +333,6 @@
                 localY < (v.getHeight() + slop);
     }
 
-    private static void initStatics(Context context) {
-        final Resources resources = context.getResources();
-        sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
-    }
-
-    public static void setIconSize(int widthPx) {
-        sIconWidth = sIconHeight = widthPx;
-    }
-
     public static void scaleRect(Rect r, float scale) {
         if (scale != 1.0f) {
             r.left = (int) (r.left * scale + 0.5f);
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 8d04be5..64fc8c5 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -241,6 +241,7 @@
             Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
             preview = Utilities.createIconBitmap(icon, mLauncher);
             createItemInfo.spanX = createItemInfo.spanY = 1;
+            scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth();
         }
 
         // Don't clip alpha values for the drag outline if we're using the default widget preview