Initial changes to tweak layout.

- Adding DeviceProfile callback for when the launcher layout changes due
  to insets.  This is necessary since there are now different layouts
  depending on which side the navigation bar is on
- Consolidating hotseat and other layout into the device profile 
  launcher layout logic
- Making the all apps icons match the workspace icon height
- Tweaking caret drawable to draw to the bounds specified to simplify
  layout in each orientation
- Fixing minor issue with page indicator shifting in landscape
- Centering overview buttons to the workspace page

Bug: 30021487
Change-Id: I1866bce00b2948f3edd06168c0f88d81207e3f13
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 632aff0..5c1fec7 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -44,7 +44,8 @@
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_gravity="right" />
+            android:layout_gravity="right"
+            launcher:layout_ignoreInsets="true" />
 
         <include
             android:id="@+id/drop_target_bar"
@@ -56,7 +57,7 @@
 
         <com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
             android:id="@+id/page_indicator"
-            android:layout_width="48dp"
+            android:layout_width="@dimen/dynamic_grid_page_indicator_height"
             android:layout_height="@dimen/dynamic_grid_page_indicator_height"
             android:layout_gravity="bottom|left"/>
 
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 0321631..b394fa8 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -45,7 +45,8 @@
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            launcher:layout_ignoreInsets="true" />
 
         <include layout="@layout/overview_panel"
             android:id="@+id/overview_panel"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 86544d3..b59c715 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -44,7 +44,8 @@
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            launcher:layout_ignoreInsets="true" />
 
         <include
             android:id="@+id/drop_target_bar"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 12a4029..03c8d82 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -22,8 +22,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
-    android:paddingBottom="@dimen/container_bounds_inset"
-    android:paddingTop="@dimen/container_bounds_inset"
     launcher:revealBackground="@drawable/quantum_panel_shape">
 
     <View
@@ -62,12 +60,10 @@
             android:layout_width="match_parent"
             android:layout_height="@dimen/all_apps_search_bar_height"
             android:layout_gravity="center|top"
-            android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
-            android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
+            android:paddingTop="@dimen/all_apps_search_bar_margin_top"
             android:gravity="center|bottom"
             android:orientation="horizontal"
-            android:saveEnabled="false"
-            android:paddingTop="@dimen/all_apps_search_bar_margin_top" >
+            android:saveEnabled="false">
 
             <TextView
                 android:layout_width="wrap_content"
diff --git a/res/layout/all_apps_icon.xml b/res/layout/all_apps_icon.xml
index 3836fed..3d4bef7 100644
--- a/res/layout/all_apps_icon.xml
+++ b/res/layout/all_apps_icon.xml
@@ -21,8 +21,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
-    android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
-    android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
     android:focusable="true"
-    launcher:iconDisplay="all_apps" />
+    launcher:iconDisplay="all_apps"
+    launcher:centerVertically="true" />
 
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index 74f7ca1..c4431be 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -22,8 +22,6 @@
     android:id="@+id/widgets_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="@dimen/container_bounds_inset"
-    android:paddingBottom="@dimen/container_bounds_inset"
     android:descendantFocusability="afterDescendants"
     launcher:revealBackground="@drawable/quantum_panel_shape_dark"
     android:theme="@style/WidgetContainerTheme">
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index 1f97d24..0000000
--- a/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<resources>
-<!-- Container -->
-    <dimen name="container_max_width">736dp</dimen>
-</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 85a436c..2838088 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -15,21 +15,15 @@
 -->
 
 <resources>
-<!-- Container -->
-    <dimen name="container_min_margin">16dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
     <dimen name="all_apps_grid_section_text_size">26sp</dimen>
-    <dimen name="all_apps_icon_top_bottom_padding">12dp</dimen>
     <dimen name="all_apps_background_canvas_width">850dp</dimen>
     <dimen name="all_apps_background_canvas_height">525dp</dimen>
-    <dimen name="all_apps_icon_width_gap">36dp</dimen>
 
 <!-- Widget tray -->
     <dimen name="widget_section_indent">56dp</dimen>
 
-
 <!-- DragController -->
     <dimen name="drag_flingToDeleteMinVelocity">-1000dp</dimen>
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index c2d20a3..358d9b6 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -18,7 +18,6 @@
 <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">8dp</dimen>
     <dimen name="all_apps_search_bar_height">54dp</dimen>
-    <dimen name="all_apps_icon_top_bottom_padding">14dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">64dp</dimen>
     <dimen name="all_apps_empty_search_bg_top_offset">180dp</dimen>
 
diff --git a/res/values-sw768dp-port/dimens.xml b/res/values-sw768dp-port/dimens.xml
deleted file mode 100644
index 6fb2bf6..0000000
--- a/res/values-sw768dp-port/dimens.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<resources>
-<!-- Container -->
-    <dimen name="container_max_width">736dp</dimen>
-</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 308c71c..3cfaf02 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -29,6 +29,7 @@
         </attr>
         <attr name="deferShadowGeneration" format="boolean" />
         <attr name="customShadows" format="boolean" />
+        <attr name="centerVertically" format="boolean" />
     </declare-styleable>
 
     <!-- PagedView specific attributes. These attributes are used to customize
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 8b02e5a..cbbafac 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,20 +16,26 @@
 
 <resources>
 <!-- Dynamic Grid -->
-    <dimen name="dynamic_grid_edge_margin">6dp</dimen>
-    <dimen name="dynamic_grid_page_indicator_height">24dp</dimen>
+    <dimen name="dynamic_grid_edge_margin">8dp</dimen>
+    <dimen name="dynamic_grid_page_indicator_height">28dp</dimen>
     <dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
     <dimen name="dynamic_grid_page_indicator_extra_touch_height">12dp</dimen>
-    <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
-    <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
+    <dimen name="dynamic_grid_page_indicator_gutter_width_left_nav_bar">38dp</dimen>
+    <dimen name="dynamic_grid_page_indicator_gutter_width_right_nav_bar">48dp</dimen>
+    <dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
     <dimen name="dynamic_grid_overview_min_icon_zone_height">80dp</dimen>
     <dimen name="dynamic_grid_overview_max_icon_zone_height">120dp</dimen>
     <dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
