Merge "Add mStartState to determine if user swipes up from Home." into ub-launcher3-edmonton
diff --git a/proguard.flags b/proguard.flags
index e9f6db4..555d13e 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -120,6 +120,12 @@
   *;
 }
 
+# Discovery bounce animation
+-keep class com.android.launcher3.allapps.DiscoveryBounce$VerticalProgressWrapper {
+  public void setProgress(float);
+  public float getProgress();
+}
+
 # BUG(70852369): Surpress additional warnings after changing from Proguard to R8
 -dontwarn android.app.**
 -dontwarn android.view.**
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 429f3a2..f163872 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -13,9 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.views.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.quickstep.views.TaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:focusable="false"
     android:elevation="4dp">
 
     <com.android.quickstep.views.TaskThumbnailView
@@ -29,5 +31,6 @@
         android:layout_width="@dimen/task_thumbnail_icon_size"
         android:layout_height="@dimen/task_thumbnail_icon_size"
         android:importantForAccessibility="no"
+        android:focusable="false"
         android:layout_gravity="top|center_horizontal" />
 </com.android.quickstep.views.TaskView>
\ 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 2e31ef2..6703bb5 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -184,7 +184,8 @@
                         // before our internal listeners.
                         mLauncher.getStateManager().setCurrentAnimation(anim);
 
-                        anim.play(getIconAnimator(v));
+                        Rect windowTargetBounds = getWindowTargetBounds(targetCompats);
+                        anim.play(getIconAnimator(v, windowTargetBounds));
                         if (launcherClosing) {
                             Pair<AnimatorSet, Runnable> launcherContentAnimator =
                                     getLauncherContentAnimator(true /* isAppOpening */);
@@ -196,7 +197,7 @@
                                 }
                             });
                         }
-                        anim.play(getOpeningWindowAnimators(v, targetCompats));
+                        anim.play(getOpeningWindowAnimators(v, targetCompats, windowTargetBounds));
                     }
 
                     if (launcherClosing) {
@@ -213,7 +214,26 @@
             return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
                     runner, duration, statusBarTransitionDelay));
         }
