Merge "Calling buildLayer only on views which are actually visible" into ub-launcher3-master
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 803a1b5..1909f3b 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -53,6 +53,7 @@
             android:clipToPadding="false"
             android:descendantFocusability="afterDescendants"
             android:focusable="true"
+            android:paddingStart="@dimen/container_fastscroll_thumb_max_width"
             android:paddingEnd="@dimen/container_fastscroll_thumb_max_width"
             android:theme="@style/CustomOverscroll.Light" />
 
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index 9ba3f09..2091721 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -15,11 +15,13 @@
      limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:launcher="http://schemas.android.com/apk/res-auto"
+      launcher:layout_ignoreInsets="true"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center_horizontal|bottom"
       android:gravity="top"
-      android:orientation="horizontal" >
+      android:orientation="horizontal">
 
     <TextView
         android:id="@+id/wallpaper_button"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 316e748..b07a400 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -33,8 +33,6 @@
     <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>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 90338ae..bb0bc2f 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -88,7 +88,6 @@
         <item name="android:background">@null</item>
         <item name="android:textColor">@color/quantum_panel_text_color</item>
         <item name="android:shadowRadius">0</item>
-        <item name="android:textSize">@dimen/folder_child_text_size</item>
         <item name="android:gravity">center_horizontal</item>
         <item name="android:includeFontPadding">false</item>
         <item name="customShadows">false</item>
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index b7321d9..ac7cbaf 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -19,7 +19,6 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
@@ -41,13 +40,9 @@
 public abstract class BaseContainerView extends FrameLayout
         implements DeviceProfile.LauncherLayoutChangeListener {
 
-    protected int mContainerPaddingLeft;
-    protected int mContainerPaddingRight;
-    protected int mContainerPaddingTop;
-    protected int mContainerPaddingBottom;
+    private static final Rect sBgPaddingRect = new Rect();
 
     protected final Drawable mBaseDrawable;
-    private final Rect mBgPaddingRect = new Rect();
 
     private View mRevealView;
     private View mContent;
@@ -110,23 +105,56 @@
     }
 
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        getRevealView().getBackground().getPadding(mBgPaddingRect);
+    public void onLauncherLayoutChanged() {
+        updatePaddings();
+    }
 
-        View touchDelegateTargetView = getTouchDelegateTargetView();
-        if (touchDelegateTargetView != null) {
-            mTouchDelegate.setBounds(
-                    touchDelegateTargetView.getLeft() - mBgPaddingRect.left,
-                    touchDelegateTargetView.getTop() - mBgPaddingRect.top,
-                    touchDelegateTargetView.getRight() + mBgPaddingRect.right,
-                    touchDelegateTargetView.getBottom() + mBgPaddingRect.bottom);
+    /**
+     * Calculate the background padding as it can change due to insets/content padding change.
+     */
+    private void updatePaddings() {
+        Context context = getContext();
+        int paddingLeft;
+        int paddingRight;
+        int paddingTop;
+        int paddingBottom;
+
+        DeviceProfile grid = Launcher.getLauncher(context).getDeviceProfile();
+        int[] padding = grid.getContainerPadding();
+        paddingLeft = padding[0] + grid.edgeMarginPx;
+        paddingRight = padding[1] + grid.edgeMarginPx;
+        if (!grid.isVerticalBarLayout()) {
+            paddingTop = paddingBottom = grid.edgeMarginPx;
+        } else {
+            paddingTop = paddingBottom = 0;
         }
+        updateBackground(paddingLeft, paddingTop, paddingRight, paddingBottom);
+    }
+
+    /**
+     * Update the background for the reveal view and content view based on the background padding.
+     */
+    protected void updateBackground(int paddingLeft, int paddingTop,
+            int paddingRight, int paddingBottom) {
+        mRevealView.setBackground(new InsetDrawable(mBaseDrawable,
+                paddingLeft, paddingTop, paddingRight, paddingBottom));
+        mContent.setBackground(new InsetDrawable(mBaseDrawable,
+                paddingLeft, paddingTop, paddingRight, paddingBottom));
     }
 
     @Override
-    public void onLauncherLayoutChanged() {
-        updatePaddings();
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        View touchDelegateTargetView = getTouchDelegateTargetView();
+        if (touchDelegateTargetView != null) {
+            getRevealView().getBackground().getPadding(sBgPaddingRect);
+            mTouchDelegate.setBounds(
+                    touchDelegateTargetView.getLeft() - sBgPaddingRect.left,
+                    touchDelegateTargetView.getTop() - sBgPaddingRect.top,
+                    touchDelegateTargetView.getRight() + sBgPaddingRect.right,
+                    touchDelegateTargetView.getBottom() + sBgPaddingRect.bottom);
+        }
     }
 
     @Override
@@ -152,33 +180,6 @@
         return mRevealView;
     }
 