-    <dimen name="dynamic_grid_overview_bar_spacer_width">20dp</dimen>
-
+    <dimen name="dynamic_grid_overview_bar_spacer_width">25dp</dimen>
+    <dimen name="dynamic_grid_hotseat_height">88dp</dimen>
+    <dimen name="dynamic_grid_hotseat_top_padding">12dp</dimen>
+    <dimen name="dynamic_grid_hotseat_gutter_width">24dp</dimen>
     <dimen name="dynamic_grid_workspace_top_padding">12dp</dimen>
+    <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
     <!-- Minimum space between workspace and hotseat in spring loaded mode -->
     <dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
+    <dimen name="dynamic_grid_container_land_left_padding">118dp</dimen>
+    <dimen name="dynamic_grid_container_land_right_padding">66dp</dimen>
 
 <!-- Drop target bar -->
     <dimen name="dynamic_grid_drop_target_size">48dp</dimen>
@@ -54,28 +60,23 @@
     <dimen name="container_fastscroll_popup_size">72dp</dimen>
     <dimen name="container_fastscroll_popup_text_size">48dp</dimen>
 
-    <item name="container_margin" format="fraction" type="fraction">0%</item>
-    <dimen name="container_min_margin">8dp</dimen>
-    <dimen name="container_max_width">0dp</dimen>
-
 <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">0dp</dimen>
     <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
     <dimen name="all_apps_grid_section_y_offset">8dp</dimen>
     <dimen name="all_apps_grid_section_text_size">24sp</dimen>
     <dimen name="all_apps_search_bar_height">60dp</dimen>
-    <dimen name="all_apps_search_bar_margin_top">5dp</dimen>
+    <dimen name="all_apps_search_bar_margin_top">12dp</dimen>
     <dimen name="all_apps_search_bar_icon_margin_right">4dp</dimen>
     <dimen name="all_apps_search_bar_icon_margin_top">1dp</dimen>
-    <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
-    <dimen name="all_apps_icon_width_gap">24dp</dimen>
     <dimen name="all_apps_list_bottom_padding">8dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
     <dimen name="all_apps_empty_search_bg_top_offset">144dp</dimen>
     <dimen name="all_apps_background_canvas_width">700dp</dimen>
     <dimen name="all_apps_background_canvas_height">475dp</dimen>
     <dimen name="all_apps_caret_stroke_width">2dp</dimen>
-    <dimen name="all_apps_caret_inset">8dp</dimen>
+    <dimen name="all_apps_caret_size">13dp</dimen>
+    <dimen name="all_apps_caret_workspace_offset">4dp</dimen>
 
 <!-- Search bar in All Apps -->
     <dimen name="all_apps_header_max_elevation">3dp</dimen>
@@ -85,6 +86,7 @@
     <dimen name="all_apps_divider_margin_vertical">8dp</dimen>
 
     <dimen name="all_apps_bezel_swipe_height">24dp</dimen>
+
 <!-- Widget tray -->
     <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
     <dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index 57a60a9..96942ee 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.InsetDrawable;
@@ -32,12 +31,16 @@
 /**
  * A base container view, which supports resizing.
  */
-public abstract class BaseContainerView extends FrameLayout {
+public abstract class BaseContainerView extends FrameLayout
+        implements DeviceProfile.LauncherLayoutChangeListener {
 
-    protected final int mHorizontalPadding;
+    protected int mContainerPaddingLeft;
+    protected int mContainerPaddingRight;
+    protected int mContainerPaddingTop;
+    protected int mContainerPaddingBottom;
 
-    private final InsetDrawable mRevealDrawable;
-    private final ColorDrawable mDrawable;
+    private InsetDrawable mRevealDrawable;
+    protected final Drawable mBaseDrawable;
 
     private View mRevealView;
     private View mContent;
@@ -53,48 +56,49 @@
     public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        Launcher launcher = Launcher.getLauncher(context);
-        int width = launcher.getDeviceProfile().availableWidthPx;
-        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
-                this instanceof AllAppsContainerView &&
-                !launcher.getDeviceProfile().isVerticalBarLayout()) {
-            mHorizontalPadding = 0;
-        } else {
-            mHorizontalPadding = DeviceProfile.getContainerPadding(context, width);
-        }
-
         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
-            mDrawable = new ColorDrawable();
-            mRevealDrawable = new InsetDrawable(mDrawable,
-                    mHorizontalPadding, 0, mHorizontalPadding, 0);
+            mBaseDrawable = new ColorDrawable();
         } else {
             TypedArray a = context.obtainStyledAttributes(attrs,
                     R.styleable.BaseContainerView, defStyleAttr, 0);
-            mRevealDrawable = new InsetDrawable(
-                    a.getDrawable(R.styleable.BaseContainerView_revealBackground),
-                    mHorizontalPadding, 0, mHorizontalPadding, 0);
-            mDrawable = null;
+            mBaseDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
             a.recycle();
         }
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+        grid.addLauncherLayoutChangedListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+        grid.removeLauncherLayoutChangedListener(this);
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
         mContent = findViewById(R.id.main_content);
         mRevealView = findViewById(R.id.reveal_view);
 
-        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
-            mRevealView.setBackground(mRevealDrawable);
-        } else {
-            mRevealView.setBackground(mRevealDrawable.getConstantState().newDrawable());
-            mContent.setBackground(mRevealDrawable);
-        }
+        updatePaddings();
+    }
 
-        // We let the content have a intent background, but still have full width.
-        // This allows the scroll bar to be used responsive outside the background bounds as well.
-        mContent.setPadding(0, 0, 0, 0);
+    @Override
+    public void onLauncherLayoutChanged() {
+        updatePaddings();
+    }
+
+    public void setRevealDrawableColor(int color) {
+        ((ColorDrawable) mBaseDrawable).setColor(color);
     }
 
     public final View getContentView() {
@@ -105,7 +109,35 @@
         return mRevealView;
     }
 