-        return getDefaultActivityLaunchOptions(launcher, v);
+        return super.getActivityLaunchOptions(launcher, v);
+    }
+
+    /**
+     * Return the window bounds of the opening target.
+     * In multiwindow mode, we need to get the final size of the opening app window target to help
+     * figure out where the floating view should animate to.
+     */
+    private Rect getWindowTargetBounds(RemoteAnimationTargetCompat[] targets) {
+        Rect bounds = new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
+        if (mLauncher.isInMultiWindowModeCompat()) {
+            for (RemoteAnimationTargetCompat target : targets) {
+                if (target.mode == MODE_OPENING) {
+                    bounds.set(target.sourceContainerBounds);
+                    bounds.offsetTo(target.position.x, target.position.y);
+                    return bounds;
+                }
+            }
+        }
+        return bounds;
     }
 
     public void setRemoteAnimationProvider(RemoteAnimationProvider animationProvider) {
@@ -382,7 +402,7 @@
     /**
      * @return Animator that controls the icon used to launch the target.
      */
-    private AnimatorSet getIconAnimator(View v) {
+    private AnimatorSet getIconAnimator(View v, Rect windowTargetBounds) {
         final boolean isBubbleTextView = v instanceof BubbleTextView;
         mFloatingView = new View(mLauncher);
         if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
@@ -418,7 +438,7 @@
         viewLocationLeft += rect.left;
         viewLocationTop += rect.top;
         int viewLocationStart = mIsRtl
-                ? mDeviceProfile.widthPx - rect.right
+                ? windowTargetBounds.width() - rect.right
                 : viewLocationLeft;
         LayoutParams lp = new LayoutParams(rect.width(), rect.height());
         lp.ignoreInsets = true;
@@ -438,12 +458,15 @@
         v.setVisibility(View.INVISIBLE);
 
         AnimatorSet appIconAnimatorSet = new AnimatorSet();
-        // Animate the app icon to the center
-        float centerX = mDeviceProfile.widthPx / 2;
-        float centerY = mDeviceProfile.heightPx / 2;
+        int[] dragLayerBounds = new int[2];
+        mDragLayer.getLocationOnScreen(dragLayerBounds);
+
+        // Animate the app icon to the center of the window bounds in screen coordinates.
+        float centerX = windowTargetBounds.centerX() - dragLayerBounds[0];
+        float centerY = windowTargetBounds.centerY() - dragLayerBounds[1];
 
         float xPosition = mIsRtl
-                ? mDeviceProfile.widthPx - lp.getMarginStart() - rect.width()
+                ? windowTargetBounds.width() - lp.getMarginStart() - rect.width()
                 : lp.getMarginStart();
         float dX = centerX - xPosition - (lp.width / 2);
         float dY = centerY - lp.topMargin - (lp.height / 2);
@@ -469,8 +492,8 @@
 
         // Scale the app icon to take up the entire screen. This simplifies the math when
         // animating the app window position / scale.
-        float maxScaleX = mDeviceProfile.widthPx / (float) rect.width();
-        float maxScaleY = mDeviceProfile.heightPx / (float) rect.height();
+        float maxScaleX = windowTargetBounds.width() / (float) rect.width();
+        float maxScaleY = windowTargetBounds.height() / (float) rect.height();
         float scale = Math.max(maxScaleX, maxScaleY);
         ObjectAnimator scaleAnim = ObjectAnimator
                 .ofFloat(mFloatingView, SCALE_PROPERTY, startScale, scale);
@@ -505,7 +528,8 @@
     /**
      * @return Animator that controls the window of the opening targets.
      */
-    private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets) {
+    private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
+            Rect windowTargetBounds) {
         Rect bounds = new Rect();
         if (v.getParent() instanceof DeepShortcutView) {
             // Deep shortcut views have their icon drawn in a separate view.
@@ -544,31 +568,35 @@
                 float iconHeight = bounds.height() * mFloatingView.getScaleY();
 
                 // Scale the app window to match the icon size.
-                float scaleX = iconWidth / mDeviceProfile.widthPx;
-                float scaleY = iconHeight / mDeviceProfile.heightPx;
+                float scaleX = iconWidth / windowTargetBounds.width();
+                float scaleY = iconHeight / windowTargetBounds.height();
                 float scale = Math.min(1f, Math.min(scaleX, scaleY));
                 matrix.setScale(scale, scale);
 
                 // Position the scaled window on top of the icon
-                int deviceWidth = mDeviceProfile.widthPx;
-                int deviceHeight = mDeviceProfile.heightPx;
-                float scaledWindowWidth = deviceWidth * scale;
-                float scaledWindowHeight = deviceHeight * scale;
+                int windowWidth = windowTargetBounds.width();
+                int windowHeight = windowTargetBounds.height();
+                float scaledWindowWidth = windowWidth * scale;
+                float scaledWindowHeight = windowHeight * scale;
 
                 float offsetX = (scaledWindowWidth - iconWidth) / 2;
                 float offsetY = (scaledWindowHeight - iconHeight) / 2;
-                mFloatingView.getLocationInWindow(floatingViewBounds);
+                if (mLauncher.isInMultiWindowModeCompat()) {
+                    mFloatingView.getLocationOnScreen(floatingViewBounds);
+                } else {
+                    mFloatingView.getLocationInWindow(floatingViewBounds);
+                }
                 float transX0 = floatingViewBounds[0] - offsetX;
                 float transY0 = floatingViewBounds[1] - offsetY;
                 matrix.postTranslate(transX0, transY0);
 
                 // Animate the window crop so that it starts off as a square, and then reveals
                 // horizontally.
-                float cropHeight = deviceHeight * easePercent + deviceWidth * (1 - easePercent);
-                float initialTop = (deviceHeight - deviceWidth) / 2f;
+                float cropHeight = windowHeight * easePercent + windowWidth * (1 - easePercent);
+                float initialTop = (windowHeight - windowWidth) / 2f;
                 crop.left = 0;
                 crop.top = (int) (initialTop * (1 - easePercent));
-                crop.right = deviceWidth;
+                crop.right = windowWidth;
                 crop.bottom = (int) (crop.top + cropHeight);
 
                 TransactionCompat t = new TransactionCompat();
@@ -579,10 +607,6 @@
                 for (RemoteAnimationTargetCompat target : targets) {
                     if (target.mode == MODE_OPENING) {
                         t.setAlpha(target.leash, mAlpha.value);
-
-                        // TODO: This isn't correct at the beginning of the animation, but better
-                        // than nothing.
-                        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));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
new file mode 100644
index 0000000..2e6dcc0
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
@@ -0,0 +1,62 @@
+/*
+ * 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.uioverrides;
+
+import android.animation.ValueAnimator;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.quickstep.OverviewInteractionState;
+
+public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler {
+
+    private static final String TAG = "BackButtonAlphaHandler";
+
+    private final Launcher mLauncher;
+    private final OverviewInteractionState mOverviewInteractionState;
+
+    public BackButtonAlphaHandler(Launcher launcher) {
+        mLauncher = launcher;
+        mOverviewInteractionState = OverviewInteractionState.getInstance(mLauncher);
+    }
+
+    @Override
+    public void setState(LauncherState state) {
+        UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+    }
+
+    @Override
+    public void setStateWithAnimation(LauncherState toState,
+            AnimatorSetBuilder builder, LauncherStateManager.AnimationConfig config) {
+        if (!config.playNonAtomicComponent()) {
+            return;
+        }
+        float fromAlpha = mOverviewInteractionState.getBackButtonAlpha();
+        float toAlpha = toState.hideBackButton ? 0 : 1;
+        if (Float.compare(fromAlpha, toAlpha) != 0) {
+            ValueAnimator anim = ValueAnimator.ofFloat(fromAlpha, toAlpha);
+            anim.setDuration(config.duration);
+            anim.addUpdateListener(valueAnimator -> {
+                final float alpha = (float) valueAnimator.getAnimatedValue();
+                mOverviewInteractionState.setBackButtonAlpha(alpha, false);
+            });
+            builder.play(anim);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 3a49294..0116a8e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -100,9 +100,9 @@
     @Override
     public int getVisibleElements(Launcher launcher) {
         if (launcher.getDeviceProfile().isVerticalBarLayout()) {
-            return 0;
+            return VERTICAL_SWIPE_INDICATOR;
         } else {
-            return HOTSEAT_SEARCH_BOX |
+            return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR |
                     (launcher.getAppsView().getFloatingHeaderView().hasVisibleContent()
                             ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
         }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index b371677..76820b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -78,11 +78,13 @@
     }
 
     public static StateHandler[] getStateHandler(Launcher launcher) {
-        return new StateHandler[] {
-                launcher.getAllAppsController(), launcher.getWorkspace(),
-                new RecentsViewStateController(launcher)};
+        return new StateHandler[] {launcher.getAllAppsController(), launcher.getWorkspace(),
+                new RecentsViewStateController(launcher), new BackButtonAlphaHandler(launcher)};
     }
 
+    /**
+     * Sets the back button visibility based on the current state/window focus.
+     */
     public static void onLauncherStateOrFocusChanged(Launcher launcher) {
         boolean shouldBackButtonBeHidden = launcher != null
                 && launcher.getStateManager().getState().hideBackButton
@@ -96,10 +98,6 @@
                 .setBackButtonAlpha(shouldBackButtonBeHidden ? 0 : 1, true /* animate */);
     }
 
-    public static void setBackButtonAlpha(Launcher launcher, float alpha, boolean animate) {
-         OverviewInteractionState.getInstance(launcher).setBackButtonAlpha(alpha,animate);
-    }
-
     public static void resetOverview(Launcher launcher) {
         RecentsView recents = launcher.getOverviewPanel();
         recents.reset();
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index d605746..922a7ff 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -91,6 +91,7 @@
     // These are updated on the background thread
     private ISystemUiProxy mISystemUiProxy;
     private boolean mSwipeUpEnabled = true;
+    private float mBackButtonAlpha = 1;
 
     private Runnable mOnSwipeUpSettingChangedListener;
 
@@ -117,7 +118,14 @@
         return mSwipeUpEnabled;
     }
 
+    public float getBackButtonAlpha() {
+        return mBackButtonAlpha;
+    }
+
     public void setBackButtonAlpha(float alpha, boolean animate) {
+        if (!mSwipeUpEnabled) {
+            alpha = 1;
+        }
         mUiHandler.removeMessages(MSG_SET_BACK_BUTTON_ALPHA);
         mUiHandler.obtainMessage(MSG_SET_BACK_BUTTON_ALPHA, animate ? 1 : 0, 0, alpha)
                 .sendToTarget();
@@ -128,6 +136,9 @@
     }
 
     private boolean handleUiMessage(Message msg) {
+        if (msg.what == MSG_SET_BACK_BUTTON_ALPHA) {
+            mBackButtonAlpha = (float) msg.obj;
+        }
         mBgHandler.obtainMessage(msg.what, msg.arg1, msg.arg2, msg.obj).sendToTarget();
         return true;
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index b472d61..3adb290 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -176,8 +176,8 @@
     }
 
     @Override
-    public ActivityOptions getActivityLaunchOptions(final View v, boolean useDefaultLaunchOptions) {
-        if (useDefaultLaunchOptions || !(v instanceof TaskView)) {
+    public ActivityOptions getActivityLaunchOptions(final View v) {
+        if (!(v instanceof TaskView)) {
             return null;
         }
 
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 9e2de33..c5d74c7 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -20,8 +20,10 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
@@ -71,4 +73,21 @@
         // Just use the activity task size for multi-window as well.
         return false;
     }
+
+    @Override
+    public void addTaskAccessibilityActionsExtra(AccessibilityNodeInfo info) {
+        info.addAction(
+                new AccessibilityNodeInfo.AccessibilityAction(
+                        R.string.recents_clear_all,
+                        getContext().getText(R.string.recents_clear_all)));
+    }
+
+    @Override
+    public boolean performTaskAccessibilityActionExtra(int action) {
+        if (action == R.string.recents_clear_all) {
+            dismissAllTasks();
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index d5c43a0..25e3dc6 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -19,6 +19,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
@@ -43,4 +44,12 @@
         }
         return res;
     }
+
+    @Override
+    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
+        if (focused) {
+            mRecentsView.revealClearAllButton();
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 950f7fb..5aca4f3 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -35,6 +35,9 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.OverviewInteractionState;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.LayoutUtils;
@@ -136,6 +139,12 @@
         }
         anim.play(ObjectAnimator.ofFloat(
                 mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen));
+
+        ObjectAnimator dragHandleAnim = ObjectAnimator.ofInt(
+                mActivity.findViewById(R.id.scrim_view), ScrimView.DRAG_HANDLE_ALPHA, 0);
+        dragHandleAnim.setInterpolator(Interpolators.ACCEL_2);
+        anim.play(dragHandleAnim);
+
         return anim;
     }
 
@@ -150,7 +159,7 @@
             mActivity.getStateManager().goToState(NORMAL, false /* animate */);
         } else {
             LauncherState state = mActivity.getStateManager().getState();
-            mActivity.getAllAppsController().setProgress(state.getVerticalProgress(mActivity));
+            mActivity.getAllAppsController().setState(state);
         }
         super.onTaskLaunched(success);
     }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a6da89f..829ed6c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -41,6 +41,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.support.annotation.Nullable;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
@@ -53,6 +54,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
@@ -108,7 +110,6 @@
             return recentsView.mAdjacentScale;
         }
     };
-    public static final boolean FLIP_RECENTS = true;
     private static final int DISMISS_TASK_DURATION = 300;
     // The threshold at which we update the SystemUI flags when animating from the task into the app
     private static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.6f;
@@ -266,10 +267,7 @@
         mQuickScrubController = new QuickScrubController(mActivity, this);
         mModel = RecentsModel.getInstance(context);
 
-        mIsRtl = Utilities.isRtl(getResources());
-        if (FLIP_RECENTS) {
-            mIsRtl = !mIsRtl;
-        }
+        mIsRtl = !Utilities.isRtl(getResources());
         setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
 
         mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
@@ -581,6 +579,11 @@
      * and unloads the associated task data for tasks that are no longer visible.
      */
     public void loadVisibleTaskData() {
+        if (!mOverviewStateEnabled) {
+            // Skip loading visible task data if we've already left the overview state
+            return;
+        }
+
         RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
         int centerPageIndex = getPageNearestToCenterOfScreen();
         int lower = Math.max(0, centerPageIndex - 2);
@@ -967,6 +970,13 @@
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             switch (event.getKeyCode()) {
                 case KeyEvent.KEYCODE_TAB:
+                    if (!event.isAltPressed() &&
+                            getNextPage() ==
+                                    (event.isShiftPressed() ? 0 : getChildCount() - 1)) {
+                        // If not Alt-Tab navigation, don't loop forever in the carousel and leave
+                        // it once we reached the end.
+                        return false;
+                    }
                     snapToPageRelative(event.isShiftPressed() ? -1 : 1);
                     return true;
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
@@ -992,6 +1002,22 @@
         return super.dispatchKeyEvent(event);
     }
 
+    @Override
+    protected void onFocusChanged(boolean gainFocus, int direction,
+            @Nullable Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        if (gainFocus && getChildCount() > 0) {
+            switch (direction) {
+                case FOCUS_FORWARD:
+                    setCurrentPage(0);
+                    break;
+                case FOCUS_BACKWARD:
+                    setCurrentPage(getChildCount() - 1);
+                    break;
+            }
+        }
+    }
+
     public void snapToTaskAfterNext() {
         snapToPageRelative(1);
     }
@@ -1303,22 +1329,26 @@
     }
 
     public void revealClearAllButton() {
+        setCurrentPage(getChildCount() - 1); // Loads tasks info if needed.
         scrollTo(mIsRtl ? 0 : computeMaxScrollX(), 0);
     }
 
     @Override
     public void addChildrenForAccessibility(ArrayList<View> outChildren) {
-        if (FLIP_RECENTS) {
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                outChildren.add(getChildAt(i));
-            }
-        } else {
-            super.addChildrenForAccessibility(outChildren);
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            outChildren.add(getChildAt(i));
         }
     }
 
     @Override
     protected boolean isPageOrderFlipped() {
-        return FLIP_RECENTS;
+        return true;
+    }
+
+    public void addTaskAccessibilityActionsExtra(AccessibilityNodeInfo info) {
+    }
+
+    public boolean performTaskAccessibilityActionExtra(int action) {
+        return false;
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
index 429432b..846c28b 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -23,12 +23,14 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
-import android.view.Gravity;
 import android.view.MotionEvent;
+import android.view.View;
 
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
 
+import java.util.ArrayList;
+
 public class RecentsViewContainer extends InsettableFrameLayout {
     public static final FloatProperty<RecentsViewContainer> CONTENT_ALPHA =
             new FloatProperty<RecentsViewContainer>("contentAlpha") {
@@ -64,10 +66,6 @@
         });
 
         mRecentsView = findViewById(R.id.overview_panel);
-        final InsettableFrameLayout.LayoutParams params =
-                (InsettableFrameLayout.LayoutParams) mClearAllButton.getLayoutParams();
-        params.gravity = Gravity.TOP | (RecentsView.FLIP_RECENTS ? Gravity.START : Gravity.END);
-        mClearAllButton.setLayoutParams(params);
         mClearAllButton.forceHasOverlappingRendering(false);
 
         mRecentsView.setClearAllButton(mClearAllButton);
@@ -104,4 +102,11 @@
         mRecentsView.setContentAlpha(alpha);
         setVisibility(alpha > 0 ? VISIBLE : GONE);
     }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        // Carousel is first in tab order.
