Merge "Fixing bug when model was not reflected properly on the UI. If launcher submits a job, and then reloads before the job is executed, the correct model is not reflected on the Launcher. In that case, we simply rebind the launcher" into ub-launcher3-master
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7240e48
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+db_files
+*.iml
+.project
+.classpath
+.project.properties
+gen/
+tests/stress/gen/
+WallpaperPicker/gen/
+WallpaperPicker/.project.properties
+bin/
+.idea/
+.gradle/
+local.properties
+gradle/
+build/
+gradlew*
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 12ae85d..b97669b 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -17,6 +17,7 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
 import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
 import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
@@ -48,6 +49,7 @@
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.InsettableFrameLayout.LayoutParams;
 import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.dragndrop.DragLayer;
@@ -227,7 +229,7 @@
         // Resolve the opening task id
         int openingTaskId = -1;
         for (RemoteAnimationTargetCompat target : targets) {
-            if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) {
+            if (target.mode == MODE_OPENING) {
                 openingTaskId = target.taskId;
                 break;
             }
@@ -247,8 +249,36 @@
         }
 
         // Found a visible recents task that matches the opening app, lets launch the app from there
-        return new LauncherTransitionAnimator(getRecentsLauncherAnimator(recentsView, taskView),
-                getRecentsWindowAnimator(taskView, targets));
+        Animator launcherAnim;
+        AnimatorListenerAdapter windowAnimEndListener;
+        boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING);
+        if (launcherClosing) {
+            launcherAnim = getRecentsLauncherAnimator(recentsView, taskView);
+            windowAnimEndListener = new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+                    mLauncher.getStateManager().reapplyState();
+                }
+            };
+        } else {
+            AnimatorPlaybackController controller =
+                    mLauncher.getStateManager()
+                            .createAnimationToNewWorkspace(NORMAL, RECENTS_LAUNCH_DURATION);
+            controller.dispatchOnStart();
+            launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
+            windowAnimEndListener = new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mLauncher.getStateManager().goToState(NORMAL, false);
+                }
+            };
+        }
+
+        MutableBoolean skipLauncherChanges = new MutableBoolean(!launcherClosing);
+        Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets);
+        windowAnim.addListener(windowAnimEndListener);
+        return new LauncherTransitionAnimator(launcherAnim, windowAnim, skipLauncherChanges);
     }
 
     /**
@@ -318,7 +348,7 @@
         launcherAnimator.play(allAppsSlideOut);
 
         Workspace workspace = mLauncher.getWorkspace();
-        float[] workspaceScaleAndTranslation = LauncherState.NORMAL
+        float[] workspaceScaleAndTranslation = NORMAL
                 .getWorkspaceScaleAndTranslation(mLauncher);
         Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder(
                 workspace, new PropertyListBuilder()
@@ -338,7 +368,7 @@
      * @return Animator that controls the window of the opening targets for the recents launch
      * animation.
      */
-    private ValueAnimator getRecentsWindowAnimator(TaskView v,
+    private ValueAnimator getRecentsWindowAnimator(TaskView v, MutableBoolean skipLauncherChanges,
             RemoteAnimationTargetCompat[] targets) {
         Rect taskViewBounds = new Rect();
         mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds);
@@ -374,13 +404,15 @@
                 final float percent = animation.getAnimatedFraction();
                 TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
 
-                v.setScaleX(tw.taskScale);
-                v.setScaleY(tw.taskScale);
-                v.setTranslationX(tw.taskX);
-                v.setTranslationY(tw.taskY);
-                // Defer fading out the view until after the app window gets faded in
-                v.setAlpha(getValue(1f, 0f, 75, 75,
-                        appAnimator.getDuration() * percent, Interpolators.LINEAR));
+                if (!skipLauncherChanges.value) {
+                    v.setScaleX(tw.taskScale);
+                    v.setScaleY(tw.taskScale);
+                    v.setTranslationX(tw.taskX);
+                    v.setTranslationY(tw.taskY);
+                    // Defer fading out the view until after the app window gets faded in
+                    v.setAlpha(getValue(1f, 0f, 75, 75,
+                            appAnimator.getDuration() * percent, Interpolators.LINEAR));
+                }
 
                 matrix.setScale(tw.winScale, tw.winScale);
                 matrix.postTranslate(tw.winX, tw.winY);
@@ -402,7 +434,10 @@
                         matrix.postTranslate(target.position.x, target.position.y);
                         t.setMatrix(target.leash, matrix);
                         t.setWindowCrop(target.leash, crop);
-                        t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface));
+
+                        if (!skipLauncherChanges.value) {
+                            t.deferTransactionUntil(target.leash, surface, frameNumber);
+                        }
                     }
                     if (isFirstFrame) {
                         t.show(target.leash);
@@ -414,13 +449,6 @@
                 isFirstFrame = false;
             }
         });