-    public void setRevealDrawableColor(int color) {
-        mDrawable.setColor(color);
+    private void updatePaddings() {
+        Context context = getContext();
+        Launcher launcher = Launcher.getLauncher(context);
+
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
+                this instanceof AllAppsContainerView &&
+                !launcher.getDeviceProfile().isVerticalBarLayout()) {
+            mContainerPaddingLeft = mContainerPaddingRight = 0;
+            mContainerPaddingTop = mContainerPaddingBottom = 0;
+        } else {
+            DeviceProfile grid = launcher.getDeviceProfile();
+            int[] padding = grid.getContainerPadding(context);
+            mContainerPaddingLeft = padding[0] + grid.edgeMarginPx;
+            mContainerPaddingRight = padding[1] + grid.edgeMarginPx;
+            if (!launcher.getDeviceProfile().isVerticalBarLayout()) {
+                mContainerPaddingTop = mContainerPaddingBottom = grid.edgeMarginPx;
+            } else {
+                mContainerPaddingTop = mContainerPaddingBottom = 0;
+            }
+        }
+
+        mRevealDrawable = new InsetDrawable(mBaseDrawable,
+                mContainerPaddingLeft, mContainerPaddingTop, mContainerPaddingRight,
+                mContainerPaddingBottom);
+        mRevealView.setBackground(mRevealDrawable);
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
+            // Skip updating the content background
+        } else {
+            mContent.setBackground(mRevealDrawable);
+        }
     }
 }
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 33e4e2a..00ec4c2 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Region;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -66,6 +67,7 @@
 
     private final Launcher mLauncher;
     private Drawable mIcon;
+    private final boolean mCenterVertically;
     private final Drawable mBackground;
     private OnLongClickListener mOnLongClickListener;
     private final CheckLongPressHelper mLongPressHelper;
@@ -119,9 +121,11 @@
         if (display == DISPLAY_WORKSPACE) {
             setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
         } else if (display == DISPLAY_ALL_APPS) {
-            setTextSize(TypedValue.COMPLEX_UNIT_SP, grid.allAppsIconTextSizeSp);
+            setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
+            setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
             defaultIconSize = grid.allAppsIconSizePx;
         }
+        mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
 
         mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
                 defaultIconSize);
@@ -428,6 +432,19 @@
     }
 
     @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mCenterVertically) {
+            Paint.FontMetrics fm = getPaint().getFontMetrics();
+            int cellHeightPx = mIconSize + getCompoundDrawablePadding() +
+                    (int) Math.ceil(fm.bottom - fm.top);
+            int height = MeasureSpec.getSize(heightMeasureSpec);
+            setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(),
+                    getPaddingBottom());
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         if (mBackground != null) mBackground.setCallback(null);
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2b130e5..ac86f0b 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -29,13 +29,18 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.config.FeatureFlags;
 
+import java.util.ArrayList;
+
 public class DeviceProfile {
 
+    public interface LauncherLayoutChangeListener {
+        void onLauncherLayoutChanged();
+    }
+
     public final InvariantDeviceProfile inv;
 
     // Device properties
@@ -68,13 +73,18 @@
     private int desiredWorkspaceLeftRightMarginPx;
     public final int edgeMarginPx;
     public final Rect defaultWidgetPadding;
-    private final int pageIndicatorHeightPx;
     private final int defaultPageSpacingPx;
     private final int topWorkspacePadding;
     private float dragViewScale;
     public float workspaceSpringLoadShrinkFactor;
     public final int workspaceSpringLoadedBottomSpace;
 
+    // Page indicator
+    private final int pageIndicatorHeightPx;
+    private final int pageIndicatorLandGutterLeftNavBarPx;
+    private final int pageIndicatorLandGutterRightNavBarPx;
+    private final int pageIndicatorLandWorkspaceOffsetPx;
+
     // Workspace icons
     public int iconSizePx;
     public int iconTextSizePx;
@@ -96,17 +106,30 @@
     public int hotseatCellHeightPx;
     public int hotseatIconSizePx;
     private int hotseatBarHeightPx;
+    private int hotseatBarTopPaddingPx;
+    private int hotseatLandGutterPx;
 
     // All apps
     public int allAppsNumCols;
     public int allAppsNumPredictiveCols;
     public int allAppsButtonVisualSize;
-    public final int allAppsIconSizePx;
-    public final float allAppsIconTextSizeSp;
+    public int allAppsIconSizePx;
+    public int allAppsIconDrawablePaddingPx;
+    public float allAppsIconTextSizePx;
+
+    // Containers
+    private final int containerLeftPaddingPx;
+    private final int containerRightPaddingPx;
 
     // Drop Target
     public int dropTargetBarSizePx;
 
+    // Insets
+    private Rect mInsets = new Rect();
+
+    // Listeners
+    private ArrayList<LauncherLayoutChangeListener> mListeners = new ArrayList<>();
+
     public DeviceProfile(Context context, InvariantDeviceProfile inv,
             Point minSize, Point maxSize,
             int width, int height, boolean isLandscape) {
@@ -130,9 +153,15 @@
                 this.getClass().getName());
         defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
         edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
-        desiredWorkspaceLeftRightMarginPx = 2 * edgeMarginPx;
+        desiredWorkspaceLeftRightMarginPx = edgeMarginPx;
         pageIndicatorHeightPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height);
+        pageIndicatorLandGutterLeftNavBarPx = res.getDimensionPixelSize(
+                R.dimen.dynamic_grid_page_indicator_gutter_width_left_nav_bar);
+        pageIndicatorLandWorkspaceOffsetPx =
+                res.getDimensionPixelSize(R.dimen.all_apps_caret_workspace_offset);
+        pageIndicatorLandGutterRightNavBarPx = res.getDimensionPixelSize(
+                R.dimen.dynamic_grid_page_indicator_gutter_width_right_nav_bar);
         defaultPageSpacingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
         topWorkspacePadding =
