Merge "Use the shortcut's long label in the container, if it is available." into ub-launcher3-calgary
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 27ff789..632aff0 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -60,6 +60,12 @@
             android:layout_height="@dimen/dynamic_grid_page_indicator_height"
             android:layout_gravity="bottom|left"/>
 
+        <!-- A place holder view instead of the QSB in transposed layout -->
+        <View
+            android:layout_width="0dp"
+            android:layout_height="10dp"
+            android:id="@+id/workspace_blocked_row" />
+
         <include layout="@layout/widgets_view"
             android:id="@+id/widgets_view"
             android:layout_width="match_parent"
@@ -71,6 +77,7 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
+
     </com.android.launcher3.dragndrop.DragLayer>
 
 </com.android.launcher3.LauncherRootView>
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 6b5bf63..0321631 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -37,6 +37,7 @@
             android:id="@+id/workspace"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_gravity="center"
             launcher:pageIndicator="@+id/page_indicator">
         </com.android.launcher3.Workspace>
 
@@ -61,6 +62,10 @@
             android:id="@+id/drop_target_bar"
             layout="@layout/drop_target_bar_horz" />
 
+        <include
+            layout="@layout/qsb_container"
+            android:id="@+id/qsb_container" />
+
         <include layout="@layout/widgets_view"
             android:id="@+id/widgets_view"
             android:layout_width="match_parent"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 33ad323..86544d3 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -33,6 +33,7 @@
         <!-- The workspace contains 5 screens of cells -->
         <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
+            android:layout_gravity="center"
             android:id="@+id/workspace"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
@@ -60,6 +61,10 @@
             android:layout_width="match_parent"
             android:layout_height="@dimen/dynamic_grid_page_indicator_height" />
 
+        <include
+            layout="@layout/qsb_container"
+            android:id="@+id/qsb_container" />
+
         <include layout="@layout/widgets_view"
             android:id="@+id/widgets_view"
             android:layout_width="match_parent"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index d55fda7..c4c6aab 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -31,7 +31,6 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center"
-        android:elevation="2dp"
         android:focusable="false"
         android:visibility="invisible" />
 
@@ -41,7 +40,6 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="center"
-        android:elevation="15dp"
         android:focusable="true"
         android:focusableInTouchMode="true"
         android:saveEnabled="false"
diff --git a/res/layout/qsb_container.xml b/res/layout/qsb_container.xml
index 55c7390..b75e3b5 100644
--- a/res/layout/qsb_container.xml
+++ b/res/layout/qsb_container.xml
@@ -18,7 +18,7 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:orientation="vertical"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="0dp"
         android:id="@+id/qsb_container"
         android:padding="0dp" >
 
diff --git a/res/values/config.xml b/res/values/config.xml
index f69fb2e..0bb3799 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -74,6 +74,9 @@
     <!-- View ID to use for QSB widget -->
     <item type="id" name="qsb_widget" />
 
+    <!-- View ID to use for blocked area on the first screen -->
+    <item type="id" name="workspace_blocked_row" />
+
     <!-- View ID used by cell layout to jail its content -->
     <item type="id" name="cell_layout_jail_id" />
 
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 6755ff7..9030dae 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -918,10 +918,6 @@
                 bottom + mTempRect.bottom);
     }
 
-    public Rect getBackgroundBounds() {
-        return mBackground.getBounds();
-    }
-
     /**
      * Returns the amount of space left over after subtracting padding and cells. This space will be
      * very small, a few pixels at most, and is a result of rounding down when calculating the cell
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 72bb343..2b130e5 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -296,7 +296,7 @@
     }
 
     public Point getTotalWorkspacePadding() {
-        Rect padding = getWorkspacePadding();
+        Rect padding = getWorkspacePadding(null);
         return new Point(padding.left + padding.right, padding.top + padding.bottom);
     }
 
@@ -306,8 +306,8 @@
      * this value is not reliable.
      * Use {@link #getTotalWorkspacePadding()} instead.
      */
