Adding a custom view for DragHandle

> Separating page indicator and drag handle
> Page indicator always draws irrespactive of oriantation
> Drag handle is responsible for accessibility interactions
> Adding assissibility actions for DragHandle

Bug: 72500733
Change-Id: I9030337456964af1bdf77f1c01956452321f9229
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 13971ad..14d8b93 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -117,6 +117,7 @@
     // Insets
     private final Rect mInsets = new Rect();
     public final Rect workspacePadding = new Rect();
+    private final Rect mHotseatPadding = new Rect();
 
     // Icon badges
     public BadgeRenderer mBadgeRenderer;
@@ -456,6 +457,33 @@
         }
     }
 
+    public Rect getHotseatLayoutPadding() {
+        if (isVerticalBarLayout()) {
+            if (isSeascape()) {
+                mHotseatPadding.set(
+                        mInsets.left, mInsets.top, hotseatBarSidePaddingPx, mInsets.bottom);
+            } else {
+                mHotseatPadding.set(
+                        hotseatBarSidePaddingPx, mInsets.top, mInsets.right, mInsets.bottom);
+            }
+        } else {
+
+            // We want the edges of the hotseat to line up with the edges of the workspace, but the
+            // icons in the hotseat are a different size, and so don't line up perfectly. To account
+            // for this, we pad the left and right of the hotseat with half of the difference of a
+            // workspace cell vs a hotseat cell.
+            float workspaceCellWidth = (float) widthPx / inv.numColumns;
+            float hotseatCellWidth = (float) widthPx / inv.numHotseatIcons;
+            int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
+            mHotseatPadding.set(
+                    hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx,
+                    hotseatBarTopPaddingPx,
+                    hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
+                    hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx);
+        }
+        return mHotseatPadding;
+    }
+
     /**
      * @return the bounds for which the open folders should be contained within
      */
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 211a756..9660468 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -152,19 +152,13 @@
 
         if (mHasVerticalHotseat) {
             mContent.setGridSize(1, grid.inv.numHotseatIcons);
-
             lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
             if (grid.isSeascape()) {
                 lp.gravity = Gravity.LEFT;
                 lp.width = grid.hotseatBarSizePx + insets.left + grid.hotseatBarSidePaddingPx;
-                getLayout().setPadding(
-                        insets.left, insets.top, grid.hotseatBarSidePaddingPx, insets.bottom);
-
             } else {
                 lp.gravity = Gravity.RIGHT;
                 lp.width = grid.hotseatBarSizePx + insets.right + grid.hotseatBarSidePaddingPx;
-                getLayout().setPadding(
-                        grid.hotseatBarSidePaddingPx, insets.top, insets.right, insets.bottom);
             }
         } else {
             mContent.setGridSize(grid.inv.numHotseatIcons, 1);
@@ -172,22 +166,10 @@
             lp.gravity = Gravity.BOTTOM;
             lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
             lp.height = grid.hotseatBarSizePx + insets.bottom;
-
-            // We want the edges of the hotseat to line up with the edges of the workspace, but the
-            // icons in the hotseat are a different size, and so don't line up perfectly. To account for
-            // this, we pad the left and right of the hotseat with half of the difference of a workspace
-            // cell vs a hotseat cell.
-            float workspaceCellWidth = (float) grid.widthPx / grid.inv.numColumns;
-            float hotseatCellWidth = (float) grid.widthPx / grid.inv.numHotseatIcons;
-            int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
-            Rect workspacePadding = grid.workspacePadding;
-
-            getLayout().setPadding(
-                    hotseatAdjustment + workspacePadding.left + grid.cellLayoutPaddingLeftRightPx,
-                    grid.hotseatBarTopPaddingPx,
-                    hotseatAdjustment + workspacePadding.right + grid.cellLayoutPaddingLeftRightPx,
-                    grid.hotseatBarBottomPaddingPx + insets.bottom + grid.cellLayoutBottomPaddingPx);
         }
+        Rect padding = grid.getHotseatLayoutPadding();
+        getLayout().setPadding(padding.left, padding.top, padding.right, padding.bottom);
+
         setLayoutParams(lp);
         InsettableFrameLayout.dispatchInsets(this, insets);
     }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ed94aa43..13f0aed 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -197,6 +197,8 @@
     private final int[] mTmpAddItemCellCoordinates = new int[2];
 
     @Thunk Hotseat mHotseat;
+    private View mDragHandleIndicator;
+    @Nullable private View mHotseatSearchBox;
 
     private DropTargetBar mDropTargetBar;
 
@@ -938,6 +940,8 @@
         mWorkspace.initParentViews(mDragLayer);
         mOverviewPanel = findViewById(R.id.overview_panel);
         mHotseat = findViewById(R.id.hotseat);