@@ -152,12 +181,14 @@
         dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
         workspaceSpringLoadedBottomSpace =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
-
-        // AllApps uses the original non-scaled icon text size
-        allAppsIconTextSizeSp = inv.iconTextSize;
-
-        // AllApps uses the original non-scaled icon size
-        allAppsIconSizePx = Utilities.pxFromDp(inv.iconSize, dm);
+        hotseatBarHeightPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height);
+        hotseatBarTopPaddingPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
+        hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_gutter_width);
+        containerLeftPaddingPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_container_land_left_padding);
+        containerRightPaddingPx =
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_container_land_right_padding);
 
         // Determine sizes.
         widthPx = width;
@@ -175,6 +206,18 @@
         computeAllAppsButtonSize(context);
     }
 
+    public void addLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+        }
+    }
+
+    public void removeLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
+        if (mListeners.contains(listener)) {
+            mListeners.remove(listener);
+        }
+    }
+
     /**
      * Determine the exact visual footprint of the all apps button, taking into account scaling
      * and internal padding of the drawable.
@@ -208,6 +251,9 @@
         iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale);
         iconDrawablePaddingPx = drawablePadding;
         hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale);
+        allAppsIconSizePx = iconSizePx;
+        allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
+        allAppsIconTextSizePx = iconTextSizePx;
 
         // Calculate the actual text height
         Paint textPaint = new Paint();
@@ -220,7 +266,6 @@
         dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
 
         // Hotseat
-        hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
         hotseatCellWidthPx = iconSizePx;
         hotseatCellHeightPx = iconSizePx;
 
@@ -247,20 +292,15 @@
         folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
     }
 
+    public void updateInsets(Rect insets) {
+        mInsets.set(insets);
+    }
+
     /**
      * @param recyclerViewWidth the available width of the AllAppsRecyclerView
      */
-    public void updateAppsViewNumCols(Resources res, int recyclerViewWidth) {
-        int appsViewLeftMarginPx =
-                res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
-        int allAppsCellWidthGap =
-                res.getDimensionPixelSize(R.dimen.all_apps_icon_width_gap);
-        int availableAppsWidthPx = (recyclerViewWidth > 0) ? recyclerViewWidth : availableWidthPx;
-        int numAppsCols = (availableAppsWidthPx + allAppsCellWidthGap - appsViewLeftMarginPx) /
-                (allAppsIconSizePx + allAppsCellWidthGap);
-        int numPredictiveAppCols = Math.max(inv.minAllAppsPredictionColumns, numAppsCols);
-        allAppsNumCols = numAppsCols;
-        allAppsNumPredictiveCols = numPredictiveAppCols;
+    public void updateAppsViewNumCols() {
+        allAppsNumCols = allAppsNumPredictiveCols = inv.numColumns;
     }
 
     /** Returns the width and height of the search bar, ignoring any padding. */
@@ -309,9 +349,13 @@
     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.
-            padding.set(dropTargetBarSizePx, edgeMarginPx, hotseatBarHeightPx, edgeMarginPx);
+            if (mInsets.left > 0) {
+                padding.set(mInsets.left + pageIndicatorLandGutterLeftNavBarPx, 0,
+                        hotseatBarHeightPx + hotseatLandGutterPx - mInsets.left, 2 * edgeMarginPx);
+            } else {
+                padding.set(pageIndicatorLandGutterRightNavBarPx, 0,
+                        hotseatBarHeightPx + hotseatLandGutterPx, 2 * edgeMarginPx);
+            }
         } else {
             int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
             if (isTablet) {
@@ -331,10 +375,10 @@
                         availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
             } else {
                 // Pad the top and bottom of the workspace with search/hotseat bar sizes
-                padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
+                padding.set(desiredWorkspaceLeftRightMarginPx,
                         topWorkspacePadding,
-                        desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
-                        paddingBottom);
+                        desiredWorkspaceLeftRightMarginPx,
+                        hotseatBarHeightPx + pageIndicatorHeightPx);
             }
         }
         return padding;
@@ -389,7 +433,7 @@
         return visibleChildren;
     }
 
-    public void layout(Launcher launcher) {
+    public void layout(Launcher launcher, boolean notifyListeners) {
         FrameLayout.LayoutParams lp;
         boolean hasVerticalBarLayout = isVerticalBarLayout();
         final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
@@ -400,18 +444,19 @@
         lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
         lp.width = searchBarBounds.x;
         lp.height = searchBarBounds.y;
-        lp.topMargin = edgeMarginPx;
+        lp.topMargin = mInsets.top + edgeMarginPx;
         searchBar.setLayoutParams(lp);
 
         // Layout the workspace
         PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
-        Rect padding = getWorkspacePadding(null);
-        workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+        Rect workspacePadding = getWorkspacePadding(null);
+        workspace.setPadding(workspacePadding.left, workspacePadding.top, workspacePadding.right,
+                workspacePadding.bottom);
         workspace.setPageSpacing(getWorkspacePageSpacing());
 
         View qsbContainer = launcher.getQsbContainer();
         lp = (FrameLayout.LayoutParams) qsbContainer.getLayoutParams();
-        lp.topMargin = padding.top;
+        lp.topMargin = mInsets.top + workspacePadding.top;
         qsbContainer.setLayoutParams(lp);
 
         // Layout the hotseat
@@ -428,26 +473,29 @@
             // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
             //                     screen regardless of RTL
             lp.gravity = Gravity.RIGHT;
-            lp.width = hotseatBarHeightPx;
+            lp.width = hotseatBarHeightPx + mInsets.left + mInsets.right;
             lp.height = LayoutParams.MATCH_PARENT;
             hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
+            hotseat.setPadding(mInsets.left, 0, mInsets.right, 0);
         } else if (isTablet) {
             // Pad the hotseat with the workspace padding calculated above
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
-            lp.height = hotseatBarHeightPx;
+            lp.height = hotseatBarHeightPx + mInsets.bottom;
             hotseat.findViewById(R.id.layout).setPadding(
-                    hotseatAdjustment + padding.left, 0,
-                    hotseatAdjustment + padding.right, 2 * edgeMarginPx);
+                    hotseatAdjustment + workspacePadding.left, 0,
+                    hotseatAdjustment + workspacePadding.right, 2 * edgeMarginPx);
+            hotseat.setPadding(0, hotseatBarTopPaddingPx, 0, mInsets.bottom);
         } else {
             // For phones, layout the hotseat without any bottom margin
             // to ensure that we have space for the folders
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
-            lp.height = hotseatBarHeightPx;
+            lp.height = hotseatBarHeightPx + mInsets.bottom;
             hotseat.findViewById(R.id.layout).setPadding(
-                    hotseatAdjustment + padding.left, 0,
-                    hotseatAdjustment + padding.right, 0);
+                    hotseatAdjustment + workspacePadding.left, 0,
+                    hotseatAdjustment + workspacePadding.right, 0);
+            hotseat.setPadding(0, hotseatBarTopPaddingPx, 0, mInsets.bottom);
         }
         hotseat.setLayoutParams(lp);
 