-    public Rect getWorkspacePadding() {
-        Rect padding = new Rect();
+    public Rect getWorkspacePadding(Rect recycle) {
+        Rect padding = recycle == null ? new Rect() : recycle;
         if (isVerticalBarLayout()) {
             // in case of isVerticalBarLayout, the hotseat is always on the right and the drop
             // target bar is on the left, independent of the layout direction.
@@ -348,7 +348,7 @@
             // In portrait, we want the pages spaced such that there is no
             // overhang of the previous / next page into the current page viewport.
             // We assume symmetrical padding in portrait mode.
-            return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding().left);
+            return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding(null).left);
         }
     }
 
@@ -405,13 +405,15 @@
 
         // Layout the workspace
         PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
-        lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
-        lp.gravity = Gravity.CENTER;
-        Rect padding = getWorkspacePadding();
-        workspace.setLayoutParams(lp);
+        Rect padding = getWorkspacePadding(null);
         workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
         workspace.setPageSpacing(getWorkspacePageSpacing());
 
+        View qsbContainer = launcher.getQsbContainer();
+        lp = (FrameLayout.LayoutParams) qsbContainer.getLayoutParams();
+        lp.topMargin = padding.top;
+        qsbContainer.setLayoutParams(lp);
+
         // Layout the hotseat
         View hotseat = launcher.findViewById(R.id.hotseat);
         lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 717b059..b7f033e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -235,6 +235,7 @@
     private View mLauncherView;
     @Thunk DragLayer mDragLayer;
     private DragController mDragController;
+    private View mQsbContainer;
 
     public View mWeightWatcher;
 
@@ -1333,6 +1334,8 @@
         mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
         mFocusHandler = mDragLayer.getFocusIndicatorHelper();
         mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
+        mQsbContainer = mDragLayer.findViewById(mDeviceProfile.isVerticalBarLayout()
+                ? R.id.workspace_blocked_row : R.id.qsb_container);
         mWorkspace.initParentViews(mDragLayer);
 
         mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -1783,6 +1786,10 @@
         return mWorkspace;
     }
 
+    public View getQsbContainer() {
+        return mQsbContainer;
+    }
+
     public Hotseat getHotseat() {
         return mHotseat;
     }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 7c8bfab..ed1079f 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -30,7 +30,6 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews;
 
-import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
 
 import java.util.ArrayList;
@@ -47,7 +46,6 @@
     private Context mContext;
     @ViewDebug.ExportedProperty(category = "launcher")
     private int mPreviousOrientation;
-    private DragLayer mDragLayer;
 
     private float mSlop;
 
@@ -62,9 +60,7 @@
         mLongPressHelper = new CheckLongPressHelper(this);
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mDragLayer = Launcher.getLauncher(context).getDragLayer();
         setAccessibilityDelegate(Launcher.getLauncher(context).getAccessibilityDelegate());
-
         setBackgroundResource(R.drawable.widget_internal_focus_bg);
     }
 
@@ -117,7 +113,7 @@
                 if (!mStylusEventHelper.inStylusButtonPressed()) {
                     mLongPressHelper.postCheckForLongPress();
                 }
-                mDragLayer.setTouchCompleteListener(this);
+                Launcher.getLauncher(getContext()).getDragLayer().setTouchCompleteListener(this);
                 break;
             }
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index a37fe5b..2758a7c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -145,9 +145,6 @@
 
     protected int mActivePointerId = INVALID_POINTER;
 
-    // If true, modify alpha of neighboring pages as user scrolls left/right
-    protected boolean mFadeInAdjacentScreens = false;
-
     protected boolean mIsPageMoving = false;
 
     protected boolean mWasInOverscroll = false;
@@ -756,10 +753,6 @@
 
                     childWidth = getViewportWidth() - horizontalPadding
                             - mInsets.left - mInsets.right;
