All Apps transition with gradient and scrim.

The transition is behind a feature flag and
turned off by default.

Change-Id: I155840ba82b5a573d874376797db5f739a52d706
diff --git a/res/drawable-xxhdpi/all_apps_alpha_mask.png b/res/drawable-xxhdpi/all_apps_alpha_mask.png
new file mode 100644
index 0000000..ed53ff9
--- /dev/null
+++ b/res/drawable-xxhdpi/all_apps_alpha_mask.png
Binary files differ
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 6c1b1d3..565728c 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -32,6 +32,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
+        <include layout="@layout/gradient_scrim" />
+
         <!-- The workspace contains 5 screens of cells -->
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 1fdf546..eccb824 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -33,6 +33,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
+        <include layout="@layout/gradient_scrim" />
+
         <!-- The workspace contains 5 screens of cells -->
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 9ef3394..7fad517 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -32,6 +32,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
+        <include layout="@layout/gradient_scrim" />
+
         <!-- The workspace contains 5 screens of cells -->
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
diff --git a/res/layout/gradient_scrim.xml b/res/layout/gradient_scrim.xml
new file mode 100644
index 0000000..02c39eb
--- /dev/null
+++ b/res/layout/gradient_scrim.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+    <com.android.launcher3.graphics.RadialGradientView
+        android:id="@+id/gradient_bg"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        app:layout_ignoreInsets="true"/>
+
+    <com.android.launcher3.graphics.ScrimView
+        android:id="@+id/scrim_bg"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        app:layout_ignoreInsets="true"/>
+</merge>
\ No newline at end of file
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 128d956..ab82c98 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -72,7 +72,9 @@
         mBackgroundColor = ColorUtils.setAlphaComponent(
                 Themes.getAttrColor(context, android.R.attr.colorPrimary), 0);
         mBackground = new ColorDrawable(mBackgroundColor);
-        setBackground(mBackground);
+        if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+            setBackground(mBackground);
+        }
     }
 
     public CellLayout getLayout() {
@@ -179,6 +181,10 @@
     }
 
     public void updateColor(ExtractedColors extractedColors, boolean animate) {
+        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+            // not hotseat visible
+            return;
+        }
         if (!mHasVerticalHotseat) {
             int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX);
             if (mBackgroundColorAnimator != null) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 90dc2ef..756a853 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -466,7 +466,9 @@
     @Override
     public void onExtractedColorsChanged() {
         loadExtractedColorsAndColorItems();
-
+        if (mAllAppsController != null) {
+            mAllAppsController.onExtractedColorsChanged();
+        }
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onExtractedColorsChanged();
         }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 776ec2f..54e7dd2 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -28,6 +28,7 @@
 import android.content.pm.ResolveInfo;
 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;
@@ -645,4 +646,28 @@
         hashSet.add(elem);
         return hashSet;
     }
+
+    /**
+     * @return creates a new alpha mask bitmap out of an existing bitmap
+     */
+    public static Bitmap convertToAlphaMask(Bitmap b, float applyAlpha) {
+        Bitmap a = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ALPHA_8);
+        Canvas c = new Canvas(a);
+        Paint paint = new Paint();
+        paint.setAlpha((int) (255f * applyAlpha));
+        c.drawBitmap(b, 0f, 0f, paint);
+        return a;
+    }
+
+    /**
+     * @return a new white 1x1 bitmap with ALPHA_8
+     */
+    public static Bitmap createOnePixBitmap() {
+        Bitmap a = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+        Canvas c = new Canvas(a);
+        Paint paint = new Paint();
+        paint.setColor(Color.WHITE);
+        c.drawPaint(paint);
+        return a;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index af67631..7be8e8f 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -492,7 +492,8 @@
             ViewGroup.LayoutParams navBarBgLp = navBarBg.getLayoutParams();
             navBarBgLp.height = insets.bottom;
             navBarBg.setLayoutParams(navBarBgLp);
-            navBarBg.setVisibility(View.VISIBLE);
+            navBarBg.setVisibility(FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS
+                    ? View.INVISIBLE : View.VISIBLE);
         }
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 30ed180..121ce4c 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -22,6 +22,10 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dynamicui.ExtractedColors;
+import com.android.launcher3.graphics.RadialGradientView;
+import com.android.launcher3.graphics.ScrimView;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.util.Themes;
@@ -91,6 +95,8 @@
     // Used in discovery bounce animation to provide the transition without workspace changing.
     private boolean mIsTranslateWithoutWorkspace = false;
     private AnimatorSet mDiscoBounceAnimation;