-    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;
-            }
-        }
-
-        InsetDrawable revealDrawable = new InsetDrawable(mBaseDrawable,
-                mContainerPaddingLeft, mContainerPaddingTop, mContainerPaddingRight,
-                mContainerPaddingBottom);
-        mRevealView.setBackground(revealDrawable);
-        mContent.setBackground(revealDrawable);
-    }
 
     /**
      * Handles the touch events that shows the workspace when clicking outside the bounds of the
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 7d693ec..bb4b2ce 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -128,7 +128,9 @@
             setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
             defaultIconSize = grid.allAppsIconSizePx;
         } else if (display == DISPLAY_FOLDER) {
+            setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
             setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
+            defaultIconSize = grid.folderChildIconSizePx;
         }
         mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 655c218..d92f659 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -96,8 +96,14 @@
     public int folderBackgroundOffset;
     public int folderIconSizePx;
     public int folderIconPreviewPadding;
+
+    // Folder cell
     public int folderCellWidthPx;
     public int folderCellHeightPx;
+
+    // Folder child
+    public int folderChildIconSizePx;
+    public int folderChildTextSizePx;
     public int folderChildDrawablePaddingPx;
 
     // Hotseat
@@ -116,10 +122,6 @@
     public int allAppsIconDrawablePaddingPx;
     public float allAppsIconTextSizePx;
 
-    // Containers
-    private final int containerLeftPaddingPx;
-    private final int containerRightPaddingPx;
-
     // Drop Target
     public int dropTargetBarSizePx;
 
@@ -184,10 +186,6 @@
         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;
@@ -205,6 +203,13 @@
         computeAllAppsButtonSize(context);
     }
 
+    DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
+        // In multi-window mode, we can have widthPx = availableWidthPx
+        // and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles'
+        // widthPx and heightPx values where it's needed.
+        return new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y, isLandscape);
+    }
+
     public void addLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
         if (!mListeners.contains(listener)) {
             mListeners.add(listener);
@@ -229,19 +234,17 @@
     }
 
     private void updateAvailableDimensions(DisplayMetrics dm, Resources res) {
-        // Check to see if the icons fit in the new available height.  If not, then we need to
-        // shrink the icon size.
-        float scale = 1f;
-        int drawablePadding = iconDrawablePaddingOriginalPx;
-        updateIconSize(1f, drawablePadding, res, dm);
-        float usedHeight = (cellHeightPx * inv.numRows);
+        updateIconSize(1f, iconDrawablePaddingOriginalPx, res, dm);
 
+        // Check to see if the icons fit within the available height.  If not, then scale down.
+        float usedHeight = (cellHeightPx * inv.numRows);
         int maxHeight = (availableHeightPx - getTotalWorkspacePadding().y);
         if (usedHeight > maxHeight) {
-            scale = maxHeight / usedHeight;
-            drawablePadding = 0;
+            float scale = maxHeight / usedHeight;
+            updateIconSize(scale, 0, res, dm);
         }
-        updateIconSize(scale, drawablePadding, res, dm);
+
+        updateAvailableFolderCellDimensions(dm, res);
     }
 
     private void updateIconSize(float scale, int drawablePadding, Resources res,
@@ -277,31 +280,47 @@
                     res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
         }
 
-        // Folder cell
-        int cellPaddingX = res.getDimensionPixelSize(R.dimen.folder_cell_x_padding);
-        int cellPaddingY = res.getDimensionPixelSize(R.dimen.folder_cell_y_padding);
-        final int folderChildTextSize =
-                Utilities.calculateTextHeight(res.getDimension(R.dimen.folder_child_text_size));
-
-        final int folderBottomPanelSize =
-                res.getDimensionPixelSize(R.dimen.folder_label_padding_top)
-                 + res.getDimensionPixelSize(R.dimen.folder_label_padding_bottom)
-                + Utilities.calculateTextHeight(res.getDimension(R.dimen.folder_label_text_size));
-
-        // Don't let the folder get too close to the edges of the screen.
-        folderCellWidthPx = Math.min(iconSizePx + 2 * cellPaddingX,
-                (availableWidthPx - 4 * edgeMarginPx) / inv.numFolderColumns);
-        folderCellHeightPx = Math.min(iconSizePx + 3 * cellPaddingY + folderChildTextSize,
-                (availableHeightPx - 4 * edgeMarginPx - folderBottomPanelSize) / inv.numFolderRows);
-        folderChildDrawablePaddingPx = Math.max(0,
-                (folderCellHeightPx - iconSizePx - folderChildTextSize) / 3);
-
         // Folder icon
         folderBackgroundOffset = -edgeMarginPx;
         folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
         folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
     }
 
+    private void updateAvailableFolderCellDimensions(DisplayMetrics dm, Resources res) {
+        int folderBottomPanelSize = res.getDimensionPixelSize(R.dimen.folder_label_padding_top)
+                + res.getDimensionPixelSize(R.dimen.folder_label_padding_bottom)
+                + Utilities.calculateTextHeight(res.getDimension(R.dimen.folder_label_text_size));
+
+        updateFolderCellSize(1f, dm, res, folderBottomPanelSize);
+
+        // Check to see if the icons fit within the available height.  If not, then scale down.
+        float usedHeight = (folderCellHeightPx * inv.numFolderRows) + folderBottomPanelSize;
+        int maxHeight = availableHeightPx - getTotalWorkspacePadding().y - (2 * edgeMarginPx);
+        if (usedHeight > maxHeight) {
+            float scale = maxHeight / usedHeight;
+            updateFolderCellSize(scale, dm, res, folderBottomPanelSize);
+        }
+    }
+
+    private void updateFolderCellSize(float scale, DisplayMetrics dm, Resources res,
+             int folderBottomPanelSize) {
+        folderChildIconSizePx = (int) (Utilities.pxFromDp(inv.iconSize, dm) * scale);
+        folderChildTextSizePx =
+                (int) (res.getDimensionPixelSize(R.dimen.folder_child_text_size) * scale);
+
+        int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
+        int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding) * scale);
+        int cellPaddingY = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_y_padding) * scale);
+
+        // Don't let the folder get too close to the edges of the screen.
+        folderCellWidthPx = Math.min(folderChildIconSizePx + 2 * cellPaddingX,
+                (availableWidthPx - 4 * edgeMarginPx) / inv.numFolderColumns);
+        folderCellHeightPx = Math.min(folderChildIconSizePx + 2 * cellPaddingY + textHeight,
+                (availableHeightPx - 4 * edgeMarginPx - folderBottomPanelSize) / inv.numFolderRows);
+        folderChildDrawablePaddingPx = Math.max(0,
+                (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3);
+    }
+
     public void updateInsets(Rect insets) {
         mInsets.set(insets);
     }
@@ -548,18 +567,13 @@
         // Layout the Overview Mode
         ViewGroup overviewMode = launcher.getOverviewPanel();
         if (overviewMode != null) {
-            lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
-            lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
-
             int visibleChildCount = getVisibleChildCount(overviewMode);
             int totalItemWidth = visibleChildCount * overviewModeBarItemWidthPx;
-            int maxWidth = totalItemWidth + (visibleChildCount-1) * overviewModeBarSpacerWidthPx;
+            int maxWidth = totalItemWidth + (visibleChildCount - 1) * overviewModeBarSpacerWidthPx;
 
+            lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
             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;
+            lp.height = getOverviewModeButtonBarHeight() + mInsets.bottom;
             overviewMode.setLayoutParams(lp);
         }
 
@@ -586,9 +600,7 @@
     /**
      * @return the left/right paddings for all containers.
      */