-
-                    if (lp.matchStartEdge) {
-                        childWidth += getPaddingStart();
-                    }
                     childHeight = getViewportHeight() - verticalPadding
                             - mInsets.top - mInsets.bottom;
                     mNormalChildHeight = childHeight;
@@ -809,8 +802,7 @@
         LayoutParams lp = (LayoutParams) getChildAt(startIndex).getLayoutParams();
         LayoutParams nextLp;
 
-        int childLeft = offsetX +
-                ((lp.isFullScreenPage || (!mIsRtl && lp.matchStartEdge)) ? 0 : getPaddingLeft());
+        int childLeft = offsetX + (lp.isFullScreenPage ? 0 : getPaddingLeft());
         if (mPageScrolls == null || childCount != mChildCountOnLastLayout) {
             mPageScrolls = new int[childCount];
         }
@@ -834,8 +826,7 @@
                 child.layout(childLeft, childTop,
                         childLeft + child.getMeasuredWidth(), childTop + childHeight);
 
-                int scrollOffsetLeft = (lp.isFullScreenPage || (!mIsRtl & lp.matchStartEdge)) ?
-                        0 : getPaddingLeft();
+                int scrollOffsetLeft = lp.isFullScreenPage ? 0 : getPaddingLeft();
                 mPageScrolls[i] = childLeft - scrollOffsetLeft - offsetX;
 
                 int pageGap = mPageSpacing;
diff --git a/src/com/android/launcher3/PinchAnimationManager.java b/src/com/android/launcher3/PinchAnimationManager.java
index c1c2519..3807945 100644
--- a/src/com/android/launcher3/PinchAnimationManager.java
+++ b/src/com/android/launcher3/PinchAnimationManager.java
@@ -51,8 +51,8 @@
     private static final int THRESHOLD_ANIM_DURATION = 150;
     private static final LinearInterpolator INTERPOLATOR = new LinearInterpolator();
 
-    private static final int INDEX_PAGE_INDICATOR = 0;
-    private static final int INDEX_HOTSEAT = 1;
+    private static final int INDEX_HOTSEAT = 0;
+    private static final int INDEX_QSB = 1;
     private static final int INDEX_OVERVIEW_PANEL_BUTTONS = 2;
     private static final int INDEX_SCRIM = 3;
 
@@ -189,11 +189,10 @@
     }
 
     private void animateHotseatAndPageIndicator(boolean show) {
-        animateShowHideView(INDEX_HOTSEAT, mLauncher.getHotseat(), show);
-        if (mWorkspace.getPageIndicator() != null) {
-            // There aren't page indicators in landscape mode on phones, hence the null check.
-            animateShowHideView(INDEX_PAGE_INDICATOR, mWorkspace.getPageIndicator(), show);
-        }
+        startAnimator(INDEX_HOTSEAT,
+                mWorkspace.createHotseatAlphaAnimator(show ? 1 : 0), THRESHOLD_ANIM_DURATION);
+        startAnimator(INDEX_QSB, mWorkspace.mQsbAlphaController.animateAlphaAtIndex(
+                show ? 1 : 0, Workspace.QSB_ALPHA_INDEX_STATE_CHANGE), THRESHOLD_ANIM_DURATION);
     }
 
     private void animateOverviewPanelButtons(boolean show) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 1b3f5df..8d46719 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -53,9 +53,11 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
+import android.widget.Space;
 import android.widget.TextView;
 
 import com.android.launcher3.Launcher.CustomContentCallbacks;
@@ -82,6 +84,7 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.MultiStateAlphaController;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -227,6 +230,12 @@
      */
     private float[] mHotseatAlpha = new float[] {1, 1, 1};
 
+    public static final int QSB_ALPHA_INDEX_STATE_CHANGE = 0;
+    public static final int QSB_ALPHA_INDEX_Y_TRANSLATION = 1;
+    public static final int QSB_ALPHA_INDEX_PAGE_SCROLL = 2;
+
+    MultiStateAlphaController mQsbAlphaController;
+
     @ViewDebug.ExportedProperty(category = "launcher")
     private State mState = State.NORMAL;
     private boolean mIsSwitchingState = false;
