Merge "Added constructor to ShortcutKey." into ub-launcher3-master
diff --git a/quickstep/res/drawable/bg_workspace_card_button.xml b/quickstep/res/drawable/bg_workspace_card_button.xml
new file mode 100644
index 0000000..3ba47bb
--- /dev/null
+++ b/quickstep/res/drawable/bg_workspace_card_button.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item android:id="@android:id/mask">
+        <color android:color="#ffffffff" />
+    </item>
+
+    <item>
+        <color android:color="#77FFFFFF" />
+    </item>
+</ripple>
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 22f014a..78238fa 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -22,4 +22,36 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:alpha="0.0"
-    android:visibility="invisible" />
\ No newline at end of file
+    android:visibility="invisible" >
+
+    <com.android.launcher3.uioverrides.WorkspaceCard
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingTop="@dimen/task_thumbnail_top_margin" >
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/workspace_click_target" />
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/widget_button"
+            android:background="@drawable/bg_workspace_card_button" >
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/widget_button_text"
+                android:drawableStart="@drawable/ic_widget"
+                android:textColor="?attr/workspaceTextColor"
+                android:drawableTint="?attr/workspaceTextColor"
+                android:gravity="center"
+                android:layout_gravity="center"
+                android:drawablePadding="20dp" />
+        </FrameLayout>
+
+    </com.android.launcher3.uioverrides.WorkspaceCard>
+
+</com.android.quickstep.RecentsView>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 267c4d0..f34aa85 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -22,6 +22,7 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.quickstep.RecentsView;
@@ -31,8 +32,9 @@
  */
 public class OverviewState extends LauncherState {
 
-    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM
-            | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
+    public static final float WORKSPACE_SCALE_ON_SCROLL = 0.9f;
+
+    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
 
     public OverviewState(int id) {
         super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, 1f, STATE_FLAGS);
@@ -42,18 +44,15 @@
     public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
         Rect pageRect = new Rect();
         RecentsView.getPageRect(launcher, pageRect);
-        Workspace ws = launcher.getWorkspace();
-        float childWidth = ws.getNormalChildWidth();
-        if (childWidth <= 0 || pageRect.isEmpty()) {
+        if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) {
             return super.getWorkspaceScaleAndTranslation(launcher);
         }
 
-        Rect insets = launcher.getDragLayer().getInsets();
-        float scale = pageRect.width() / childWidth;
-
-        float halfHeight = ws.getHeight() / 2;
-        float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
-        return new float[] {scale, pageRect.top - childTop};
+        RecentsView rv = launcher.getOverviewPanel();
+        if (rv.getCurrentPage() >= rv.getFirstTaskIndex()) {
+            Utilities.scaleRectAboutCenter(pageRect, WORKSPACE_SCALE_ON_SCROLL);
+        }
+        return getScaleAndTranslationForPageRect(launcher, pageRect);
     }
 
     @Override
@@ -77,4 +76,16 @@
     public View getFinalFocus(Launcher launcher) {
         return launcher.getOverviewPanel();
     }
+
+    public static float[] getScaleAndTranslationForPageRect(Launcher launcher, Rect pageRect) {
+        Workspace ws = launcher.getWorkspace();
+        float childWidth = ws.getNormalChildWidth();
+
+        Rect insets = launcher.getDragLayer().getInsets();
+        float scale = pageRect.width() / childWidth;
+
+        float halfHeight = ws.getHeight() / 2;
+        float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
+        return new float[] {scale, pageRect.top - childTop};
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 60cd0c2..1f6ffe9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -30,10 +30,13 @@
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsView;
 
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
 public class RecentsViewStateController implements StateHandler {
 
     private final Launcher mLauncher;
     private final RecentsView mRecentsView;
+    private final WorkspaceCard mWorkspaceCard;
 
     private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::applyProgress);
     // The fraction representing the visibility of the RecentsView. This allows delaying the
@@ -44,24 +47,40 @@
         mLauncher = launcher;
         mRecentsView = launcher.getOverviewPanel();
         mRecentsView.setStateController(this);
+
+        mWorkspaceCard = (WorkspaceCard) mRecentsView.getChildAt(0);
+        mWorkspaceCard.setup(launcher);
     }
 
     @Override
     public void setState(LauncherState state) {
-        setVisibility(state == LauncherState.OVERVIEW);
-        setTransitionProgress(state == LauncherState.OVERVIEW ? 1 : 0);
+        mWorkspaceCard.setWorkspaceScrollingEnabled(state == OVERVIEW);
+        setVisibility(state == OVERVIEW);
+        setTransitionProgress(state == OVERVIEW ? 1 : 0);
     }
 
     @Override