+        views.add(mRecentsView);
+        views.add(mClearAllButton);
+    }
 }
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 24afd48..aca8351 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -154,15 +154,6 @@
     }
 
     @Override
-    protected void updateDragHandleAlpha() {
-        if (mDrawingFlatColor) {
-            super.updateDragHandleAlpha();
-        } else if (mDragHandle != null) {
-            mDragHandle.setAlpha(255);
-        }
-    }
-
-    @Override
     protected void onDraw(Canvas canvas) {
         float translate = drawBackground(canvas);
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 82aa45a..0df0580 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -17,6 +17,7 @@
 package com.android.quickstep.views;
 
 import static android.widget.Toast.LENGTH_SHORT;
+
 import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA_MULTIPLIER;
 
 import android.animation.Animator;
@@ -116,7 +117,7 @@
             }
             launchTask(true /* animate */);
             BaseActivity.fromContext(context).getUserEventDispatcher().logTaskLaunchOrDismiss(
-                    Touch.TAP, Direction.NONE, ((RecentsView) getParent()).indexOfChild(this),
+                    Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
                     TaskUtils.getComponentKeyForTask(getTask().key));
         });
         setOutlineProvider(new TaskOutlineProvider(getResources()));
@@ -168,7 +169,7 @@
             final ActivityOptions opts;
             if (animate) {
                 opts = BaseDraggingActivity.fromContext(getContext())
-                        .getActivityLaunchOptions(this, false);
+                        .getActivityLaunchOptions(this);
             } else {
                 opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
             }
