Updating landscape layout for launcher/quickstep

> Hotseat is tied to navbar (on left in seascape)
> Search box shows up in Overview (clicking it would crash for now)
> All-apps is no longer fullscreen in landscape
> Recents cards are appropriately scaled down
> Hotseat is visible in Overview

Bug: 70179916
Change-Id: I53149eaeac9557e8a01021b7e2d139f3d6ceef37
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 4087df1..5e4f670 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -847,10 +847,6 @@
         return super.verifyDrawable(who) || (who == mBackground);
     }
 
-    public void setShortcutAndWidgetAlpha(float alpha) {
-        mShortcutsAndWidgets.setAlpha(alpha);
-    }
-
     public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
         return mShortcutsAndWidgets;
     }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 3bfc41c..52b1249 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -80,9 +80,6 @@
 
     // Page indicator
     private int pageIndicatorSizePx;
-    private final int pageIndicatorLandLeftNavBarGutterPx;
-    private final int pageIndicatorLandRightNavBarGutterPx;
-    private final int pageIndicatorLandWorkspaceOffsetPx;
 
     // Workspace icons
     public int iconSizePx;
@@ -114,12 +111,7 @@
     public int hotseatBarSizePx;
     public int hotseatBarTopPaddingPx;
     public int hotseatBarBottomPaddingPx;
-
-    public int hotseatBarLeftNavBarLeftPaddingPx;
-    public int hotseatBarLeftNavBarRightPaddingPx;
-
-    public int hotseatBarRightNavBarLeftPaddingPx;
-    public int hotseatBarRightNavBarRightPaddingPx;
+    public int hotseatBarSidePaddingPx;
 
     // All apps
     public int allAppsCellHeightPx;
@@ -181,12 +173,6 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_bottom_padding);
         pageIndicatorSizePx = res.getDimensionPixelSize(
                 R.dimen.dynamic_grid_min_page_indicator_size);
-        pageIndicatorLandLeftNavBarGutterPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_page_indicator_land_left_nav_bar_gutter_width);
-        pageIndicatorLandRightNavBarGutterPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_page_indicator_land_right_nav_bar_gutter_width);
-        pageIndicatorLandWorkspaceOffsetPx =
-                res.getDimensionPixelSize(R.dimen.all_apps_caret_workspace_offset);
         defaultPageSpacingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
         topWorkspacePadding =
@@ -203,14 +189,8 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
         hotseatBarBottomPaddingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
-        hotseatBarLeftNavBarRightPaddingPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_hotseat_land_left_nav_bar_right_padding);
-        hotseatBarRightNavBarRightPaddingPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_hotseat_land_right_nav_bar_right_padding);
-        hotseatBarLeftNavBarLeftPaddingPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_hotseat_land_left_nav_bar_left_padding);
-        hotseatBarRightNavBarLeftPaddingPx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_hotseat_land_right_nav_bar_left_padding);
+        hotseatBarSidePaddingPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
         hotseatBarSizePx = isVerticalBarLayout()
                 ? Utilities.pxFromDp(inv.iconSize, dm)
                 : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size)