@@ -455,11 +503,21 @@
         View pageIndicator = launcher.findViewById(R.id.page_indicator);
         if (pageIndicator != null) {
             lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
-            if (!hasVerticalBarLayout) {
+            if (isVerticalBarLayout()) {
+                if (mInsets.left > 0) {
+                    lp.leftMargin = mInsets.left + pageIndicatorLandGutterLeftNavBarPx -
+                            lp.width - pageIndicatorLandWorkspaceOffsetPx;
+                } else if (mInsets.right > 0) {
+                    lp.leftMargin = pageIndicatorLandGutterRightNavBarPx - lp.width -
+                            pageIndicatorLandWorkspaceOffsetPx;
+                }
+                lp.bottomMargin = workspacePadding.bottom;
+            } else {
                 // Put the page indicators above the hotseat
                 lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
                 lp.width = LayoutParams.WRAP_CONTENT;
-                lp.bottomMargin = hotseatBarHeightPx;
+                lp.height = pageIndicatorHeightPx;
+                lp.bottomMargin = hotseatBarHeightPx + mInsets.bottom;
             }
             pageIndicator.setLayoutParams(lp);
         }
@@ -468,7 +526,7 @@
         ViewGroup overviewMode = launcher.getOverviewPanel();
         if (overviewMode != null) {
             lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
-            lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+            lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
 
             int visibleChildCount = getVisibleChildCount(overviewMode);
             int totalItemWidth = visibleChildCount * overviewModeBarItemWidthPx;
@@ -476,30 +534,15 @@
 
             lp.width = Math.min(availableWidthPx, maxWidth);
             lp.height = getOverviewModeButtonBarHeight();
+            // Center the overview buttons on the workspace page
+            lp.leftMargin = workspacePadding.left + (availableWidthPx -
+                    workspacePadding.left - workspacePadding.right - lp.width) / 2;
             overviewMode.setLayoutParams(lp);
+        }
 
-            if (lp.width > totalItemWidth && visibleChildCount > 1) {
-                // We have enough space. Lets add some margin too.
-                int margin = (lp.width - totalItemWidth) / (visibleChildCount-1);
-                View lastChild = null;
-
-                // Set margin of all visible children except the last visible child
-                for (int i = 0; i < visibleChildCount; i++) {
-                    if (lastChild != null) {
-                        MarginLayoutParams clp = (MarginLayoutParams) lastChild.getLayoutParams();
-                        if (isLayoutRtl) {
-                            clp.leftMargin = margin;
-                        } else {
-                            clp.rightMargin = margin;
-                        }
-                        lastChild.setLayoutParams(clp);
-                        lastChild = null;
-                    }
-                    View thisChild = overviewMode.getChildAt(i);
-                    if (thisChild.getVisibility() != View.GONE) {
-                        lastChild = thisChild;
-                    }
-                }
+        if (notifyListeners) {
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                mListeners.get(i).onLauncherLayoutChanged();
             }
         }
     }
@@ -517,17 +560,20 @@
     }
 
 