@@ -318,12 +319,14 @@
                         context.getText(menuOption.labelResId)));
             }
         }
+
+        getRecentsView().addTaskAccessibilityActionsExtra(info);
     }
 
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
         if (action == R.string.accessibility_close_task) {
-            ((RecentsView) getParent()).dismissTask(this, true /*animateTaskView*/,
+            getRecentsView().dismissTask(this, true /*animateTaskView*/,
                     true /*removeTask*/);
             return true;
         }
@@ -339,9 +342,15 @@
             }
         }
 
+        if (getRecentsView().performTaskAccessibilityActionExtra(action)) return true;
+
         return super.performAccessibilityAction(action, arguments);
     }
 
+    private RecentsView getRecentsView() {
+        return (RecentsView) getParent();
+    }
+
     public void notifyTaskLaunchFailed(String tag) {
         String msg = "Failed to launch task";
         if (mTask != null) {
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 5e7b117..02d793e 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -23,8 +23,7 @@
     android:layout_height="match_parent"
     android:clipChildren="true"
     android:clipToPadding="false"
-    android:focusable="true"
-    android:focusableInTouchMode="true"
+    android:focusable="false"
     android:saveEnabled="false" >
 
     <include layout="@layout/all_apps_rv_layout" />
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index e47dbe5..d9e7d20 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -141,13 +141,12 @@
         return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
     }
 
-    public final Bundle getActivityLaunchOptionsAsBundle(View v, boolean useDefaultLaunchOptions) {
-        ActivityOptions activityOptions = getActivityLaunchOptions(v, useDefaultLaunchOptions);
+    public final Bundle getActivityLaunchOptionsAsBundle(View v) {
+        ActivityOptions activityOptions = getActivityLaunchOptions(v);
         return activityOptions == null ? null : activityOptions.toBundle();
     }
 
-    public abstract ActivityOptions getActivityLaunchOptions(
-            View v, boolean useDefaultLaunchOptions);
+    public abstract ActivityOptions getActivityLaunchOptions(View v);
 
     public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
         if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
@@ -160,7 +159,7 @@
         boolean useLaunchAnimation = (v != null) &&
                 !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
         Bundle optsBundle = useLaunchAnimation
-                ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
+                ? getActivityLaunchOptionsAsBundle(v)
                 : null;
 
         UserHandle user = item == null ? null : item.user;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 14390ec..bddcde3 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1614,10 +1614,8 @@
 
     @TargetApi(Build.VERSION_CODES.M)
     @Override
-    public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
-        return useDefaultLaunchOptions
-                ? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v)
-                : mAppTransitionManager.getActivityLaunchOptions(this, v);
+    public ActivityOptions getActivityLaunchOptions(View v) {
+        return mAppTransitionManager.getActivityLaunchOptions(this, v);
     }
 
     public LauncherAppTransitionManager getAppTransitionManager() {
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 04f9b3a..4037a23 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -33,7 +33,7 @@
                 context, R.string.app_transition_manager_class);
     }
 