-    public final int[] getContainerPadding(Context context) {
-        Resources res = context.getResources();
-
+    public final int[] getContainerPadding() {
         // No paddings for portrait phone
         if (isPhone && !isVerticalBarLayout()) {
             return new int[] {0, 0};
@@ -599,4 +611,11 @@
                 hotseatBarHeightPx + hotseatLandGutterPx + mInsets.left) / 2;
         return new int[]{ padding, padding };
     }
+
+    public boolean shouldIgnoreLongPressToOverview(float touchX, float edgeThreshold) {
+        boolean inMultiWindowMode = this != inv.landscapeProfile && this != inv.portraitProfile;
+        boolean touchedLhsEdge = mInsets.left == 0 && touchX < edgeThreshold;
+        boolean touchedRhsEdge = mInsets.right == 0 && touchX > (widthPx - edgeThreshold);
+        return !inMultiWindowMode && (touchedLhsEdge || touchedRhsEdge);
+    }
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d870f9e..9a42513 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -45,6 +45,7 @@
 import android.content.res.Configuration;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Bitmap;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
@@ -360,10 +361,17 @@
         LauncherAppState app = LauncherAppState.getInstance();
 
         // Load configuration-specific DeviceProfile
-        mDeviceProfile = getResources().getConfiguration().orientation
-                == Configuration.ORIENTATION_LANDSCAPE ?
-                app.getInvariantDeviceProfile().landscapeProfile
-                : app.getInvariantDeviceProfile().portraitProfile;
+        mDeviceProfile =
+                getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE
+                        ? app.getInvariantDeviceProfile().landscapeProfile
+                        : app.getInvariantDeviceProfile().portraitProfile;
+
+        if (Utilities.ATLEAST_NOUGAT && isInMultiWindowMode()) {
+            Display display = getWindowManager().getDefaultDisplay();
+            Point mwSize = new Point();
+            display.getSize(mwSize);
+            mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
+        }
 
         mSharedPrefs = Utilities.getPrefs(this);
         mIsSafeModeEnabled = getPackageManager().isSafeMode();
@@ -459,7 +467,7 @@
 
     private void loadExtractedColorsAndColorItems() {
         // TODO: do this in pre-N as well, once the extraction part is complete.
-        if (Utilities.isNycOrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT) {
             mExtractedColors.load(this);
             mHotseat.updateColor(mExtractedColors, !mPaused);
             mWorkspace.getPageIndicator().updateColor(mExtractedColors);
@@ -906,7 +914,7 @@
             mLauncherCallbacks.onStop();
         }
 
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             mAppWidgetHost.stopListening();
         }
     }
