Removing click-feedback shadow generation logic in BubbleTextView

Instead of animating the shadow, animating the icon scale. This avoids
unnecessary bitmap creating at app-launch and also plays nice with the
app-launch transition

Change-Id: I1d3d24bc7212a6d659855ff1002a45388e269e52
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 4f50d1a..8b6d9f8 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -37,7 +36,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
-import android.view.ViewParent;
 import android.widget.TextView;
 
 import com.android.launcher3.IconCache.IconLoadRequest;
@@ -48,7 +46,6 @@
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.FolderIconPreviewVerifier;
 import com.android.launcher3.graphics.DrawableFactory;
-import com.android.launcher3.graphics.HolographicOutlineHelper;
 import com.android.launcher3.graphics.IconPalette;
 import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.model.PackageItemInfo;
@@ -73,13 +70,9 @@
     private final boolean mCenterVertically;
 
     private final CheckLongPressHelper mLongPressHelper;
-    private final HolographicOutlineHelper mOutlineHelper;
     private final StylusEventHelper mStylusEventHelper;
     private final float mSlop;
 
-    private Bitmap mPressedBackground;
-
-    private final boolean mDeferShadowGenerationOnTouch;
     private final boolean mLayoutHorizontal;
     private final int mIconSize;
     @ViewDebug.ExportedProperty(category = "launcher")
@@ -147,8 +140,6 @@
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.BubbleTextView, defStyle, 0);
         mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
-        mDeferShadowGenerationOnTouch =
-                a.getBoolean(R.styleable.BubbleTextView_deferShadowGeneration, false);
 
         int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
         int defaultIconSize = grid.iconSizePx;
@@ -173,7 +164,6 @@
         mLongPressHelper = new CheckLongPressHelper(this);
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
 
-        mOutlineHelper = HolographicOutlineHelper.getInstance(getContext());
         setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
 
     }
@@ -290,13 +280,6 @@
 
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
-                // So that the pressed outline is visible immediately on setStayPressed(),
-                // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
-                // to create it)
-                if (!mDeferShadowGenerationOnTouch && mPressedBackground == null) {
-                    mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
-                }
-
                 // If we're in a stylus button press, don't check for long press.
                 if (!mStylusEventHelper.inStylusButtonPressed()) {
                     mLongPressHelper.postCheckForLongPress();
@@ -304,12 +287,6 @@
                 break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                // If we've touched down and up on an item, and it's still not "pressed", then
-                // destroy the pressed outline
-                if (!isPressed()) {
-                    mPressedBackground = null;
-                }
-
                 mLongPressHelper.cancelLongPress();
                 break;
             case MotionEvent.ACTION_MOVE:
@@ -323,22 +300,6 @@
 
     void setStayPressed(boolean stayPressed) {
         mStayPressed = stayPressed;
-        if (!stayPressed) {
-            HolographicOutlineHelper.getInstance(getContext()).recycleShadowBitmap(mPressedBackground);
-            mPressedBackground = null;
-        } else {
-            if (mPressedBackground == null) {
-                mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
-            }
-        }
-
-        // Only show the shadow effect when persistent pressed state is set.
-        ViewParent parent = getParent();
-        if (parent != null && parent.getParent() instanceof BubbleTextShadowHandler) {
-            ((BubbleTextShadowHandler) parent.getParent()).setPressedIcon(
-                    this, mPressedBackground);
-        }
-
         refreshDrawableState();
     }
 
@@ -355,26 +316,12 @@
     }
 
     @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (super.onKeyDown(keyCode, event)) {
-            // Pre-create shadow so show immediately on click.
-            if (mPressedBackground == null) {
-                mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         // Unlike touch events, keypress event propagate pressed state change immediately,
         // without waiting for onClickHandler to execute. Disable pressed state changes here
         // to avoid flickering.
         mIgnorePressedStateChange = true;
         boolean result = super.onKeyUp(keyCode, event);
-
-        mPressedBackground = null;
         mIgnorePressedStateChange = false;
         refreshDrawableState();
         return result;
@@ -662,11 +609,4 @@
     public int getIconSize() {
         return mIconSize;
     }
-
-    /**
-     * Interface to be implemented by the grand parent to allow click shadow effect.
-     */
-    public interface BubbleTextShadowHandler {
-        void setPressedIcon(BubbleTextView icon, Bitmap background);
-    }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 5e4f670..734aec3 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -21,6 +21,7 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -45,7 +46,6 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
 import com.android.launcher3.accessibility.FolderAccessibilityHelper;
@@ -70,7 +70,7 @@
 import java.util.Comparator;
 import java.util.Stack;
 
-public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
+public class CellLayout extends ViewGroup {
     public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
     public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
 
@@ -128,8 +128,6 @@
     private int mDragOutlineCurrent = 0;
     private final Paint mDragOutlinePaint = new Paint();
 
-    private final ClickShadowView mTouchFeedbackView;
-
     @Thunk final ArrayMap<LayoutParams, Animator> mReorderAnimators = new ArrayMap<>();
     @Thunk final ArrayMap<View, ReorderPreviewAnimation> mShakeAnimators = new ArrayMap<>();
 
@@ -285,9 +283,6 @@
         mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mCountX, mCountY);
 
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
-
-        mTouchFeedbackView = new ClickShadowView(context);
-        addView(mTouchFeedbackView);
         addView(mShortcutsAndWidgets);
     }
 
@@ -384,11 +379,6 @@
         return mDropPending;
     }
 