-    public ActivityOptions getDefaultActivityLaunchOptions(Launcher launcher, View v) {
+    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
         if (Utilities.ATLEAST_MARSHMALLOW) {
             int left = 0, top = 0;
             int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
@@ -58,8 +58,4 @@
         }
         return null;
     }
-
-    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
-        return getDefaultActivityLaunchOptions(launcher, v);
-    }
 }
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index fbe27b0..76681f2 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -51,6 +51,7 @@
     public static final int ALL_APPS_HEADER = 1 << 2;
     public static final int ALL_APPS_HEADER_EXTRA = 1 << 3; // e.g. app predictions
     public static final int ALL_APPS_CONTENT = 1 << 4;
+    public static final int VERTICAL_SWIPE_INDICATOR = 1 << 5;
 
     protected static final int FLAG_MULTI_PAGE = 1 << 0;
     protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 1;
@@ -201,9 +202,9 @@
 
     public int getVisibleElements(Launcher launcher) {
         if (launcher.getDeviceProfile().isVerticalBarLayout()) {
-            return HOTSEAT_ICONS;
+            return HOTSEAT_ICONS | VERTICAL_SWIPE_INDICATOR;
         }
-        return HOTSEAT_ICONS | HOTSEAT_SEARCH_BOX;
+        return HOTSEAT_ICONS | HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR;
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index e6fc4c6..3fcdee9 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -396,7 +396,6 @@
             setRestState(null);
         }
 