@@ -305,6 +314,7 @@
     private boolean mForceDrawAdjacentPages = false;
     // Total over scrollX in the overlay direction.
     private float mOverlayTranslation;
+    private int mFirstPageScrollX;
 
     // Handles workspace state transitions
     private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
@@ -339,7 +349,6 @@
         final Resources res = getResources();
         DeviceProfile grid = mLauncher.getDeviceProfile();
         mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
-        mFadeInAdjacentScreens = false;
         mWallpaperManager = WallpaperManager.getInstance(context);
 
         mWallpaperOffset = new WallpaperOffsetInterpolator(this);
@@ -484,6 +493,7 @@
     public void initParentViews(View parent) {
         super.initParentViews(parent);
         mPageIndicator.setAccessibilityDelegate(new OverviewAccessibilityDelegate());
+        mQsbAlphaController = new MultiStateAlphaController(mLauncher.getQsbContainer(), 3);
     }
 
     private int getDefaultPage() {
@@ -548,6 +558,11 @@
         return mTouchState != TOUCH_STATE_REST;
     }
 
+    private int getEmbeddedQsbId() {
+        return mLauncher.getDeviceProfile().isVerticalBarLayout()
+                ? R.id.qsb_container : R.id.workspace_blocked_row;
+    }
+
     /**
      * Initializes and binds the first page
      * @param qsb an exisitng qsb to recycle or null.
@@ -559,31 +574,45 @@
         // Add the first page
         CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
 
-        if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            // Let the cell layout extend the start padding. On transposed layout, there is page
-            // indicator on left and hotseat on right, as such workspace does not touch the edge.
-            ((LayoutParams) firstPage.getLayoutParams()).matchStartEdge = true;
-            firstPage.setPaddingRelative(getPaddingStart(), 0, 0, 0);
-        }
-
+        // Always add a QSB on the first screen.
         if (qsb == null) {
-            // Always add a QSB on the first screen.
-            qsb = mLauncher.getLayoutInflater().inflate(R.layout.qsb_container,
-                    firstPage, false);
+            // In transposed layout, we add the QSB in the Grid. As workspace does not touch the
+            // edges, we do not need a full width QSB.
+            if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+                qsb = mLauncher.getLayoutInflater().inflate(R.layout.qsb_container, firstPage, false);
+            } else {
+                qsb = new Space(getContext());
+            }
         }
 
-        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) qsb.getLayoutParams();
-        lp.cellX = 0;
-        lp.cellY = 0;
-        lp.cellHSpan = firstPage.getCountX();
-        lp.cellVSpan = 1;
+        CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1);
         lp.canReorder = false;
-
-        if (!firstPage.addViewToCellLayout(qsb, 0, R.id.qsb_container, lp, true)) {
+        if (!firstPage.addViewToCellLayout(qsb, 0, getEmbeddedQsbId(), lp, true)) {
             Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
         }
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        // Update the QSB to match the cell height. This is treating the QSB essentially as a child
+        // of workspace despite that it's not a true child.
+        // Note that it relies on the strict ordering of measuring the workspace before the QSB
+        // at the dragLayer level.
+        if (getChildCount() > 0) {
+            CellLayout firstPage = (CellLayout) getChildAt(0);
+            int cellHeight = firstPage.getCellHeight();
+
+            View qsbContainer = mLauncher.getQsbContainer();
+            ViewGroup.LayoutParams lp = qsbContainer.getLayoutParams();
+            if (cellHeight > 0 && lp.height != cellHeight) {
+                lp.height = cellHeight;
+            }
+            qsbContainer.setLayoutParams(lp);
+        }
+    }
+
     public void removeAllWorkspaceScreens() {
         // Disable all layout transitions before removing all pages to ensure that we don't get the
         // transition animations competing with us changing the scroll when we add pages or the
@@ -597,7 +626,7 @@
         }
 
         // Recycle the QSB widget
-        View qsb = findViewById(R.id.qsb_container);
+        View qsb = findViewById(getEmbeddedQsbId());
         if (qsb != null) {
             ((ViewGroup) qsb.getParent()).removeView(qsb);
         }
@@ -1366,9 +1395,15 @@
         super.scrollTo(x, y);
     }
 
+    private void onWorkspaceOverallScrollChanged() {
+        mLauncher.getQsbContainer().setTranslationX(
+                mOverlayTranslation + mFirstPageScrollX - getScrollX());
+    }
+
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
+        onWorkspaceOverallScrollChanged();
 
         // Update the page indicator progress.
         boolean isTransitioning = mIsSwitchingState
@@ -1438,6 +1473,19 @@
         // device I've tried, translating the launcher causes things to get quite laggy.
         setWorkspaceTranslationAndAlpha(Direction.X, transX, alpha);
         setHotseatTranslationAndAlpha(Direction.X, transX, alpha);
+        onWorkspaceOverallScrollChanged();
+    }
+
+    /**
+     * Moves the workspace UI in the Y direction.
+     * @param translation the amount of shift.
+     * @param alpha the alpha for the workspace page
+     */
+    public void setWorkspaceYTranslationAndAlpha(float translation, float alpha) {
+        setWorkspaceTranslationAndAlpha(Direction.Y, translation, alpha);
+
+        mLauncher.getQsbContainer().setTranslationY(translation);
+        mQsbAlphaController.setAlphaAtIndex(alpha, QSB_ALPHA_INDEX_Y_TRANSLATION);
     }
 
     /**
@@ -1446,7 +1494,7 @@
      * @param translation the amount of shift.
      * @param alpha the alpha for the workspace page
      */