+        mDragHandleIndicator = findViewById(R.id.drag_indicator);
+        mHotseatSearchBox = findViewById(R.id.search_container_hotseat);
 
         mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
@@ -1201,6 +1205,14 @@
         return mHotseat;
     }
 
+    public View getDragHandleIndicator() {
+        return mDragHandleIndicator;
+    }
+
+    public View getHotseatSearchBox() {
+        return mHotseatSearchBox;
+    }
+
     public <T extends View> T getOverviewPanel() {
         return (T) mOverviewPanel;
     }
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index b1bf6ec..21f9d5a 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -47,10 +47,11 @@
      */
     public static final int NONE = 0;
     public static final int HOTSEAT_ICONS = 1 << 0;
-    public static final int HOTSEAT_EXTRA = 1 << 1; // e.g. a search box
+    public static final int HOTSEAT_SEARCH_BOX = 1 << 1;
     public static final int ALL_APPS_HEADER = 1 << 2;
     public static final int ALL_APPS_HEADER_EXTRA = 1 << 3; // e.g. app predictions
     public static final int ALL_APPS_CONTENT = 1 << 4;
+    public static final int DRAG_HANDLE_INDICATOR = 1 << 5;
 
     protected static final int FLAG_SHOW_SCRIM = 1 << 0;
     protected static final int FLAG_MULTI_PAGE = 1 << 1;
@@ -201,9 +202,9 @@
 
     public int getVisibleElements(Launcher launcher) {
         if (launcher.getDeviceProfile().isVerticalBarLayout()) {
-            return HOTSEAT_ICONS;
+            return HOTSEAT_ICONS | DRAG_HANDLE_INDICATOR;
         }
-        return HOTSEAT_ICONS | HOTSEAT_EXTRA;
+        return HOTSEAT_ICONS | DRAG_HANDLE_INDICATOR | HOTSEAT_SEARCH_BOX;
     }
 
     /**
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 68ad253..34ae8ea 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -443,12 +443,6 @@
         setWallpaperDimension();
     }
 
-    @Override
-    public void initParentViews(View parent) {
-        super.initParentViews(parent);
-        mPageIndicator.setAccessibilityDelegate(UiFactory.newPageIndicatorAccessibilityDelegate());
-    }
-
     private void setupLayoutTransition() {
         // We want to show layout transitions when pages are deleted, to close the gap.
         mLayoutTransition = new LayoutTransition();
@@ -3351,11 +3345,6 @@
     }
 
     @Override
-    protected String getPageIndicatorDescription() {
-        return getResources().getString(R.string.all_apps_button_label);
-    }
-
-    @Override
     protected String getCurrentPageDescription() {
         int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
         return getPageDescription(page);
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 3a222c2..fa86906 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,8 +18,9 @@
 
 import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.LauncherState.HOTSEAT_EXTRA;
+import static com.android.launcher3.LauncherState.DRAG_HANDLE_INDICATOR;
 import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.LauncherState.HOTSEAT_SEARCH_BOX;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 
 import android.view.View;
@@ -81,16 +82,19 @@
 
         int elements = state.getVisibleElements(mLauncher);
         float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
-        float hotseatExtraAlpha = (elements & HOTSEAT_EXTRA) != 0 ? 1 : 0;
         propertySetter.setViewAlpha(mLauncher.getHotseat().getLayout(), hotseatIconsAlpha,
                 pageAlphaProvider.interpolator);
-        for (View hotseatExtraContent : UiFactory.getHotseatExtraContent(mLauncher.getHotseat())) {
-            propertySetter.setViewAlpha(hotseatExtraContent, hotseatExtraAlpha,
-                    pageAlphaProvider.interpolator);
-        }
         propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
                 hotseatIconsAlpha, pageAlphaProvider.interpolator);
 
+        propertySetter.setViewAlpha(mLauncher.getHotseatSearchBox(),
+                (elements & HOTSEAT_SEARCH_BOX) != 0 ? 1 : 0,
+                pageAlphaProvider.interpolator);
+
+        propertySetter.setViewAlpha(mLauncher.getDragHandleIndicator(),
+                (elements & DRAG_HANDLE_INDICATOR) != 0 ? 1 : 0,
+                pageAlphaProvider.interpolator);
+
         // Set scrim
         propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS,
                 state.hasScrim ? 1 : 0, Interpolators.LINEAR);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 9be123f..aafae10 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -122,6 +122,7 @@
         if (!mIsVerticalLayout) {
             mLauncher.getHotseat().setTranslationY(hotseatTranslation);
             mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
+            mLauncher.getDragHandleIndicator().setTranslationY(hotseatTranslation);
         }
 
         // Use a light system UI (dark icons) if all apps is behind at least half of the
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 94ae39b..4ad7feb 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -1,9 +1,5 @@
 package com.android.launcher3.pageindicators;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -20,9 +16,7 @@
 import android.util.Property;
 import android.view.Gravity;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.DeviceProfile;
@@ -31,18 +25,13 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
 
 /**
- * A PageIndicator that briefly shows a fraction of a line when moving between pages in
- * portrait mode. In Landscape simply draws the caret drawable bottom-corner aligned in
- * the drag-layer.
+ * A PageIndicator that briefly shows a fraction of a line when moving between pages
  *
  * The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
  */