+    private RadialGradientView mGradientView;
+    private ScrimView mScrimView;
 
     public AllAppsTransitionController(Launcher l) {
         mLauncher = l;
@@ -247,7 +253,9 @@
             if (!mLauncher.isAllAppsVisible()) {
                 mLauncher.tryAndUpdatePredictedApps();
                 mAppsView.setVisibility(View.VISIBLE);
-                mAppsView.setRevealDrawableColor(mHotseatBackgroundColor);
+                if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+                    mAppsView.setRevealDrawableColor(mHotseatBackgroundColor);
+                }
             }
         }
     }
@@ -263,6 +271,36 @@
         mLauncher.activateLightSystemBars(forceLight, true /* statusBar */, true /* navBar */);
     }
 
+    private void updateAllAppsBg(float progress) {
+        // gradient
+        if (mGradientView == null) {
+            mGradientView = (RadialGradientView) mLauncher.findViewById(R.id.gradient_bg);
+            mGradientView.setVisibility(View.VISIBLE);
+            onExtractedColorsChanged();
+        }
+        mGradientView.setProgress(progress);
+
+        // scrim
+        if (mScrimView == null) {
+            mScrimView = (ScrimView) mLauncher.findViewById(R.id.scrim_bg);
+            mScrimView.setVisibility(View.VISIBLE);
+        }
+        mScrimView.setProgress(progress);
+    }
+
+    public void onExtractedColorsChanged() {
+        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+            if (mGradientView != null) {
+                int color1 = mLauncher.getExtractedColors()
+                        .getColor(ExtractedColors.ALLAPPS_GRADIENT_MAIN_INDEX);
+                int color2 = mLauncher.getExtractedColors()
+                        .getColor(ExtractedColors.ALLAPPS_GRADIENT_SECONDARY_INDEX);
+                mGradientView.onExtractedColorsChanged(color1, color2);
+                mGradientView.requestLayout();
+            }
+        }
+    }
+
     /**
      * @param progress       value between 0 and 1, 0 shows all apps and 1 shows workspace
      */
@@ -280,7 +318,12 @@
         int bgAlpha = Color.alpha((int) mEvaluator.evaluate(alpha,
                 mHotseatBackgroundColor, mAllAppsBackgroundColor));
 
-        mAppsView.setRevealDrawableColor(ColorUtils.setAlphaComponent(color, bgAlpha));
+        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+            updateAllAppsBg(alpha);
+        } else {
+            mAppsView.setRevealDrawableColor(ColorUtils.setAlphaComponent(color, bgAlpha));
+        }
+
         mAppsView.getContentView().setAlpha(alpha);
         mAppsView.setTranslationY(shiftCurrent);
 
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
index 9379a72..f6b02aa 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionService.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
@@ -63,8 +63,11 @@
             // We can't extract colors from live wallpapers, so just use the default color always.
             extractedColors.updateHotseatPalette(null);
 
-            if (FeatureFlags.QSB_IN_HOTSEAT) {
+            if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
                 extractedColors.updateWallpaperThemePalette(null);
+                if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+                    extractedColors.updateAllAppsGradientPalette(null);
+                }
             }
         } else {
             // We extract colors for the hotseat and status bar separately,
@@ -75,8 +78,12 @@
                 extractedColors.updateStatusBarPalette(getStatusBarPalette());
             }
 
