Merge "Re-enable chips in qt-r1-dev" into ub-launcher3-qt-r1-dev
diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
index 3c55854..db5515b 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -46,13 +46,15 @@
 
     private IconNormalizer mNormalizer;
     private ShadowGenerator mShadowGenerator;
+    private final boolean mShapeDetection;
 
     private Drawable mWrapperIcon;
     private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
 
-    protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
+    protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
+            boolean shapeDetection) {
         mContext = context.getApplicationContext();
-
+        mShapeDetection = shapeDetection;
         mFillResIconDpi = fillResIconDpi;
         mIconBitmapSize = iconBitmapSize;
 
@@ -64,6 +66,10 @@
         clear();
     }
 
+    protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize) {
+        this(context, fillResIconDpi, iconBitmapSize, false);
+    }
+
     protected void clear() {
         mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
         mDisableColorExtractor = false;
@@ -78,7 +84,7 @@
 
     public IconNormalizer getNormalizer() {
         if (mNormalizer == null) {
-            mNormalizer = new IconNormalizer(mIconBitmapSize);
+            mNormalizer = new IconNormalizer(mContext, mIconBitmapSize, mShapeDetection);
         }
         return mNormalizer;
     }
@@ -212,18 +218,19 @@
             }
             AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
             dr.setBounds(0, 0, 1, 1);
-            scale = getNormalizer().getScale(icon, outIconBounds);
-            if (!(icon instanceof AdaptiveIconDrawable)) {
+            boolean[] outShape = new boolean[1];
+            scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
+            if (!(icon instanceof AdaptiveIconDrawable) && !outShape[0]) {
                 FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
                 fsd.setDrawable(icon);
                 fsd.setScale(scale);
                 icon = dr;
-                scale = getNormalizer().getScale(icon, outIconBounds);
+                scale = getNormalizer().getScale(icon, outIconBounds, null, null);
 
                 ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
             }
         } else {
-            scale = getNormalizer().getScale(icon, outIconBounds);
+            scale = getNormalizer().getScale(icon, outIconBounds, null, null);
         }
 
         outScale[0] = scale;
diff --git a/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java b/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
index 4a2a7cf..de39e79 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/IconNormalizer.java
@@ -18,16 +18,22 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.util.Log;
 
 import java.nio.ByteBuffer;
 
@@ -51,6 +57,9 @@
 
     private static final int MIN_VISIBLE_ALPHA = 40;
 
+    // Shape detection related constants
+    private static final float BOUND_RATIO_MARGIN = .05f;
+    private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f;
     private static final float SCALE_NOT_INITIALIZED = 0;
 
     // Ratio of the diameter of an normalized circular icon to the actual icon size.
@@ -59,18 +68,24 @@
     private final int mMaxSize;
     private final Bitmap mBitmap;
     private final Canvas mCanvas;
+    private final Paint mPaintMaskShape;
+    private final Paint mPaintMaskShapeOutline;
     private final byte[] mPixels;
 
     private final RectF mAdaptiveIconBounds;
     private float mAdaptiveIconScale;
 
+    private boolean mEnableShapeDetection;
+
     // for each y, stores the position of the leftmost x and the rightmost x
     private final float[] mLeftBorder;
     private final float[] mRightBorder;
     private final Rect mBounds;
+    private final Path mShapePath;
+    private final Matrix mMatrix;
 
     /** package private **/