-public class WorkspacePageIndicator extends View
-        implements Insettable, OnClickListener, PageIndicator {
+public class WorkspacePageIndicator extends View implements Insettable, PageIndicator {
 
     private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
     private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
@@ -57,7 +46,6 @@
 
     private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper());
     private final Launcher mLauncher;
-    private final AccessibilityManager mAccessibilityManager;
 
     private boolean mShouldAutoHide = true;
 
@@ -72,8 +60,6 @@
     private Paint mLinePaint;
     private final int mLineHeight;
 
-    private boolean mIsLandscapeUi;
-
     private static final Property<WorkspacePageIndicator, Integer> PAINT_ALPHA
             = new Property<WorkspacePageIndicator, Integer>(Integer.class, "paint_alpha") {
         @Override
@@ -84,7 +70,7 @@
         @Override
         public void set(WorkspacePageIndicator obj, Integer alpha) {
             obj.mLinePaint.setAlpha(alpha);
-            obj.invalidateIfPortrait();
+            obj.invalidate();
         }
     };
 
@@ -98,7 +84,7 @@
         @Override
         public void set(WorkspacePageIndicator obj, Float numPages) {
             obj.mNumPagesFloat = numPages;
-            obj.invalidateIfPortrait();
+            obj.invalidate();
         }
     };
 
@@ -112,7 +98,7 @@
         @Override
         public void set(WorkspacePageIndicator obj, Integer totalScroll) {
             obj.mTotalScroll = totalScroll;
-            obj.invalidateIfPortrait();
+            obj.invalidate();
         }
     };
 
@@ -139,24 +125,23 @@
         boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText();
         mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
         mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
-        mAccessibilityManager = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (mTotalScroll == 0 || mNumPagesFloat == 0 || mIsLandscapeUi) {
+        if (mTotalScroll == 0 || mNumPagesFloat == 0) {
             return;
         }
 
         // Compute and draw line rect.
         float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f);
-        int availableWidth = canvas.getWidth();
+        int availableWidth = getWidth();
         int lineWidth = (int) (availableWidth / mNumPagesFloat);
         int lineLeft = (int) (progress * (availableWidth - lineWidth));
         int lineRight = lineLeft + lineWidth;
-        canvas.drawRoundRect(lineLeft, canvas.getHeight() / 2 - mLineHeight / 2, lineRight,
-                canvas.getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint);
+
+        canvas.drawRoundRect(lineLeft, getHeight() / 2 - mLineHeight / 2, lineRight,
+                getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint);
     }
 
     @Override
@@ -172,7 +157,7 @@
         } else if (mTotalScroll != totalScroll) {
             animateToTotalScroll(totalScroll);
         } else {
-            invalidateIfPortrait();
+            invalidate();
         }
 
         if (mShouldAutoHide) {
@@ -191,7 +176,13 @@
     @Override
     public void setMarkersCount(int numMarkers) {
         if (Float.compare(numMarkers, mNumPagesFloat) != 0) {
-            animateToNumPages(numMarkers);
+            setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numMarkers),
+                    NUM_PAGES_ANIMATOR_INDEX);
+        } else {
+            if (mAnimators[NUM_PAGES_ANIMATOR_INDEX] != null) {
+                mAnimators[NUM_PAGES_ANIMATOR_INDEX].cancel();
+                mAnimators[NUM_PAGES_ANIMATOR_INDEX] = null;
+            }
         }
     }
 
@@ -219,11 +210,6 @@
                 LINE_ALPHA_ANIMATOR_INDEX);
     }
 
-    private void animateToNumPages(int numPages) {
-        setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numPages),
-                NUM_PAGES_ANIMATOR_INDEX);
-    }
-
     private void animateToTotalScroll(int totalScroll) {
         setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll),
                 TOTAL_SCROLL_ANIMATOR_INDEX);