-        UiFactory.onLauncherStateOrFocusChanged(mLauncher);
         UiFactory.onLauncherStateOrResumeChanged(mLauncher);
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index f8648bb..68ad6e3 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,12 +15,14 @@
  */
 package com.android.launcher3.allapps;
 
+import android.animation.ValueAnimator;
 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.animation.DynamicAnimation;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
@@ -61,6 +63,10 @@
 public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
         Insettable, OnDeviceProfileChangeListener {
 
+    private static final float FLING_VELOCITY_MULTIPLIER = 135f;
+    // Starts the springs after at least 55% of the animation has passed.
+    private static final float FLING_ANIMATION_THRESHOLD = 0.55f;
+
     private final Launcher mLauncher;
     private final AdapterHolder[] mAH;
     private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
@@ -455,6 +461,32 @@
         }
     }
 
+    /**
+     * Adds an update listener to {@param animator} that adds springs to the animation.
+     */
+    public void addSpringFromFlingUpdateListener(ValueAnimator animator, float velocity) {
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                if (valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) {
+                    int searchViewId = getSearchView().getId();
+                    addSpringView(searchViewId);
+
+                    finishWithShiftAndVelocity(1, velocity * FLING_VELOCITY_MULTIPLIER,
+                            new DynamicAnimation.OnAnimationEndListener() {
+                                @Override
+                                public void onAnimationEnd(DynamicAnimation animation,
+                                        boolean canceled, float value, float velocity) {
+                                    removeSpringView(searchViewId);
+                                }
+                            });
+
+                    animator.removeUpdateListener(this);
+                }
+            }
+        });
+    }
+
     public class AdapterHolder {
         public static final int MAIN = 0;
         public static final int WORK = 1;
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index b5c821a..ccd5586 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -4,6 +4,7 @@
 import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
 import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
 import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
@@ -25,11 +26,9 @@
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ScrimView;
 
@@ -184,13 +183,6 @@
         anim.setDuration(config.duration);
         anim.setInterpolator(builder.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
         anim.addListener(getProgressAnimatorListener());
-        if (toState.hideBackButton) {
-            anim.addUpdateListener(animation -> {
-                final float alpha = (float) animation.getAnimatedValue();
-                UiFactory.setBackButtonAlpha(mLauncher, 1 - Utilities.boundToRange(alpha, 0, 1),
-                        false /* animate */);
-            });
-        }
 
         builder.play(anim);
 
@@ -207,6 +199,9 @@
         setter.setViewAlpha(mAppsView.getContentView(), hasContent ? 1 : 0, LINEAR);
         setter.setViewAlpha(mAppsView.getScrollBar(), hasContent ? 1 : 0, LINEAR);
         mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasContent, setter);
+
+        setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA,
+                (visibleElements & VERTICAL_SWIPE_INDICATOR) != 0 ? 255 : 0, LINEAR);
     }
 
     public AnimatorListenerAdapter getProgressAnimatorListener() {
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index e1cd06a..a0a79c8 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -24,14 +24,9 @@
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.Keyframe;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.os.Handler;
 import android.view.MotionEvent;
-import android.view.animation.PathInterpolator;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
@@ -52,21 +47,21 @@
     private final Launcher mLauncher;
     private final Animator mDiscoBounceAnimation;
 
-    public DiscoveryBounce(Launcher launcher, Animator animator) {
+    public DiscoveryBounce(Launcher launcher, float delta) {
         super(launcher, null);
         mLauncher = launcher;
-
-        mDiscoBounceAnimation = animator;
         AllAppsTransitionController controller = mLauncher.getAllAppsController();
-        mDiscoBounceAnimation.setTarget(controller);
-        mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
 
+        mDiscoBounceAnimation =
+                AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce);
+        mDiscoBounceAnimation.setTarget(new VerticalProgressWrapper(controller, delta));
         mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 handleClose(false);
             }
         });