-    IconNormalizer(int iconBitmapSize) {
+    IconNormalizer(Context context, int iconBitmapSize, boolean shapeDetection) {
         // Use twice the icon size as maximum size to avoid scaling down twice.
         mMaxSize = iconBitmapSize * 2;
         mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
@@ -81,7 +96,22 @@
         mBounds = new Rect();
         mAdaptiveIconBounds = new RectF();
 
+        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 * context.getResources().getDisplayMetrics().density);
+        mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
+        mPaintMaskShapeOutline.setColor(Color.BLACK);
+        mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+
+        mShapePath = new Path();
+        mMatrix = new Matrix();
         mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
+        mEnableShapeDetection = shapeDetection;
     }
 
     private static float getScale(float hullArea, float boundingArea, float fullArea) {
@@ -127,6 +157,72 @@
     }
 
     /**
+     * Returns if the shape of the icon is same as the path.
+     * For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds.
+     */
+    private boolean isShape(Path maskPath) {
+        // Condition1:
+        // If width and height of the path not close to a square, then the icon shape is
+        // not same as the mask shape.
+        float iconRatio = ((float) mBounds.width()) / mBounds.height();
+        if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) {
+            if (DEBUG) {
+                Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio);
+            }
+            return false;
+        }
+
+        // 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.
+
+        // 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, mShapePath);
+
+        // XOR operation
+        mCanvas.drawPath(mShapePath, mPaintMaskShape);
+
+        // DST_OUT operation around the mask path outline
+        mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline);
+
+        // Check if the result is almost transparent
+        return isTransparentBitmap();
+    }
+
+    /**
+     * Used to determine if certain the bitmap is transparent.
+     */
+    private boolean isTransparentBitmap() {
+        ByteBuffer buffer = ByteBuffer.wrap(mPixels);
+        buffer.rewind();
+        mBitmap.copyPixelsToBuffer(buffer);
+
+        int y = mBounds.top;
+        // buffer position
+        int index = y * mMaxSize;
+        // buffer shift after every row, width of buffer = mMaxSize
+        int rowSizeDiff = mMaxSize - mBounds.right;
+
+        int sum = 0;
+        for (; y < mBounds.bottom; y++) {
+            index += mBounds.left;
+            for (int x = mBounds.left; x < mBounds.right; x++) {
+                if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) {
+                    sum++;
+                }
+                index++;
+            }
+            index += rowSizeDiff;
+        }
+
+        float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
+        return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
+    }
+
+    /**
      * Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it
      * matches the design guidelines for a launcher icon.
      *
@@ -140,7 +236,8 @@
      *
      * @param outBounds optional rect to receive the fraction distance from each edge.
      */
-    public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds) {
+    public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
+            @Nullable Path path, @Nullable boolean[] outMaskShape) {
         if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
             if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
                 mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds);
@@ -242,7 +339,9 @@
                     1 - ((float) mBounds.right) / width,
                     1 - ((float) mBounds.bottom) / height);
         }
-
+        if (outMaskShape != null && mEnableShapeDetection && outMaskShape.length > 0) {
+            outMaskShape[0] = isShape(path);
+        }
         // Area of the rectangle required to fit the convex hull
         float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX);
         return getScale(area, rectArea, width * height);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 1d36d1a..b5d8424 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -32,7 +32,6 @@
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.PropertySetter;
-import com.android.quickstep.hints.ProactiveHintsContainer;
 import com.android.quickstep.views.ClearAllButton;
 import com.android.quickstep.views.LauncherRecentsView;
 import com.android.quickstep.views.RecentsView;
@@ -55,14 +54,6 @@
         if (state.overviewUi) {
             mRecentsView.updateEmptyMessage();
             mRecentsView.resetTaskVisuals();
-            mRecentsView.setHintVisibility(1f);
-        } else {
-            mRecentsView.setHintVisibility(0f);
-            ProactiveHintsContainer
-                    proactiveHintsContainer = mRecentsView.getProactiveHintsContainer();
-            if (proactiveHintsContainer != null) {
-                proactiveHintsContainer.removeAllViews();
-            }
         }
         setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state.getVisibleElements(mLauncher));
         mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