@@ -254,54 +240,18 @@
     @Override
     public void setInsets(Rect insets) {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        mIsLandscapeUi = grid.isVerticalBarLayout();
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
 
-        if (mIsLandscapeUi) {
-            if (grid.isSeascape()) {
-                lp.leftMargin = grid.hotseatBarSidePaddingPx;
-                lp.rightMargin = insets.right;
-                lp.gravity =  Gravity.RIGHT | Gravity.BOTTOM;
-            } else {
-                lp.leftMargin = insets.left;
-                lp.rightMargin = grid.hotseatBarSidePaddingPx;
-                lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
-            }
-            lp.bottomMargin = grid.workspacePadding.bottom;
-            lp.width = lp.height = getResources()
-                    .getDimensionPixelSize(R.dimen.dynamic_grid_min_page_indicator_size);
-
-            setBackgroundResource(R.drawable.all_apps_handle_landscape);
-            setOnFocusChangeListener(mLauncher.mFocusHandler);
-            setOnClickListener(this);
-
+        if (grid.isVerticalBarLayout()) {
+            Rect padding = grid.workspacePadding;
+            lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
+            lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
+            lp.bottomMargin = padding.bottom;
         } else {
             lp.leftMargin = lp.rightMargin = 0;
             lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
-            lp.height = grid.pageIndicatorSizePx;
             lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
-            lp.width = MATCH_PARENT;
-
-            setBackgroundResource(0);
-            setOnFocusChangeListener(null);
-            setOnClickListener(mAccessibilityManager.isTouchExplorationEnabled() ? this : null);
         }
-
         setLayoutParams(lp);
     }
-
-    private void invalidateIfPortrait() {
-        if (!mIsLandscapeUi) {
-            invalidate();
-        }
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (!mLauncher.isInState(ALL_APPS)) {
-            mLauncher.getUserEventDispatcher().logActionOnControl(
-                    Action.Touch.TAP, ControlType.ALL_APPS_BUTTON);
-            mLauncher.getStateManager().goToState(ALL_APPS);
-        }
-    }
 }
diff --git a/src/com/android/launcher3/views/LauncherDragIndicator.java b/src/com/android/launcher3/views/LauncherDragIndicator.java
new file mode 100644
index 0000000..f15129c
--- /dev/null
+++ b/src/com/android/launcher3/views/LauncherDragIndicator.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+
+public class LauncherDragIndicator extends ImageView implements Insettable, OnClickListener {
+
+    private static final int WALLPAPERS = R.string.wallpaper_button_text;
+    private static final int WIDGETS = R.string.widget_button_text;
+    private static final int SETTINGS = R.string.settings_button_text;
+
+    protected final Launcher mLauncher;
+
+    public LauncherDragIndicator(Context context) {
+        this(context, null);
+    }
+
+    public LauncherDragIndicator(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public LauncherDragIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLauncher = Launcher.getLauncher(context);
+        setOnClickListener(this);
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+
+        if (grid.isVerticalBarLayout()) {
+            if (grid.isSeascape()) {
+                lp.leftMargin = grid.hotseatBarSidePaddingPx;
+                lp.rightMargin = insets.right;
+                lp.gravity =  Gravity.RIGHT | Gravity.BOTTOM;
+            } else {
+                lp.leftMargin = insets.left;
+                lp.rightMargin = grid.hotseatBarSidePaddingPx;
+                lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
+            }
+            lp.bottomMargin = grid.workspacePadding.bottom;
+            setImageResource(R.drawable.all_apps_handle_landscape);
+        } else {
+            lp.leftMargin = lp.rightMargin = 0;
+            lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+            lp.bottomMargin = getPortraitBottomMargin(grid, insets);
+            setImageResource(R.drawable.ic_drag_indicator);
+        }
+
+        lp.width = lp.height = grid.pageIndicatorSizePx;
+        setLayoutParams(lp);
+    }
+
+    protected int getPortraitBottomMargin(DeviceProfile grid, Rect insets) {
+        return grid.hotseatBarSizePx + insets.bottom - grid.pageIndicatorSizePx;
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        initCustomActions(info);
+    }
+
+    protected void initCustomActions(AccessibilityNodeInfo info) {
+        Context context = getContext();
+        if (Utilities.isWallpaperAllowed(context)) {
+            info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS)));
+        }
+        info.addAction(new AccessibilityAction(WIDGETS, context.getText(WIDGETS)));
+        info.addAction(new AccessibilityAction(SETTINGS, context.getText(SETTINGS)));
+    }
+
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        Launcher launcher = Launcher.getLauncher(getContext());
+        if (action == WALLPAPERS) {
+            launcher.onClickWallpaperPicker(this);
+            return true;
+        } else if (action == WIDGETS) {
+            return OptionsPopupView.onWidgetsClicked(launcher);
+        } else if (action == SETTINGS) {
+            OptionsPopupView.startSettings(launcher);
+            return true;
+        }
+        return super.performAccessibilityAction(action, arguments);
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (!mLauncher.isInState(ALL_APPS)) {
+            mLauncher.getUserEventDispatcher().logActionOnControl(
+                    Action.Touch.TAP, ControlType.ALL_APPS_BUTTON);
+            mLauncher.getStateManager().goToState(ALL_APPS);
+        }
+    }
+}