-    public static final int getContainerPadding(Context context, int availableWidth) {
+    /**
+     * @return the left/right paddings for all containers.
+     */
+    public final int[] getContainerPadding(Context context) {
         Resources res = context.getResources();
 
-        int maxSize = res.getDimensionPixelSize(R.dimen.container_max_width);
-        int minMargin = res.getDimensionPixelSize(R.dimen.container_min_margin);
-
-        if (maxSize > 0) {
-            return Math.max(minMargin, (availableWidth - maxSize) / 2);
-        } else {
-            return Math.max(minMargin,
-                    (int) res.getFraction(R.fraction.container_margin, availableWidth, 1));
+        // No paddings for portrait phone
+        if (isPhone && !isVerticalBarLayout()) {
+            return new int[] {0, 0};
         }
+
+        // In landscape, we just match the vertical display width
+        int containerWidth = heightPx;
+        int padding = (availableWidthPx - containerWidth) / 2;
+        return new int[]{ padding, padding };
     }
 }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 7e2b42e..084de70 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -39,7 +39,7 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
 public class Hotseat extends FrameLayout
-        implements UserEventDispatcher.LaunchSourceProvider, Insettable {
+        implements UserEventDispatcher.LaunchSourceProvider {
 
     private CellLayout mContent;
 
@@ -49,9 +49,6 @@
     private final boolean mHasVerticalHotseat;
 
     @ViewDebug.ExportedProperty(category = "launcher")
-    private Rect mInsets = new Rect();
-
-    @ViewDebug.ExportedProperty(category = "launcher")
     private int mBackgroundColor;
     @ViewDebug.ExportedProperty(category = "launcher")
     private ColorDrawable mBackground;
@@ -180,28 +177,6 @@
         targetParent.containerType = LauncherLogProto.HOTSEAT;
     }
 
-    //Overridden so that the background color extends behind the navigation buttons.
-    @Override
-    public void setInsets(Rect insets) {
-        int rightInset = insets.right - mInsets.right;
-        int bottomInset = insets.bottom - mInsets.bottom;
-        mInsets.set(insets);
-        LayoutParams lp = (LayoutParams) getLayoutParams();
-        if (mHasVerticalHotseat) {
-            setPadding(getPaddingLeft(), getPaddingTop(),
-            getPaddingRight() + rightInset, getPaddingBottom());
-            if (lp.width != LayoutParams.MATCH_PARENT && lp.width != LayoutParams.WRAP_CONTENT) {
-                lp.width += rightInset;
-            }
-        } else {
-            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
-            getPaddingBottom() + bottomInset);
-            if (lp.height != LayoutParams.MATCH_PARENT && lp.height != LayoutParams.WRAP_CONTENT) {
-                lp.height += bottomInset;
-            }
-        }
-    }
-
     public void updateColor(ExtractedColors extractedColors, boolean animate) {
         if (!mHasVerticalHotseat) {
             int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX, Color.TRANSPARENT);
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 9ce941b..a49162c 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -72,6 +72,7 @@
     private static final String EMPTY_CLASS_NAME = ".";
 
     private static final boolean DEBUG = false;
+    private static final boolean DEBUG_IGNORE_CACHE = false;
 
     private static final int LOW_RES_SCALE_FACTOR = 5;
 
@@ -552,7 +553,7 @@
             mCache.put(cacheKey, entry);
 
             // Check the DB first.
-            if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
+            if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
                 if (info != null) {
                     entry.icon = Utilities.createBadgedIconBitmap(
                             mIconProvider.getIcon(info, mIconDpi), info.getUser(),
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 4e6911c..38545e2 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -67,6 +67,7 @@
     /**
      * The minimum number of predicted apps in all apps.
      */
+    @Deprecated
     int minAllAppsPredictionColumns;
 
     /**
@@ -103,11 +104,6 @@
 
     InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
             float is, float its, int hs, float his, int dlId) {
-        // Ensure that we have an odd number of hotseat items (since we need to place all apps)
-        if (hs % 2 == 0) {
-            throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
-        }
-
         name = n;
         minWidthDps = w;
         minHeightDps = h;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b7f033e..651e91b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -438,7 +438,7 @@
         setContentView(R.layout.launcher);
 
         setupViews();
-        mDeviceProfile.layout(this);
+        mDeviceProfile.layout(this, false /* notifyListeners */);
         mExtractedColors = new ExtractedColors();
         loadExtractedColorsAndColorItems();
 
@@ -521,6 +521,11 @@
         }
     }
 
+    public void onInsetsChanged(Rect insets) {
+        mDeviceProfile.updateInsets(insets);
+        mDeviceProfile.layout(this, true /* notifyListeners */);
+    }
+
     /**
      * Call this after onCreate to set or clear overlay.
      */
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 7bcf5d0..643d48a 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -44,6 +44,7 @@
     @TargetApi(23)
     @Override
     protected boolean fitSystemWindows(Rect insets) {
+        boolean rawInsetsChanged = !mInsets.equals(insets);
         mDrawSideInsetBar = (insets.right > 0 || insets.left > 0) &&
                 (!Utilities.ATLEAST_MARSHMALLOW ||
                 getContext().getSystemService(ActivityManager.class).isLowRamDevice());
@@ -61,6 +62,12 @@
             }
         }
 