-            if (FeatureFlags.QSB_IN_HOTSEAT) {
-                extractedColors.updateWallpaperThemePalette(getWallpaperPalette());
+            if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+                Palette wallpaperPalette = getWallpaperPalette();
+                extractedColors.updateWallpaperThemePalette(wallpaperPalette);
+                if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+                    extractedColors.updateAllAppsGradientPalette(wallpaperPalette);
+                }
             }
         }
 
diff --git a/src/com/android/launcher3/dynamicui/ExtractedColors.java b/src/com/android/launcher3/dynamicui/ExtractedColors.java
index 2e52a0b..3c4aba1 100644
--- a/src/com/android/launcher3/dynamicui/ExtractedColors.java
+++ b/src/com/android/launcher3/dynamicui/ExtractedColors.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.graphics.Color;
+import android.support.annotation.Nullable;
 import android.support.v4.graphics.ColorUtils;
 import android.support.v7.graphics.Palette;
 import android.util.Log;
@@ -42,12 +43,24 @@
     public static final int HOTSEAT_INDEX = 1;
     public static final int STATUS_BAR_INDEX = 2;
     public static final int WALLPAPER_VIBRANT_INDEX = 3;
+    public static final int ALLAPPS_GRADIENT_MAIN_INDEX = 4;
+    public static final int ALLAPPS_GRADIENT_SECONDARY_INDEX = 5;
 
     private static final int VERSION;
     private static final int[] DEFAULT_VALUES;
 
     static {
-        if (FeatureFlags.QSB_IN_HOTSEAT) {
+        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+            VERSION = 3;
+            DEFAULT_VALUES = new int[] {
+                    VERSION,            // VERSION_INDEX
+                    0x40FFFFFF,         // HOTSEAT_INDEX: White with 25% alpha
+                    DEFAULT_DARK,       // STATUS_BAR_INDEX
+                    0xFFCCCCCC,         // WALLPAPER_VIBRANT_INDEX
+                    0xFF000000,         // ALLAPPS_GRADIENT_MAIN_INDEX
+                    0xFF000000          // ALLAPPS_GRADIENT_SECONDARY_INDEX
+            };
+        } else if (FeatureFlags.QSB_IN_HOTSEAT) {
             VERSION = 2;
             DEFAULT_VALUES = new int[] {
                     VERSION,            // VERSION_INDEX
@@ -142,9 +155,20 @@
                 DEFAULT_LIGHT : DEFAULT_DARK);
     }
 
-    public void updateWallpaperThemePalette(Palette wallpaperPalette) {
+    public void updateWallpaperThemePalette(@Nullable Palette wallpaperPalette) {
         int defaultColor = DEFAULT_VALUES[WALLPAPER_VIBRANT_INDEX];
         setColorAtIndex(WALLPAPER_VIBRANT_INDEX, wallpaperPalette == null
                 ? defaultColor : wallpaperPalette.getVibrantColor(defaultColor));
     }
+
+    public void updateAllAppsGradientPalette(@Nullable Palette wallpaperPalette) {
+        // TODO b/37089857 will be modified to take the system extracted colors into account
+        int idx;
+        idx = ALLAPPS_GRADIENT_MAIN_INDEX;
+        setColorAtIndex(idx, wallpaperPalette == null
+                ? DEFAULT_VALUES[idx] : wallpaperPalette.getDarkVibrantColor(DEFAULT_VALUES[idx]));
+        idx = ALLAPPS_GRADIENT_SECONDARY_INDEX;
+        setColorAtIndex(idx, wallpaperPalette == null
+                ? DEFAULT_VALUES[idx] : wallpaperPalette.getVibrantColor(DEFAULT_VALUES[idx]));
+    }
 }
diff --git a/src/com/android/launcher3/graphics/RadialGradientView.java b/src/com/android/launcher3/graphics/RadialGradientView.java
new file mode 100644
index 0000000..cf6851c
--- /dev/null
+++ b/src/com/android/launcher3/graphics/RadialGradientView.java
@@ -0,0 +1,146 @@
+/*
+ * 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.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+/**
+ * Draws a translucent radial gradient background from an initial state with progress 0.0 to a
+ * final state with progress 1.0;
+ */
+public class RadialGradientView extends View {
+
+    public static final int DEFAULT_COLOR_1 = Color.WHITE;
+    public static final int DEFAULT_COLOR_2 = Color.BLACK;
+
+    private static Bitmap sFinalGradientMask;
+    private static Bitmap sAlphaGradientMask;
+
+    // TODO needs to be cleaned up once design finalizes
+    static class Config {
+        // dimens
+        final float gradientCenterX = 0.5f;
+        final float gradientCenterY = 1.05f;
+        final float gradientHeadStartFactor = 0.35f;
+        final float gradientAlphaMaskLengthDp = 700;
+        // interpolation
+        final boolean useGradientAlphaDecel = false;
+        final float decelFactorForGradientAlpha = 2f;
+        // colors
+        final float finalGradientAlpha = 0.75f;
+        int color1 = DEFAULT_COLOR_1;
+        int color2 = DEFAULT_COLOR_2;
+    }
+
+    private final RectF mAlphaMaskRect = new RectF();
+    private final RectF mFinalMaskRect = new RectF();
+    private final Paint mPaint = new Paint();
+    private final Config mConfig = new Config();
+    private final DecelerateInterpolator mDecelInterpolator;
+    private float mProgress;
+    private int mWidth;
+    private int mHeight;
+    private final int mMaskHeight;
+    private final Context mAppContext;
+
+    public RadialGradientView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        this.mAppContext = context.getApplicationContext();
+        this.mDecelInterpolator = new DecelerateInterpolator(mConfig.decelFactorForGradientAlpha);
+        this.mMaskHeight = Utilities.pxFromDp(mConfig.gradientAlphaMaskLengthDp,
+                mAppContext.getResources().getDisplayMetrics());
+
+        if (sFinalGradientMask == null) {
+            sFinalGradientMask = Utilities.convertToAlphaMask(
+                    Utilities.createOnePixBitmap(), mConfig.finalGradientAlpha);
+        }
+        if (sAlphaGradientMask == null) {
+            Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(context.getResources(),
+                    R.drawable.all_apps_alpha_mask);
+            sAlphaGradientMask = Utilities.convertToAlphaMask(
+                    alphaMaskFromResource, mConfig.finalGradientAlpha);
+        }
+    }
+
+    public void onExtractedColorsChanged(int color1, int color2) {
+        mConfig.color1 = color1;
+        mConfig.color2 = color2;
+        if (mWidth + mHeight > 0) {
+            createRadialShader();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        this.mWidth = getMeasuredWidth();
+        this.mHeight = getMeasuredHeight();
+        if (mWidth + mHeight > 0) {
+            createRadialShader();
+        }
+    }
+
+    // only being called when colors change
+    private void createRadialShader() {
+        float radius = Math.max(mHeight, mWidth) * mConfig.gradientCenterY;
+
+        float posScreenBottom = (radius - mHeight) / radius; // center lives below screen
+        RadialGradient shader = new RadialGradient(
+                mWidth * mConfig.gradientCenterX,
+                mHeight * mConfig.gradientCenterY,
+                radius,
+                new int[] {mConfig.color1, mConfig.color1, mConfig.color2},
+                new float[] {0f, posScreenBottom, 1f},
+                Shader.TileMode.CLAMP);
+        mPaint.setShader(shader);
+    }
+
+    public void setProgress(float progress) {
+        this.mProgress = progress;
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        float head = mConfig.gradientHeadStartFactor;
+        float linearProgress = head + (mProgress * (1f - head));
+        float adjustProgress = mConfig.useGradientAlphaDecel
+                ? mDecelInterpolator.getInterpolation(linearProgress)
+                : linearProgress;
+        float startMaskY = (1f - adjustProgress) * mHeight - mMaskHeight * adjustProgress;
+
+        mAlphaMaskRect.set(0, startMaskY, mWidth, startMaskY + mMaskHeight);
+        mFinalMaskRect.set(0, startMaskY + mMaskHeight, mWidth, mHeight);
+        canvas.drawBitmap(sAlphaGradientMask, null, mAlphaMaskRect, mPaint);
+        canvas.drawBitmap(sFinalGradientMask, null, mFinalMaskRect, mPaint);
+    }
+
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/graphics/ScrimView.java b/src/com/android/launcher3/graphics/ScrimView.java
new file mode 100644
index 0000000..521fbed
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ScrimView.java
@@ -0,0 +1,97 @@
+/*
+ * 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.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.support.v4.graphics.ColorUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+public class ScrimView extends View {
+
+    // Config
+    private static final int MASK_HEIGHT_DP = 600;
+    private static final float MASK_START_LENGTH_FACTOR = 0.4f;
+    private static final float FINAL_ALPHA = 0.87f;
+    private static final int SCRIM_COLOR = ColorUtils.setAlphaComponent(
+            Color.WHITE, (int) (FINAL_ALPHA * 255));
+
+    private static Bitmap sFinalScrimMask;
+    private static Bitmap sAlphaScrimMask;
+
+    private final int mMaskHeight;
+    private int mVisibleHeight;
+    private final int mHeadStart;
+
+    private final RectF mAlphaMaskRect = new RectF();
+    private final RectF mFinalMaskRect = new RectF();
+    private final Paint mPaint = new Paint();
+    private float mProgress;
+
+    public ScrimView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mMaskHeight = Utilities.pxFromDp(MASK_HEIGHT_DP, getResources().getDisplayMetrics());
+        mHeadStart = (int) (mMaskHeight * MASK_START_LENGTH_FACTOR);
+        mPaint.setColor(SCRIM_COLOR);
+
+        if (sFinalScrimMask == null) {
+            sFinalScrimMask = Utilities.convertToAlphaMask(
+                    Utilities.createOnePixBitmap(), FINAL_ALPHA);
+        }
+        if (sAlphaScrimMask == null) {
+            Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.all_apps_alpha_mask);
+            sAlphaScrimMask = Utilities.convertToAlphaMask(alphaMaskFromResource, FINAL_ALPHA);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        mVisibleHeight = MeasureSpec.getSize(heightMeasureSpec);
+        int fullHeight = mVisibleHeight * 2 + mMaskHeight;
+        setMeasuredDimension(width, fullHeight);
+        setProgress(mProgress);
+    }
+
+    public void setProgress(float progress) {
+        mProgress = progress;
+        float initialY = mVisibleHeight - mHeadStart;
+        float fullTranslationY = mMaskHeight + initialY + mVisibleHeight;
+        float translationY = initialY - progress * fullTranslationY;
+        setTranslationY(translationY);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        mAlphaMaskRect.set(0, 0, getWidth(), mMaskHeight);
+        mFinalMaskRect.set(0, mMaskHeight, getWidth(), getHeight());
+        canvas.drawBitmap(sAlphaScrimMask, null, mAlphaMaskRect, mPaint);
+        canvas.drawBitmap(sFinalScrimMask, null, mFinalMaskRect, mPaint);
+    }
+
+}
diff --git a/src_flags/com/android/launcher3/config/FeatureFlags.java b/src_flags/com/android/launcher3/config/FeatureFlags.java
index 159f125..c0184fa 100644
--- a/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -38,6 +38,8 @@
     public static boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = true;
     // When enabled the promise icon is visible in all apps while installation an app.
     public static boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = true;
+    // When enabled uses the AllAppsRadialGradientAndScrimDrawable for all apps
+    public static boolean LAUNCHER3_GRADIENT_ALL_APPS = false;
 
     // Feature flag to enable moving the QSB on the 0th screen of the workspace.
     public static final boolean QSB_ON_FIRST_SCREEN = true;