+        mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
     }
 
     @Override
@@ -102,6 +97,9 @@
         if (mIsOpen) {
             mIsOpen = false;
             mLauncher.getDragLayer().removeView(this);
+            // Reset the all-apps progress to what ever it was previously.
+            mLauncher.getAllAppsController().setProgress(mLauncher.getStateManager()
+                    .getState().getVerticalProgress(mLauncher));
         }
     }
 
@@ -115,6 +113,12 @@
         return (type & TYPE_ON_BOARD_POPUP) != 0;
     }
 
+    private void show(int containerType) {
+        mIsOpen = true;
+        mLauncher.getDragLayer().addView(this);
+        mLauncher.getUserEventDispatcher().logActionBounceTip(containerType);
+    }
+
     public static void showForHomeIfNeeded(Launcher launcher) {
         showForHomeIfNeeded(launcher, true);
     }
@@ -133,11 +137,7 @@
             return;
         }
 
-        DiscoveryBounce view = new DiscoveryBounce(launcher,
-                AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce));
-        view.mIsOpen = true;
-        launcher.getDragLayer().addView(view);
-        launcher.getUserEventDispatcher().logActionBounceTip(HOTSEAT);
+        new DiscoveryBounce(launcher, 0).show(HOTSEAT);
     }
 
     public static void showForOverviewIfNeeded(Launcher launcher) {
@@ -164,26 +164,29 @@
             return;
         }
 
-        float verticalProgress = OVERVIEW.getVerticalProgress(launcher);
+        new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher)))
+                .show(PREDICTION);
+    }
 
-        TimeInterpolator pathInterpolator = new PathInterpolator(0.35f, 0, 0.5f, 1);
-        Keyframe keyframe3 = Keyframe.ofFloat(0.423f, verticalProgress - (1 - 0.9738f));
-        keyframe3.setInterpolator(pathInterpolator);
-        Keyframe keyframe4 = Keyframe.ofFloat(0.754f, verticalProgress);
-        keyframe4.setInterpolator(pathInterpolator);
+    /**
+     * A wrapper around {@link AllAppsTransitionController} allowing a fixed shift in the value.
+     */
+    public static class VerticalProgressWrapper {
 
-        PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("progress",
-                Keyframe.ofFloat(0, verticalProgress),
-                Keyframe.ofFloat(0.246f, verticalProgress), keyframe3, keyframe4,
-                Keyframe.ofFloat(1f, verticalProgress));
-        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(null,
-                new PropertyValuesHolder[]{propertyValuesHolder});
-        animator.setDuration(2166);
-        animator.setRepeatCount(5);
+        private final float mDelta;
+        private final AllAppsTransitionController mController;
 
-        DiscoveryBounce view = new DiscoveryBounce(launcher, animator);
-        view.mIsOpen = true;
-        launcher.getDragLayer().addView(view);
-        launcher.getUserEventDispatcher().logActionBounceTip(PREDICTION);
+        private VerticalProgressWrapper(AllAppsTransitionController controller, float delta) {
+            mController = controller;
+            mDelta = delta;
+        }
+
+        public float getProgress() {
+            return mController.getProgress() + mDelta;
+        }
+
+        public void setProgress(float progress) {
+            mController.setProgress(progress - mDelta);
+        }
     }
 }
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 3b5585b..f020d2d 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -360,16 +360,18 @@
                 .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
         IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
 
-        Bitmap unbadgedBitmap = null;
+        final Bitmap unbadgedBitmap;
         if (unbadgedDrawable != null) {
             unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
         } else {
             if (fallbackIconProvider != null) {
-                unbadgedBitmap = fallbackIconProvider.get();
+                // Fallback icons are already badged and with appropriate shadow
+                Bitmap fullIcon = fallbackIconProvider.get();
+                if (fullIcon != null) {
+                    return createIconBitmap(fullIcon);
+                }
             }
-            if (unbadgedBitmap == null) {
-                unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
-            }
+            unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
         }
 
         BitmapInfo result = new BitmapInfo();
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index a20149e..3c1cc90 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -76,7 +76,7 @@
                 BaseDraggingActivity activity, ItemInfo itemInfo) {
             return (view) -> {
                 Rect sourceBounds = activity.getViewBounds(view);
-                Bundle opts = activity.getActivityLaunchOptionsAsBundle(view, false);
+                Bundle opts = activity.getActivityLaunchOptionsAsBundle(view);
                 new PackageManagerHelper(activity).startDetailsActivityForInfo(
                         itemInfo, sourceBounds, opts);
                 activity.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index c89012a..a9006e3 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -225,8 +224,6 @@
             cancelAtomicComponentsController();
         }
         mProgressMultiplier = initCurrentAnimation(animComponents);
-        mCurrentAnimation.getAnimationPlayer().addUpdateListener(animation ->
-                setBackButtonAlphaWithProgress((float) animation.getAnimatedValue()));
         mCurrentAnimation.dispatchOnStart();
         return true;
     }
