Updating the hotseat background to a solid color with rounded corners

Change-Id: I297920518f925e122f2e9f55a68228b96b42ea27
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c6226f4..7b3da67 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.CellLayout.ContainerType;
 import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.badge.BadgeRenderer;
+import com.android.launcher3.views.AllAppsScrim;
 
 import java.util.ArrayList;
 
@@ -588,14 +589,16 @@
         searchBar.setLayoutParams(lp);
 
         // Layout the workspace
-        PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
+        PagedView workspace = launcher.getWorkspace();
         Rect workspacePadding = getWorkspacePadding(null);
         workspace.setPadding(workspacePadding.left, workspacePadding.top, workspacePadding.right,
                 workspacePadding.bottom);
         workspace.setPageSpacing(getWorkspacePageSpacing());
 
+        AllAppsScrim allAppsScrim = launcher.findViewById(R.id.all_apps_scrim);
+
         // Layout the hotseat
-        Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat);
+        Hotseat hotseat = launcher.getHotseat();
         lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
         // We want the edges of the hotseat to line up with the edges of the workspace, but the
         // icons in the hotseat are a different size, and so don't line up perfectly. To account for
@@ -604,6 +607,8 @@
         float workspaceCellWidth = (float) getCurrentWidth() / inv.numColumns;
         float hotseatCellWidth = (float) getCurrentWidth() / inv.numHotseatIcons;
         int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