+        if (rawInsetsChanged) {
+            // Update the grid again
+            Launcher launcher = Launcher.getLauncher(getContext());
+            launcher.onInsetsChanged(insets);
+        }
+
         return true; // I'll take it from here
     }
 
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index c016aa9..d98734b 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -129,7 +129,7 @@
             if (child instanceof LauncherAppWidgetHostView) {
                 // Widgets have their own padding, so skip
             } else {
-                // Otherwise, center the icon
+                // Otherwise, center the icon/folder
                 int cHeight = getCellContentHeight();
                 int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
                 int cellPaddingX = (int) (grid.edgeMarginPx / 2f);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 78ef074..bcd87b5 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -53,11 +53,9 @@
 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;
@@ -366,16 +364,7 @@
 
     @Override
     public void setInsets(Rect insets) {
-        int extraLeftPadding = insets.left - mInsets.left;
         mInsets.set(insets);
-        if (extraLeftPadding != 0) {
-            /**
-             * Initial layout assumes that the insets is on the right,
-             * {@link DeviceProfile#getWorkspacePadding()}. Compensate for the difference.
-             */
-            setPadding(getPaddingLeft() + extraLeftPadding, getPaddingTop(),
-                    getPaddingRight() - extraLeftPadding, getPaddingBottom());
-        }
 
         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);
         if (customScreen != null) {
@@ -1517,12 +1506,15 @@
     /**
      * Moves the Hotseat UI in the provided direction.
      * @param direction the direction to move the workspace
-     * @param translation the amound of shift.
+     * @param translation the amount of shift.
      * @param alpha the alpha for the hotseat page
      */
     public void setHotseatTranslationAndAlpha(Direction direction, float translation, float alpha) {
         Property<View, Float> property = direction.viewProperty;
-        property.set(mPageIndicator, translation);
+        // Skip the page indicator movement in the vertical bar layout
+        if (direction != Direction.Y || !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+            property.set(mPageIndicator, translation);
+        }
         property.set(mLauncher.getHotseat(), translation);
         setHotseatAlphaAtIndex(alpha, direction.ordinal());
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index cc96934..3ef510c 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -347,12 +347,10 @@
         int widthPx = MeasureSpec.getSize(widthMeasureSpec);
         int heightPx = MeasureSpec.getSize(heightMeasureSpec);
         updatePaddingsAndMargins(widthPx, heightPx);
-        mContentBounds.set(mHorizontalPadding, 0, widthPx - mHorizontalPadding, heightPx);
+        mContentBounds.set(mContainerPaddingLeft, 0, widthPx - mContainerPaddingRight, heightPx);
 
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() : widthPx)
-                - 2 * mAppsRecyclerView.getMaxScrollbarWidth();
-        grid.updateAppsViewNumCols(getResources(), availableWidth);
+        grid.updateAppsViewNumCols();
         if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
             if (mNumAppsPerRow != grid.inv.numColumns ||
                     mNumPredictedAppsPerRow != grid.inv.numColumns) {
@@ -368,9 +366,9 @@
                             getResources().getDimensionPixelSize(
                                     R.dimen.container_fastscroll_thumb_max_width);
                     mSearchContainer.setPadding(
-                            rvPadding - mHorizontalPadding + thumbMaxWidth,
+                            rvPadding - mContainerPaddingLeft + thumbMaxWidth,
                             mSearchContainer.getPaddingTop(),
-                            rvPadding - mHorizontalPadding + thumbMaxWidth,
+                            rvPadding - mContainerPaddingRight + thumbMaxWidth,
                             mSearchContainer.getPaddingBottom());
                 }
             }
@@ -383,7 +381,7 @@
         // Update the number of items in the grid before we measure the view
         // TODO: mSectionNamesMargin is currently 0, but also account for it,
         // if it's enabled in the future.
-        grid.updateAppsViewNumCols(getResources(), availableWidth);
+        grid.updateAppsViewNumCols();
         if (mNumAppsPerRow != grid.allAppsNumCols ||
                 mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
             mNumAppsPerRow = grid.allAppsNumCols;
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 0f0c333..97c46b1 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -20,6 +20,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -37,6 +38,8 @@
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -331,7 +334,9 @@
     private final boolean mIsRtl;
 
     // Section drawing
+    @Deprecated
     private final int mSectionNamesMargin;
+    @Deprecated
     private final int mSectionHeaderOffset;
     private final Paint mSectionTextPaint;
 
@@ -452,6 +457,14 @@
                 icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
                         .getLongPressTimeout());
                 icon.setOnFocusChangeListener(mIconFocusListener);
+
+                // Ensure the all apps icon height matches the workspace icons
+                DeviceProfile profile = mLauncher.getDeviceProfile();
+                Point cellSize = profile.getCellSize();
+                GridLayoutManager.LayoutParams lp =
+                        (GridLayoutManager.LayoutParams) icon.getLayoutParams();
+                lp.height = cellSize.y;
+                icon.setLayoutParams(lp);
                 return new ViewHolder(icon);
             }
             case VIEW_TYPE_EMPTY_SEARCH:
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 93da297..641656c 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -120,10 +120,9 @@
         // Icons
         BubbleTextView icon = (BubbleTextView) adapter.onCreateViewHolder(this,
                 AllAppsGridAdapter.VIEW_TYPE_ICON).mContent;
-        icon.applyDummyInfo();
-        icon.measure(widthMeasureSpec, heightMeasureSpec);
-        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, icon.getMeasuredHeight());
-        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, icon.getMeasuredHeight());
+        int iconHeight = icon.getLayoutParams().height;
+        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, iconHeight);
+        mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, iconHeight);
 
         // Search divider
         View searchDivider = adapter.onCreateViewHolder(this,
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 6518ab1..03b3107 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -298,6 +298,7 @@
         mShiftCurrent = progress;
         float alpha = calcAlphaAllApps(progress);
         float workspaceHotseatAlpha = 1 - alpha;
+        float interpolation = mAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
 
         int color = (Integer) mEvaluator.evaluate(mDecelInterpolator.getInterpolation(alpha),
                 mHotseatBackgroundColor, mAllAppsBackgroundColor);
@@ -306,14 +307,13 @@
         mAppsView.setTranslationY(progress);
         mWorkspace.setWorkspaceYTranslationAndAlpha(
                 PARALLAX_COEFFICIENT * (-mShiftRange + progress),
-                mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
-        if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            mWorkspace.setHotseatTranslationAndAlpha(Direction.Y, -mShiftRange + progress,
-                    mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+                interpolation);
+        if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+            mWorkspace.setHotseatTranslationAndAlpha(Direction.Y,
+                    PARALLAX_COEFFICIENT * (-mShiftRange + progress), interpolation);
         } else {
             mWorkspace.setHotseatTranslationAndAlpha(Direction.Y,
-                    PARALLAX_COEFFICIENT * (-mShiftRange + progress),
-                    mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+                    -mShiftRange + progress, interpolation);
         }
     }
 
diff --git a/src/com/android/launcher3/pageindicators/CaretDrawable.java b/src/com/android/launcher3/pageindicators/CaretDrawable.java
index 8971323..e5d128e 100644
--- a/src/com/android/launcher3/pageindicators/CaretDrawable.java
+++ b/src/com/android/launcher3/pageindicators/CaretDrawable.java
@@ -36,7 +36,6 @@
 
     private Paint mPaint = new Paint();
     private Path mPath = new Path();
-    private int mInset;
 
     public CaretDrawable(Context context) {
         final Resources res = context.getResources();
@@ -47,8 +46,6 @@
         mPaint.setStyle(Paint.Style.STROKE);
         mPaint.setStrokeCap(Paint.Cap.SQUARE);
         mPaint.setStrokeJoin(Paint.Join.MITER);
-
-        mInset = res.getDimensionPixelSize(R.dimen.all_apps_caret_inset);
     }
 
     @Override
@@ -57,10 +54,10 @@
             return;
         }
 
-        final float width = getBounds().width();
-        final float height = getBounds().height();
-        final float left = getBounds().left;
-        final float top = getBounds().top;
+        final float width = getBounds().width() - mPaint.getStrokeWidth();
+        final float height = getBounds().height() - mPaint.getStrokeWidth();
+        final float left = getBounds().left + (mPaint.getStrokeWidth() / 2);
+        final float top = getBounds().top + (mPaint.getStrokeWidth() / 2);
 
         final float verticalInset = (height / 4);
         final float caretHeight = (height - (verticalInset * 2));