-        appAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                // Make sure recents gets fixed up by resetting task alphas and scales, etc.
-                mLauncher.getStateManager().reapplyState();
-            }
-        });
         return appAnimator;
     }
 
diff --git a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java b/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
index aec2869..ab9234b 100644
--- a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
+++ b/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
@@ -27,11 +27,20 @@
  */
 public class LauncherTransitionAnimator {
 
+    private final MutableBoolean mLauncherAnimCancelState;
+
     private AnimatorSet mAnimatorSet;
     private Animator mLauncherAnimator;
     private Animator mWindowAnimator;
 
     LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) {
+        this(launcherAnimator, windowAnimator, new MutableBoolean(false));
+    }
+
+
+    LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator,
+            MutableBoolean launcherAnimCancelState) {
+        mLauncherAnimCancelState = launcherAnimCancelState;
         if (launcherAnimator != null) {
             mLauncherAnimator = launcherAnimator;
         }
@@ -50,6 +59,7 @@
 
     public void cancel() {
         mAnimatorSet.cancel();
+        mLauncherAnimCancelState.value = true;
     }
 
     public boolean isRunning() {
@@ -58,6 +68,7 @@
 
     public void finishLauncherAnimation() {
         if (mLauncherAnimator != null) {
+            mLauncherAnimCancelState.value = true;
             mLauncherAnimator.end();
         }
     }
diff --git a/quickstep/src/com/android/launcher3/MutableBoolean.java b/quickstep/src/com/android/launcher3/MutableBoolean.java
new file mode 100644
index 0000000..7538217
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/MutableBoolean.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+public class MutableBoolean {
+    public boolean value;
+
+    public MutableBoolean(boolean value) {
+        this.value = value;
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 7f98935..352cd9c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -18,28 +18,22 @@
 
 import static com.android.launcher3.LauncherState.NORMAL;
 
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.PointF;
 import android.view.View.AccessibilityDelegate;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.OverviewInteractionState;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RecentsView;
-import com.android.systemui.shared.recents.view.RecentsTransition;
 
 public class UiFactory {
 
     private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
             "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
 
-    public static final boolean USE_HARDWARE_BITMAP = false; // FeatureFlags.IS_DOGFOOD_BUILD;
-
     public static TouchController[] createTouchControllers(Launcher launcher) {
         if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
             return new TouchController[] {
@@ -72,17 +66,6 @@
                 || !launcher.isInState(NORMAL) || !launcher.hasWindowFocus());
     }
 
-    public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
-            BitmapRenderer renderer) {
-        if (USE_HARDWARE_BITMAP && !forceSoftwareRenderer) {
-            return RecentsTransition.createHardwareBitmap(width, height, renderer::render);
-        } else {
-            Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-            renderer.render(new Canvas(result));
-            return result;
-        }
-    }
-
     public static void resetOverview(Launcher launcher) {
         RecentsView recents = launcher.getOverviewPanel();
         recents.reset();
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index a7f0026..450d107 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -29,8 +29,6 @@
 
     <include layout="@layout/all_apps_rv_layout" />
 
-    <include layout="@layout/all_apps_fast_scroller" />
-
     <include layout="@layout/all_apps_floating_header" />
 
     <!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
@@ -39,10 +37,5 @@
         android:id="@id/search_container_all_apps"
         layout="@layout/search_container_all_apps"/>
 
-    <View
-        android:id="@+id/nav_bar_bg"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_alignParentBottom="true"
-        android:background="?attr/allAppsNavBarScrimColor" />
+    <include layout="@layout/all_apps_fast_scroller" />
 </com.android.launcher3.allapps.AllAppsContainerView>
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index ca397bd..978b5a1 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -47,13 +47,5 @@
             android:layout_height="match_parent"
             android:layout_gravity="end"
             android:layout_marginEnd="@dimen/fastscroll_end_margin" />
-
-        <View
-            android:id="@+id/nav_bar_bg"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_gravity="bottom"
-            android:background="?attr/allAppsNavBarScrimColor"
-            android:focusable="false"  />
     </com.android.launcher3.views.TopRoundedCornerView>
 </com.android.launcher3.widget.WidgetsFullSheet>
\ No newline at end of file
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index cc13263..74b9cfa 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -33,8 +33,7 @@
  *   <li> Enable fast scroller.
  * </ul>
  */
-public abstract class BaseRecyclerView extends RecyclerView
-        implements RecyclerView.OnItemTouchListener {
+public abstract class BaseRecyclerView extends RecyclerView  {
 
     protected RecyclerViewFastScroller mScrollbar;
 
@@ -51,12 +50,6 @@
     }
 
     @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        addOnItemTouchListener(this);
-    }
-
-    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         bindFastScrollbar();
@@ -69,40 +62,8 @@
         onUpdateScrollbar(0);
     }
 
-    /**
-     * We intercept the touch handling only to support fast scrolling when initiated from the
-     * scroll bar.  Otherwise, we fall back to the default RecyclerView touch handling.
-     */
-    @Override
-    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
-        return handleTouchEvent(ev);
-    }
-
-    @Override
-    public void onTouchEvent(RecyclerView rv, MotionEvent ev) {
-        handleTouchEvent(ev);
-    }
-
-    /**
-     * Handles the touch event and determines whether to show the fast scroller (or updates it if
-     * it is already showing).
-     */
-    private boolean handleTouchEvent(MotionEvent ev) {
-        // Move to mScrollbar's coordinate system.
-        // We need to take parent into account (view pager's location)
-        ViewGroup parent = (ViewGroup) getParent();
-        int left = parent.getLeft() - mScrollbar.getLeft();
-        int top = parent.getTop() + getTop() - mScrollbar.getTop() - getScrollBarTop();
-        ev.offsetLocation(left, top);
-        try {
-            return mScrollbar.handleTouchEvent(ev);
-        } finally {
-            ev.offsetLocation(-left, -top);
-        }
-    }
-
-    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        // DO NOT REMOVE, NEEDED IMPLEMENTATION FOR M BUILDS
+    public RecyclerViewFastScroller getScrollbar() {
+        return mScrollbar;
     }
 
     public int getScrollBarTop() {
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index d0581a2..f4ae62a 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -45,12 +45,10 @@
 
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.BitmapInfo;
-import com.android.launcher3.graphics.ColorExtractor;
+import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.util.Preconditions;
@@ -126,7 +124,7 @@
         // automatically be loaded as ALPHA_8888.
         mLowResOptions.inPreferredConfig = Bitmap.Config.RGB_565;
 
-        if (UiFactory.USE_HARDWARE_BITMAP) {
+        if (BitmapRenderer.USE_HARDWARE_BITMAP) {
             mHighResOptions = new BitmapFactory.Options();
             mHighResOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
         } else {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 77ac9de..f6d0248 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -137,6 +137,8 @@
 
         propertySetter.setViewAlpha(mLauncher.getHotseat(), state.getHoseatAlpha(mLauncher),
                 pageAlphaProvider.interpolator);
+        propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
+                state.getHoseatAlpha(mLauncher), pageAlphaProvider.interpolator);
 
         // Set scrim
         propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS,
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 5cd54ca..26922ad 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -18,6 +18,9 @@
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Process;
 import android.support.annotation.NonNull;
@@ -57,6 +60,7 @@
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BottomUserEducationView;
+import com.android.launcher3.views.RecyclerViewFastScroller;
 
 /**
  * The all apps view container.
@@ -70,6 +74,9 @@
     private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
     private final AllAppsStore mAllAppsStore = new AllAppsStore();
 
+    private final Paint mNavBarScrimPaint;
+    private int mNavBarScrimHeight = 0;
+
     private SearchUiManager mSearchUiManager;
     private View mSearchContainer;
     private AllAppsPagedView mViewPager;
@@ -80,6 +87,9 @@
     private boolean mUsingTabs;
     private boolean mSearchModeWhileUsingTabs = false;
 
+    private RecyclerViewFastScroller mTouchHandler;
+    private final Point mFastScrollerOffset = new Point();
+
     public AllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -101,6 +111,9 @@
         mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
         mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
 
+        mNavBarScrimPaint = new Paint();
+        mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
+
         mAllAppsStore.addUpdateListener(this::onAppsUpdated);
 
         // Attach a scrim to be drawn behind all-apps and hotseat
@@ -108,27 +121,11 @@
                 .attach();
     }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        applyTouchDelegate();
-    }
-
-    private void applyTouchDelegate() {
-        // TODO: Reimplement once fast scroller is fixed.
-    }
-
     public AllAppsStore getAppsStore() {
         return mAllAppsStore;
     }
 
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        applyTouchDelegate();
-    }
-
-    @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
         for (AdapterHolder holder : mAH) {
             if (holder.recyclerView != null) {
@@ -163,7 +160,38 @@
             return true;
         }
         AllAppsRecyclerView rv = getActiveRecyclerView();
-        return rv == null || rv.shouldContainerScroll(ev, mLauncher.getDragLayer());
+        if (rv == null) {
+            return true;
+        }
+        if (rv.getScrollbar().getThumbOffsetY() >= 0 &&
+                mLauncher.getDragLayer().isEventOverView(rv.getScrollbar(), ev)) {
+            return false;
+        }
+        return rv.shouldContainerScroll(ev, mLauncher.getDragLayer());
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            AllAppsRecyclerView rv = getActiveRecyclerView();
+            if (rv != null &&
+                    rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(), mFastScrollerOffset)) {
+                mTouchHandler = rv.getScrollbar();
+            }
+        }
+        if (mTouchHandler != null) {
+            return mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mTouchHandler != null) {
+            mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
+            return true;
+        }
+        return false;
     }
 
     public AllAppsRecyclerView getActiveRecyclerView() {
@@ -282,14 +310,20 @@
         }
         setLayoutParams(mlp);
 
-        View navBarBg = findViewById(R.id.nav_bar_bg);
-        ViewGroup.LayoutParams navBarBgLp = navBarBg.getLayoutParams();
-        navBarBgLp.height = insets.bottom;
-        navBarBg.setLayoutParams(navBarBgLp);
-
+        mNavBarScrimHeight = insets.bottom;
         InsettableFrameLayout.dispatchInsets(this, insets);
     }
 
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+
+        if (mNavBarScrimHeight > 0) {
+            canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
+                    mNavBarScrimPaint);
+        }
+    }
+
     public SpringAnimationHandler getSpringAnimationHandler() {
         return mUsingTabs ? null : mAH[AdapterHolder.MAIN].animationHandler;
     }
@@ -320,8 +354,6 @@
 
         mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
         mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
-
-        applyTouchDelegate();
     }
 
     private void replaceRVContainer(boolean showTabs) {
@@ -352,7 +384,6 @@
     public void onTabChanged(int pos) {
         mHeader.setMainActive(pos == 0);
         reset();
-        applyTouchDelegate();
         if (mAH[pos].recyclerView != null) {
             mAH[pos].recyclerView.bindFastScrollbar();
 
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 53d19eb..4a393c9 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -97,7 +97,6 @@
             int defStyleRes) {
         super(context, attrs, defStyleAttr);
         Resources res = getResources();
-        addOnItemTouchListener(this);
         mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize(
                 R.dimen.all_apps_empty_search_bg_top_offset);
 
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 1c6f77c..5576d91 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -36,7 +36,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.PreviewBackground;
-import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.util.Preconditions;
 
 /**
@@ -113,7 +113,7 @@
         final float previewShiftX = shiftFactor * previewWidth;
         final float previewShiftY = shiftFactor * previewHeight;
 
-        Bitmap previewBitmap = UiFactory.createFromRenderer(previewWidth, previewHeight, false,
+        Bitmap previewBitmap = BitmapRenderer.createHardwareBitmap(previewWidth, previewHeight,
                 (canvas) -> {
                     int count = canvas.save();
                     canvas.translate(previewShiftX, previewShiftY);
diff --git a/src/com/android/launcher3/graphics/BitmapRenderer.java b/src/com/android/launcher3/graphics/BitmapRenderer.java
index 4652ded..f2a9f7c 100644
--- a/src/com/android/launcher3/graphics/BitmapRenderer.java
+++ b/src/com/android/launcher3/graphics/BitmapRenderer.java
@@ -15,9 +15,40 @@
  */
 package com.android.launcher3.graphics;
 
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Picture;
+import android.os.Build;
 
-public interface BitmapRenderer {
+import com.android.launcher3.Utilities;
 
-     void render(Canvas out);
+public class BitmapRenderer {
+
+     public static final boolean USE_HARDWARE_BITMAP = false && Utilities.ATLEAST_P;
+
+     public static Bitmap createSoftwareBitmap(int width, int height, Renderer renderer) {
+          Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+          renderer.draw(new Canvas(result));
+          return result;
+     }
+
+     @TargetApi(Build.VERSION_CODES.P)
+     public static Bitmap createHardwareBitmap(int width, int height, Renderer renderer) {
+          if (!USE_HARDWARE_BITMAP) {
+               return createSoftwareBitmap(width, height, renderer);
+          }
+
+          Picture picture = new Picture();
+          renderer.draw(picture.beginRecording(width, height));
+          picture.endRecording();
+          return Bitmap.createBitmap(picture);
+     }
+
+     /**
+      * Interface representing a bitmap draw operation.
+      */
+     public interface Renderer {
+          void draw(Canvas out);
+     }
 }
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index b770785..e60a2c7 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -24,19 +24,17 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.View;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.UiThreadHelper;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 import java.nio.ByteBuffer;
 
@@ -119,28 +117,26 @@
      * Responsibility for the bitmap is transferred to the caller.
      */
     public Bitmap createDragBitmap() {
-        float scale = 1f;
         int width = mView.getWidth();
         int height = mView.getHeight();
 
-        boolean forceSoftwareRenderer = false;
         if (mView instanceof BubbleTextView) {
             Drawable d = ((BubbleTextView) mView).getIcon();
             Rect bounds = getDrawableBounds(d);
             width = bounds.width();
             height = bounds.height();
         } else if (mView instanceof LauncherAppWidgetHostView) {
-            scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
+            float scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
             width = (int) (mView.getWidth() * scale);
             height = (int) (mView.getHeight() * scale);
 
             // Use software renderer for widgets as we know that they already work
-            forceSoftwareRenderer = true;
+            return BitmapRenderer.createSoftwareBitmap(width + blurSizeOutline,
+                    height + blurSizeOutline, (c) -> drawDragView(c, scale));
         }
 
-        final float scaleFinal = scale;
-        return UiFactory.createFromRenderer(width + blurSizeOutline, height + blurSizeOutline,
-                forceSoftwareRenderer, (c) -> drawDragView(c, scaleFinal));
+        return BitmapRenderer.createHardwareBitmap(width + blurSizeOutline,
+                height + blurSizeOutline, (c) -> drawDragView(c, 1));
     }
 
     public final void generateDragOutline(Bitmap preview) {
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 8abfdea..4a9cdd9 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -52,7 +52,6 @@
 import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.Themes;
 
@@ -349,7 +348,7 @@
         final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache);
 
         result.color = badge.iconColor;
-        result.icon = UiFactory.createFromRenderer(mIconBitmapSize, mIconBitmapSize, false, (c) -> {
+        result.icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
             getShadowGenerator().recreateIcon(unbadgedfinal, c);
             badgeWithDrawable(c, new FastBitmapDrawable(badge));
         });
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
index b80e94d..b793f54 100644
--- a/src/com/android/launcher3/util/FocusLogic.java
+++ b/src/com/android/launcher3/util/FocusLogic.java
@@ -177,7 +177,10 @@
             }
             int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
             int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
-            matrix[invert ? (m - cx - 1) : cx][cy] = i;
+            int x = invert ? (m - cx - 1) : cx;
+            if (x < m && cy < n) { // check if view fits into matrix, else skip
+                matrix[x][cy] = i;
+            }
         }
         if (DEBUG) {
             printMatrix(matrix);
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 58c9148..1cd6699 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -22,6 +22,8 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.util.Property;
@@ -43,6 +45,7 @@
 public class RecyclerViewFastScroller extends View {
 
     private static final int SCROLL_DELTA_THRESHOLD_DP = 4;
+    private static final Rect sTempRect = new Rect();
 
     private static final Property<RecyclerViewFastScroller, Integer> TRACK_WIDTH =
             new Property<RecyclerViewFastScroller, Integer>(Integer.class, "width") {
@@ -204,9 +207,9 @@
      * Handles the touch event and determines whether to show the fast scroller (or updates it if
      * it is already showing).
      */
-    public boolean handleTouchEvent(MotionEvent ev) {
-        int x = (int) ev.getX();
-        int y = (int) ev.getY();
+    public boolean handleTouchEvent(MotionEvent ev, Point offset) {
+        int x = (int) ev.getX() - offset.x;
+        int y = (int) ev.getY() - offset.y;
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 // Keep track of the down positions
@@ -260,7 +263,6 @@
     }
 
     private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
-        mRv.getParent().requestDisallowInterceptTouchEvent(true);
         mIsDragging = true;
         if (mCanThumbDetach) {
             mIsThumbDetached = true;
@@ -358,4 +360,16 @@
                 mMaxWidth, mRv.getScrollbarTrackHeight() - mMaxWidth - height);
         mPopupView.setTranslationY(top);
     }
+
+    public boolean isHitInParent(float x, float y, Point outOffset) {
+        if (mThumbOffsetY < 0) {
+            return false;
+        }
+        getHitRect(sTempRect);
+        sTempRect.top += mRv.getScrollBarTop();
+        if (outOffset != null) {
+            outOffset.set(sTempRect.left, sTempRect.top);
+        }
+        return sTempRect.contains((int) x, (int) y);
+    }
 }
diff --git a/src/com/android/launcher3/views/TopRoundedCornerView.java b/src/com/android/launcher3/views/TopRoundedCornerView.java
index ba223c4..3ba8ca3 100644
--- a/src/com/android/launcher3/views/TopRoundedCornerView.java
+++ b/src/com/android/launcher3/views/TopRoundedCornerView.java
@@ -17,12 +17,14 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
 
 /**
  * View with top rounded corners.
@@ -33,23 +35,41 @@
     private final Path mClipPath = new Path();
     private float[] mRadii;
 
+    private final Paint mNavBarScrimPaint;
+    private int mNavBarScrimHeight = 0;
+
     public TopRoundedCornerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
         int radius = getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius);
         mRadii = new float[] {radius, radius, radius, radius, 0, 0, 0, 0};
+
+        mNavBarScrimPaint = new Paint();
+        mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
     }
 
     public TopRoundedCornerView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
+    public void setNavBarScrimHeight(int height) {
+        if (mNavBarScrimHeight != height) {
+            mNavBarScrimHeight = height;
+            invalidate();
+        }
+    }
+
     @Override
     public void draw(Canvas canvas) {
         canvas.save();
         canvas.clipPath(mClipPath);
         super.draw(canvas);
         canvas.restore();
+
+        if (mNavBarScrimHeight > 0) {
+            canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
+                    mNavBarScrimPaint);
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index 48f8afe..b31feed 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -23,7 +23,6 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.View;
 import android.view.animation.AnimationUtils;
 
 import com.android.launcher3.Insettable;
@@ -31,6 +30,8 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
 import com.android.launcher3.R;
+import com.android.launcher3.views.RecyclerViewFastScroller;
+import com.android.launcher3.views.TopRoundedCornerView;
 
 /**
  * Popup for showing the full list of available widgets
@@ -46,7 +47,6 @@
 
     private final WidgetsListAdapter mAdapter;
 
-    private View mNavBarScrim;
     private WidgetsRecyclerView mRecyclerView;
 
     public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -65,7 +65,6 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mContent = findViewById(R.id.container);
-        mNavBarScrim = findViewById(R.id.nav_bar_bg);
 
         mRecyclerView = findViewById(R.id.widgets_list_view);
         mRecyclerView.setAdapter(mAdapter);
@@ -91,7 +90,6 @@
     public void setInsets(Rect insets) {
         mInsets.set(insets);
 
-        mNavBarScrim.getLayoutParams().height = insets.bottom;
         mRecyclerView.setPadding(
                 mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
                 mRecyclerView.getPaddingRight(), insets.bottom);
@@ -100,6 +98,8 @@
         } else {
             clearNavBarColor();
         }
+
+        ((TopRoundedCornerView) mContent).setNavBarScrimHeight(mInsets.bottom);
         requestLayout();
     }
 
@@ -195,7 +195,11 @@
         // Disable swipe down when recycler view is scrolling
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mNoIntercept = false;
-            if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
+            RecyclerViewFastScroller scroller = mRecyclerView.getScrollbar();
+            if (scroller.getThumbOffsetY() >= 0 &&
+                    mLauncher.getDragLayer().isEventOverView(scroller, ev)) {
+                mNoIntercept = true;
+            } else if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
                 mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, mLauncher.getDragLayer());
             }
         }
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 89c88a4..124058e 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -17,8 +17,12 @@
 package com.android.launcher3.widget;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.launcher3.BaseRecyclerView;
@@ -27,13 +31,15 @@
 /**
  * The widgets recycler view.
  */
-public class WidgetsRecyclerView extends BaseRecyclerView {
+public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouchListener {
 
-    private static final String TAG = "WidgetsRecyclerView";
     private WidgetsListAdapter mAdapter;
 
     private final int mScrollbarTop;
 
+    private final Point mFastScrollerOffset = new Point();
+    private boolean mTouchDownOnScroller;
+
     public WidgetsRecyclerView(Context context) {
         this(context, null);
     }
@@ -46,6 +52,7 @@
         // API 21 and below only support 3 parameter ctor.
         super(context, attrs, defStyleAttr);
         mScrollbarTop = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+        addOnItemTouchListener(this);
     }
 
     public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
@@ -56,7 +63,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        addOnItemTouchListener(this);
         // create a layout manager with Launcher's context so that scroll position
         // can be preserved during screen rotation.
         setLayoutManager(new LinearLayoutManager(getContext()));
@@ -145,4 +151,26 @@
     public int getScrollBarTop() {
         return mScrollbarTop;
     }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (e.getAction() == MotionEvent.ACTION_DOWN) {
+            mTouchDownOnScroller =
+                    mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
+        }
+        if (mTouchDownOnScroller) {
+            return mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+        }
+        return false;
+    }
+
+    @Override
+    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (mTouchDownOnScroller) {
+            mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+        }
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
 }
\ No newline at end of file
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index a16ae48..de75ac9 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,25 +16,17 @@
 
 package com.android.launcher3.uioverrides;
 
-import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.PointF;
-import android.os.Bundle;
-import android.view.View;
 import android.view.View.AccessibilityDelegate;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.util.TouchController;
 
 public class UiFactory {
 
-    public static final boolean USE_HARDWARE_BITMAP = false;
-
     public static TouchController[] createTouchControllers(Launcher launcher) {
         return new TouchController[] {
                 new AllAppsSwipeController(launcher), new PinchToOverviewListener(launcher)};
@@ -54,13 +46,6 @@
         launcher.getStateManager().goToState(OVERVIEW);
     }
 
-    public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
-            BitmapRenderer renderer) {
-        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        renderer.render(new Canvas(result));
-        return result;
-    }
-
     public static void resetOverview(Launcher launcher) { }
 
     public static void onLauncherStateOrFocusChanged(Launcher launcher) { }