-    @Override
-    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
-        mTouchFeedbackView.setPressedIcon(icon, background);
-    }
-
     void setIsDragOverlapping(boolean isDragOverlapping) {
         if (mIsDragOverlapping != isDragOverlapping) {
             mIsDragOverlapping = isDragOverlapping;
@@ -785,13 +775,6 @@
             throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
         }
 
-        // Make the feedback view large enough to hold the blur bitmap.
-        mTouchFeedbackView.measure(
-                MeasureSpec.makeMeasureSpec(mCellWidth + mTouchFeedbackView.getExtraSize(),
-                        MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(mCellHeight + mTouchFeedbackView.getExtraSize(),
-                        MeasureSpec.EXACTLY));
-
         mShortcutsAndWidgets.measure(
                 MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
@@ -815,11 +798,7 @@
         int top = getPaddingTop();
         int bottom = b - t - getPaddingBottom();
 
-        mTouchFeedbackView.layout(left, top,
-                left + mTouchFeedbackView.getMeasuredWidth(),
-                top + mTouchFeedbackView.getMeasuredHeight());
         mShortcutsAndWidgets.layout(left, top, right, bottom);
-
         // Expand the background drawing bounds by the padding baked into the background drawable
         mBackground.getPadding(mTempRect);
         mBackground.setBounds(
@@ -1012,6 +991,7 @@
         }
     }
 
+    @SuppressLint("StringFormatMatches")
     public String getItemMoveDescription(int cellX, int cellY) {
         if (mContainerType == HOTSEAT) {
             return getContext().getString(R.string.move_to_hotseat_position,
diff --git a/src/com/android/launcher3/ClickShadowView.java b/src/com/android/launcher3/ClickShadowView.java
deleted file mode 100644
index 5391b4d..0000000
--- a/src/com/android/launcher3/ClickShadowView.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2014 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.launcher3;
-
-import static com.android.launcher3.FastBitmapDrawable.CLICK_FEEDBACK_DURATION;
-import static com.android.launcher3.FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR;
-import static com.android.launcher3.LauncherAnimUtils.ELEVATION;
-import static com.android.launcher3.graphics.HolographicOutlineHelper.ADAPTIVE_ICON_SHADOW_BITMAP;
-
-import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.util.Property;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-
-public class ClickShadowView extends View {
-
-    private static final int SHADOW_SIZE_FACTOR = 3;
-    private static final int SHADOW_LOW_ALPHA = 30;
-    private static final int SHADOW_HIGH_ALPHA = 60;
-
-    private static float sAdaptiveIconScaleFactor = 1f;
-
-    private final Paint mPaint;
-
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private final float mShadowOffset;
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private final float mShadowPadding;
-
-    private Bitmap mBitmap;
-    private ObjectAnimator mAnim;
-
-    private Drawable mAdaptiveIcon;
-    private ViewOutlineProvider mOutlineProvider;
-
-    public ClickShadowView(Context context) {
-        super(context);
-        mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-        mPaint.setColor(Color.BLACK);
-
-        mShadowPadding = getResources().getDimension(R.dimen.blur_size_click_shadow);
-        mShadowOffset = getResources().getDimension(R.dimen.click_shadow_high_shift);
-    }
-
-    public static void setAdaptiveIconScaleFactor(float factor) {
-        sAdaptiveIconScaleFactor = factor;
-    }
-
-    /**
-     * @return extra space required by the view to show the shadow.
-     */
-    public int getExtraSize() {
-        return (int) (SHADOW_SIZE_FACTOR * mShadowPadding);
-    }
-
-    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
-        if (icon == null) {
-            setBitmap(null);
-            cancelAnim();
-            return;
-        }
-        if (background == null) {
-            if (mBitmap == ADAPTIVE_ICON_SHADOW_BITMAP) {
-                // clear animation shadow
-            }
-            setBitmap(null);
-            cancelAnim();
-            icon.setOutlineProvider(null);
-        } else if (setBitmap(background)) {
-            if (mBitmap == ADAPTIVE_ICON_SHADOW_BITMAP) {
-                setupAdaptiveShadow(icon);
-                cancelAnim();
-                startAnim(icon, ELEVATION,
-                        getResources().getDimension(R.dimen.click_shadow_elevation));
-            } else {
-                alignWithIconView(icon);
-                startAnim(this, ALPHA, 1);
-            }
-        }
-    }
-
-    @TargetApi(Build.VERSION_CODES.O)
-    private void setupAdaptiveShadow(final BubbleTextView view) {
-        if (mAdaptiveIcon == null) {
-            mAdaptiveIcon = new AdaptiveIconDrawable(null, null);
-            mOutlineProvider = new ViewOutlineProvider() {
-                @Override
-                public void getOutline(View view, Outline outline) {
-                    mAdaptiveIcon.getOutline(outline);
-                }
-            };
-        }
-
-        int iconWidth = view.getRight() - view.getLeft();
-        int iconHSpace = iconWidth - view.getCompoundPaddingRight() - view.getCompoundPaddingLeft();
-        int drawableWidth = view.getIcon().getBounds().width();
-
-        Rect bounds = new Rect();
-        bounds.left = view.getCompoundPaddingLeft() + (iconHSpace - drawableWidth) / 2;
-        bounds.right = bounds.left + drawableWidth;
-        bounds.top = view.getPaddingTop();
-        bounds.bottom = bounds.top + view.getIcon().getBounds().height();
-        Utilities.scaleRectAboutCenter(bounds, sAdaptiveIconScaleFactor);
-
-        mAdaptiveIcon.setBounds(bounds);
-        view.setOutlineProvider(mOutlineProvider);
-    }
-
-    /**
-     * Applies the new bitmap.
-     * @return true if the view was invalidated.
-     */
-    private boolean setBitmap(Bitmap b) {
-        if (b != mBitmap){
-            mBitmap = b;
-            invalidate();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mBitmap != null) {
-            mPaint.setAlpha(SHADOW_LOW_ALPHA);
-            canvas.drawBitmap(mBitmap, 0, 0, mPaint);
-            mPaint.setAlpha(SHADOW_HIGH_ALPHA);
-            canvas.drawBitmap(mBitmap, 0, mShadowOffset, mPaint);
-        }
-    }
-
-    private void cancelAnim() {
-        if (mAnim != null) {
-            mAnim.cancel();
-            mAnim.setCurrentPlayTime(0);
-            mAnim = null;
-        }
-    }
-
-    private void startAnim(View target, Property<View, Float> property, float endValue) {
-        cancelAnim();
-        property.set(target, 0f);
-        mAnim = ObjectAnimator.ofFloat(target, property, endValue);
-        mAnim.setDuration(CLICK_FEEDBACK_DURATION)
-                .setInterpolator(CLICK_FEEDBACK_INTERPOLATOR);
-        mAnim.start();
-    }
-
-    /**
-     * Aligns the shadow with {@param view}
-     * Note: {@param view} must be a descendant of my parent.
-     */
-    private void alignWithIconView(BubbleTextView view) {
-        int[] coords = new int[] {0, 0};
-        Utilities.getDescendantCoordRelativeToAncestor(
-                (ViewGroup) view.getParent(), (View) getParent(), coords, false);
-
-        float leftShift = view.getLeft() + coords[0] - getLeft();
-        float topShift = view.getTop() + coords[1] - getTop();
-        int iconWidth = view.getRight() - view.getLeft();
-        int iconHeight = view.getBottom() - view.getTop();
-        int iconHSpace = iconWidth - view.getCompoundPaddingRight() - view.getCompoundPaddingLeft();
-        float drawableWidth = view.getIcon().getBounds().width();
-
-        // Set the bounds to clip against
-        int clipLeft = (int) Math.max(0, coords[0] - leftShift - mShadowPadding);
-        int clipTop = (int) Math.max(0, coords[1] - topShift - mShadowPadding) ;
-        setClipBounds(new Rect(clipLeft, clipTop, clipLeft + iconWidth, clipTop + iconHeight));
-
-        setTranslationX(leftShift
-                + view.getCompoundPaddingLeft() * view.getScaleX()
-                + (iconHSpace - drawableWidth) * view.getScaleX() / 2  /* drawable gap */
-                + iconWidth * (1 - view.getScaleX()) / 2  /* gap due to scale */
-                - mShadowPadding  /* extra shadow size */
-                );
-        setTranslationY(topShift
-                + view.getPaddingTop() * view.getScaleY()  /* drawable gap */
-                + view.getHeight() * (1 - view.getScaleY()) / 2  /* gap due to scale */
-                - mShadowPadding  /* extra shadow size */
-                );
-    }
-}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index c4ec8c9..5354edf 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -16,8 +16,9 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+
 import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -28,9 +29,8 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.util.Property;
 import android.util.SparseArray;
 
@@ -38,14 +38,12 @@
 
 public class FastBitmapDrawable extends Drawable {
 
-    private static final float PRESSED_BRIGHTNESS = 100f / 255f;
+    private static final float PRESSED_SCALE = 1.1f;
+
     private static final float DISABLED_DESATURATION = 1f;
     private static final float DISABLED_BRIGHTNESS = 0.5f;
 
-    public static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = (input) ->
-            (input < 0.05f) ? (input / 0.05f) : ((input < 0.3f) ? 1 : (1 - input) / 0.7f);
-
-    public static final int CLICK_FEEDBACK_DURATION = 2000;
+    public static final int CLICK_FEEDBACK_DURATION = 200;
 
     // Since we don't need 256^2 values for combinations of both the brightness and saturation, we
     // reduce the value space to a smaller value V, which reduces the number of cached
@@ -66,18 +64,23 @@
     private boolean mIsPressed;
     private boolean mIsDisabled;
 
-    private static final Property<FastBitmapDrawable, Float> BRIGHTNESS
-            = new Property<FastBitmapDrawable, Float>(Float.TYPE, "brightness") {
+    // Animator and properties for the fast bitmap drawable's scale
+    private static final Property<FastBitmapDrawable, Float> SCALE
+            = new Property<FastBitmapDrawable, Float>(Float.TYPE, "scale") {
         @Override
         public Float get(FastBitmapDrawable fastBitmapDrawable) {
-            return fastBitmapDrawable.getBrightness();
+            return fastBitmapDrawable.mScale;
         }
 
         @Override
         public void set(FastBitmapDrawable fastBitmapDrawable, Float value) {
-            fastBitmapDrawable.setBrightness(value);
+            fastBitmapDrawable.mScale = value;
+            fastBitmapDrawable.invalidateSelf();
         }
     };
+    private ObjectAnimator mScaleAnimation;
+    private float mScale = 1;
+
 
     // The saturation and brightness are values that are mapped to REDUCED_FILTER_VALUE_SPACE and
     // as a result, can be used to compose the key for the cached ColorMatrixColorFilters
@@ -86,9 +89,6 @@
     private int mAlpha = 255;
     private int mPrevUpdateKey = Integer.MAX_VALUE;
 
-    // Animators for the fast bitmap drawable's brightness
-    private ObjectAnimator mBrightnessAnimator;
-
     public FastBitmapDrawable(Bitmap b) {
         this(b, Color.TRANSPARENT);
     }
@@ -108,8 +108,20 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
+    public final void draw(Canvas canvas) {
+        if (mScaleAnimation != null) {
+            int count = canvas.save();
+            Rect bounds = getBounds();
+            canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
+            drawInternal(canvas, bounds);
+            canvas.restoreToCount(count);
+        } else {
+            drawInternal(canvas, getBounds());
+        }
+    }
+
+    protected void drawInternal(Canvas canvas, Rect bounds) {
+        canvas.drawBitmap(mBitmap, null, bounds, mPaint);
     }
 
     @Override
@@ -138,6 +150,10 @@
         return mAlpha;
     }
 
+    public float getAnimatedScale() {
+        return mScaleAnimation == null ? 1 : mScale;
+    }
+
     @Override
     public int getIntrinsicWidth() {
         return mBitmap.getWidth();
@@ -184,19 +200,20 @@
         if (mIsPressed != isPressed) {
             mIsPressed = isPressed;
 
-            if (mBrightnessAnimator != null) {
-                mBrightnessAnimator.cancel();
+            if (mScaleAnimation != null) {
+                mScaleAnimation.cancel();
+                mScaleAnimation = null;
             }
 
             if (mIsPressed) {
                 // Animate when going to pressed state
-                mBrightnessAnimator = ObjectAnimator.ofFloat(
-                        this, BRIGHTNESS, getExpectedBrightness());
-                mBrightnessAnimator.setDuration(CLICK_FEEDBACK_DURATION);
-                mBrightnessAnimator.setInterpolator(CLICK_FEEDBACK_INTERPOLATOR);
-                mBrightnessAnimator.start();
+                mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, PRESSED_SCALE);
+                mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
+                mScaleAnimation.setInterpolator(ACCEL);
+                mScaleAnimation.start();
             } else {
-                setBrightness(getExpectedBrightness());
+                mScale = 1f;
+                invalidateSelf();
             }
             return true;
         }
@@ -205,12 +222,7 @@
 
     private void invalidateDesaturationAndBrightness() {
         setDesaturation(mIsDisabled ? DISABLED_DESATURATION : 0);
-        setBrightness(getExpectedBrightness());
-    }
-
-    private float getExpectedBrightness() {
-        return mIsDisabled ? DISABLED_BRIGHTNESS :
-                (mIsPressed ? PRESSED_BRIGHTNESS : 0);
+        setBrightness(mIsDisabled ? DISABLED_BRIGHTNESS : 0);
     }
 
     public void setIsDisabled(boolean isDisabled) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 82bdef9..774ea65 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 
 import android.content.Context;
-import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.os.Process;
 import android.support.annotation.NonNull;
@@ -37,9 +36,6 @@
 import android.widget.RelativeLayout;
 
 import com.android.launcher3.AppInfo;
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
-import com.android.launcher3.ClickShadowView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
@@ -66,11 +62,10 @@
  * The all apps view container.
  */
 public class AllAppsContainerView extends RelativeLayout implements DragSource,
-        OnLongClickListener, Insettable, BubbleTextShadowHandler, OnDeviceProfileChangeListener {
+        OnLongClickListener, Insettable, OnDeviceProfileChangeListener {
 
     private final Launcher mLauncher;
     private final AdapterHolder[] mAH;
-    private final ClickShadowView mTouchFeedbackView;
     private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
     private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
     private final AllAppsStore mAllAppsStore = new AllAppsStore();
@@ -100,15 +95,8 @@
         mLauncher.addOnDeviceProfileChangeListener(this);
 
         mSearchQueryBuilder = new SpannableStringBuilder();
-
         Selection.setSelection(mSearchQueryBuilder, 0);
 
-        mTouchFeedbackView = new ClickShadowView(context);
-        // Make the feedback view large enough to hold the blur bitmap.
-        int size = mLauncher.getDeviceProfile().allAppsIconSizePx
-                + mTouchFeedbackView.getExtraSize();
-        addView(mTouchFeedbackView, size, size);
-
         mAH = new AdapterHolder[2];
         mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
         mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
@@ -165,11 +153,6 @@
         }
     }
 
-    @Override
-    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
-        mTouchFeedbackView.setPressedIcon(icon, background);
-    }
-
     /**
      * Returns whether the view itself will handle the touch event or not.
      */
diff --git a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
deleted file mode 100644
index ebfe1e7..0000000
--- a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2008 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.launcher3.graphics;
-
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_ADAPTIVE_ICON;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.SparseArray;
-
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.ItemInfoWithIcon;
-import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.UiFactory;
-
-/**
- * Utility class to generate shadow and outline effect, which are used for click feedback
- * and drag-n-drop respectively.
- */
-public class HolographicOutlineHelper {
-
-    /**
-     * Bitmap used as shadow for Adaptive icons
-     */
-    public static final Bitmap ADAPTIVE_ICON_SHADOW_BITMAP =
-            Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
-
-    private static HolographicOutlineHelper sInstance;
-
-    private final Canvas mCanvas = new Canvas();
-    private final Paint mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-    private final Paint mErasePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-
-    private final float mShadowBitmapShift;
-    private final BlurMaskFilter mShadowBlurMaskFilter;
-
-    // We have 4 different icon sizes: homescreen, hotseat, folder & all-apps
-    private final SparseArray<Bitmap> mBitmapCache = new SparseArray<>(4);
-
-    private HolographicOutlineHelper(Context context) {
-        mShadowBitmapShift = context.getResources().getDimension(R.dimen.blur_size_click_shadow);
-        mShadowBlurMaskFilter = new BlurMaskFilter(mShadowBitmapShift, BlurMaskFilter.Blur.NORMAL);
-        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
-    }
-
-    public static HolographicOutlineHelper getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new HolographicOutlineHelper(context.getApplicationContext());
-        }
-        return sInstance;
-    }
-
-    public Bitmap createMediumDropShadow(BubbleTextView view) {
-        if (view.getTag() instanceof ItemInfoWithIcon &&
-                ((((ItemInfoWithIcon) view.getTag()).runtimeStatusFlags & FLAG_ADAPTIVE_ICON)
-                        != 0)) {
-            return ADAPTIVE_ICON_SHADOW_BITMAP;
-        }
-        Drawable drawable = view.getIcon();
-        if (drawable == null) {
-            return null;
-        }
-
-        float scaleX = view.getScaleX();
-        float scaleY = view.getScaleY();
-        Rect rect = drawable.getBounds();
-
-        int bitmapWidth = (int) (rect.width() * scaleX);
-        int bitmapHeight = (int) (rect.height() * scaleY);
-        if (bitmapHeight <= 0 || bitmapWidth <= 0) {
-            return null;
-        }
-
-        int key = (bitmapWidth << 16) | bitmapHeight;
-        Bitmap cache = mBitmapCache.get(key);
-        if (cache == null) {
-            cache = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ALPHA_8);
-            mCanvas.setBitmap(cache);
-            mBitmapCache.put(key, cache);
-        } else {
-            mCanvas.setBitmap(cache);
-            mCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
-        }
-
-        int saveCount = mCanvas.save();
-        mCanvas.scale(scaleX, scaleY);
-        mCanvas.translate(-rect.left, -rect.top);
-        if (!UiFactory.USE_HARDWARE_BITMAP) {
-            // TODO: Outline generation requires alpha extraction, which is costly for
-            // hardware bitmaps. Instead use canvas layer operations once its available.
-            drawable.draw(mCanvas);
-        }
-        mCanvas.restoreToCount(saveCount);
-        mCanvas.setBitmap(null);
-
-        mBlurPaint.setMaskFilter(mShadowBlurMaskFilter);
-
-        int extraSize = (int) (2 * mShadowBitmapShift);
-
-        int resultWidth = bitmapWidth + extraSize;
-        int resultHeight = bitmapHeight + extraSize;
-        key = (resultWidth << 16) | resultHeight;
-        Bitmap result = mBitmapCache.get(key);
-        if (result == null) {
-            result = Bitmap.createBitmap(resultWidth, resultHeight, Bitmap.Config.ALPHA_8);
-            mCanvas.setBitmap(result);
-        } else {
-            // Use put instead of delete, to avoid unnecessary shrinking of cache array
-            mBitmapCache.put(key, null);
-            mCanvas.setBitmap(result);
-            mCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
-        }
-        mCanvas.drawBitmap(cache, mShadowBitmapShift, mShadowBitmapShift, mBlurPaint);
-        mCanvas.setBitmap(null);
-        return result;
-    }
-
-    public void recycleShadowBitmap(Bitmap bitmap) {
-        if (bitmap != null && bitmap != ADAPTIVE_ICON_SHADOW_BITMAP) {
-            mBitmapCache.put((bitmap.getWidth() << 16) | bitmap.getHeight(), bitmap);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index ea55ba4..bc75268 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -162,7 +162,7 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
+    public void drawInternal(Canvas canvas, Rect bounds) {
         if (mRanFinishAnimation) {
             super.draw(canvas);
             return;
@@ -172,13 +172,11 @@
         mProgressPaint.setColor(mIndicatorColor);
         mProgressPaint.setAlpha(mTrackAlpha);
         if (mShadowBitmap != null) {
-            canvas.drawBitmap(mShadowBitmap, getBounds().left, getBounds().top, mProgressPaint);
+            canvas.drawBitmap(mShadowBitmap, bounds.left, bounds.top, mProgressPaint);
         }
         canvas.drawPath(mScaledProgressPath, mProgressPaint);
 
         int saveCount = canvas.save();
-        Rect bounds = getBounds();
-
         canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY());
         super.draw(canvas);
         canvas.restoreToCount(saveCount);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index c615050..9d1ff83 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -16,6 +16,11 @@
 
 package com.android.launcher3.model;
 
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -25,7 +30,6 @@
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.PackageInstaller;
 import android.graphics.Bitmap;
-import android.graphics.drawable.AdaptiveIconDrawable;
 import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
@@ -36,7 +40,6 @@
 
 import com.android.launcher3.AllAppsList;
 import com.android.launcher3.AppInfo;
-import com.android.launcher3.ClickShadowView;
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.IconCache;
 import com.android.launcher3.InstallShortcutReceiver;
@@ -75,11 +78,6 @@
 import java.util.Map;
 import java.util.concurrent.CancellationException;
 
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
-
 /**
  * Runnable for the thread that loads the contents of the launcher:
  *   - workspace icons
@@ -146,9 +144,7 @@
 
         TraceHelper.beginSection(TAG);
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
-            TraceHelper.partitionSection(TAG, "step 1.1: loading UI resources");
-            loadUiResources();
-            TraceHelper.partitionSection(TAG, "step 1.2: loading workspace");
+            TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
             loadWorkspace();
 
             verifyNotStopped();
@@ -211,15 +207,6 @@
         this.notify();
     }
 
-    public void loadUiResources() {
-        if (Utilities.ATLEAST_OREO) {
-            LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
-            ClickShadowView.setAdaptiveIconScaleFactor(li.getNormalizer()
-                    .getScale(new AdaptiveIconDrawable(null, null), null, null, null));
-            li.recycle();
-        }
-    }
-
     private void loadWorkspace() {
         final Context context = mApp.getContext();
         final ContentResolver contentResolver = context.getContentResolver();