Merge "Fix folder animations in spring loaded mode + polish." into ub-launcher3-master
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a5552aa..a472a3a 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -763,7 +763,7 @@
     }
 
     private static final class IconDB extends SQLiteCacheHelper {
-        private final static int DB_VERSION = 10;
+        private final static int DB_VERSION = 11;
 
         private final static int RELEASE_VERSION = DB_VERSION +
                 (FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index ebbca95..f34933e 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -60,7 +60,7 @@
 
     // Shape detection related constants
     private static final float BOUND_RATIO_MARGIN = .05f;
-    private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.1f;
+    private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f;
     private static final float SCALE_NOT_INITIALIZED = 0;
 
     private static final Object LOCK = new Object();
@@ -71,6 +71,7 @@
     private final Bitmap mBitmapARGB;
     private final Canvas mCanvas;
     private final Paint mPaintMaskShape;
+    private final Paint mPaintMaskShapeOutline;
     private final byte[] mPixels;
     private final int[] mPixelsARGB;
     private float mAdaptiveIconScale;
@@ -79,14 +80,15 @@
     private final float[] mLeftBorder;
     private final float[] mRightBorder;
     private final Rect mBounds;
-    private final RectF mShapeBounds;
     private final Matrix mMatrix;
 
     private Paint mPaintIcon;
     private Canvas mCanvasARGB;
 
     private File mDir;
+    private int mFileId;
     private Random mRandom;
+    private float mDensity;
 
     private IconNormalizer(Context context) {
         // Use twice the icon size as maximum size to avoid scaling down twice.
@@ -98,17 +100,25 @@
         mLeftBorder = new float[mMaxSize];
         mRightBorder = new float[mMaxSize];
         mBounds = new Rect();
-
+        mDensity = context.getResources().getDisplayMetrics().density;
         // Needed for isShape() method
         mBitmapARGB = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ARGB_8888);
         mCanvasARGB = new Canvas(mBitmapARGB);
-        mShapeBounds = new RectF();
 
         mPaintIcon = new Paint();
         mPaintIcon.setColor(Color.WHITE);
+
         mPaintMaskShape = new Paint();
         mPaintMaskShape.setColor(Color.RED);
+        mPaintMaskShape.setStyle(Paint.Style.FILL);
         mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
+
+        mPaintMaskShapeOutline = new Paint();
+        mPaintMaskShapeOutline.setStrokeWidth(2 * mDensity);
+        mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
+        mPaintMaskShapeOutline.setColor(Color.BLACK);
+        mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+
         mMatrix = new Matrix();
         int[] mPixels = new int[mMaxSize * mMaxSize];
         mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
@@ -136,12 +146,12 @@
         // Condition 2:
         // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation
         // should generate transparent image, if the actual icon is equivalent to the shape.
-        int id = mRandom.nextInt();
+        mFileId = mRandom.nextInt();
         mBitmapARGB.eraseColor(Color.TRANSPARENT);
         mCanvasARGB.drawBitmap(mBitmap, 0, 0, mPaintIcon);
 
         if (DEBUG) {
-            final File beforeFile = new File(mDir, "isShape" + id + "_before.png");
+            final File beforeFile = new File(mDir, "isShape" + mFileId + "_before.png");
             try {
                 mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
                         new FileOutputStream(beforeFile));
@@ -149,24 +159,28 @@
         }
 
         // Fit the shape within the icon's bounding box
+        mMatrix.reset();
         mMatrix.setScale(mBounds.width(), mBounds.height());
         mMatrix.postTranslate(mBounds.left, mBounds.top);
         maskPath.transform(mMatrix);
-        maskPath.computeBounds(mShapeBounds, false);
 
         // XOR operation
         mCanvasARGB.drawPath(maskPath, mPaintMaskShape);
 
+        // DST_OUT operation around the mask path outline
+        mCanvasARGB.drawPath(maskPath, mPaintMaskShapeOutline);
+
+        boolean isTrans = isTransparentBitmap(mBitmapARGB);
         if (DEBUG) {
-            final File afterFile = new File(mDir, "isShape" + id + "_after.png");
+            final File afterFile = new File(mDir, "isShape" + mFileId + "_after_" + isTrans + ".png");
             try {
                 mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
                         new FileOutputStream(afterFile));
             } catch (Exception e) {}
         }
 
-        // Check if the XOR operation result is almost transparent
-        if (!isTransparentBitmap(mBitmapARGB)) {
+        // Check if the result is almost transparent
+        if (!isTrans) {
             if (DEBUG) {
                 Log.d(TAG, "Not same as mask shape");
             }
@@ -194,7 +208,7 @@
         float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
         boolean transparentImage = percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
         if (DEBUG) {
-            Log.d(TAG, "Total # pixel that is different:" + percentageDiffPixels + "="+ sum + "/" + mBounds.width() * mBounds.height());
+            Log.d(TAG, "Total # pixel that is different (id="+ mFileId + "):" + percentageDiffPixels + "="+ sum + "/" + mBounds.width() * mBounds.height());
         }
         return transparentImage;
     }