+        float scrimMargin = launcher.getResources().getDimension(R.dimen.all_apps_scrim_margin);
+
         if (hasVerticalBarLayout) {
             // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
             //                     screen regardless of RTL
@@ -629,6 +634,8 @@
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
             lp.height = hotseatBarSizePx + mInsets.bottom;
+            allAppsScrim.setDrawRegion(lp.height + scrimMargin);
+
             hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
                             + cellLayoutPaddingLeftRightPx,
                     hotseatBarTopPaddingPx,
@@ -640,6 +647,8 @@
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
             lp.height = hotseatBarSizePx + mInsets.bottom;
+            allAppsScrim.setDrawRegion(lp.height + scrimMargin);
+
             hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
                             + cellLayoutPaddingLeftRightPx,
                     hotseatBarTopPaddingPx,
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 8a20bb9..80818f2 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.Partner.TAG;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
 
 import android.animation.Animator;
@@ -26,7 +25,6 @@
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.util.Log;
 import android.util.Property;
 import android.view.View;
 
@@ -165,7 +163,6 @@
     public static class PropertySetter {
 
         public void setViewAlpha(Animator anim, View view, float alpha) {
-            Log.d(TAG, "setViewAlpha: " + anim + " " + alpha);
             if (anim != null) {
                 anim.end();
                 return;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 5de58b4..5830f74 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -24,6 +24,7 @@
 import com.android.launcher3.graphics.GradientView;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.AllAppsScrim;
 
 /**
  * Handles AllApps view transition.
@@ -74,7 +75,7 @@
 
     private static final float DEFAULT_SHIFT_RANGE = 10;
 
-    private GradientView mGradientView;
+    private AllAppsScrim mAllAppsScrim;
 
     public AllAppsTransitionController(Launcher l) {
         mLauncher = l;
@@ -106,14 +107,6 @@
         }
     }
 
-    private void updateAllAppsBg(float progress) {
-        // gradient
-        if (mGradientView == null) {
-            mGradientView = mLauncher.findViewById(R.id.gradient_bg);
-        }
-        mGradientView.setProgress(progress);
-    }
-
     /**
      * Note this method should not be called outside this class. This is public because it is used
      * in xml-based animations which also handle updating the appropriate UI.
@@ -131,17 +124,21 @@
         float alpha = 1 - workspaceHotseatAlpha;
         float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
 
-        updateAllAppsBg(alpha);
         mAppsView.setAlpha(alpha);
         mAppsView.setTranslationY(shiftCurrent);
 
+        if (mAllAppsScrim == null) {
+            mAllAppsScrim = mLauncher.findViewById(R.id.all_apps_scrim);
+        }
+        float hotseatTranslation = -mShiftRange + shiftCurrent;
+        mAllAppsScrim.setProgress(hotseatTranslation, alpha);
+
         if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, -mShiftRange + shiftCurrent,
+            mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, hotseatTranslation,
                     hotseatAlpha);
         } else {
             mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y,
-                    PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent),
-                    hotseatAlpha);
+                    PARALLAX_COEFFICIENT * hotseatTranslation, hotseatAlpha);
         }
 
         updateLightStatusBar(shiftCurrent);
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
new file mode 100644
index 0000000..6df1ecb
--- /dev/null
+++ b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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 android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * Utility class which draws a bitmap by dissecting it into 3 segments and stretching
+ * the middle segment.
+ */
+public class NinePatchDrawHelper {
+
+    // The extra width used for the bitmap. This portion of the bitmap is stretched to match the
+    // width of the draw region. Randomly chosen, any value > 4 will be sufficient.
+    public static final int EXTENSION_PX = 20;
+
+    private final Rect mSrc = new Rect();
+    private final RectF mDst = new RectF();
+    public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    public void draw(Bitmap bitmap, Canvas canvas, float left, float top, float right) {
+        int width = bitmap.getWidth();
+        int height = bitmap.getHeight();
+
+        mSrc.top = 0;
+        mSrc.bottom = height;
+
+        mDst.top = top;
+        mDst.bottom = top + height;
+
+        int halfWidth = width / 2;
+
+        // Draw left edge
+        drawRegion(bitmap, canvas, 0, halfWidth, left, left + halfWidth);
+
+        // Draw right edge
+        drawRegion(bitmap, canvas, halfWidth, width, right - halfWidth, right);
+
+        // Draw middle stretched region
+        int halfExt = EXTENSION_PX / 4;
+        drawRegion(bitmap, canvas, halfWidth - halfExt, halfWidth + halfExt,
+                left + halfWidth, right - halfWidth);
+    }
+
+    private void drawRegion(Bitmap bitmap, Canvas c,
+            int srcLeft, int srcRight, float dstLeft, float dstRight) {
+        mSrc.left = srcLeft;
+        mSrc.right = srcRight;
+
+        mDst.left = dstLeft;
+        mDst.right = dstRight;
+        c.drawBitmap(bitmap, mSrc, mDst, paint);
+    }
+}
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 08be4c9..96f2629 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -24,6 +24,8 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.RectF;
 import android.support.v4.graphics.ColorUtils;
 
@@ -167,6 +169,18 @@
             p.setShadowLayer(shadowBlur, 0, 0,
                     ColorUtils.setAlphaComponent(Color.BLACK, ambientShadowAlpha));
             c.drawRoundRect(bounds, radius, radius, p);
+
+            if (Color.alpha(color) < 255) {
+                // Clear any content inside the pill-rect for translucent fill.
+                p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+                p.clearShadowLayer();
+                p.setColor(Color.BLACK);
+                c.drawRoundRect(bounds, radius, radius, p);
+
+                p.setXfermode(null);
+                p.setColor(color);
+                c.drawRoundRect(bounds, radius, radius, p);
+            }
         }
     }
 }
diff --git a/src/com/android/launcher3/views/AllAppsScrim.java b/src/com/android/launcher3/views/AllAppsScrim.java
new file mode 100644
index 0000000..1ada251
--- /dev/null
+++ b/src/com/android/launcher3/views/AllAppsScrim.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 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.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.v4.graphics.ColorUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
+import com.android.launcher3.graphics.NinePatchDrawHelper;
+import com.android.launcher3.graphics.ShadowGenerator;
+import com.android.launcher3.util.Themes;
+
+import static com.android.launcher3.graphics.NinePatchDrawHelper.EXTENSION_PX;
+
+public class AllAppsScrim extends View implements WallpaperColorInfo.OnChangeListener {
+
+    private static final int MAX_ALPHA = 235;
+    private static final int MIN_ALPHA_PORTRAIT = 100;
+    private static final int MIN_ALPHA_LANDSCAPE = MAX_ALPHA;
+
+    private final WallpaperColorInfo mWallpaperColorInfo;
+    private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    private final float mRadius;
+    private final int mMinAlpha;
+    private final int mAlphaRange;
+    private final int mScrimColor;
+
+    private final float mShadowBlur;
+    private final Bitmap mShadowBitmap;
+
+    private final NinePatchDrawHelper mShadowHelper = new NinePatchDrawHelper();
+
+    private int mFillAlpha;
+
+    private float mDrawHeight;
+    private float mTranslateY;
+
+    public AllAppsScrim(Context context) {
+        this(context, null);
+    }
+
+    public AllAppsScrim(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsScrim(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        mWallpaperColorInfo = WallpaperColorInfo.getInstance(context);
+        mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
+        mRadius = getResources().getDimension(R.dimen.all_apps_scrim_radius);
+        mShadowBlur = getResources().getDimension(R.dimen.all_apps_scrim_blur);
+
+        Launcher launcher = Launcher.getLauncher(context);
+        mFillAlpha = mMinAlpha = launcher.getDeviceProfile().isVerticalBarLayout()
+                ? MIN_ALPHA_LANDSCAPE : MIN_ALPHA_PORTRAIT;
+        mAlphaRange = MAX_ALPHA - mMinAlpha;
+        mShadowBitmap = generateShadowBitmap();
+
+        updateColors(mWallpaperColorInfo);
+    }
+
+    private Bitmap generateShadowBitmap() {
+        float curveBot = mRadius + mShadowBlur;
+
+        ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
+        builder.radius = mRadius;
+        builder.shadowBlur = mShadowBlur;
+
+        // Create the bitmap such that only the top half is drawn in the bitmap.
+        int bitmapHeight = Math.round(curveBot);
+        int bitmapWidth = bitmapHeight + EXTENSION_PX;
+        Bitmap result = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+
+        builder.bounds.set(0, mShadowBlur, bitmapWidth, 2 * curveBot + EXTENSION_PX);
+        builder.drawShadow(new Canvas(result));
+        return result;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mWallpaperColorInfo.addOnChangeListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mWallpaperColorInfo.removeOnChangeListener(this);
+    }
+
+    @Override
+    public void onExtractedColorsChanged(WallpaperColorInfo info) {
+        updateColors(info);
+        invalidate();
+    }
+
+    private void updateColors(WallpaperColorInfo info) {
+        mFillPaint.setColor(ColorUtils.compositeColors(mScrimColor,
+                ColorUtils.compositeColors(mScrimColor, info.getMainColor())));
+        mFillPaint.setAlpha(mFillAlpha);
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        float edgeTop = getHeight() + mTranslateY - mDrawHeight;
+
+        mShadowHelper.draw(mShadowBitmap, canvas, 0, edgeTop - mShadowBlur, getWidth());
+        canvas.drawRoundRect(0, edgeTop, getWidth(),
+                getHeight() + mRadius, mRadius, mRadius, mFillPaint);
+    }
+
+    public void setProgress(float translateY, float alpha) {
+        mFillAlpha = Math.round(alpha * mAlphaRange + mMinAlpha);
+        mFillPaint.setAlpha(mFillAlpha);
+
+        mTranslateY = translateY;
+
+        invalidate();
+    }
+
+    public void setDrawRegion(float height) {
+        mDrawHeight = height;
+    }
+}