Setup SearchResultIcon for single cell results

SearchResultIcon will be able to render apps, shortcuts and remote actions. It can also handle its own focused state drawing.

Screenshot: https://screenshot.googleplex.com/C3KgjJtLQTBPgaf

Bug: 170752716
Test: Manual
Change-Id: I460a9c128ea3f5814784e342c5d5fa5b7e310882
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 817d028..6245637 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -17,6 +17,7 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.FastBitmapDrawable.newIcon;
+import static com.android.launcher3.graphics.IconShape.getShape;
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 
@@ -27,15 +28,18 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
+import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Path;
 import android.graphics.PointF;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Process;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
 import android.util.Property;
@@ -50,6 +54,8 @@
 
 import com.android.launcher3.Launcher.OnResumeCallback;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.allapps.AllAppsSectionDecorator;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dot.DotInfo;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.folder.FolderIcon;
@@ -60,6 +66,7 @@
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.IconCache.IconLoadRequest;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -79,7 +86,7 @@
  * too aggressive.
  */
 public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback,
-        IconLabelDotView, DraggableView, Reorderable {
+        IconLabelDotView, DraggableView, Reorderable, AllAppsSectionDecorator.SelfDecoratingView {
 
     private static final int DISPLAY_WORKSPACE = 0;
     private static final int DISPLAY_ALL_APPS = 1;
@@ -87,6 +94,8 @@
     private static final int DISPLAY_HERO_APP = 5;
 
     private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed};
+    private static final float HIGHLIGHT_SCALE = 1.16f;
+
 
     private final PointF mTranslationForReorderBounce = new PointF(0, 0);
     private final PointF mTranslationForReorderPreview = new PointF(0, 0);
@@ -95,6 +104,11 @@
 
     private float mScaleForReorderBounce = 1f;
 
+    protected final Paint mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private final Path mHighlightPath = new Path();
+    protected int mHighlightColor = Color.TRANSPARENT;
+    private final BlurMaskFilter mHighlightShadowFilter;
+
     private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
             = new Property<BubbleTextView, Float>(Float.TYPE, "dotScale") {
         @Override
@@ -208,6 +222,11 @@
         setEllipsize(TruncateAt.END);
         setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
         setTextAlpha(1f);
+
+        int shadowSize = context.getResources().getDimensionPixelSize(
+                R.dimen.blur_size_click_shadow);
+        mHighlightShadowFilter = new BlurMaskFilter(shadowSize, BlurMaskFilter.Blur.INNER);
+
     }
 
     @Override
@@ -421,8 +440,38 @@
 
     @Override
     public void onDraw(Canvas canvas) {
+        if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mHighlightColor != Color.TRANSPARENT) {
+            int count = canvas.save();
+            drawFocusHighlight(canvas);
+            canvas.restoreToCount(count);
+        }
         super.onDraw(canvas);
-        drawDotIfNecessary(canvas);
+    }
+
+    protected void drawFocusHighlight(Canvas canvas) {
+        boolean isBadged = getTag() instanceof ItemInfo && !Process.myUserHandle().equals(
+                ((ItemInfo) getTag()).user);
+        float insetScale = (HIGHLIGHT_SCALE - 1) / 2;
+        canvas.translate(-getIconSize() * insetScale, -insetScale * getIconSize());
+        float outlineSize = getIconSize() * HIGHLIGHT_SCALE;
+        mHighlightPath.reset();
+        mHighlightPaint.reset();
+        getIconBounds(mDotParams.iconBounds);
+        getShape().addToPath(mHighlightPath, mDotParams.iconBounds.left, mDotParams.iconBounds.top,
+                outlineSize / 2);
+        if (isBadged) {
+            float borderSize = outlineSize - getIconSize();
+            float badgeSize = LauncherIcons.getBadgeSizeForIconSize(getIconSize()) + borderSize;
+            float badgeInset = outlineSize - badgeSize;
+            getShape().addToPath(mHighlightPath, mDotParams.iconBounds.left + badgeInset,
+                    mDotParams.iconBounds.top + badgeInset, badgeSize / 2);
+        }
+        mHighlightPaint.setMaskFilter(mHighlightShadowFilter);
+        mHighlightPaint.setColor(mDotParams.color);
+        canvas.drawPath(mHighlightPath, mHighlightPaint);
+        mHighlightPaint.setMaskFilter(null);
+        mHighlightPaint.setColor(mHighlightColor);
+        canvas.drawPath(mHighlightPath, mHighlightPaint);
     }
 
     /**
@@ -787,10 +836,11 @@
 
     @Override
     public SafeCloseable prepareDrawDragView() {
+        int highlightColor = mHighlightColor;
+        mHighlightColor = Color.TRANSPARENT;
         resetIconScale();
         setForceHideDot(true);
-        return () -> {
-        };
+        return () -> mHighlightColor = highlightColor;
     }
 
     private void resetIconScale() {
@@ -827,4 +877,17 @@
         });
         iconUpdateAnimation.start();
     }
+
+
+    @Override
+    public void decorate(int color) {
+        mHighlightColor = color;
+        invalidate();
+    }
+
+    @Override
+    public void removeDecoration() {
+        mHighlightColor = Color.TRANSPARENT;
+        invalidate();
+    }
 }