@@ -287,7 +284,6 @@
             mAtomicComponentsController.setPlayFraction(fraction - mAtomicComponentsStartProgress);
         }
         maybeUpdateAtomicAnim(mFromState, mToState, fraction);
-        setBackButtonAlphaWithProgress(fraction);
     }
 
     /**
@@ -403,6 +399,9 @@
         updateSwipeCompleteAnimation(anim, Math.max(duration, getRemainingAtomicDuration()),
                 targetState, velocity, fling);
         mCurrentAnimation.dispatchOnStart();
+        if (fling && targetState == LauncherState.ALL_APPS) {
+            mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity);
+        }
         anim.start();
         if (mAtomicAnim == null) {
             startAtomicComponentsAnim(endProgress, anim.getDuration());
@@ -480,14 +479,6 @@
         }
     }
 
-    private void setBackButtonAlphaWithProgress(float progress) {
-        if (mFromState.hideBackButton ^ mToState.hideBackButton) {
-            progress = Utilities.boundToRange(progress, 0, 1);
-            final float alpha = mToState.hideBackButton ? 1 - progress : progress;
-            UiFactory.setBackButtonAlpha(mLauncher, alpha, false /* animate */);
-        }
-    }
-
     private void logReachedState(int logAction) {
         // Transition complete. log the action
         mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 6bbce00..6e3ef07 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -45,6 +45,7 @@
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
 import android.support.v4.widget.ExploreByTouchHelper;
 import android.util.AttributeSet;
+import android.util.Property;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -73,6 +74,19 @@
 public class ScrimView extends View implements Insettable, OnChangeListener,
         AccessibilityStateChangeListener, StateListener {
 
+    public static final Property<ScrimView, Integer> DRAG_HANDLE_ALPHA =
+            new Property<ScrimView, Integer>(Integer.TYPE, "dragHandleAlpha") {
+
+                @Override
+                public Integer get(ScrimView scrimView) {
+                    return scrimView.mDragHandleAlpha;
+                }
+
+                @Override
+                public void set(ScrimView scrimView, Integer value) {
+                    scrimView.setDragHandleAlpha(value);
+                }
+            };
     private static final int WALLPAPERS = R.string.wallpaper_button_text;
     private static final int WIDGETS = R.string.widget_button_text;
     private static final int SETTINGS = R.string.settings_button_text;
@@ -102,6 +116,8 @@
     @Nullable
     protected Drawable mDragHandle;
 
+    private int mDragHandleAlpha = 255;
+
     public ScrimView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mLauncher = Launcher.getLauncher(context);
@@ -118,6 +134,7 @@
         ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
 
         mAM = (AccessibilityManager) context.getSystemService(ACCESSIBILITY_SERVICE);
+        setFocusable(false);
     }
 
     @NonNull
@@ -187,7 +204,17 @@
 
     protected void updateDragHandleAlpha() {
         if (mDragHandle != null) {
-            mDragHandle.setAlpha(Math.round(255 * Utilities.boundToRange(mProgress, 0, 1)));
+            mDragHandle.setAlpha(mDragHandleAlpha);
+        }
+    }
+
+    private void setDragHandleAlpha(int alpha) {
+        if (alpha != mDragHandleAlpha) {
+            mDragHandleAlpha = alpha;
+            if (mDragHandle != null) {
+                mDragHandle.setAlpha(mDragHandleAlpha);
+                invalidate();
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
index 598738b..5022d65 100644
--- a/src/com/android/launcher3/views/SpringRelativeLayout.java
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
+import android.support.animation.DynamicAnimation;
 import android.support.animation.FloatPropertyCompat;
 import android.support.animation.SpringAnimation;
 import android.support.animation.SpringForce;
@@ -79,6 +80,11 @@
         mSpringViews.put(id, true);
     }
 
+    public void removeSpringView(int id) {
+        mSpringViews.delete(id);
+        invalidate();
+    }
+
     @Override
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         if (mDampedScrollShift != 0 && mSpringViews.get(child.getId())) {
@@ -110,6 +116,13 @@
         mSpring.start();
     }
 
+    protected void finishWithShiftAndVelocity(float shift, float velocity,
+            DynamicAnimation.OnAnimationEndListener listener) {
+        setDampedScrollShift(shift);
+        mSpring.addEndListener(listener);
+        finishScrollWithVelocity(velocity);
+    }
+
     public EdgeEffectFactory createEdgeEffectFactory() {
         return new SpringEdgeEffectFactory();
     }