-    public void setStateWithAnimation(LauncherState toState,
+    public void setStateWithAnimation(final LauncherState toState,
             AnimatorSetBuilder builder, AnimationConfig config) {
         ObjectAnimator progressAnim =
-                mTransitionProgress.animateToValue(toState == LauncherState.OVERVIEW ? 1 : 0);
+                mTransitionProgress.animateToValue(toState == OVERVIEW ? 1 : 0);
         progressAnim.setDuration(config.duration);
         progressAnim.setInterpolator(Interpolators.LINEAR);
+        progressAnim.addListener(new AnimationSuccessListener() {
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mWorkspaceCard.setWorkspaceScrollingEnabled(false);
+            }
+
+            @Override
+            public void onAnimationSuccess(Animator animator) {
+                mWorkspaceCard.setWorkspaceScrollingEnabled(toState == OVERVIEW);
+            }
+        });
         builder.play(progressAnim);
 
-        ObjectAnimator visibilityAnim = animateVisibility(toState == LauncherState.OVERVIEW);
+        ObjectAnimator visibilityAnim = animateVisibility(toState == OVERVIEW);
         visibilityAnim.setDuration(config.duration);
         visibilityAnim.setInterpolator(Interpolators.LINEAR);
         builder.play(visibilityAnim);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 9be0d32..73bf85f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -34,7 +34,7 @@
 
 public class UiFactory {
 
-    public static final boolean USE_HARDWARE_BITMAP = FeatureFlags.IS_DOGFOOD_BUILD;
+    public static final boolean USE_HARDWARE_BITMAP = false; // FeatureFlags.IS_DOGFOOD_BUILD;
 
     public static TouchController[] createTouchControllers(Launcher launcher) {
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
new file mode 100644
index 0000000..990d286
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
@@ -0,0 +1,186 @@
+/*
+ * 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.uioverrides;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.uioverrides.OverviewState.WORKSPACE_SCALE_ON_SCROLL;
+import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
+
+import android.animation.FloatArrayEvaluator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.widget.WidgetsFullSheet;
+import com.android.quickstep.RecentsView;
+import com.android.quickstep.RecentsView.PageCallbacks;
+import com.android.quickstep.RecentsView.ScrollState;
+
+public class WorkspaceCard extends FrameLayout implements PageCallbacks, OnClickListener {
+
+    private final Rect mTempRect = new Rect();
+    private final float[] mEvaluatedFloats = new float[2];
+    private final FloatArrayEvaluator mEvaluator = new FloatArrayEvaluator(mEvaluatedFloats);
+
+    // UI related information
+    private float[] mScaleAndTranslatePage0, mScaleAndTranslatePage1;
+    private boolean mUIDataValid = false;
+
+    private Launcher mLauncher;
+    private Workspace mWorkspace;
+
+    private boolean mIsWorkspaceScrollingEnabled;
+
+    private View mWorkspaceClickTarget;
+    private View mWidgetsButton;
+
+    public WorkspaceCard(Context context) {
+        super(context);
+    }
+
+    public WorkspaceCard(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public WorkspaceCard(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mWorkspaceClickTarget = findViewById(R.id.workspace_click_target);
+        mWidgetsButton = findViewById(R.id.widget_button);
+
+        mWorkspaceClickTarget.setOnClickListener(this);
+        mWidgetsButton.setOnClickListener(this);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // We measure the dimensions of the PagedView to be larger than the pages so that when we
+        // zoom out (and scale down), the view is still contained in the parent
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+
+        // Return early if we aren't given a proper dimension
+        if (widthSize <= 0 || heightSize <= 0) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+
+        int childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
+
+        int pageHeight = mWorkspace.getNormalChildHeight() * widthSize /
+                mWorkspace.getNormalChildWidth();
+        mWorkspaceClickTarget.measure(childWidthSpec,
+                MeasureSpec.makeMeasureSpec(pageHeight, MeasureSpec.EXACTLY));
+
+        int buttonHeight = heightSize - pageHeight - getPaddingTop() - getPaddingBottom();
+        mWidgetsButton.measure(childWidthSpec,
+                MeasureSpec.makeMeasureSpec(buttonHeight, MeasureSpec.EXACTLY));
+
+        setMeasuredDimension(widthSize, heightSize);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        int y1 = getPaddingTop();
+        int y2 = y1 + mWorkspaceClickTarget.getMeasuredHeight();
+
+        mWorkspaceClickTarget.layout(getPaddingLeft(), y1,
+                mWorkspaceClickTarget.getMeasuredWidth(), y2);
+
+        mWidgetsButton.layout(getPaddingLeft(), y2, mWidgetsButton.getMeasuredWidth(),
+                mWidgetsButton.getMeasuredHeight() + y2);
+
+        mUIDataValid = false;
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (view == mWorkspaceClickTarget) {
+            mLauncher.getStateManager().goToState(NORMAL);
+        } else if (view == mWidgetsButton) {
+            WidgetsFullSheet.show(mLauncher, true);
+        }
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mUIDataValid = false;
+    }
+
+    public void setup(Launcher launcher) {
+        mLauncher = launcher;
+        mWorkspace = mLauncher.getWorkspace();
+    }
+
+    public void setWorkspaceScrollingEnabled(boolean isEnabled) {
+        mIsWorkspaceScrollingEnabled = isEnabled;
+    }
+
+    @Override
+    public int onPageScroll(ScrollState scrollState) {
+        setTranslationX(scrollState.distanceFromScreenCenter);
+
+        float factor = scrollState.linearInterpolation;
+        float scale = factor * WORKSPACE_SCALE_ON_SCROLL + (1 - factor);
+        setScaleX(scale);
+        setScaleY(scale);
+
+        if (mIsWorkspaceScrollingEnabled) {
+            initUiData();
+
+            mEvaluator.evaluate(factor, mScaleAndTranslatePage0, mScaleAndTranslatePage1);
+            mWorkspace.setScaleX(mEvaluatedFloats[0]);
+            mWorkspace.setScaleY(mEvaluatedFloats[0]);
+            mWorkspace.setTranslationY(mEvaluatedFloats[1]);
+        }
+        return SCROLL_TYPE_WORKSPACE;
+    }
+
+    private void initUiData() {
+        if (mUIDataValid && mScaleAndTranslatePage0 != null) {
+            return;
+        }
+
+        RecentsView.getPageRect(mLauncher, mTempRect);
+        mScaleAndTranslatePage0 = OverviewState
+                .getScaleAndTranslationForPageRect(mLauncher, mTempRect);
+        Rect scaledDown = new Rect(mTempRect);
+        Utilities.scaleRectAboutCenter(scaledDown, WORKSPACE_SCALE_ON_SCROLL);
+        mScaleAndTranslatePage1 = OverviewState
+                .getScaleAndTranslationForPageRect(mLauncher, scaledDown);
+        mUIDataValid = true;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 43a01a7..095b445 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -250,6 +250,7 @@
 
     private void setTaskPlanToUi() {
         mRecentsView.update(mLoadPlan);
+        mRecentsView.initToPage(mRecentsView.getFirstTaskIndex());
         ObjectAnimator anim = mStateController.animateVisibility(true /* isVisible */)
                 .setDuration(RECENTS_VIEW_VISIBILITY_DURATION);
         anim.addListener(new AnimationSuccessListener() {
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index fd9010d..6161858 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -17,7 +17,6 @@
 package com.android.quickstep;
 
 import android.animation.LayoutTransition;
-import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
@@ -47,17 +46,11 @@
  */
 public class RecentsView extends PagedView {
 
-    /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
-    private static final float CURVE_FACTOR = 0.25f;
-    /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
-    private static final TimeInterpolator CURVE_INTERPOLATOR
-        = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));
-    /**
-     * The alpha of a black scrim on a page in the carousel as it leaves the screen.
-     * In the resting position of the carousel, the adjacent pages have about half this scrim.
-     */
-    private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
+    public static final int SCROLL_TYPE_NONE = 0;
+    public static final int SCROLL_TYPE_TASK = 1;
+    public static final int SCROLL_TYPE_WORKSPACE = 2;
 
+    private final ScrollState mScrollState = new ScrollState();
     private boolean mOverviewStateEnabled;
     private boolean mTaskStackListenerRegistered;
     private LayoutTransition mLayoutTransition;
@@ -65,7 +58,7 @@
     private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
         @Override
         public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
-            for (int i = 0; i < getChildCount(); i++) {
+            for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
                 final TaskView taskView = (TaskView) getChildAt(i);
                 if (taskView.getTask().key.id == taskId) {
                     taskView.getThumbnail().setThumbnail(snapshot);
@@ -76,6 +69,7 @@
     };
 
     private RecentsViewStateController mStateController;
+    private int mFirstTaskIndex;
 
     public RecentsView(Context context) {
         this(context, null);
@@ -87,10 +81,12 @@
 
     public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        setWillNotDraw(false);
-        setPageSpacing((int) getResources().getDimension(R.dimen.recents_page_spacing));
+        setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
         enableFreeScroll(true);
+        setClipChildren(true);
         setupLayoutTransition();
+
+        mScrollState.isRtl = mIsRtl;
     }
 
     private void setupLayoutTransition() {
@@ -110,6 +106,8 @@
 
         Rect padding = getPadding(Launcher.getLauncher(getContext()));
         setPadding(padding.left, padding.top, padding.right, padding.bottom);
+
+        mFirstTaskIndex = getPageCount();
     }
 
     @Override
@@ -130,6 +128,10 @@
         updateTaskStackListenerState();
     }
 
+    public int getFirstTaskIndex() {
+        return mFirstTaskIndex;
+    }
+
     public void setStateController(RecentsViewStateController stateController) {
         mStateController = stateController;
     }
@@ -145,10 +147,6 @@
 
     public void update(RecentsTaskLoadPlan loadPlan) {
         final RecentsTaskLoader loader = TouchInteractionService.getRecentsTaskLoader();
-        setCurrentPage(0);
-        if (getPageAt(mCurrentPage) instanceof TaskView) {
-            ((TaskView) getPageAt(mCurrentPage)).setIconScale(0);
-        }
         TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
         if (stack == null) {
             removeAllViews();
@@ -160,11 +158,13 @@
         final LayoutInflater inflater = LayoutInflater.from(getContext());
         final ArrayList<Task> tasks = stack.getTasks();
         setLayoutTransition(null);
-        for (int i = getChildCount(); i < tasks.size(); i++) {
+        int requiredChildCount = tasks.size() + mFirstTaskIndex;
+
+        for (int i = getChildCount(); i < requiredChildCount; i++) {
             final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
             addView(taskView);
         }
-        while (getChildCount() > tasks.size()) {
+        while (getChildCount() > requiredChildCount) {
             final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
             removeView(taskView);
             loader.unloadTaskData(taskView.getTask());
@@ -174,14 +174,21 @@
         // Rebind all task views
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final Task task = tasks.get(i);
-            final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1);
+            final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex);
             taskView.bind(task);
             loader.loadTaskData(task);
         }
     }
 
+    public void initToPage(int pageNo) {
+        setCurrentPage(pageNo);
+        if (getPageAt(mCurrentPage) instanceof TaskView) {
+            ((TaskView) getPageAt(mCurrentPage)).setIconScale(0);
+        }
+    }
+
     public void launchTaskWithId(int taskId) {
-        for (int i = 0; i < getChildCount(); i++) {
+        for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
             final TaskView taskView = (TaskView) getChildAt(i);
             if (taskView.getTask().key.id == taskId) {
                 taskView.launchTask(false /* animate */);
@@ -245,35 +252,50 @@
         }
         final int halfScreenWidth = getMeasuredWidth() / 2;
         final int screenCenter = halfScreenWidth + getScrollX();
-        final int pageSpacing = getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
+        final int pageSpacing = mPageSpacing;
+        final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2;
+        mScrollState.lastScrollType = SCROLL_TYPE_NONE;
+
         final int pageCount = getPageCount();
         for (int i = 0; i < pageCount; i++) {
             View page = getPageAt(i);
-            int pageWidth = page.getMeasuredWidth();
-            int halfPageWidth = pageWidth / 2;
             int pageCenter = page.getLeft() + halfPageWidth;
-            float distanceFromScreenCenter = Math.abs(pageCenter - screenCenter);
+            mScrollState.distanceFromScreenCenter = screenCenter - pageCenter;
             float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
-            float linearInterpolation = Math.min(1, distanceFromScreenCenter / distanceToReachEdge);
-            float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation);
-            float scale = 1 - curveInterpolation * CURVE_FACTOR;
-            page.setScaleX(scale);
-            page.setScaleY(scale);
-            // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
-            page.setTranslationZ(scale);
-            page.setTranslationX((screenCenter - pageCenter) * curveInterpolation * CURVE_FACTOR);
-            if (page instanceof TaskView) {
-                TaskThumbnailView thumbnail = ((TaskView) page).getThumbnail();
-                thumbnail.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
-            }
+            mScrollState.linearInterpolation = Math.min(1,
+                    Math.abs(mScrollState.distanceFromScreenCenter) / distanceToReachEdge);
+            mScrollState.lastScrollType = ((PageCallbacks) page).onPageScroll(mScrollState);
         }
     }
 
     public void onTaskDismissed(TaskView taskView) {
         ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
         removeView(taskView);
-        if (getChildCount() == 0) {
+        if (getChildCount() == mFirstTaskIndex) {
             Launcher.getLauncher(getContext()).getStateManager().goToState(LauncherState.NORMAL);
         }
     }
+
+    public interface PageCallbacks {
+
+        /**
+         * Updates the page UI based on scroll params and returns the type of scroll
+         * effect performed.
+         *
+         * @see #SCROLL_TYPE_NONE
+         * @see #SCROLL_TYPE_TASK
+         * @see #SCROLL_TYPE_WORKSPACE
+         */
+        int onPageScroll(ScrollState scrollState);
+    }
+
+    public static class ScrollState {
+
+        public boolean isRtl;
+        public int lastScrollType;
+
+        public int halfPageWidth;
+        public float distanceFromScreenCenter;
+        public float linearInterpolation;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index d834881..6b37ada 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -16,9 +16,13 @@
 
 package com.android.quickstep;
 
+import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
+import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.app.ActivityOptions;
 import android.content.Context;
@@ -35,6 +39,8 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.touch.SwipeDetector;
+import com.android.quickstep.RecentsView.PageCallbacks;
+import com.android.quickstep.RecentsView.ScrollState;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -49,7 +55,20 @@
 /**
  * A task in the Recents view.
  */
-public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetector.Listener {
+public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetector.Listener,
+        PageCallbacks {
+
+    /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
+    private static final float CURVE_FACTOR = 0.25f;
+    /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
+    private static final TimeInterpolator CURVE_INTERPOLATOR
+            = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));
+
+    /**
+     * The alpha of a black scrim on a page in the carousel as it leaves the screen.
+     * In the resting position of the carousel, the adjacent pages have about half this scrim.
+     */
+    private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
 
     private static final int SWIPE_DIRECTIONS = SwipeDetector.DIRECTION_POSITIVE;
 
@@ -288,4 +307,35 @@
             mIconView.setScaleY(mIconScale);
         }
     }
+
+    @Override
+    public int onPageScroll(ScrollState scrollState) {
+        float curveInterpolation =
+                CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
+        float scale = 1 - curveInterpolation * CURVE_FACTOR;
+        setScaleX(scale);
+        setScaleY(scale);
+
+        // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
+        setTranslationZ(scale);
+
+        mSnapshotView.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
+
+        float translation =
+                scrollState.distanceFromScreenCenter * curveInterpolation * CURVE_FACTOR;
+        setTranslationX(translation);
+
+        if (scrollState.lastScrollType == SCROLL_TYPE_WORKSPACE) {
+            // Make sure that the task cards do not overlap with the workspace card
+            float min = scrollState.halfPageWidth * (1 - scale);
+            if (scrollState.isRtl) {
+                setTranslationX(Math.min(translation, min));
+            } else {
+                setTranslationX(Math.max(translation, -min));
+            }
+        } else {
+            setTranslationX(translation);
+        }
+        return SCROLL_TYPE_TASK;
+    }
 }
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index d21e45d..0a4fec1 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -50,7 +50,15 @@
             android:layout_gravity="bottom|left"
             android:background="@drawable/all_apps_handle_landscape" />
 
-        <include layout="@layout/gradient_bg" />
+        <include layout="@layout/overview_panel"
+            android:id="@+id/overview_panel"
+            android:visibility="gone" />
+
+        <com.android.launcher3.views.AllAppsScrim
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/all_apps_scrim"
+            launcher:layout_ignoreInsets="true" />
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
@@ -64,10 +72,6 @@
             android:id="@+id/drop_target_bar"
             layout="@layout/drop_target_bar_vert" />
 
-        <include layout="@layout/overview_panel"
-            android:id="@+id/overview_panel"
-            android:visibility="gone" />
-
         <include layout="@layout/all_apps"
             android:id="@+id/apps_view"
             android:layout_width="match_parent"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index f58a87e..33b350a 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -44,7 +44,15 @@
             launcher:pageIndicator="@+id/page_indicator">
         </com.android.launcher3.Workspace>
 
-        <include layout="@layout/gradient_bg" />
+        <include layout="@layout/overview_panel"
+            android:id="@+id/overview_panel"
+            android:visibility="gone" />
+
+        <com.android.launcher3.views.AllAppsScrim
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/all_apps_scrim"
+            launcher:layout_ignoreInsets="true" />
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
@@ -53,10 +61,6 @@
             android:layout_height="match_parent"
             launcher:layout_ignoreInsets="true" />
 
-        <include layout="@layout/overview_panel"
-            android:id="@+id/overview_panel"
-            android:visibility="gone" />
-
         <!-- Keep these behind the workspace so that they are not visible when
              we go into AllApps -->
         <include layout="@layout/page_indicator"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 660d0ed..d7e931a 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -43,7 +43,15 @@
             launcher:pageIndicator="@id/page_indicator">
         </com.android.launcher3.Workspace>
 
-        <include layout="@layout/gradient_bg" />
+        <include layout="@layout/overview_panel"
+            android:id="@+id/overview_panel"
+            android:visibility="gone" />
+
+        <com.android.launcher3.views.AllAppsScrim
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/all_apps_scrim"
+            launcher:layout_ignoreInsets="true" />
 
         <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
@@ -56,10 +64,6 @@
             android:id="@+id/drop_target_bar"
             layout="@layout/drop_target_bar_horz" />
 
-        <include layout="@layout/overview_panel"
-            android:id="@+id/overview_panel"
-            android:visibility="gone" />
-
         <!-- Keep these behind the workspace so that they are not visible when
              we go into AllApps -->
         <include layout="@layout/page_indicator"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 3f6be2c..8cf32bd 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -41,14 +41,6 @@
 
         <include layout="@layout/predictions_view" android:id="@+id/header_content" />
 
-        <include layout="@layout/all_apps_divider"
-            android:id="@+id/divider"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
-            android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
-            android:layout_alignBottom="@+id/tabs" />
-
         <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
             android:id="@+id/tabs"
             android:layout_width="match_parent"
diff --git a/res/layout/gradient_bg.xml b/res/layout/widgets_bottom_sheet_scrim.xml
similarity index 100%
rename from res/layout/gradient_bg.xml
rename to res/layout/widgets_bottom_sheet_scrim.xml
diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml
index 48578d7..2606b87 100644
--- a/res/layout/work_tab_footer.xml
+++ b/res/layout/work_tab_footer.xml
@@ -13,60 +13,68 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical"
-      android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding"
-      android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
-      android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
-      android:paddingTop="@dimen/all_apps_work_profile_tab_footer_top_padding">
+<com.android.launcher3.views.WorkFooterContainer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding"
+    android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
+    android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
+    android:paddingTop="@dimen/all_apps_work_profile_tab_footer_top_padding">
 
-    <RelativeLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-        <Switch
-            android:id="@+id/work_mode_toggle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentRight="true"
-            android:theme="@style/WorkModeSwitchTheme"/>
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignBaseline="@id/work_mode_toggle"
-            android:layout_alignParentLeft="true"
-            android:ellipsize="end"
-            android:fontFamily="roboto-regular"
-            android:lines="1"
-            android:text="@string/work_profile_toggle_label"
-            android:textColor="?android:attr/textColorTertiary"
-            android:textSize="16sp"/>
-
-    </RelativeLayout>
-
-    <LinearLayout
+    <ImageView
+        android:id="@+id/work_footer_divider"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:paddingTop="8dp">
+        android:focusable="false"
+        android:importantForAccessibility="no"
+        android:paddingBottom="@dimen/all_apps_divider_margin_vertical"
+        android:paddingTop="@dimen/all_apps_divider_margin_vertical"
+        android:scaleType="fitXY"
+        android:src="@drawable/all_apps_divider"/>
 
-        <ImageView
-            android:layout_width="24dp"
-            android:layout_height="24dp"
-            android:src="@drawable/ic_corp"/>
+    <Switch
+        android:id="@+id/work_mode_toggle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_below="@id/work_footer_divider"
+        android:theme="@style/WorkModeSwitchTheme"/>
 
-        <TextView
-            android:id="@+id/managed_by_label"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:ellipsize="end"
-            android:lines="1"
-            android:paddingLeft="12dp"
-            android:textColor="?android:attr/textColorHint"
-            android:textSize="13sp"/>
-    </LinearLayout>
-</LinearLayout>
\ No newline at end of file
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@id/work_mode_toggle"
+        android:layout_alignParentStart="true"
+        android:ellipsize="end"
+        android:lines="1"
+        android:text="@string/work_profile_toggle_label"
+        android:textColor="?android:attr/textColorTertiary"
+        android:textSize="16sp"/>
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_below="@android:id/title"
+        android:layout_marginTop="8dp"
+        android:src="@drawable/ic_corp"/>
+
+    <TextView
+        android:id="@+id/managed_by_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@android:id/title"
+        android:layout_marginTop="8dp"
+        android:layout_toEndOf="@android:id/icon"
+        android:ellipsize="end"
+        android:gravity="center_vertical"
+        android:lines="1"
+        android:minHeight="24dp"
+        android:paddingStart="12dp"
+        android:text="@string/managed_by_your_organisation"
+        android:textColor="?android:attr/textColorHint"
+        android:textSize="13sp"/>
+
+</com.android.launcher3.views.WorkFooterContainer>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 93c5114..1ae7cbf 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -50,6 +50,10 @@
     <dimen name="dynamic_grid_hotseat_land_left_nav_bar_left_padding">0dp</dimen>
     <dimen name="dynamic_grid_hotseat_land_right_nav_bar_left_padding">0dp</dimen>
 
+    <!-- Hotseat/all-apps scrim -->
+    <dimen name="all_apps_scrim_radius">10dp</dimen>
+    <dimen name="all_apps_scrim_margin">10dp</dimen>
+    <dimen name="all_apps_scrim_blur">5dp</dimen>
 
 <!-- Drop target bar -->
     <dimen name="dynamic_grid_drop_target_size">48dp</dimen>
@@ -97,6 +101,7 @@
     <dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
     <dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
     <dimen name="all_apps_tabs_side_padding">12dp</dimen>
+    <dimen name="all_apps_divider_height">1dp</dimen>
 
 <!-- Search bar in All Apps -->
     <dimen name="all_apps_header_max_elevation">3dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index eca64c8..d77065c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -330,5 +330,7 @@
     <string name="bottom_work_tab_user_education_title">Find work apps here</string>
     <!-- Body text in bottom user education view in work tab -->
     <string name="bottom_work_tab_user_education_body">Each work app has an orange badge, which means it\'s kept secure by your organization. Work apps can be moved to your Home Screen for easier access.</string>
+    <!-- Label in work tab to tell users that work profile is managed by their organisation. -->
+    <string name="managed_by_your_organisation">Managed by your organisation</string>
 
 </resources>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 79a34a0..01b6ca9 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -106,7 +106,7 @@
     final PreviewBackground mFolderLeaveBehind = new PreviewBackground();
 
     private static final int[] BACKGROUND_STATE_ACTIVE = new int[] { android.R.attr.state_active };
-    private static final int[] BACKGROUND_STATE_DEFAULT = new int[0];
+    private static final int[] BACKGROUND_STATE_DEFAULT = EMPTY_STATE_SET;
     private final Drawable mBackground;
 
     // These values allow a fixed measurement to be set on the CellLayout.
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/PagedView.java b/src/com/android/launcher3/PagedView.java
index d6b5656..5ed722c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -106,7 +106,7 @@
     protected LauncherScroller mScroller;
     private Interpolator mDefaultInterpolator;
     private VelocityTracker mVelocityTracker;
-    @Thunk int mPageSpacing = 0;
+    protected int mPageSpacing = 0;
 
     private float mParentDownMotionX;
     private float mParentDownMotionY;
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/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index b98d852..8154845 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -547,7 +547,7 @@
         return mHeader;
     }
 
-    private void setupHeader() {
+    public void setupHeader() {
         if (mHeader == null) {
             return;
         }
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index da4d9f0..246f7be 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -381,10 +381,6 @@
             case VIEW_TYPE_WORK_TAB_FOOTER:
                 Switch workModeToggle = holder.itemView.findViewById(R.id.work_mode_toggle);
                 workModeToggle.setChecked(!isAnyProfileQuietModeEnabled());
-
-                TextView textView = holder.itemView.findViewById(R.id.managed_by_label);
-                // TODO: Configure the textview properly.
-                textView.setText("Managed by your company");
                 break;
         }
         if (mBindViewCallback != null) {
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index fd80784..4f931ca 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -168,6 +168,8 @@
                 AllAppsGridAdapter.VIEW_TYPE_SEARCH_MARKET);
         putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
                 AllAppsGridAdapter.VIEW_TYPE_EMPTY_SEARCH);
+        putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
+                AllAppsGridAdapter.VIEW_TYPE_WORK_TAB_FOOTER);
         if (FeatureFlags.DISCOVERY_ENABLED) {
             putSameHeightFor(adapter, widthMeasureSpec, heightMeasureSpec,
                     AllAppsGridAdapter.VIEW_TYPE_APPS_LOADING_DIVIDER);
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/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 2b9cba3..02e731a 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -621,7 +621,6 @@
 
         // Add the work profile footer if required.
         if (mIsWork) {
-            mAdapterItems.add(AdapterItem.asAllAppsDivider(position++));
             mAdapterItems.add(AdapterItem.asWorkTabFooter(position++));
         }
     }
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 409985c..1419a2a 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -18,7 +18,6 @@
 
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.support.annotation.NonNull;
@@ -66,7 +65,6 @@
 
     private PredictionRowView mPredictionRow;
     private ViewGroup mTabLayout;
-    private View mDivider;
     private AllAppsRecyclerView mMainRV;
     private AllAppsRecyclerView mWorkRV;
     private AllAppsRecyclerView mCurrentRV;
@@ -90,7 +88,6 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mTabLayout = findViewById(R.id.tabs);
-        mDivider = findViewById(R.id.divider);
         mPredictionRow = findViewById(R.id.header_content);
     }
 