@@ -920,7 +928,7 @@
             mLauncherCallbacks.onStart();
         }
 
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             mAppWidgetHost.startListening();
         }
     }
@@ -2470,20 +2478,27 @@
             return;
         }
 
-        String pickerPackage = getString(R.string.wallpaper_picker_package);
-        if (TextUtils.isEmpty(pickerPackage)) {
-            pickerPackage =  PackageManagerHelper.getWallpaperPickerPackage(getPackageManager());
-        }
-
         int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
         float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
-
         setWaitingForResult(new PendingRequestArgs(new ItemInfo()));
         Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
-                .setPackage(pickerPackage)
                 .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset);
+
+        String pickerPackage = getString(R.string.wallpaper_picker_package);
+        boolean hasTargetPackage = TextUtils.isEmpty(pickerPackage);
+        if (!hasTargetPackage) {
+            intent.setPackage(pickerPackage);
+        }
+
         intent.setSourceBounds(getViewBounds(v));
-        startActivityForResult(intent, REQUEST_PICK_WALLPAPER, getActivityLaunchOptions(v));
+        try {
+            startActivityForResult(intent, REQUEST_PICK_WALLPAPER,
+                    // If there is no target package, use the default intent chooser animation
+                    hasTargetPackage ? getActivityLaunchOptions(v) : null);
+        } catch (ActivityNotFoundException e) {
+            setWaitingForResult(null);
+            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+        }
     }
 
     /**
@@ -2702,12 +2717,13 @@
             return true;
         }
 
-        boolean fromEdgeOfScreen = mLastDispatchTouchEventX < mEdgeOfScreenThresholdPx
-                || mLastDispatchTouchEventX > (mDeviceProfile.widthPx - mEdgeOfScreenThresholdPx);
+
+        boolean ignoreLongPressToOverview = mDeviceProfile.shouldIgnoreLongPressToOverview(
+                mLastDispatchTouchEventX, mEdgeOfScreenThresholdPx);
 
         if (v instanceof Workspace) {
             if (!mWorkspace.isInOverviewMode()) {
-                if (!mWorkspace.isTouchActive() && !fromEdgeOfScreen) {
+                if (!mWorkspace.isTouchActive() && !ignoreLongPressToOverview) {
                     getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.LONGPRESS,
                             LauncherLogProto.Action.NONE, LauncherLogProto.WORKSPACE,
                             mWorkspace.getCurrentPage());
@@ -2742,7 +2758,7 @@
                     getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.LONGPRESS,
                             LauncherLogProto.Action.NONE, LauncherLogProto.OVERVIEW);
                 } else {
-                    if (fromEdgeOfScreen) {
+                    if (ignoreLongPressToOverview) {
                         return false;
                     }
                     getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.LONGPRESS,
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 1ee4a1a..2a43aad 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -115,7 +115,7 @@
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
         // For extracting colors from the wallpaper
-        if (Utilities.isNycOrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT) {
             // TODO: add a broadcast entry to the manifest for pre-N.
             filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
         }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 55bd0a4..955f51f 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2692,7 +2692,7 @@
      * use partial updates similar to {@link UserManagerCompat}
      */
     public void refreshShortcutsIfRequired() {
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             sWorker.removeCallbacks(mShortcutPermissionCheckRunnable);
             sWorker.post(mShortcutPermissionCheckRunnable);
         }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 0abac36..ee7f9f8 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1068,6 +1068,10 @@
 
     @Override
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
+            return;
+        }
+
         // XXX-RTL: This will be fixed in a future CL
         if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
             getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 95e3d82..568a52f 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -48,7 +48,6 @@
 import android.util.Pair;
 import android.util.SparseArray;
 import android.util.TypedValue;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -60,7 +59,6 @@
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Locale;
 import java.util.Set;
@@ -83,14 +81,15 @@
 
     private static final int[] sLoc0 = new int[2];
     private static final int[] sLoc1 = new int[2];