@@ -95,9 +92,4 @@
     public void setColorFilter(ColorFilter cf) {
         // no-op
     }
-
-    @Override
-    public void setBounds(int left, int top, int right, int bottom) {
-        super.setBounds(left + mInset, top + mInset, right - mInset, bottom - mInset);
-    }
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
index 8075201..1eee59e 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
@@ -16,13 +16,19 @@
 package com.android.launcher3.pageindicators;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
 
 /**
- * Simply draws the caret drawable in the center. Used for the landscape layout.
+ * Simply draws the caret drawable bottom-right aligned in the view. This ensures that we can have
+ * a view with as large an area as we want (for touching) while maintaining a caret of size
+ * all_apps_caret_size.  Used only for the landscape layout.
  */
 public class PageIndicatorCaretLandscape extends PageIndicator {
     // all apps pull up handle drawable.
@@ -38,7 +44,11 @@
     public PageIndicatorCaretLandscape(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        setCaretDrawable(new CaretDrawable(context));
+        int caretSize = context.getResources().getDimensionPixelSize(R.dimen.all_apps_caret_size);
+        CaretDrawable caretDrawable = new CaretDrawable(context);
+        caretDrawable.setBounds(0, 0, caretSize, caretSize);
+        setCaretDrawable(caretDrawable);
+
         Launcher l = (Launcher) context;
         setOnTouchListener(l.getHapticFeedbackTouchListener());
         setOnClickListener(l);
@@ -46,15 +56,12 @@
     }
 
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        int size = bottom - top;
-        int l = (right - left) / 2 - size / 2;
-        getCaretDrawable().setBounds(l, 0, l + size, size);
-    }
-
-    @Override
     protected void onDraw(Canvas canvas) {
+        Rect drawableBounds = getCaretDrawable().getBounds();
+        int count = canvas.save();
+        canvas.translate(getWidth() - drawableBounds.width(),
+                getHeight() - drawableBounds.height());
         getCaretDrawable().draw(canvas);
+        canvas.restoreToCount(count);
     }
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
index f18c799..45df369 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -63,6 +63,8 @@
     private final int mLineHeight;
     private final Rect mTouchHitRect = new Rect();
     private final int mTouchExtensionHeight;
+    private final int mCaretSizePx;
+    private final int mCaretWorkspaceOffsetPx;
 
     private static final Property<PageIndicatorLineCaret, Integer> PAINT_ALPHA
             = new Property<PageIndicatorLineCaret, Integer>(Integer.class, "paint_alpha") {
@@ -123,14 +125,18 @@
 
     public PageIndicatorLineCaret(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+
+        Resources res = context.getResources();
         mLinePaint = new Paint();
         mLinePaint.setAlpha(0);
+        mCaretSizePx = res.getDimensionPixelSize(R.dimen.all_apps_caret_size);
+        mCaretWorkspaceOffsetPx = res.getDimensionPixelSize(
+                R.dimen.all_apps_caret_workspace_offset);
 
         mLauncher = (Launcher) context;
         setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
         setOnClickListener(mLauncher);
         setOnFocusChangeListener(mLauncher.mFocusHandler);
-        Resources res = context.getResources();
         setCaretDrawable(new CaretDrawable(context));
         mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height);
         mTouchExtensionHeight = res.getDimensionPixelSize(
@@ -140,9 +146,9 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        int size = bottom - top;
-        int l = (right - left) / 2 - size / 2;
-        getCaretDrawable().setBounds(l, 0, l + size, size);
+        // Top/center align the caret in the page indicator space
+        int l = (right - left) / 2 - mCaretSizePx / 2;
+        getCaretDrawable().setBounds(l, mCaretWorkspaceOffsetPx, l + mCaretSizePx, mCaretSizePx);
 
         // The touch area is expanded below this view by #mTouchExtensionHeight
         // which extends to the top of the hotseat.
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 8a58d34..34bee1b 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -20,7 +20,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView.State;
 import android.util.AttributeSet;
@@ -32,7 +31,6 @@
 import com.android.launcher3.BaseContainerView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.folder.Folder;
@@ -62,6 +60,9 @@
     private DragController mDragController;
     private IconCache mIconCache;
 
+    private final Rect mTmpBgPaddingRect = new Rect();
+    private final Rect mTmpRect = new Rect();
+
     /* Recycler view related member variables */
     private WidgetsRecyclerView mRecyclerView;
     private WidgetsListAdapter mAdapter;
@@ -97,18 +98,24 @@
         mRecyclerView = (WidgetsRecyclerView) getContentView().findViewById(R.id.widgets_list_view);
         mRecyclerView.setAdapter(mAdapter);
         mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+    }
 
-        Rect bgPadding = new Rect();
-        getRevealView().getBackground().getPadding(bgPadding);
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        getRevealView().getBackground().getPadding(mTmpBgPaddingRect);
         if (Utilities.isRtl(getResources())) {
-            getContentView().setPadding(0, bgPadding.top,
-                    bgPadding.right, bgPadding.bottom);
-            mRecyclerView.updateBackgroundPadding(new Rect(bgPadding.left, 0, 0, 0));
+            getContentView().setPadding(0, mTmpBgPaddingRect.top, mTmpBgPaddingRect.right,
+                    mTmpBgPaddingRect.bottom);
+            mTmpRect.set(mTmpBgPaddingRect.left, 0, 0, 0);
+            mRecyclerView.updateBackgroundPadding(mTmpRect);
         } else {
-            getContentView().setPadding(bgPadding.left, bgPadding.top,
-                    0, bgPadding.bottom);
-            mRecyclerView.updateBackgroundPadding(new Rect(0, 0, bgPadding.right, 0));
+            getContentView().setPadding(mTmpBgPaddingRect.left, mTmpBgPaddingRect.top, 0,
+                    mTmpBgPaddingRect.bottom);
+            mTmpRect.set(0, 0, mTmpBgPaddingRect.right, 0);
+            mRecyclerView.updateBackgroundPadding(mTmpRect);
         }
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
     //