@@ -98,17 +95,15 @@
             HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
         mTabsHidden = mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null;
         mTabLayout.setVisibility(mTabsHidden ? View.GONE : View.VISIBLE);
-        mPredictionRow.setPadding(0, 0, 0, mTabsHidden ? getResources()
-                .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0);
         mPredictionRow.setup(mAH[AllAppsContainerView.AdapterHolder.MAIN].adapter,
                 componentToAppMap, numPredictedAppsPerRow);
+        mPredictionRow.setShowDivider(mTabsHidden);
         mMaxTranslation = mPredictionRow.getExpectedHeight();
         mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
         mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
         mParent = (ViewGroup) mMainRV.getParent();
         setMainActive(true);
         reset();
-        setupDivider();
     }
 
     private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
@@ -118,17 +113,6 @@
         return updated;
     }
 
-    private void setupDivider() {
-        Resources res = getResources();
-        int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
-        int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
-        mDivider.setPadding(sideGap, verticalGap,sideGap, mTabsHidden ? verticalGap : 0);
-        RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
-        lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
-        lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTabsHidden ? R.id.header_content : R.id.tabs);
-        mDivider.setLayoutParams(lp);
-    }
-
     public void setMainActive(boolean active) {
         mCurrentRV = active ? mMainRV : mWorkRV;
     }