+    private static final float[] sPoint = new float[2];
+    private static final Matrix sMatrix = new Matrix();
+    private static final Matrix sInverseMatrix = new Matrix();
 
-    public static boolean isNycMR1OrAbove() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1;
-    }
+    public static final boolean ATLEAST_NOUGAT_MR1 =
+        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1;
 
-    public static boolean isNycOrAbove() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
-    }
+    public static final boolean ATLEAST_NOUGAT =
+        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
 
     public static final boolean ATLEAST_MARSHMALLOW =
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
@@ -137,7 +136,7 @@
     }
 
     public static boolean getAllowRotationDefaultValue(Context context) {
-        if (isNycOrAbove()) {
+        if (ATLEAST_NOUGAT) {
             // If the device was scaled, used the original dimensions to determine if rotation
             // is allowed of not.
             Resources res = context.getResources();
@@ -163,68 +162,52 @@
      */
     public static float getDescendantCoordRelativeToAncestor(
             View descendant, View ancestor, int[] coord, boolean includeRootScroll) {
-        float[] pt = {coord[0], coord[1]};
+        sPoint[0] = coord[0];
+        sPoint[1] = coord[1];
+
         float scale = 1.0f;
         View v = descendant;
         while(v != ancestor && v != null) {
             // For TextViews, scroll has a meaning which relates to the text position
             // which is very strange... ignore the scroll.
             if (v != descendant || includeRootScroll) {
-                pt[0] -= v.getScrollX();
-                pt[1] -= v.getScrollY();
+                sPoint[0] -= v.getScrollX();
+                sPoint[1] -= v.getScrollY();
             }
 
-            v.getMatrix().mapPoints(pt);
-            pt[0] += v.getLeft();
-            pt[1] += v.getTop();
+            v.getMatrix().mapPoints(sPoint);
+            sPoint[0] += v.getLeft();
+            sPoint[1] += v.getTop();
             scale *= v.getScaleX();
 
             v = (View) v.getParent();
         }
 
-        coord[0] = Math.round(pt[0]);
-        coord[1] = Math.round(pt[1]);
+        coord[0] = Math.round(sPoint[0]);
+        coord[1] = Math.round(sPoint[1]);
         return scale;
     }
 
     /**
      * Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, int[], boolean)}.
      */
-    public static float mapCoordInSelfToDescendent(View descendant, View root,
-                                                   int[] coord) {
-        ArrayList<View> ancestorChain = new ArrayList<View>();
-
-        float[] pt = {coord[0], coord[1]};
-
+    public static void mapCoordInSelfToDescendant(View descendant, View root, int[] coord) {
+        sMatrix.reset();
         View v = descendant;
         while(v != root) {
-            ancestorChain.add(v);
+            sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY());
+            sMatrix.postConcat(v.getMatrix());
+            sMatrix.postTranslate(v.getLeft(), v.getTop());
             v = (View) v.getParent();
         }
-        ancestorChain.add(root);
+        sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY());
+        sMatrix.invert(sInverseMatrix);
 
-        float scale = 1.0f;
-        Matrix inverse = new Matrix();
-        int count = ancestorChain.size();
-        for (int i = count - 1; i >= 0; i--) {
-            View ancestor = ancestorChain.get(i);
-            View next = i > 0 ? ancestorChain.get(i-1) : null;
-
-            pt[0] += ancestor.getScrollX();
-            pt[1] += ancestor.getScrollY();
-
-            if (next != null) {
-                pt[0] -= next.getLeft();
-                pt[1] -= next.getTop();
-                next.getMatrix().invert(inverse);
-                inverse.mapPoints(pt);
-                scale *= next.getScaleX();
-            }
-        }
-
-        coord[0] = (int) Math.round(pt[0]);
-        coord[1] = (int) Math.round(pt[1]);
-        return scale;
+        sPoint[0] = coord[0];
+        sPoint[1] = coord[1];
+        sInverseMatrix.mapPoints(sPoint);
+        coord[0] = Math.round(sPoint[0]);
+        coord[1] = Math.round(sPoint[1]);
     }
 
     /**
@@ -238,30 +221,6 @@
                 localY < (v.getHeight() + slop);
     }
 
-    /** Translates MotionEvents from src's coordinate system to dst's. */
-    public static void translateEventCoordinates(View src, View dst, MotionEvent dstEvent) {
-        toGlobalMotionEvent(src, dstEvent);
-        toLocalMotionEvent(dst, dstEvent);
-    }
-
-    /**
-     * Emulates View.toGlobalMotionEvent(). This implementation does not handle transformations
-     * (scaleX, scaleY, etc).
-     */
-    private static void toGlobalMotionEvent(View view, MotionEvent event) {
-        view.getLocationOnScreen(sLoc0);
-        event.offsetLocation(sLoc0[0], sLoc0[1]);
-    }
-
-    /**
-     * Emulates View.toLocalMotionEvent(). This implementation does not handle transformations
-     * (scaleX, scaleY, etc).
-     */
-    private static void toLocalMotionEvent(View view, MotionEvent event) {
-        view.getLocationOnScreen(sLoc0);
-        event.offsetLocation(-sLoc0[0], -sLoc0[1]);
-    }
-
     public static int[] getCenterDeltaInScreenSpace(View v0, View v1, int[] delta) {
         v0.getLocationInWindow(sLoc0);
         v1.getLocationInWindow(sLoc1);
@@ -619,7 +578,7 @@
     }
 
     public static boolean isWallpaperAllowed(Context context) {
-        if (isNycOrAbove()) {
+        if (ATLEAST_NOUGAT) {
             try {
                 WallpaperManager wm = context.getSystemService(WallpaperManager.class);
                 return (Boolean) wm.getClass().getDeclaredMethod("isSetWallpaperAllowed")
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 45e65b5..354b8ec 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -242,7 +242,7 @@
                     CacheDb.COLUMN_COMPONENT + " = ? AND " + CacheDb.COLUMN_USER + " = ? AND "
                             + CacheDb.COLUMN_SIZE + " = ?",
                     new String[]{
-                            key.componentName.flattenToString(),
+                            key.componentName.flattenToShortString(),
                             Long.toString(mUserManager.getSerialNumberForUser(key.user)),
                             key.size
                     });
@@ -301,7 +301,14 @@
 
         Drawable drawable = null;
         if (info.previewImage != 0) {
-            drawable = mWidgetManager.loadPreview(info);
+            try {
+                drawable = mWidgetManager.loadPreview(info);
+            } catch (OutOfMemoryError e) {
+                Log.w(TAG, "Error loading widget preview for: " + info.provider, e);
+                // During OutOfMemoryError, the previous heap stack is not affected. Catching
+                // an OOM error here should be safe & not affect other parts of launcher.
+                drawable = null;
+            }
             if (drawable != null) {
                 drawable = mutateOnMainThread(drawable);
             } else {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 1738093..95a5ee2 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1678,7 +1678,7 @@
         if (mWorkspaceFadeInAdjacentScreens &&
                 !workspaceInModalState() &&
                 !mIsSwitchingState) {
-            int screenCenter = getScrollX() + getViewportOffsetX() + getViewportWidth() / 2;
+            int screenCenter = getScrollX() + getViewportWidth() / 2;
             for (int i = numCustomPages(); i < getChildCount(); i++) {
                 CellLayout child = (CellLayout) getChildAt(i);
                 if (child != null) {
@@ -1815,7 +1815,7 @@
                 }
             });
         }
-
+        updatePageAlphaValues();
     }
 
     @Override
@@ -3597,8 +3597,10 @@
     public void onDropCompleted(final View target, final DragObject d,
             final boolean isFlingToDelete, final boolean success) {
         if (mDeferDropAfterUninstall) {
+            final CellLayout.CellInfo dragInfo = mDragInfo;
             mDeferredAction = new Runnable() {
                 public void run() {
+                    mDragInfo = dragInfo; // Restore the drag info that was cleared in onDragEnd()
                     onDropCompleted(target, d, isFlingToDelete, success);
                     mDeferredAction = null;
                 }
@@ -3626,6 +3628,7 @@
                 && mDragInfo.cell != null) {
             mDragInfo.cell.setVisibility(VISIBLE);
         }
+        mDragInfo = null;
 
         if (!isFlingToDelete) {
             // Fling to delete already exits spring loaded mode after the animation finishes.
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 768d17b..34d8a83 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -16,7 +16,10 @@
 package com.android.launcher3.allapps;
 
 import android.content.Context;
+import android.graphics.Color;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.InsetDrawable;
 import android.support.v7.widget.RecyclerView;
 import android.text.Selection;
 import android.text.Spannable;
@@ -100,6 +103,24 @@
         Selection.setSelection(mSearchQueryBuilder, 0);
     }
 
+    @Override
+    protected void updateBackground(
+            int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
+        if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+            if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+                getRevealView().setBackground(new InsetDrawable(mBaseDrawable,
+                        paddingLeft, paddingTop, paddingRight, paddingBottom));
+                getContentView().setBackground(
+                        new InsetDrawable(new ColorDrawable(Color.TRANSPARENT),
+                                paddingLeft, paddingTop, paddingRight, paddingBottom));
+            } else {
+                getRevealView().setBackground(mBaseDrawable);
+            }
+        } else {
+            super.updateBackground(paddingLeft, paddingTop, paddingRight, paddingBottom);
+        }
+    }
+
     /**
      * Sets the current set of predicted apps.
      */
@@ -172,7 +193,7 @@
         int[] point = new int[2];
         point[0] = (int) ev.getX();
         point[1] = (int) ev.getY();
-        Utilities.mapCoordInSelfToDescendent(mAppsRecyclerView, this, point);
+        Utilities.mapCoordInSelfToDescendant(mAppsRecyclerView, this, point);
 
         // IF the MotionEvent is inside the search box, and the container keeps on receiving
         // touch input, container should move down.
diff --git a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
index c7a529d..84e82e3 100644
--- a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
+++ b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
@@ -23,7 +23,7 @@
         BaseIndex index = null;
 
         try {
-            if (Utilities.isNycOrAbove()) {
+            if (Utilities.ATLEAST_NOUGAT) {
                 index = new AlphabeticIndexVN(context);
             }
         } catch (Exception e) {
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
index a5f8dd2..b40eaa2 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -32,9 +32,9 @@
     public static UserManagerCompat getInstance(Context context) {
         synchronized (sInstanceLock) {
             if (sInstance == null) {
-                if (Utilities.isNycMR1OrAbove()) {
+                if (Utilities.ATLEAST_NOUGAT_MR1) {
                     sInstance = new UserManagerCompatVNMr1(context.getApplicationContext());
-                } else if (Utilities.isNycOrAbove()) {
+                } else if (Utilities.ATLEAST_NOUGAT) {
                     sInstance = new UserManagerCompatVN(context.getApplicationContext());
                 } else if (Utilities.ATLEAST_MARSHMALLOW) {
                     sInstance = new UserManagerCompatVM(context.getApplicationContext());
diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java
index 4db8c07..d0c8e16 100644
--- a/src/com/android/launcher3/dragndrop/DragDriver.java
+++ b/src/com/android/launcher3/dragndrop/DragDriver.java
@@ -92,7 +92,7 @@
 
     public static DragDriver create(Context context, DragController dragController,
             DragObject dragObject, DragOptions options) {
-        if (Utilities.isNycOrAbove() && options.systemDndStartPoint != null) {
+        if (Utilities.ATLEAST_NOUGAT && options.systemDndStartPoint != null) {
             return new SystemDragDriver(dragController, context, dragObject);
         } else {
             return new InternalDragDriver(dragController);
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 59d18c2..9de4452 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -390,7 +390,7 @@
 
     @TargetApi(Build.VERSION_CODES.N)
     private void handleSystemDragStart(DragEvent event) {
-        if (!FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER || !Utilities.isNycOrAbove()) {
+        if (!FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER || !Utilities.ATLEAST_NOUGAT) {
             return;
         }
         if (mLauncher.isWorkspaceLocked()) {
@@ -480,8 +480,8 @@
     /**
      * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
      */
-    public float mapCoordInSelfToDescendant(View descendant, int[] coord) {
-        return Utilities.mapCoordInSelfToDescendent(descendant, this, coord);
+    public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
+        Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
     }
 
     public void getViewRectRelativeToSelf(View v, Rect r) {
diff --git a/src/com/android/launcher3/dynamicui/ExtractionUtils.java b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
index 1e663a9..1cf5d55 100644
--- a/src/com/android/launcher3/dynamicui/ExtractionUtils.java
+++ b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
@@ -62,7 +62,7 @@
     }
 
     private static boolean hasWallpaperIdChanged(Context context) {
-        if (!Utilities.isNycOrAbove()) {
+        if (!Utilities.ATLEAST_NOUGAT) {
             // TODO: update an id in sharedprefs in onWallpaperChanged broadcast, and read it here.
             return false;
         }
@@ -74,7 +74,7 @@
 
     @TargetApi(Build.VERSION_CODES.N)
     public static int getWallpaperId(WallpaperManager wallpaperManager) {
-        return Utilities.isNycOrAbove() ?
+        return Utilities.ATLEAST_NOUGAT ?
                 wallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM) : -1;
     }
 
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index fd647c7..599dcd0 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -42,7 +42,7 @@
  */
 public class GridSizeMigrationTask {
 
-    public static boolean ENABLED = Utilities.isNycOrAbove();
+    public static boolean ENABLED = Utilities.ATLEAST_NOUGAT;
 
     private static final String TAG = "GridSizeMigrationTask";
     private static final boolean DEBUG = true;
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 9037af4..c2c7c17 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -91,7 +91,7 @@
      */
     @TargetApi(25)
     public void unpinShortcut(final ShortcutKey key) {
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             String packageName = key.componentName.getPackageName();
             String id = key.getId();
             UserHandleCompat user = key.user;
@@ -113,7 +113,7 @@
      */
     @TargetApi(25)
     public void pinShortcut(final ShortcutKey key) {
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             String packageName = key.componentName.getPackageName();
             String id = key.getId();
             UserHandleCompat user = key.user;
@@ -132,7 +132,7 @@
     @TargetApi(25)
     public void startShortcut(String packageName, String id, Rect sourceBounds,
           Bundle startActivityOptions, UserHandleCompat user) {
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             try {
                 mLauncherApps.startShortcut(packageName, id, sourceBounds,
                         startActivityOptions, user.getUser());
@@ -146,7 +146,7 @@
 
     @TargetApi(25)
     public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             try {
                 Drawable icon = mLauncherApps.getShortcutIconDrawable(
                         shortcutInfo.getShortcutInfo(), density);
@@ -191,7 +191,7 @@
     @TargetApi(25)
     private List<ShortcutInfoCompat> query(int flags, String packageName,
             ComponentName activity, List<String> shortcutIds, UserHandleCompat user) {
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             ShortcutQuery q = new ShortcutQuery();
             q.setQueryFlags(flags);
             if (packageName != null) {
@@ -222,7 +222,7 @@
 
     @TargetApi(25)
     public boolean hasHostPermission() {
-        if (Utilities.isNycMR1OrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT_MR1) {
             try {
                 return mLauncherApps.hasShortcutHostPermission();
             } catch (SecurityException|IllegalStateException e) {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 4daa09e..08ca242 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.TimeInterpolator;
+import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
@@ -27,6 +28,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.ShapeDrawable;
 import android.os.Build;
@@ -37,6 +39,7 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.LinearLayout;
@@ -88,6 +91,7 @@
 
     private BubbleTextView mOriginalIcon;
     private final Rect mTempRect = new Rect();
+    private PointF mInterceptTouchDown = new PointF();
     private Point mIconLastTouchPos = new Point();
     private boolean mIsLeftAligned;
     private boolean mIsAboveIcon;
@@ -413,6 +417,26 @@
     }
 
     @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mInterceptTouchDown.set(ev.getX(), ev.getY());
+            return false;
+        }
+        // Stop sending touch events to deep shortcut views if user moved beyond touch slop.
+        return Math.hypot(mInterceptTouchDown.x - ev.getX(), mInterceptTouchDown.y - ev.getY())
+                > ViewConfiguration.get(getContext()).getScaledTouchSlop();
+    }
+
+    /**
+     * We need to handle touch events to prevent them from falling through to the workspace below.
+     */
+    @SuppressLint("ClickableViewAccessibility")
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return true;
+    }
+
+    @Override
     public boolean onTouch(View v, MotionEvent ev) {
         // Touched a shortcut, update where it was touched so we can drag from there on long click.
         switch (ev.getAction()) {
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 3e15d05..b61d609 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -28,15 +28,12 @@
 
 import com.android.launcher3.Utilities;
 
-import java.util.ArrayList;
-
 /**
  * Utility methods using package manager
  */
 public class PackageManagerHelper {
 
     private static final int FLAG_SUSPENDED = 1<<30;
-    private static final String LIVE_WALLPAPER_PICKER_PKG = "com.android.wallpaper.livepicker";
 
     /**
      * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
@@ -72,7 +69,7 @@
         // The value of FLAG_SUSPENDED was reused by a hidden constant
         // ApplicationInfo.FLAG_PRIVILEGED prior to N, so only check for suspended flag on N
         // or later.
-        if (Utilities.isNycOrAbove()) {
+        if (Utilities.ATLEAST_NOUGAT) {
             return (info.flags & FLAG_SUSPENDED) != 0;
         } else {
             return false;
@@ -80,29 +77,6 @@
     }
 
     /**
-     * Returns the package for a wallpaper picker system app giving preference to a app which
-     * is not as image picker.
-     */
-    public static String getWallpaperPickerPackage(PackageManager pm) {
-        ArrayList<String> excludePackages = new ArrayList<>();
-        // Exclude packages which contain an image picker
-        for (ResolveInfo info : pm.queryIntentActivities(
-                new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"), 0)) {
-            excludePackages.add(info.activityInfo.packageName);
-        }
-        excludePackages.add(LIVE_WALLPAPER_PICKER_PKG);
-
-        for (ResolveInfo info : pm.queryIntentActivities(
-                new Intent(Intent.ACTION_SET_WALLPAPER), 0)) {
-            if (!excludePackages.contains(info.activityInfo.packageName) &&
-                    (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                return info.activityInfo.packageName;
-            }
-        }
-        return excludePackages.get(0);
-    }
-
-    /**
      * Returns true if {@param srcPackage} has the permission required to start the activity from
      * {@param intent}. If {@param srcPackage} is null, then the activity should not need
      * any permissions