-    public void setWorkspaceTranslationAndAlpha(Direction direction, float translation, float alpha) {
+    private void setWorkspaceTranslationAndAlpha(Direction direction, float translation, float alpha) {
         Property<View, Float> property = direction.viewProperty;
         mPageAlpha[direction.ordinal()] = alpha;
         float finalAlpha = mPageAlpha[0] * mPageAlpha[1];
@@ -1630,6 +1678,10 @@
                     float scrollProgress = getScrollProgress(screenCenter, child, i);
                     float alpha = 1 - Math.abs(scrollProgress);
                     child.getShortcutsAndWidgets().setAlpha(alpha);
+
+                    if (isQsbContainerPage(i)) {
+                        mQsbAlphaController.setAlphaAtIndex(alpha, QSB_ALPHA_INDEX_PAGE_SCROLL);
+                    }
                 }
             }
         }
@@ -1751,6 +1803,8 @@
             mWallpaperOffset.jumpToFinal();
         }
         super.onLayout(changed, left, top, right, bottom);
+        mFirstPageScrollX = getScrollForPage(0);
+        onWorkspaceOverallScrollChanged();
     }
 
     @Override
@@ -2027,10 +2081,10 @@
 
     int getOverviewModeTranslationY() {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        Rect workspacePadding = grid.getWorkspacePadding();
         int overviewButtonBarHeight = grid.getOverviewModeButtonBarHeight();
 
         int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight());
+        Rect workspacePadding = grid.getWorkspacePadding(sTempRect);
         int workspaceTop = mInsets.top + workspacePadding.top;
         int workspaceBottom = getViewportHeight() - mInsets.bottom - workspacePadding.bottom;
         int overviewTop = mInsets.top;
@@ -2045,12 +2099,12 @@
         if (grid.isVerticalBarLayout() || getChildCount() == 0) {
             return 0;
         }
-        Rect workspacePadding = grid.getWorkspacePadding();
 
         float scaledHeight = grid.workspaceSpringLoadShrinkFactor * getNormalChildHeight();
         float shrunkTop = mInsets.top + grid.dropTargetBarSizePx;
         float shrunkBottom = getViewportHeight() - mInsets.bottom