@@ -137,10 +121,6 @@
         return mPredictionRow;
     }
 
-    public View getDivider() {
-        return mDivider;
-    }
-
     private boolean canSnapAt(int currentScrollY) {
         return Math.abs(currentScrollY) <= mPredictionRow.getHeight();
     }
@@ -180,7 +160,6 @@
             mPredictionRow.setTranslationY(uncappedTranslationY);
         }
         mTabLayout.setTranslationY(mTranslationY);
-        mDivider.setTranslationY(mTabsHidden ? uncappedTranslationY : mTranslationY);
         mClip.top = mMaxTranslation + mTranslationY;
         // clipping on a draw might cause additional redraw
         mMainRV.setClipBounds(mClip);
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 54948b0..47dc36d 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -35,12 +35,14 @@
 public class PersonalWorkSlidingTabStrip extends LinearLayout {
     private final Paint mPersonalTabIndicatorPaint;
     private final Paint mWorkTabIndicatorPaint;
+    private final Paint mDividerPaint;
 
     private int mSelectedIndicatorHeight;
     private int mIndicatorLeft = -1;
     private int mIndicatorRight = -1;
+    private int mIndicatorPosition = 0;
+    private float mIndicatorOffset;
     private int mSelectedPosition = 0;
-    private float mSelectionOffset;
     private boolean mIsRtl;
 
     public PersonalWorkSlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
@@ -59,15 +61,20 @@
         mWorkTabIndicatorPaint.setColor(getResources().getColor(R.color.work_profile_color));
 
         mIsRtl = Utilities.isRtl(getResources());
+
+        mDividerPaint = new Paint();
+        mDividerPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
+        mDividerPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
     }
 
     public void updateIndicatorPosition(int position, float positionOffset) {
-        mSelectedPosition = position;
-        mSelectionOffset = positionOffset;
+        mIndicatorPosition = position;
+        mIndicatorOffset = positionOffset;
         updateIndicatorPosition();
     }
 
     public void updateTabTextColor(int pos) {
+        mSelectedPosition = pos;
         for (int i = 0; i < getChildCount(); i++) {
             Button tab = (Button) getChildAt(i);
             tab.setSelected(i == pos);
@@ -78,24 +85,24 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
         updateTabTextColor(mSelectedPosition);
-        updateIndicatorPosition(mSelectedPosition, 0);
+        updateIndicatorPosition(mIndicatorPosition, mIndicatorOffset);
     }
 
     private void updateIndicatorPosition() {
-        final View tab = getChildAt(mSelectedPosition);
+        final View tab = getChildAt(mIndicatorPosition);
         int left, right;
 
         if (tab != null && tab.getWidth() > 0) {
             left = tab.getLeft();
             right = tab.getRight();
 
-            if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {
+            if (mIndicatorOffset > 0f && mIndicatorPosition < getChildCount() - 1) {
                 // Draw the selection partway between the tabs
-                View nextTitle = getChildAt(mSelectedPosition + 1);
-                left = (int) (mSelectionOffset * nextTitle.getLeft() +
-                        (1.0f - mSelectionOffset) * left);
-                right = (int) (mSelectionOffset * nextTitle.getRight() +
-                        (1.0f - mSelectionOffset) * right);
+                View nextTitle = getChildAt(mIndicatorPosition + 1);
+                left = (int) (mIndicatorOffset * nextTitle.getLeft() +
+                        (1.0f - mIndicatorOffset) * left);
+                right = (int) (mIndicatorOffset * nextTitle.getRight() +
+                        (1.0f - mIndicatorOffset) * right);
             }
         } else {
             left = right = -1;
@@ -116,6 +123,9 @@
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
+        float y = getHeight() - mDividerPaint.getStrokeWidth();
+        canvas.drawLine(getPaddingLeft(), y, getWidth() - getPaddingRight(), y, mDividerPaint);
+
         final float middleX = getWidth() / 2.0f;
         if (mIndicatorLeft <= middleX) {
             canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java
index 1aee948..4aacc6d 100644
--- a/src/com/android/launcher3/allapps/PredictionRowView.java
+++ b/src/com/android/launcher3/allapps/PredictionRowView.java
@@ -17,6 +17,8 @@
 package com.android.launcher3.allapps;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
@@ -27,9 +29,11 @@
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ComponentKeyMapper;
+import com.android.launcher3.util.Themes;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -46,8 +50,10 @@
     private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
     // The set of predicted apps resolved from the component names and the current set of apps
     private final List<AppInfo> mPredictedApps = new ArrayList<>();
+    private final Paint mPaint;
     // This adapter is only used to create an identical item w/ same behavior as in the all apps RV
     private AllAppsGridAdapter mAdapter;
+    private boolean mShowDivider;
 
     public PredictionRowView(@NonNull Context context) {
         this(context, null);
@@ -56,6 +62,10 @@
     public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         setOrientation(LinearLayout.HORIZONTAL);
+        setWillNotDraw(false);
+        mPaint = new Paint();
+        mPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
+        mPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
     }
 
     public void setup(AllAppsGridAdapter adapter, HashMap<ComponentKey, AppInfo> componentToAppMap,
@@ -82,6 +92,13 @@
         return height;
     }
 
+    public void setShowDivider(boolean showDivider) {
+        mShowDivider = showDivider;
+        int paddingBottom = showDivider ? getResources()
+                .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0;
+        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+    }
+
     /**
      * Sets the number of apps per row.
      */
@@ -169,4 +186,17 @@
         }
         return predictedApps;
     }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        if (mShowDivider) {
+            int side = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+            int y = getHeight() - (getPaddingBottom() / 2);
+            int x1 = getPaddingLeft() + side;
+            int x2 = getWidth() - getPaddingRight() - side;
+            canvas.drawLine(x1, y, x2, y, mPaint);
+        }
+    }
 }
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..d1354ad
--- /dev/null
+++ b/src/com/android/launcher3/views/AllAppsScrim.java
@@ -0,0 +1,148 @@
+/*
+ * 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.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;
+
+    protected 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;
+    }
+}
diff --git a/src/com/android/launcher3/views/WorkFooterContainer.java b/src/com/android/launcher3/views/WorkFooterContainer.java
new file mode 100644
index 0000000..fb17b4f
--- /dev/null
+++ b/src/com/android/launcher3/views/WorkFooterContainer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+/**
+ * Container to show work footer in all-apps.
+ */
+public class WorkFooterContainer extends RelativeLayout {
+
+    public WorkFooterContainer(Context context) {
+        super(context);
+    }
+
+    public WorkFooterContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public WorkFooterContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        updateTranslation();
+    }
+
+    @Override
+    public void offsetTopAndBottom(int offset) {
+        super.offsetTopAndBottom(offset);
+        updateTranslation();
+    }
+
+    private void updateTranslation() {
+        if (getParent() instanceof View) {
+            View parent = (View) getParent();
+            int availableBot = parent.getHeight() - parent.getPaddingBottom();
+            setTranslationY(Math.max(0, availableBot - getBottom()));
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 7fa5ff0..6a9013d 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -57,7 +57,7 @@
         mInsets = new Rect();
 
         mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
-                R.layout.gradient_bg, mLauncher.getDragLayer(), false);
+                R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false);
         mGradientView.setProgress(1, false);
         mContent = this;
     }