@@ -75,14 +66,6 @@
 
         if (!toState.overviewUi) {
             builder.addOnFinishRunnable(mRecentsView::resetTaskVisuals);
-            mRecentsView.setHintVisibility(0f);
-            builder.addOnFinishRunnable(() -> {
-                ProactiveHintsContainer
-                        proactiveHintsContainer = mRecentsView.getProactiveHintsContainer();
-                if (proactiveHintsContainer != null) {
-                    proactiveHintsContainer.removeAllViews();
-                }
-            });
         }
 
         if (toState.overviewUi) {
@@ -94,7 +77,6 @@
             updateAnim.setDuration(config.duration);
             builder.play(updateAnim);
             mRecentsView.updateEmptyMessage();
-            builder.addOnFinishRunnable(() -> mRecentsView.setHintVisibility(1f));
         }
 
         PropertySetter propertySetter = config.getPropertySetter(builder);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintUtil.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintUtil.java
deleted file mode 100644
index f2d40ec..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintUtil.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.hints;
-
-import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-
-public final class HintUtil {
-
-    public static final String ID_KEY = "id";
-    public static final String ICON_KEY = "icon";
-    public static final String TEXT_KEY = "text";
-    public static final String TAP_ACTION_KEY = "tap_action";
-
-    private HintUtil() {}
-
-    public static Bundle makeHint(String id, Icon icon, CharSequence text) {
-        Bundle hint = new Bundle();
-        hint.putString(ID_KEY, id);
-        hint.putParcelable(ICON_KEY, icon);
-        hint.putCharSequence(TEXT_KEY, text);
-        return hint;
-    }
-
-    public static Bundle makeHint(Icon icon, CharSequence text, PendingIntent tapAction) {
-        Bundle hint = new Bundle();
-        hint.putParcelable(ICON_KEY, icon);
-        hint.putCharSequence(TEXT_KEY, text);
-        hint.putParcelable(TAP_ACTION_KEY, tapAction);
-        return hint;
-    }
-
-    public static String getId(Bundle hint) {
-        String id = hint.getString(ID_KEY);
-        if (id == null) {
-            throw new IllegalArgumentException("Hint does not contain an ID");
-        }
-        return id;
-    }
-
-    public static Icon getIcon(Bundle hint) {
-        Icon icon = hint.getParcelable(ICON_KEY);
-        if (icon == null) {
-            throw new IllegalArgumentException("Hint does not contain an icon");
-        }
-        return icon;
-    }
-
-    public static CharSequence getText(Bundle hint) {
-        CharSequence text = hint.getCharSequence(TEXT_KEY);
-        if (text == null) {
-            throw new IllegalArgumentException("Hint does not contain text");
-        }
-        return text;
-    }
-
-    public static PendingIntent getTapAction(Bundle hint) {
-        PendingIntent tapAction = hint.getParcelable(TAP_ACTION_KEY);
-        if (tapAction == null) {
-            throw new IllegalArgumentException("Hint does not contain a tap action");
-        }
-        return tapAction;
-    }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintView.java
deleted file mode 100644
index 5399cc4..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintView.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.hints;
-
-import static com.android.quickstep.hints.HintUtil.getIcon;
-import static com.android.quickstep.hints.HintUtil.getText;
-
-import android.content.Context;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.R;
-
-public class HintView extends LinearLayout {
-    private ImageView mIconView;
-    private TextView mLabelView;
-
-    public HintView(Context context) {
-        super(context);
-    }
-
-    public HintView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public HintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    public HintView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    public void setHint(Bundle hint) {
-        mLabelView.setText(getText(hint));
-
-        Icon icon = getIcon(hint);
-        if (icon == null) {
-            mIconView.setVisibility(GONE);
-        } else {
-            mIconView.setImageIcon(icon);
-            mIconView.setVisibility(VISIBLE);
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mIconView = findViewById(R.id.icon);
-        mLabelView = findViewById(R.id.label);
-    }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ProactiveHintsContainer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ProactiveHintsContainer.java
deleted file mode 100644
index 74a4851..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ProactiveHintsContainer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.android.quickstep.hints;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.view.View;
-import android.widget.FrameLayout;
-
-public class ProactiveHintsContainer extends FrameLayout {
-
-  public static final FloatProperty<ProactiveHintsContainer> HINT_VISIBILITY =
-      new FloatProperty<ProactiveHintsContainer>("hint_visibility") {
-        @Override
-        public void setValue(ProactiveHintsContainer proactiveHintsContainer, float v) {
-          proactiveHintsContainer.setHintVisibility(v);
-        }
-
-        @Override
-        public Float get(ProactiveHintsContainer proactiveHintsContainer) {
-          return proactiveHintsContainer.mHintVisibility;
-        }
-      };
-
-  private float mHintVisibility;
-
-  public ProactiveHintsContainer(Context context) {
-    super(context);
-  }
-
-  public ProactiveHintsContainer(Context context, AttributeSet attrs) {
-    super(context, attrs);
-  }
-
-  public ProactiveHintsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
-    super(context, attrs, defStyleAttr);
-  }
-
-  public ProactiveHintsContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-    super(context, attrs, defStyleAttr, defStyleRes);
-  }
-
-  public void setView(View v) {
-    removeAllViews();
-    addView(v);
-  }
-
-  public void setHintVisibility(float v) {
-    if (v == 1) {
-      setVisibility(VISIBLE);
-    } else {
-      setVisibility(GONE);
-    }
-    mHintVisibility = v;
-  }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiHintListenerConstants.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiHintListenerConstants.java
deleted file mode 100644
index 420033d..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiHintListenerConstants.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.hints;
-
-public final class UiHintListenerConstants {
-
-    private UiHintListenerConstants() {}
-
-    // Operations
-    public static final int ON_HINTS_RETURNED_CODE = 5;
-
-    // Keys
-    public static final String SESSION_ID_KEY = "session_id";
-    public static final String HINTS_KEY = "hints";
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiInterfaceConstants.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiInterfaceConstants.java
deleted file mode 100644
index 0140613..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiInterfaceConstants.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.hints;
-
-public final class UiInterfaceConstants {
-
-    private UiInterfaceConstants() {}
-
-    // Operations
-    public static final int ON_HINT_TAP_CODE = 4;
-
-    public static final int REQUEST_HINTS_CODE = 7;
-
-    // Keys
-    public static final String SESSION_ID_KEY = "session_id";
-    public static final String HINT_ID_KEY = "hint_id";
-    public static final String WIDTH_PX_KEY = "width_px";
-    public static final String HEIGHT_PX_KEY = "height_px";
-    public static final String HINT_SPACE_WIDTH_PX_KEY = "hint_space_width_px";
-    public static final String HINT_SPACE_HEIGHT_PX_KEY = "hint_space_height_px";
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index deedd21..3b23bd1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -30,13 +30,10 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
@@ -44,11 +41,8 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.appprediction.PredictionUiStateManager;
 import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
-import com.android.launcher3.util.PendingAnimation;
-import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.hints.ProactiveHintsContainer;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
 import com.android.quickstep.util.LayoutUtils;
@@ -60,8 +54,6 @@
 public class LauncherRecentsView extends RecentsView<Launcher> {
 
     private final TransformParams mTransformParams = new TransformParams();
-    private final int mChipOverhang;
-    @Nullable private ProactiveHintsContainer mProactiveHintsContainer;
 
     public LauncherRecentsView(Context context) {
         this(context, null);
@@ -74,16 +66,6 @@
     public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         setContentAlpha(0);
-        mChipOverhang = (int) context.getResources().getDimension(R.dimen.chip_hint_overhang);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        View hintContainer = mActivity.findViewById(R.id.hints);
-        mProactiveHintsContainer =
-                hintContainer instanceof ProactiveHintsContainer
-                        ? (ProactiveHintsContainer) hintContainer : null;
     }
 
     @Override
@@ -102,11 +84,6 @@
         }
     }
 
-    @Nullable
-    public ProactiveHintsContainer getProactiveHintsContainer() {
-        return mProactiveHintsContainer;
-    }
-
     @Override
     public void draw(Canvas canvas) {
         maybeDrawEmptyMessage(canvas);
@@ -160,23 +137,6 @@
     @Override
     protected void getTaskSize(DeviceProfile dp, Rect outRect) {
         LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
-        if (mProactiveHintsContainer != null) {
-            BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) mProactiveHintsContainer.getLayoutParams();
-            params.bottomMargin = getHeight() - outRect.bottom - mChipOverhang;
-            params.width = outRect.width();
-        }
-    }
-
-    @Override
-    public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) {
-        PendingAnimation anim = super.createTaskLauncherAnimation(tv, duration);
-
-        if (mProactiveHintsContainer != null) {
-            anim.anim.play(ObjectAnimator.ofFloat(
-                    mProactiveHintsContainer, ProactiveHintsContainer.HINT_VISIBILITY, 0));
-        }
-
-        return anim;
     }
 
     @Override
@@ -195,31 +155,6 @@
     }
 
     @Override
-    public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
-            boolean shouldRemoveTask, long duration) {
-        PendingAnimation anim = super.createTaskDismissAnimation(taskView, animateTaskView,
-                shouldRemoveTask, duration);
-
-        if (mProactiveHintsContainer != null) {
-            anim.anim.play(ObjectAnimator.ofFloat(
-                    mProactiveHintsContainer, ProactiveHintsContainer.HINT_VISIBILITY, 0));
-            anim.addEndListener(onEndListener -> {
-                if (!onEndListener.isSuccess) {
-                    mProactiveHintsContainer.setHintVisibility(1);
-                }
-            });
-        }
-
-        return anim;
-    }
-
-    public void setHintVisibility(float v) {
-        if (mProactiveHintsContainer != null) {
-            mProactiveHintsContainer.setHintVisibility(v);
-        }
-    }
-
-    @Override
     protected void onTaskLaunched(boolean success) {
         if (success) {
             mActivity.getStateManager().goToState(NORMAL, false /* animate */);
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 9cab9c2..cca899b 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -48,11 +48,6 @@
             layout="@layout/overview_panel"
             android:visibility="gone" />
 
-        <include
-            android:id="@+id/hints"
-            layout="@layout/proactive_hints_container"
-            android:visibility="gone"/>
-
         <!-- Keep these behind the workspace so that they are not visible when
          we go into AllApps -->
         <com.android.launcher3.pageindicators.WorkspacePageIndicator
diff --git a/res/layout/proactive_hints_container.xml b/res/layout/proactive_hints_container.xml
deleted file mode 100644
index 2637f03..0000000
--- a/res/layout/proactive_hints_container.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<Space
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="0dp"
-    android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0da56da..4bcb8a7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -232,11 +232,6 @@
     <dimen name="snackbar_min_text_size">12sp</dimen>
     <dimen name="snackbar_max_text_size">14sp</dimen>
 
-<!-- Hints -->
-    <dimen name="chip_hint_height">26dp</dimen>
-    <dimen name="chip_hint_bottom_margin">194dp</dimen>
-    <dimen name="chip_hint_overhang">15dp</dimen>
-
 <!-- Theming related -->
     <dimen name="default_dialog_corner_radius">8dp</dimen>
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c1f898c..883e8c6 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -99,10 +99,6 @@
     public int folderChildTextSizePx;
     public int folderChildDrawablePaddingPx;
 
-    // Hints
-    public int chipHintHeightPx;
-    public int chipHintBottomMarginPx;
-
     // Hotseat
     public int hotseatCellHeightPx;
     // In portrait: size = height, in landscape: size = width
@@ -200,9 +196,6 @@
 
         workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
 
-        chipHintHeightPx = res.getDimensionPixelSize(R.dimen.chip_hint_height);
-        chipHintBottomMarginPx = res.getDimensionPixelSize(R.dimen.chip_hint_bottom_margin);
-
         hotseatBarTopPaddingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
         hotseatBarBottomPaddingPx = (isTallDevice ? 0
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index dc27516..d07638a 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -68,9 +68,6 @@
     }
 
     private LauncherAppState(Context context) {
-        if (!UserManagerCompat.getInstance(context).isUserUnlocked(Process.myUserHandle())) {
-            throw new RuntimeException("LauncherAppState should not start in direct boot mode");
-        }
         if (getLocalProvider(context) == null) {
             throw new RuntimeException(
                     "Initializing LauncherAppState in the absence of LauncherProvider");
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index d1bd2db..09c5e5b 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -243,7 +243,7 @@
                             nDr = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
                         }
                         Utilities.scaleRectAboutCenter(bounds,
-                                li.getNormalizer().getScale(nDr, null));
+                                li.getNormalizer().getScale(nDr, null, null, null));
                     }
                     AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr;
 
diff --git a/src/com/android/launcher3/graphics/IconShape.java b/src/com/android/launcher3/graphics/IconShape.java
index 88e4452..4369385 100644
--- a/src/com/android/launcher3/graphics/IconShape.java
+++ b/src/com/android/launcher3/graphics/IconShape.java
@@ -91,6 +91,10 @@
 
     private SparseArray<TypedValue> mAttrs;
 
+    public boolean enableShapeDetection(){
+        return false;
+    };
+
     public abstract void drawShape(Canvas canvas, float offsetX, float offsetY, float radius,
             Paint paint);
 
@@ -194,6 +198,11 @@
         protected float getStartRadius(Rect startRect) {
             return startRect.width() / 2f;
         }
+
+        @Override
+        public boolean enableShapeDetection() {
+            return true;
+        }
     }
 
     public static class RoundedSquare extends SimpleRectShape {
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 5c4af1f..3b74307 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -30,6 +30,7 @@
 import com.android.launcher3.ItemInfoWithIcon;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
+import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.util.Themes;
@@ -50,11 +51,15 @@
     private static LauncherIcons sPool;
     private static int sPoolId = 0;
 
+    public static LauncherIcons obtain(Context context) {
+        return obtain(context, IconShape.getShape().enableShapeDetection());
+    }
+
     /**
      * Return a new Message instance from the global pool. Allows us to
      * avoid allocating new objects in many cases.
      */
-    public static LauncherIcons obtain(Context context) {
+    public static LauncherIcons obtain(Context context, boolean shapeDetection) {
         int poolId;
         synchronized (sPoolSync) {
             if (sPool != null) {
@@ -67,7 +72,8 @@
         }
 
         InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
-        return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId);
+        return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId,
+                shapeDetection);
     }
 
     public static void clearPool() {
@@ -81,8 +87,9 @@
 
     private LauncherIcons next;
 
-    private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
-        super(context, fillResIconDpi, iconBitmapSize);
+    private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId,
+            boolean shapeDetection) {
+        super(context, fillResIconDpi, iconBitmapSize, shapeDetection);
         mPoolId = poolId;
     }
 
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 07ddccb..310d598 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -99,7 +99,6 @@
                 handleLongPress = mTempRect.contains((int) ev.getX(), (int) ev.getY());
             }
 
-            cancelLongPress();
             if (handleLongPress) {
                 mLongPressState = STATE_REQUESTED;
                 mTouchDownPoint.set(ev.getX(), ev.getY());
@@ -148,6 +147,10 @@
             }
         }
 
+        if (action == ACTION_UP || action == ACTION_CANCEL) {
+            cancelLongPress();
+        }
+
         return result;
     }
 
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index e4591b6..95c9681 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -529,7 +529,8 @@
         bounds.inset(mBlurSizeOutline / 2, mBlurSizeOutline / 2);
 
         try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
-            Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(drawable, null));
+            Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(drawable, null,
+                    null, null));
         }
 
         bounds.inset(