-                - workspacePadding.bottom - grid.workspaceSpringLoadedBottomSpace;
+                - grid.getWorkspacePadding(sTempRect).bottom
+                - grid.workspaceSpringLoadedBottomSpace;
         float totalShrunkSpace = shrunkBottom - shrunkTop;
 
         float desiredCellTop = shrunkTop + (totalShrunkSpace - scaledHeight) / 2;
@@ -4523,4 +4577,8 @@
          */
         void prepareStateChange(State toState, AnimatorSet targetAnim);
     }
+
+    public static final boolean isQsbContainerPage(int pageNo) {
+        return pageNo == 0;
+    }
 }
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index a73f3ec..c2631b0 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -276,6 +276,8 @@
         float finalHotseatAlpha = (states.stateIsNormal || states.stateIsSpringLoaded ||
                 (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f;
         float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f;
+        float finalQsbAlpha = (states.stateIsNormal ||
+                (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f;
 
         float finalWorkspaceTranslationY = 0;
         if (states.stateIsOverview || states.stateIsOverviewHidden) {
@@ -355,9 +357,28 @@
                 cl.setBackgroundAlpha(finalBackgroundAlpha);
                 cl.setShortcutAndWidgetAlpha(finalAlpha);
             }
+
+            if (Workspace.isQsbContainerPage(i)) {
+                if (animated) {
+                    Animator anim = mWorkspace.mQsbAlphaController
+                            .animateAlphaAtIndex(finalAlpha, Workspace.QSB_ALPHA_INDEX_PAGE_SCROLL);
+                    anim.setDuration(duration);
+                    anim.setInterpolator(mZoomInInterpolator);
+                    mStateAnimator.play(anim);
+                } else {
+                    mWorkspace.mQsbAlphaController.setAlphaAtIndex(
+                            finalAlpha, Workspace.QSB_ALPHA_INDEX_PAGE_SCROLL);
+                }
+            }
         }
 
         final ViewGroup overviewPanel = mLauncher.getOverviewPanel();
+
+        final View qsbContainer = mLauncher.getQsbContainer();
+
+        Animator qsbAlphaAnimation = mWorkspace.mQsbAlphaController
+                .animateAlphaAtIndex(finalQsbAlpha, Workspace.QSB_ALPHA_INDEX_STATE_CHANGE);
+
         if (animated) {
             LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(mWorkspace);
             scale.scaleX(mNewScale)
@@ -376,10 +397,13 @@
             // For animation optimations, we may need to provide the Launcher transition
             // with a set of views on which to force build layers in certain scenarios.
             overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            qsbContainer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
             if (layerViews != null) {
                 // If layerViews is not null, we add these views, and indicate that
                 // the caller can manage layer state.
                 layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+                layerViews.put(qsbContainer, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+
                 layerViews.put(mLauncher.getHotseat(),
                         LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
                 layerViews.put(mWorkspace.getPageIndicator(),
@@ -399,9 +423,11 @@
 
             overviewPanelAlpha.setDuration(duration);
             hotseatAlpha.setDuration(duration);
+            qsbAlphaAnimation.setDuration(duration);
 
             mStateAnimator.play(overviewPanelAlpha);
             mStateAnimator.play(hotseatAlpha);
+            mStateAnimator.play(qsbAlphaAnimation);
             mStateAnimator.addListener(new AnimatorListenerAdapter() {
                 boolean canceled = false;
                 @Override
@@ -422,6 +448,8 @@
         } else {
             overviewPanel.setAlpha(finalOverviewPanelAlpha);
             AlphaUpdateListener.updateVisibility(overviewPanel, accessibilityEnabled);
+
+            qsbAlphaAnimation.end();
             mWorkspace.createHotseatAlphaAnimator(finalHotseatAlpha).end();
             mWorkspace.updateCustomContentVisibility();
             mWorkspace.setScaleX(mNewScale);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 028f065..e7108a1 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -291,7 +291,7 @@
                 mDecelInterpolator.getInterpolation(alpha))));
         mAppsView.getContentView().setAlpha(alpha);
         mAppsView.setTranslationY(progress);
-        mWorkspace.setWorkspaceTranslationAndAlpha(Direction.Y,
+        mWorkspace.setWorkspaceYTranslationAndAlpha(
                 PARALLAX_COEFFICIENT * (-mShiftRange + progress),
                 mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
         if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 82b5dd3..5f8faab 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -747,13 +747,14 @@
      *        location doesn't account for scaling, and so should be centered about the desired
      *        final location (including scaling).
      * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
-     * @param finalScale The final scale of the view. The view is scaled about its center.
+     * @param finalScaleX The final scale of the view. The view is scaled about its center.
+     * @param finalScaleY The final scale of the view. The view is scaled about its center.
      * @param duration The duration of the animation.
      * @param motionInterpolator The interpolator to use for the location of the view.
      * @param alphaInterpolator The interpolator to use for the alpha of the view.
      * @param onCompleteRunnable Optional runnable to run on animation completion.
-     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
-     *        the runnable will execute after the view is faded out.
+     * @param animationEndStyle Whether or not to fade out the view once the animation completes.
+     *        {@link #ANIMATION_END_DISAPPEAR} or {@link #ANIMATION_END_REMAIN_VISIBLE}.
      * @param anchorView If not null, this represents the view which the animated view stays
      *        anchored to in case scrolling is currently taking place. Note: currently this is
      *        only used for the X dimension for the case of the workspace.
@@ -988,12 +989,7 @@
             canvas.save();
             if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
                 // Cut a hole in the darkening scrim on the page that should be highlighted, if any.
-                float scale = getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
-                Rect backBounds = currCellLayout.getBackgroundBounds();
-                mHighlightRect.left += (int) (backBounds.left * scale);
-                mHighlightRect.top += (int) (backBounds.top * scale);
-                mHighlightRect.right = (int) (mHighlightRect.left + backBounds.width() * scale);
-                mHighlightRect.bottom = (int) (mHighlightRect.top + backBounds.height() * scale);
+                getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
                 canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
             }
             canvas.drawColor((alpha << 24) | SCRIM_COLOR);
diff --git a/src/com/android/launcher3/util/MultiStateAlphaController.java b/src/com/android/launcher3/util/MultiStateAlphaController.java
new file mode 100644
index 0000000..df73bfd
--- /dev/null
+++ b/src/com/android/launcher3/util/MultiStateAlphaController.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+import java.util.Arrays;
+
+/**
+ * A utility class which divides the alpha for a view across multiple states.
+ */
+public class MultiStateAlphaController {
+
+    private final View mTargetView;
+    private final float[] mAlphas;
+    private final AccessibilityManager mAm;
+
+    public MultiStateAlphaController(View view, int stateCount) {
+        mTargetView = view;
+        mAlphas = new float[stateCount];
+        Arrays.fill(mAlphas, 1);
+
+        mAm = (AccessibilityManager) view.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+    }
+
+    public void setAlphaAtIndex(float alpha, int index) {
+        mAlphas[index] = alpha;
+        float finalAlpha = 1;
+        for (float a : mAlphas) {
+            finalAlpha = finalAlpha * a;
+        }
+        mTargetView.setAlpha(finalAlpha);
+        mTargetView.setVisibility(alpha > 0 ? View.VISIBLE
+                : (mAm.isEnabled() ? View.GONE : View.INVISIBLE));
+    }
+
+    public Animator animateAlphaAtIndex(float finalAlpha, final int index) {
+        if (Float.compare(finalAlpha, mAlphas[index]) == 0) {
+            // Return a dummy animator to avoid null checks.
+            return ValueAnimator.ofFloat(0, 0);
+        } else {
+            ValueAnimator animator = ValueAnimator.ofFloat(mAlphas[index], finalAlpha);
+            animator.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                    float value = (Float) valueAnimator.getAnimatedValue();
+                    setAlphaAtIndex(value, index);
+                }
+            });
+            return animator;
+        }
+    }
+}