@@ -445,10 +425,9 @@
             if (isTablet) {
                 // Pad the left and right of the workspace to ensure consistent spacing
                 // between all icons
-                int width = getCurrentWidth();
                 // XXX: If the icon size changes across orientations, we will have to take
                 //      that into account here too.
-                gap = ((width - 2 * edgeMarginPx
+                gap = ((widthPx - 2 * edgeMarginPx
                         - (inv.numColumns * cellWidthPx)) / (2 * (inv.numColumns + 1)))
                         + edgeMarginPx;
             } else {
@@ -481,33 +460,28 @@
     public Rect getWorkspacePadding(Rect recycle) {
         Rect padding = recycle == null ? new Rect() : recycle;
         if (isVerticalBarLayout()) {
-            if (mInsets.left > 0) {
-                padding.set(mInsets.left + pageIndicatorLandLeftNavBarGutterPx,
-                        0,
-                        hotseatBarSizePx + hotseatBarLeftNavBarRightPaddingPx
-                                + hotseatBarLeftNavBarLeftPaddingPx
-                                - mInsets.left,
-                        edgeMarginPx);
+            padding.top = 0;
+            padding.bottom = edgeMarginPx;
+            padding.left = hotseatBarSidePaddingPx;
+            padding.right = hotseatBarSidePaddingPx;
+            if (mInsets.left > mInsets.right) {
+                padding.left += hotseatBarSizePx;
+                padding.right += pageIndicatorSizePx;
             } else {
-                padding.set(pageIndicatorLandRightNavBarGutterPx,
-                        0,
-                        hotseatBarSizePx + hotseatBarRightNavBarRightPaddingPx
-                                + hotseatBarRightNavBarLeftPaddingPx,
-                        edgeMarginPx);
+                padding.left += pageIndicatorSizePx;
+                padding.right += hotseatBarSizePx;
             }
         } else {
             int paddingBottom = hotseatBarSizePx + pageIndicatorSizePx;
             if (isTablet) {
                 // Pad the left and right of the workspace to ensure consistent spacing
                 // between all icons
-                int width = getCurrentWidth();
-                int height = getCurrentHeight();
                 // The amount of screen space available for left/right padding.
-                int availablePaddingX = Math.max(0, width - ((inv.numColumns * cellWidthPx) +
+                int availablePaddingX = Math.max(0, widthPx - ((inv.numColumns * cellWidthPx) +
                         ((inv.numColumns - 1) * cellWidthPx)));
                 availablePaddingX = (int) Math.min(availablePaddingX,
-                            width * MAX_HORIZONTAL_PADDING_PERCENT);
-                int availablePaddingY = Math.max(0, height - topWorkspacePadding - paddingBottom
+                            widthPx * MAX_HORIZONTAL_PADDING_PERCENT);
+                int availablePaddingY = Math.max(0, heightPx - topWorkspacePadding - paddingBottom
                         - (2 * inv.numRows * cellHeightPx) - hotseatBarTopPaddingPx
                         - hotseatBarBottomPaddingPx);
                 padding.set(availablePaddingX / 2, topWorkspacePadding + availablePaddingY / 2,
@@ -575,6 +549,12 @@
         return isVerticalBarLayout() || isLargeTablet;
     }
 
+    private static void setLayoutGravity(View v, int gravity) {
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
+        lp.gravity = gravity;
+        v.setLayoutParams(lp);
+    }
+
     public void layout(Launcher launcher, boolean notifyListeners) {
         FrameLayout.LayoutParams lp;
         boolean hasVerticalBarLayout = isVerticalBarLayout();
@@ -604,31 +584,30 @@
         // icons in the hotseat are a different size, and so don't line up perfectly. To account for
         // this, we pad the left and right of the hotseat with half of the difference of a workspace
         // cell vs a hotseat cell.
-        float workspaceCellWidth = (float) getCurrentWidth() / inv.numColumns;
-        float hotseatCellWidth = (float) getCurrentWidth() / inv.numHotseatIcons;
+        float workspaceCellWidth = (float) widthPx / inv.numColumns;
+        float hotseatCellWidth = (float) widthPx / 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
-            int paddingRight = mInsets.left > 0
-                    ? hotseatBarLeftNavBarRightPaddingPx
-                    : hotseatBarRightNavBarRightPaddingPx;
-            int paddingLeft = mInsets.left > 0
-                    ? hotseatBarLeftNavBarLeftPaddingPx
-                    : hotseatBarRightNavBarLeftPaddingPx;
-
-            lp.gravity = Gravity.RIGHT;
-            lp.width = hotseatBarSizePx + mInsets.left + mInsets.right
-                    + paddingLeft + paddingRight;
+            // Vertical hotseat, on left or right based on the insets
             lp.height = LayoutParams.MATCH_PARENT;
+            if (mInsets.left > mInsets.right) {
+                lp.gravity = Gravity.LEFT;
+                lp.width = hotseatBarSizePx + mInsets.left + hotseatBarSidePaddingPx;
+                hotseat.getLayout().setPadding(
+                        mInsets.left, mInsets.top, hotseatBarSidePaddingPx, mInsets.bottom);
 
-            hotseat.getLayout().setPadding(mInsets.left + cellLayoutPaddingLeftRightPx
-                            + paddingLeft,
-                    mInsets.top,
-                    mInsets.right + cellLayoutPaddingLeftRightPx + paddingRight,
-                    workspacePadding.bottom + cellLayoutBottomPaddingPx);
+                setLayoutGravity(launcher.getDropTargetBar(), Gravity.RIGHT);
+            } else {
+                lp.gravity = Gravity.RIGHT;
+                lp.width = hotseatBarSizePx + mInsets.right + hotseatBarSidePaddingPx;
+                hotseat.getLayout().setPadding(
+                        hotseatBarSidePaddingPx, mInsets.top, mInsets.right, mInsets.bottom);
+
+                setLayoutGravity(launcher.getDropTargetBar(), Gravity.LEFT);
+            }
+
         } else if (isTablet) {
             // Pad the hotseat with the workspace padding calculated above
             lp.gravity = Gravity.BOTTOM;
@@ -661,11 +640,15 @@
         View pageIndicator = launcher.findViewById(R.id.page_indicator);
         if (pageIndicator != null) {
             lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
-            if (isVerticalBarLayout()) {
-                if (mInsets.left > 0) {
-                    lp.leftMargin = mInsets.left;
+            if (hasVerticalBarLayout) {
+                if (mInsets.left > mInsets.right) {
+                    lp.leftMargin = hotseatBarSidePaddingPx;
+                    lp.rightMargin = mInsets.right;
+                    lp.gravity =  Gravity.RIGHT | Gravity.BOTTOM;
                 } else {
-                    lp.leftMargin = pageIndicatorLandWorkspaceOffsetPx;
+                    lp.leftMargin = mInsets.left;
+                    lp.rightMargin = hotseatBarSidePaddingPx;
+                    lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
                 }
                 lp.bottomMargin = workspacePadding.bottom;
             } else {
@@ -689,18 +672,6 @@
         }
     }
 
-    public int getCurrentWidth() {
-        return isLandscape
-                ? Math.max(widthPx, heightPx)
-                : Math.min(widthPx, heightPx);
-    }
-
-    public int getCurrentHeight() {
-        return isLandscape
-                ? Math.min(widthPx, heightPx)
-                : Math.max(widthPx, heightPx);
-    }
-
     public int getCellHeight(@ContainerType int containerType) {
         switch (containerType) {
             case CellLayout.WORKSPACE:
@@ -715,20 +686,6 @@
         }
     }
 
-    /**
-     * @return the left/right paddings for all containers.
-     */
-    public final int[] getContainerPadding() {
-        // No paddings for portrait phone
-        if (isPhone && !isVerticalBarLayout()) {
-            return new int[] {0, 0};
-        }
-
-        // In landscape, we match the width of the workspace
-        Rect padding = getWorkspacePadding(null);
-        return new int[] { padding.left - mInsets.left, padding.right + mInsets.left};
-    }
-
     public boolean inMultiWindowMode() {
         return this != inv.landscapeProfile && this != inv.portraitProfile;
     }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 20a6be2..490feda 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -17,7 +17,6 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
 
 import android.content.Context;
 import android.graphics.Rect;
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index a1f5879..4f65d19 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -55,7 +55,7 @@
     private static final LauncherState[] sAllStates = new LauncherState[4];
 
     public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
-            0, 1f, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
+            0, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
 
     public static final LauncherState ALL_APPS = new AllAppsState(1);
 
@@ -95,13 +95,6 @@
     public final int transitionDuration;
 
     /**
-     * Fraction shift in the vertical translation UI and related properties
-     *
-     * @see com.android.launcher3.allapps.AllAppsTransitionController
-     */
-    public final float verticalProgress;
-
-    /**
      * True if the state allows workspace icons to be dragged.
      */
     public final boolean workspaceIconsCanBeDragged;
@@ -112,8 +105,7 @@
      */
     public final boolean disablePageClipping;
 
-    public LauncherState(int id, int containerType, int transitionDuration, float verticalProgress,
-            int flags) {
+    public LauncherState(int id, int containerType, int transitionDuration, int flags) {
         this.containerType = containerType;
         this.transitionDuration = transitionDuration;
 
@@ -126,8 +118,6 @@
         this.workspaceIconsCanBeDragged = (flags & FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED) != 0;
         this.disablePageClipping = (flags & FLAG_DISABLE_PAGE_CLIPPING) != 0;
 
-        this.verticalProgress = verticalProgress;
-
         this.ordinal = id;
         sAllStates[id] = this;
     }
@@ -154,6 +144,15 @@
         return launcher.getWorkspace();
     }
 
+    /**
+     * Fraction shift in the vertical translation UI and related properties
+     *
+     * @see com.android.launcher3.allapps.AllAppsTransitionController
+     */
+    public float getVerticalProgress(Launcher launcher) {
+        return 1f;
+    }
+
     public String getDescription(Launcher launcher) {
         return launcher.getWorkspace().getCurrentPageDescription();
     }
@@ -162,7 +161,7 @@
         if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
             return DEFAULT_ALPHA_PROVIDER;
         }
-        final int centerPage = launcher.getWorkspace().getPageNearestToCenterOfScreen();
+        final int centerPage = launcher.getWorkspace().getNextPage();
         return new PageAlphaProvider(ACCEL_2) {
             @Override
             public float getPageAlpha(int pageIndex) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 87595d9..4c30853 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -155,10 +155,6 @@
     // Page Indicator
     @Thunk int mPageIndicatorViewId;
     protected PageIndicator mPageIndicator;
-    // The viewport whether the pages are to be contained (the actual view may be larger than the
-    // viewport)
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private Rect mViewport = new Rect();
 
     // Reordering
     // We use the min scale to determine how much to expand the actually PagedView measured
@@ -283,25 +279,6 @@
         }
     }
 
-    // Convenience methods to get the actual width/height of the PagedView (since it is measured
-    // to be larger to account for the minimum possible scale)
-    int getViewportWidth() {
-        return mViewport.width();
-    }
-    public int getViewportHeight() {
-        return mViewport.height();
-    }
-
-    // Convenience methods to get the offset ASSUMING that we are centering the pages in the
-    // PagedView both horizontally and vertically
-    int getViewportOffsetX() {
-        return (getMeasuredWidth() - getViewportWidth()) / 2;
-    }
-
-    int getViewportOffsetY() {
-        return (getMeasuredHeight() - getViewportHeight()) / 2;
-    }
-
     public PageIndicator getPageIndicator() {
         return mPageIndicator;
     }
@@ -587,12 +564,12 @@
     }
 
     public int getNormalChildHeight() {
-        return  getViewportHeight() - getPaddingTop() - getPaddingBottom()
+        return  getMeasuredHeight() - getPaddingTop() - getPaddingBottom()
                 - mInsets.top - mInsets.bottom;
     }
 
     public int getNormalChildWidth() {
-        return  getViewportWidth() - getPaddingLeft() - getPaddingRight()
+        return  getMeasuredWidth() - getPaddingLeft() - getPaddingRight()
                 - mInsets.left - mInsets.right;
     }
 
@@ -610,8 +587,6 @@
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         int heightSize = MeasureSpec.getSize(heightMeasureSpec);
 
-        mViewport.set(0, 0, widthSize, heightSize);
-
         if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
             return;
@@ -628,9 +603,9 @@
         if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
 
         int myWidthSpec = MeasureSpec.makeMeasureSpec(
-                getViewportWidth() - mInsets.left - mInsets.right, MeasureSpec.EXACTLY);
+                widthSize - mInsets.left - mInsets.right, MeasureSpec.EXACTLY);
         int myHeightSpec = MeasureSpec.makeMeasureSpec(
-                getViewportHeight() - mInsets.top - mInsets.bottom, MeasureSpec.EXACTLY);
+                heightSize - mInsets.top - mInsets.bottom, MeasureSpec.EXACTLY);
 
         // measureChildren takes accounts for content padding, we only need to care about extra
         // space due to insets.
@@ -648,19 +623,15 @@
         if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
         final int childCount = getChildCount();
 
-        int offsetX = getViewportOffsetX();
-        int offsetY = getViewportOffsetY();
-
-        // Update the viewport offsets
-        mViewport.offset(offsetX, offsetY);
-
         final int startIndex = mIsRtl ? childCount - 1 : 0;
         final int endIndex = mIsRtl ? -1 : childCount;
         final int delta = mIsRtl ? -1 : 1;
 
         int verticalPadding = getPaddingTop() + getPaddingBottom();
 
-        int childLeft = offsetX + getPaddingLeft();
+        int scrollOffsetLeft = mInsets.left + getPaddingLeft();
+        int childLeft = scrollOffsetLeft;
+
         if (mPageScrolls == null || childCount != mChildCountOnLastLayout) {
             mPageScrolls = new int[childCount];
         }
@@ -668,8 +639,8 @@
         for (int i = startIndex; i != endIndex; i += delta) {
             final View child = getPageAt(i);
             if (child.getVisibility() != View.GONE) {
-                int childTop = offsetY + getPaddingTop() + mInsets.top;
-                childTop += (getViewportHeight() - mInsets.top - mInsets.bottom - verticalPadding
+                int childTop = getPaddingTop() + mInsets.top;
+                childTop += (getMeasuredHeight() - mInsets.top - mInsets.bottom - verticalPadding
                         - child.getMeasuredHeight()) / 2;
 
                 final int childWidth = child.getMeasuredWidth();
@@ -679,8 +650,7 @@
                 child.layout(childLeft, childTop,
                         childLeft + child.getMeasuredWidth(), childTop + childHeight);
 
-                int scrollOffsetLeft = getPaddingLeft();
-                mPageScrolls[i] = childLeft - scrollOffsetLeft - offsetX;
+                mPageScrolls[i] = childLeft - scrollOffsetLeft;
 
                 childLeft += childWidth + mPageSpacing + getChildGap();
             }
@@ -809,10 +779,7 @@
 
     protected int getChildOffset(int index) {
         if (index < 0 || index > getChildCount() - 1) return 0;
-
-        int offset = getPageAt(index).getLeft() - getViewportOffsetX();
-
-        return offset;
+        return getPageAt(index).getLeft();
     }
 
     @Override
@@ -930,32 +897,9 @@
         super.requestDisallowInterceptTouchEvent(disallowIntercept);
     }
 
-    /**
-     * Return true if a tap at (x, y) should trigger a flip to the previous page.
-     */
-    protected boolean hitsPreviousPage(float x, float y) {
-        if (mIsRtl) {
-            return (x > (getViewportOffsetX() + getViewportWidth() -
-                    getPaddingRight() - mPageSpacing));
-        }
-        return (x < getViewportOffsetX() + getPaddingLeft() + mPageSpacing);
-    }
-
-    /**
-     * Return true if a tap at (x, y) should trigger a flip to the next page.
-     */
-    protected boolean hitsNextPage(float x, float y) {
-        if (mIsRtl) {
-            return (x < getViewportOffsetX() + getPaddingLeft() + mPageSpacing);
-        }
-        return  (x > (getViewportOffsetX() + getViewportWidth() -
-                getPaddingRight() - mPageSpacing));
-    }
-
     /** Returns whether x and y originated within the buffered viewport */
     private boolean isTouchPointInViewportWithBuffer(int x, int y) {
-        sTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
-                mViewport.right + mViewport.width() / 2, mViewport.bottom);
+        sTmpRect.set(-getMeasuredWidth() / 2, 0, 3 * getMeasuredWidth() / 2, getMeasuredHeight());
         return sTmpRect.contains(x, y);
     }
 
@@ -1105,7 +1049,7 @@
     }
 
     protected float getScrollProgress(int screenCenter, View v, int page) {
-        final int halfScreenSize = getViewportWidth() / 2;
+        final int halfScreenSize = getMeasuredWidth() / 2;
 
         int delta = screenCenter - (getScrollForPage(page) + halfScreenSize);
         int count = getChildCount();
@@ -1145,8 +1089,8 @@
         } else {
             View child = getChildAt(index);
 
-            int scrollOffset = scrollOffset = mIsRtl ? getPaddingRight() : getPaddingLeft();
-            int baselineX = mPageScrolls[index] + scrollOffset + getViewportOffsetX();
+            int scrollOffset = mIsRtl ? getPaddingRight() : getPaddingLeft();
+            int baselineX = mPageScrolls[index] + scrollOffset;
             return (int) (child.getX() - baselineX);
         }
     }
@@ -1154,7 +1098,7 @@
     protected void dampedOverScroll(float amount) {
         if (Float.compare(amount, 0f) == 0) return;
 
-        int overScrollAmount = OverScroll.dampedScroll(amount, getViewportWidth());
+        int overScrollAmount = OverScroll.dampedScroll(amount, getMeasuredWidth());
         if (amount < 0) {
             mOverScrollX = overScrollAmount;
             super.scrollTo(mOverScrollX, getScrollY());
@@ -1328,8 +1272,8 @@
                                     // dragViewIndex < pageUnderPointIndex, so after we remove the
                                     // drag view all subsequent views to pageUnderPointIndex will
                                     // shift down.
-                                    int oldX = getViewportOffsetX() + getChildOffset(i);
-                                    int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);
+                                    int oldX = getChildOffset(i);
+                                    int newX = getChildOffset(i + shiftDelta);
 
                                     // Animate the view translation from its old position to its new
                                     // position
@@ -1600,20 +1544,20 @@
         }
     }
 
-    int getPageNearestToCenterOfScreen() {
+    public int getPageNearestToCenterOfScreen() {
         return getPageNearestToCenterOfScreen(getScrollX());
     }
 
     private int getPageNearestToCenterOfScreen(int scaledScrollX) {
-        int screenCenter = getViewportOffsetX() + scaledScrollX + (getViewportWidth() / 2);
+        int screenCenter = scaledScrollX + (getMeasuredWidth() / 2);
         int minDistanceFromScreenCenter = Integer.MAX_VALUE;
         int minDistanceFromScreenCenterIndex = -1;
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; ++i) {
-            View layout = (View) getPageAt(i);
+            View layout = getPageAt(i);
             int childWidth = layout.getMeasuredWidth();
             int halfChildWidth = (childWidth / 2);
-            int childCenter = getViewportOffsetX() + getChildOffset(i) + halfChildWidth;
+            int childCenter = getChildOffset(i) + halfChildWidth;
             int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
             if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
                 minDistanceFromScreenCenter = distanceFromScreenCenter;
@@ -1650,7 +1594,7 @@
 
     protected void snapToPageWithVelocity(int whichPage, int velocity) {
         whichPage = validateNewPage(whichPage);
-        int halfScreenSize = getViewportWidth() / 2;
+        int halfScreenSize = getMeasuredWidth() / 2;
 
         final int newX = getScrollForPage(whichPage);
         int delta = newX - getUnboundedScrollX();
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index efafb9c..1b72f83 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1133,7 +1133,7 @@
                 mLauncherOverlay.onScrollInteractionBegin();
             }
 
-            mLastOverlayScroll = Math.abs(amount / getViewportWidth());
+            mLastOverlayScroll = Math.abs(amount / getMeasuredWidth());
             mLauncherOverlay.onScrollChange(mLastOverlayScroll, mIsRtl);
         } else {
             dampedOverScroll(amount);
@@ -1331,7 +1331,7 @@
 
     private void updatePageAlphaValues() {
         if (!workspaceInModalState() && !mIsSwitchingState) {
-            int screenCenter = getScrollX() + getViewportWidth() / 2;
+            int screenCenter = getScrollX() + getMeasuredWidth() / 2;
             for (int i = 0; i < getChildCount(); i++) {
                 CellLayout child = (CellLayout) getChildAt(i);
                 if (child != null) {
@@ -1415,8 +1415,8 @@
         if (mChildrenLayersEnabled) {
             final int screenCount = getChildCount();
 
-            float visibleLeft = getViewportOffsetX();
-            float visibleRight = visibleLeft + getViewportWidth();
+            float visibleLeft = 0;
+            float visibleRight = visibleLeft + getMeasuredWidth();
             float scaleX = getScaleX();
             if (scaleX < 1 && scaleX > 0) {
                 float mid = getMeasuredWidth() / 2;
@@ -2164,7 +2164,7 @@
         // Use the absolute left instead of the child left, as we want the visible area
         // irrespective of the visible child. Since the view can only scroll horizontally, the
         // top position is not affected.
-        mTempXY[0] = getViewportOffsetX() + getPaddingLeft() + boundingLayout.getLeft();
+        mTempXY[0] = getPaddingLeft() + boundingLayout.getLeft();
         mTempXY[1] = child.getTop() + boundingLayout.getTop();
 
         float scale = mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY);
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 9ed86ed..cf35e52 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -154,10 +154,13 @@
 
     private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
             PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter) {
+        float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
+        int drawableAlpha = Math.round(pageAlpha * (state.hasScrim ? 255 : 0));
+
         propertySetter.setInt(cl.getScrimBackground(),
-                DRAWABLE_ALPHA, state.hasScrim ? 255 : 0, Interpolators.ZOOM_IN);
+                DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_IN);
         propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
-                pageAlphaProvider.getPageAlpha(childIndex), pageAlphaProvider.interpolator);
+                pageAlpha, pageAlphaProvider.interpolator);
     }
 
     public static class PropertySetter {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 7444545..2a7f46a 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -59,7 +59,6 @@
 import com.android.launcher3.util.ComponentKeyMapper;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.TransformingTouchDelegate;
 import com.android.launcher3.views.BottomUserEducationView;
 
 import java.util.HashMap;
@@ -73,8 +72,6 @@
         View.OnLongClickListener, Insettable, DeviceProfile.LauncherLayoutChangeListener,
         BubbleTextView.BubbleTextShadowHandler {
 
-    protected final Rect mBasePadding = new Rect();
-
     private final Launcher mLauncher;
     private final AdapterHolder[] mAH;
     private final ClickShadowView mTouchFeedbackView;
@@ -92,7 +89,6 @@
     private int mNumAppsPerRow;
     private int mNumPredictedAppsPerRow;
 
-    private TransformingTouchDelegate mTouchDelegate;
     private boolean mUsingTabs;
     private boolean mHasPredictions = false;
     private boolean mSearchModeWhileUsingTabs = false;
@@ -133,19 +129,13 @@
 
         DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
         grid.addLauncherLayoutChangedListener(this);
+        onLauncherLayoutChanged();
 
         applyTouchDelegate();
     }
 
     private void applyTouchDelegate() {
-        RecyclerView rv = getActiveRecyclerView();
-        mTouchDelegate = new TransformingTouchDelegate(rv);
-        mTouchDelegate.setBounds(
-                rv.getLeft() - mBasePadding.left,
-                rv.getTop() - mBasePadding.top,
-                rv.getRight() + mBasePadding.right,
-                rv.getBottom() + mBasePadding.bottom);
-        setTouchDelegate(mTouchDelegate);
+        // TODO: Reimplement once fast scroller is fixed.
     }
 
     @Override
@@ -166,11 +156,8 @@
             return;
         }
 
-        int[] padding = grid.getContainerPadding();
-        int paddingLeft = padding[0];
-        int paddingRight = padding[1];
-        mBasePadding.set(paddingLeft, 0, paddingRight, 0);
-        setPadding(paddingLeft, 0, paddingRight, 0);
+        Rect workspacePadding = grid.getWorkspacePadding(null);
+        setPadding(workspacePadding.left, 0, workspacePadding.right, 0);
     }
 
     @Override
@@ -294,12 +281,9 @@
 
         // This is a focus listener that proxies focus from a view into the list view.  This is to
         // work around the search box from getting first focus and showing the cursor.
-        setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (hasFocus && getActiveRecyclerView() != null) {
-                    getActiveRecyclerView().requestFocus();
-                }
+        setOnFocusChangeListener((v, hasFocus) -> {
+            if (hasFocus && getActiveRecyclerView() != null) {
+                getActiveRecyclerView().requestFocus();
             }
         });
 
@@ -309,8 +293,6 @@
         mSearchContainer = findViewById(R.id.search_container_all_apps);
         mSearchUiManager = (SearchUiManager) mSearchContainer;
         mSearchUiManager.initialize(this);
-
-        onLauncherLayoutChanged();
     }
 
     public SearchUiManager getSearchUiManager() {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 5830f74..5d1fc8e 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -21,7 +21,6 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.graphics.GradientView;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.AllAppsScrim;
@@ -63,6 +62,7 @@
 
     private final Launcher mLauncher;
     private final boolean mIsDarkTheme;
+    private final boolean mIsVerticalLayout;
 
     // Animation in this class is controlled by a single variable {@link mProgress}.
     // Visually, it represents top y coordinate of the all apps container if multiplied with
@@ -83,6 +83,7 @@
         mProgress = 1f;
 
         mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
+        mIsVerticalLayout = mLauncher.getDeviceProfile().isVerticalBarLayout();
     }
 
     public float getShiftRange() {
@@ -95,18 +96,6 @@
         mAppsView.setVisibility(View.VISIBLE);
     }
 
-    private void updateLightStatusBar(float shift) {
-        // Use a light system UI (dark icons) if all apps is behind at least half of the status bar.
-        boolean forceChange = shift <= mShiftRange / 4;
-        if (forceChange) {
-            mLauncher.getSystemUiController().updateUiState(
-                    SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme);
-        } else {
-            mLauncher.getSystemUiController().updateUiState(
-                    SystemUiController.UI_STATE_ALL_APPS, 0);
-        }
-    }
-
     /**
      * 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.
@@ -124,24 +113,30 @@
         float alpha = 1 - workspaceHotseatAlpha;
         float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
 
-        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()) {
+        if (!mIsVerticalLayout) {
+            mAppsView.setAlpha(alpha);
             mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, hotseatTranslation,
                     hotseatAlpha);
-        } else {
-            mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y,
-                    PARALLAX_COEFFICIENT * hotseatTranslation, hotseatAlpha);
-        }
 
-        updateLightStatusBar(shiftCurrent);
+            // Use a light system UI (dark icons) if all apps is behind at least half of the
+            // status bar.
+            boolean forceChange = shiftCurrent <= mShiftRange / 4;
+            if (forceChange) {
+                mLauncher.getSystemUiController().updateUiState(
+                        SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme);
+            } else {
+                mLauncher.getSystemUiController().updateUiState(
+                        SystemUiController.UI_STATE_ALL_APPS, 0);
+            }
+
+        }
     }
 
     public float getProgress() {
@@ -154,7 +149,7 @@
      */
     @Override
     public void setState(LauncherState state) {
-        setProgress(state.verticalProgress);
+        setProgress(state.getVerticalProgress(mLauncher));
         onProgressAnimationEnd();
     }
 
@@ -165,15 +160,15 @@
     @Override
     public void setStateWithAnimation(LauncherState toState,
             AnimatorSetBuilder builder, AnimationConfig config) {
-        if (Float.compare(mProgress, toState.verticalProgress) == 0) {
+        float targetProgress = toState.getVerticalProgress(mLauncher);
+        if (Float.compare(mProgress, targetProgress) == 0) {
             // Fail fast
             onProgressAnimationEnd();
             return;
         }
 
         Interpolator interpolator = config.userControlled ? LINEAR : FAST_OUT_SLOW_IN;
-        ObjectAnimator anim = ObjectAnimator.ofFloat(
-                this, PROGRESS, mProgress, toState.verticalProgress);
+        ObjectAnimator anim = ObjectAnimator.ofFloat(this, PROGRESS, mProgress, targetProgress);
         anim.setDuration(config.duration);
         anim.setInterpolator(interpolator);
         anim.addListener(getProgressAnimatorListener());
@@ -221,6 +216,9 @@
         } else if (Float.compare(mProgress, 0f) == 0) {
             mHotseat.setVisibility(View.INVISIBLE);
             mAppsView.setVisibility(View.VISIBLE);
+        } else {
+            mAppsView.setVisibility(View.VISIBLE);
+            mHotseat.setVisibility(View.VISIBLE);
         }
     }
 }
diff --git a/src/com/android/launcher3/allapps/LandscapeFastScroller.java b/src/com/android/launcher3/allapps/LandscapeFastScroller.java
deleted file mode 100644
index cdde657..0000000
--- a/src/com/android/launcher3/allapps/LandscapeFastScroller.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.allapps;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-
-import com.android.launcher3.views.RecyclerViewFastScroller;
-
-/**
- * Extension of {@link RecyclerViewFastScroller} to be used in landscape layout.
- */
-public class LandscapeFastScroller extends RecyclerViewFastScroller {
-
-    public LandscapeFastScroller(Context context) {
-        super(context);
-    }
-
-    public LandscapeFastScroller(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public LandscapeFastScroller(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    public boolean handleTouchEvent(MotionEvent ev) {
-        // We handle our own touch event, no need to handle recycler view touch delegates.
-        return false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        event.offsetLocation(0, -mRv.getPaddingTop());
-        if (super.handleTouchEvent(event)) {
-            getParent().requestDisallowInterceptTouchEvent(true);
-        }
-        event.offsetLocation(0, mRv.getPaddingTop());
-        return true;
-    }
-
-    @Override
-    public boolean shouldBlockIntercept(int x, int y) {
-        // If the user touched the scroll bar area, block swipe
-        return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
-    }
-}
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
index 6df1ecb..fc20926 100644
--- a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
+++ b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
@@ -35,16 +35,43 @@
     private final RectF mDst = new RectF();
     public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
+    /**
+     * Draws the bitmap split into three parts horizontally, with the middle part having width
+     * as {@link #EXTENSION_PX} in the center of the bitmap.
+     */
     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;
+        draw3Patch(bitmap, canvas, left, right);
+    }
 
+
+    /**
+     * Draws the bitmap split horizontally into 3 parts (same as {@link #draw}) and split
+     * vertically into two parts, bottom part of size {@link #EXTENSION_PX} / 2 which is
+     * stretched vertically.
+     */
+    public void drawVerticallyStretched(Bitmap bitmap, Canvas canvas, float left, float top,
+            float right, float bottom) {
+        draw(bitmap, canvas, left, top, right);
+
+        // Draw bottom stretched region.
+        int height = bitmap.getHeight();
+        mSrc.top = height - EXTENSION_PX / 4;
+        mSrc.bottom = height;
+        mDst.top = top + height;
+        mDst.bottom = bottom;
+        draw3Patch(bitmap, canvas, left, right);
+    }
+
+
+
+    private void draw3Patch(Bitmap bitmap, Canvas canvas, float left, float right) {
+        int width = bitmap.getWidth();
         int halfWidth = width / 2;
 
         // Draw left edge
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index da656db..ddcd8ae 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -43,23 +43,28 @@
     private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500;
 
     public SpringLoadedState(int id) {
-        super(id, ContainerType.OVERVIEW, SPRING_LOADED_TRANSITION_MS, 1f, STATE_FLAGS);
+        super(id, ContainerType.OVERVIEW, SPRING_LOADED_TRANSITION_MS, STATE_FLAGS);
     }
 
     @Override
     public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
         DeviceProfile grid = launcher.getDeviceProfile();
         Workspace ws = launcher.getWorkspace();
-        if (grid.isVerticalBarLayout() || ws.getChildCount() == 0) {
+        if (ws.getChildCount() == 0) {
             return super.getWorkspaceScaleAndTranslation(launcher);
         }
 
+        if (grid.isVerticalBarLayout()) {
+            float scale = grid.workspaceSpringLoadShrinkFactor;
+            return new float[] {scale, 0, 0};
+        }
+
         float scale = grid.workspaceSpringLoadShrinkFactor;
         Rect insets = launcher.getDragLayer().getInsets();
 
         float scaledHeight = scale * ws.getNormalChildHeight();
         float shrunkTop = insets.top + grid.dropTargetBarSizePx;
-        float shrunkBottom = ws.getViewportHeight() - insets.bottom
+        float shrunkBottom = ws.getMeasuredHeight() - insets.bottom
                 - grid.getWorkspacePadding(null).bottom
                 - grid.workspaceSpringLoadedBottomSpace;
         float totalShrunkSpace = shrunkBottom - shrunkTop;
diff --git a/src/com/android/launcher3/views/AllAppsScrim.java b/src/com/android/launcher3/views/AllAppsScrim.java
index d1354ad..17ddae3 100644
--- a/src/com/android/launcher3/views/AllAppsScrim.java
+++ b/src/com/android/launcher3/views/AllAppsScrim.java
@@ -20,10 +20,13 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Rect;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.View;
 
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.dynamicui.WallpaperColorInfo;
@@ -33,7 +36,8 @@
 
 import static com.android.launcher3.graphics.NinePatchDrawHelper.EXTENSION_PX;
 
-public class AllAppsScrim extends View implements WallpaperColorInfo.OnChangeListener {
+public class AllAppsScrim extends View implements WallpaperColorInfo.OnChangeListener, Insettable,
+        DeviceProfile.LauncherLayoutChangeListener {
 
     private static final int MAX_ALPHA = 235;
     private static final int MIN_ALPHA_PORTRAIT = 100;
@@ -42,6 +46,9 @@
     protected final WallpaperColorInfo mWallpaperColorInfo;
     private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
+    private final Rect mPadding = new Rect();
+    private final Rect mInsets = new Rect();
+    private final DeviceProfile mGrid;
     private final float mRadius;
     private final int mMinAlpha;
     private final int mAlphaRange;
@@ -74,7 +81,8 @@
         mShadowBlur = getResources().getDimension(R.dimen.all_apps_scrim_blur);
 
         Launcher launcher = Launcher.getLauncher(context);
-        mFillAlpha = mMinAlpha = launcher.getDeviceProfile().isVerticalBarLayout()
+        mGrid = launcher.getDeviceProfile();
+        mFillAlpha = mMinAlpha = mGrid.isVerticalBarLayout()
                 ? MIN_ALPHA_LANDSCAPE : MIN_ALPHA_PORTRAIT;
         mAlphaRange = MAX_ALPHA - mMinAlpha;
         mShadowBitmap = generateShadowBitmap();
@@ -90,11 +98,12 @@
         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;
+        int bitmapWidth = 2 * Math.round(curveBot) + EXTENSION_PX;
+        int bitmapHeight = bitmapWidth / 2;
         Bitmap result = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
 
-        builder.bounds.set(0, mShadowBlur, bitmapWidth, 2 * curveBot + EXTENSION_PX);
+        float fullSize = 2 * curveBot + EXTENSION_PX - mShadowBlur;
+        builder.bounds.set(mShadowBlur, mShadowBlur, fullSize, fullSize);
         builder.drawShadow(new Canvas(result));
         return result;
     }
@@ -103,12 +112,15 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mWallpaperColorInfo.addOnChangeListener(this);
+        mGrid.addLauncherLayoutChangedListener(this);
+        onLauncherLayoutChanged();
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mWallpaperColorInfo.removeOnChangeListener(this);
+        mGrid.removeLauncherLayoutChangedListener(this);
     }
 
     @Override
@@ -126,10 +138,20 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        float edgeTop = getHeight() + mTranslateY - mDrawHeight;
+        float edgeTop = getHeight() + mTranslateY - mDrawHeight + mPadding.top;
+        float edgeRight = getWidth() - mPadding.right;
 
-        mShadowHelper.draw(mShadowBitmap, canvas, 0, edgeTop - mShadowBlur, getWidth());
-        canvas.drawRoundRect(0, edgeTop, getWidth(),
+        if (mPadding.left > 0 || mPadding.right > 0) {
+            mShadowHelper.drawVerticallyStretched(mShadowBitmap, canvas,
+                    mPadding.left - mShadowBlur,
+                    edgeTop - mShadowBlur,
+                    edgeRight + mShadowBlur,
+                    getHeight());
+        } else {
+            mShadowHelper.draw(mShadowBitmap, canvas, mPadding.left - mShadowBlur,
+                    edgeTop - mShadowBlur, edgeRight + mShadowBlur);
+        }
+        canvas.drawRoundRect(mPadding.left, edgeTop, edgeRight,
                 getHeight() + mRadius, mRadius, mRadius, mFillPaint);
     }
 
@@ -145,4 +167,23 @@
     public void setDrawRegion(float height) {
         mDrawHeight = height;
     }
+
+    @Override
+    public void setInsets(Rect insets) {
+        mInsets.set(insets);
+        onLauncherLayoutChanged();
+    }
+
+    @Override
+    public void onLauncherLayoutChanged() {
+        if (!mGrid.isVerticalBarLayout()) {
+            return;
+        }
+        mGrid.getWorkspacePadding(mPadding);
+        mPadding.bottom = 0;
+        mPadding.left += mInsets.left;
+        mPadding.top = mInsets.top;
+        mPadding.right += mInsets.right;
+        invalidate();
+    }
 }