Merge "Reduce alpha delay 25ms to reduce flashy feeling of appearing large." into ub-launcher3-qt-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 1042c60..eac4dce 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -121,12 +121,16 @@
         alpha.setDuration(CONTENT_ALPHA_DURATION);
         alpha.setInterpolator(LINEAR);
         anim.play(alpha);
+        overview.setFreezeViewVisibility(true);
 
         ObjectAnimator transY = ObjectAnimator.ofFloat(overview, View.TRANSLATION_Y, trans);
         transY.setInterpolator(AGGRESSIVE_EASE);
         transY.setDuration(CONTENT_TRANSLATION_DURATION);
         anim.play(transY);
 
-        return mLauncher.getStateManager()::reapplyState;
+        return () -> {
+            overview.setFreezeViewVisibility(false);
+            mLauncher.getStateManager().reapplyState();
+        };
     }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 1d36d1a..b5d8424 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -32,7 +32,6 @@
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.PropertySetter;
-import com.android.quickstep.hints.ProactiveHintsContainer;
 import com.android.quickstep.views.ClearAllButton;
 import com.android.quickstep.views.LauncherRecentsView;
 import com.android.quickstep.views.RecentsView;
@@ -55,14 +54,6 @@
         if (state.overviewUi) {
             mRecentsView.updateEmptyMessage();
             mRecentsView.resetTaskVisuals();
-            mRecentsView.setHintVisibility(1f);
-        } else {
-            mRecentsView.setHintVisibility(0f);
-            ProactiveHintsContainer
-                    proactiveHintsContainer = mRecentsView.getProactiveHintsContainer();
-            if (proactiveHintsContainer != null) {
-                proactiveHintsContainer.removeAllViews();
-            }
         }
         setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state.getVisibleElements(mLauncher));
         mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
@@ -75,14 +66,6 @@
 
         if (!toState.overviewUi) {
             builder.addOnFinishRunnable(mRecentsView::resetTaskVisuals);
-            mRecentsView.setHintVisibility(0f);
-            builder.addOnFinishRunnable(() -> {
-                ProactiveHintsContainer
-                        proactiveHintsContainer = mRecentsView.getProactiveHintsContainer();
-                if (proactiveHintsContainer != null) {
-                    proactiveHintsContainer.removeAllViews();
-                }
-            });
         }
 
         if (toState.overviewUi) {
@@ -94,7 +77,6 @@
             updateAnim.setDuration(config.duration);
             builder.play(updateAnim);
             mRecentsView.updateEmptyMessage();
-            builder.addOnFinishRunnable(() -> mRecentsView.setHintVisibility(1f));
         }
 
         PropertySetter propertySetter = config.getPropertySetter(builder);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index a6c4445..d66af1a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -98,9 +98,6 @@
         if (mStartState == OVERVIEW || mStartState == ALL_APPS) {
             return true;
         }
-        if (!mLauncher.hasWindowFocus()) {
-            return true;
-        }
         if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
             return true;
         }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
index dc58a4e..2c42fd6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.quickstep.fallback.FallbackRecentsView.ZOOM_PROGRESS;
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 
 import android.animation.Animator;
@@ -33,6 +34,7 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.quickstep.fallback.FallbackRecentsView;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.RemoteAnimationTargetSet;
 import com.android.quickstep.views.RecentsView;
@@ -120,11 +122,14 @@
             return (transitionLength) -> { };
         }
 
-        RecentsView rv = activity.getOverviewPanel();
+        FallbackRecentsView rv = activity.getOverviewPanel();
         rv.setContentAlpha(0);
         rv.getClearAllButton().setVisibilityAlpha(0);
         rv.setDisallowScrollToClearAll(true);
 
+        boolean fromState = !animateActivity;
+        rv.setInOverviewState(fromState);
+
         return new AnimationFactory() {
 
             boolean isAnimatingToRecents = false;
@@ -141,15 +146,28 @@
 
             @Override
             public void createActivityController(long transitionLength) {
-                if (!isAnimatingToRecents) {
-                    return;
+                AnimatorSet animatorSet = new AnimatorSet();
+                if (isAnimatingToRecents) {
+                    ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1);
+                    anim.setDuration(transitionLength).setInterpolator(LINEAR);
+                    animatorSet.play(anim);
                 }
 
-                ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1);
+                ObjectAnimator anim = ObjectAnimator.ofFloat(rv, ZOOM_PROGRESS, 1, 0);
                 anim.setDuration(transitionLength).setInterpolator(LINEAR);
-                AnimatorSet animatorSet = new AnimatorSet();
                 animatorSet.play(anim);
-                callback.accept(AnimatorPlaybackController.wrap(animatorSet, transitionLength));
+
+                AnimatorPlaybackController controller =
+                        AnimatorPlaybackController.wrap(animatorSet, transitionLength);
+
+                // Since we are changing the start position of the UI, reapply the state, at the end
+                controller.setEndAction(() -> {
+                    boolean endState = true;
+                    rv.setInOverviewState(controller.getInterpolatedProgress() > 0.5 ?
+                                    endState : fromState);
+                });
+
+                callback.accept(controller);
             }
         };
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
index 5decc3e..32a9261 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
@@ -125,7 +125,14 @@
             @Override
             public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
                     AnimationResult result) {
-                result.setAnimation(composeRecentsLaunchAnimator(taskView, targetCompats));
+                AnimatorSet anim = composeRecentsLaunchAnimator(taskView, targetCompats);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mFallbackRecentsView.resetViewUI();
+                    }
+                });
+                result.setAnimation(anim);
             }
         };
         return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index cbc94ba..dc35440 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -62,6 +62,7 @@
 
 import androidx.annotation.BinderThread;
 
+import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
@@ -79,6 +80,7 @@
 import com.android.quickstep.inputconsumers.InputConsumer;
 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
+import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -566,10 +568,9 @@
             info.id = mSwipeSharedState.nextRunningTaskId;
             return createOtherActivityInputConsumer(event, info);
         } else if (mSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
-            return OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false);
-        } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() &&
-                activityControl.isInLiveTileMode()) {
-            return OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false);
+            return createOverviewInputConsumer(event);
+        } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) {
+            return createOverviewInputConsumer(event);
         } else if (mGestureBlockingActivity != null && runningTaskInfo != null
                 && mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
             return InputConsumer.NO_OP;
@@ -578,20 +579,24 @@
         }
     }
 
+    private boolean disableHorizontalSwipe(MotionEvent event) {
+        // mExclusionRegion can change on binder thread, use a local instance here.
+        Region exclusionRegion = mExclusionRegion;
+        return mMode == Mode.NO_BUTTON && exclusionRegion != null
+                && exclusionRegion.contains((int) event.getX(), (int) event.getY());
+    }
+
     private OtherActivityInputConsumer createOtherActivityInputConsumer(MotionEvent event,
             RunningTaskInfo runningTaskInfo) {
         final ActivityControlHelper activityControl =
                 mOverviewComponentObserver.getActivityControlHelper();
         boolean shouldDefer = activityControl.deferStartingActivity(mActiveNavBarRegion, event);
 
-        // mExclusionRegion can change on binder thread, use a local instance here.
-        Region exclusionRegion = mExclusionRegion;
-        boolean disableHorizontalSwipe = mMode == Mode.NO_BUTTON && exclusionRegion != null
-                && exclusionRegion.contains((int) event.getX(), (int) event.getY());
         return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
                 mOverviewComponentObserver.getOverviewIntent(), activityControl,
                 shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive,
-                mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion, disableHorizontalSwipe);
+                mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
+                disableHorizontalSwipe(event));
     }
 
     private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
@@ -603,6 +608,23 @@
         }
     }
 
+    public InputConsumer createOverviewInputConsumer(MotionEvent event) {
+        final ActivityControlHelper activityControl =
+                mOverviewComponentObserver.getActivityControlHelper();
+        BaseDraggingActivity activity = activityControl.getCreatedActivity();
+        if (activity == null) {
+            return InputConsumer.NO_OP;
+        }
+
+        if (activity.getRootView().hasWindowFocus()) {
+            return new OverviewInputConsumer(activity, mInputMonitorCompat,
+                    false /* startingInActivityBounds */);
+        } else {
+            return new OverviewWithoutFocusInputConsumer(this, mInputMonitorCompat,
+                    disableHorizontalSwipe(event));
+        }
+    }
+
     /**
      * To be called by the consumer when it's no longer active.
      */
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 87b7326..8b1efb2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -267,6 +267,7 @@
     private MultiStateCallback mStateCallback;
     // Used to control launcher components throughout the swipe gesture.
     private AnimatorPlaybackController mLauncherTransitionController;
+    private boolean mHasLauncherTransitionControllerStarted;
 
     private T mActivity;
     private RecentsView mRecentsView;
@@ -647,8 +648,7 @@
     }
 
     private void buildAnimationController() {
-        if (mGestureEndTarget == HOME || (mLauncherTransitionController != null
-                && mLauncherTransitionController.getAnimationPlayer().isStarted())) {
+        if (mGestureEndTarget == HOME || mHasLauncherTransitionControllerStarted) {
             // We don't want a new mLauncherTransitionController if mGestureEndTarget == HOME (it
             // has its own animation) or if we're already animating the current controller.
             return;
@@ -858,7 +858,9 @@
             setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha);
         }
 
-        return OverviewInputConsumer.newInstance(mActivityControlHelper, null, true);
+        BaseDraggingActivity activity = mActivityControlHelper.getCreatedActivity();
+        return activity == null
+                ? InputConsumer.NO_OP : new OverviewInputConsumer(activity, null, true);
     }
 
     private void endRunningWindowAnim() {
@@ -1122,6 +1124,7 @@
             }
             mLauncherTransitionController.getAnimationPlayer().start();
         }
+        mHasLauncherTransitionControllerStarted = true;
     }
 
     /**
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
index a5aa1bf..c2876180 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -15,19 +15,45 @@
  */
 package com.android.quickstep.fallback;
 
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.view.View;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
+import com.android.launcher3.Utilities;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
 
 public class FallbackRecentsView extends RecentsView<RecentsActivity> {
 
+    public static final FloatProperty<FallbackRecentsView> ZOOM_PROGRESS =
+            new FloatProperty<FallbackRecentsView> ("zoomInProgress") {
+
+                @Override
+                public void setValue(FallbackRecentsView view, float value) {
+                    view.setZoomProgress(value);
+                }
+
+                @Override
+                public Float get(FallbackRecentsView view) {
+                    return view.mZoomInProgress;
+                }
+            };
+
+    private float mZoomInProgress = 0;
+    private boolean mInOverviewState = true;
+
+    private float mZoomScale = 1f;
+    private float mZoomTranslationY = 0f;
+
     public FallbackRecentsView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -71,4 +97,46 @@
         // Just use the activity task size for multi-window as well.
         return false;
     }
+
+    public void resetViewUI() {
+        setZoomProgress(0);
+        resetTaskVisuals();
+    }
+
+    public void setInOverviewState(boolean inOverviewState) {
+        if (mInOverviewState != inOverviewState) {
+            mInOverviewState = inOverviewState;
+            if (mInOverviewState) {
+                resetTaskVisuals();
+            } else {
+                setZoomProgress(1);
+            }
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (getTaskViewCount() == 0) {
+            mZoomScale = 1f;
+            mZoomTranslationY = 0f;
+        } else {
+            TaskView dummyTask = getTaskViewAt(0);
+            ScaleAndTranslation sat = getTempClipAnimationHelper()
+                    .updateForFullscreenOverview(dummyTask)
+                    .getScaleAndTranslation();
+            mZoomScale = sat.scale;
+            mZoomTranslationY = sat.translationY;
+        }
+
+        setZoomProgress(mZoomInProgress);
+    }
+
+    public void setZoomProgress(float progress) {
+        mZoomInProgress = progress;
+        SCALE_PROPERTY.set(this, Utilities.mapRange(mZoomInProgress, 1, mZoomScale));
+        TRANSLATION_Y.set(this, Utilities.mapRange(mZoomInProgress, 0, mZoomTranslationY));
+        FULLSCREEN_PROGRESS.set(this, mZoomInProgress);
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintUtil.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintUtil.java
deleted file mode 100644
index f2d40ec..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintUtil.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2019 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.quickstep.hints;
-
-import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-
-public final class HintUtil {
-
-    public static final String ID_KEY = "id";
-    public static final String ICON_KEY = "icon";
-    public static final String TEXT_KEY = "text";
-    public static final String TAP_ACTION_KEY = "tap_action";
-
-    private HintUtil() {}
-
-    public static Bundle makeHint(String id, Icon icon, CharSequence text) {
-        Bundle hint = new Bundle();
-        hint.putString(ID_KEY, id);
-        hint.putParcelable(ICON_KEY, icon);
-        hint.putCharSequence(TEXT_KEY, text);
-        return hint;
-    }
-
-    public static Bundle makeHint(Icon icon, CharSequence text, PendingIntent tapAction) {
-        Bundle hint = new Bundle();
-        hint.putParcelable(ICON_KEY, icon);
-        hint.putCharSequence(TEXT_KEY, text);
-        hint.putParcelable(TAP_ACTION_KEY, tapAction);
-        return hint;
-    }
-
-    public static String getId(Bundle hint) {
-        String id = hint.getString(ID_KEY);
-        if (id == null) {
-            throw new IllegalArgumentException("Hint does not contain an ID");
-        }
-        return id;
-    }
-
-    public static Icon getIcon(Bundle hint) {
-        Icon icon = hint.getParcelable(ICON_KEY);
-        if (icon == null) {
-            throw new IllegalArgumentException("Hint does not contain an icon");
-        }
-        return icon;
-    }
-
-    public static CharSequence getText(Bundle hint) {
-        CharSequence text = hint.getCharSequence(TEXT_KEY);
-        if (text == null) {
-            throw new IllegalArgumentException("Hint does not contain text");
-        }
-        return text;
-    }
-
-    public static PendingIntent getTapAction(Bundle hint) {
-        PendingIntent tapAction = hint.getParcelable(TAP_ACTION_KEY);
-        if (tapAction == null) {
-            throw new IllegalArgumentException("Hint does not contain a tap action");
-        }
-        return tapAction;
-    }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintView.java
deleted file mode 100644
index 5399cc4..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/HintView.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2019 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.quickstep.hints;
-
-import static com.android.quickstep.hints.HintUtil.getIcon;
-import static com.android.quickstep.hints.HintUtil.getText;
-
-import android.content.Context;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.R;
-
-public class HintView extends LinearLayout {
-    private ImageView mIconView;
-    private TextView mLabelView;
-
-    public HintView(Context context) {
-        super(context);
-    }
-
-    public HintView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public HintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    public HintView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    public void setHint(Bundle hint) {
-        mLabelView.setText(getText(hint));
-
-        Icon icon = getIcon(hint);
-        if (icon == null) {
-            mIconView.setVisibility(GONE);
-        } else {
-            mIconView.setImageIcon(icon);
-            mIconView.setVisibility(VISIBLE);
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mIconView = findViewById(R.id.icon);
-        mLabelView = findViewById(R.id.label);
-    }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ProactiveHintsContainer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ProactiveHintsContainer.java
deleted file mode 100644
index 74a4851..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/ProactiveHintsContainer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.android.quickstep.hints;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.view.View;
-import android.widget.FrameLayout;
-
-public class ProactiveHintsContainer extends FrameLayout {
-
-  public static final FloatProperty<ProactiveHintsContainer> HINT_VISIBILITY =
-      new FloatProperty<ProactiveHintsContainer>("hint_visibility") {
-        @Override
-        public void setValue(ProactiveHintsContainer proactiveHintsContainer, float v) {
-          proactiveHintsContainer.setHintVisibility(v);
-        }
-
-        @Override
-        public Float get(ProactiveHintsContainer proactiveHintsContainer) {
-          return proactiveHintsContainer.mHintVisibility;
-        }
-      };
-
-  private float mHintVisibility;
-
-  public ProactiveHintsContainer(Context context) {
-    super(context);
-  }
-
-  public ProactiveHintsContainer(Context context, AttributeSet attrs) {
-    super(context, attrs);
-  }
-
-  public ProactiveHintsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
-    super(context, attrs, defStyleAttr);
-  }
-
-  public ProactiveHintsContainer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-    super(context, attrs, defStyleAttr, defStyleRes);
-  }
-
-  public void setView(View v) {
-    removeAllViews();
-    addView(v);
-  }
-
-  public void setHintVisibility(float v) {
-    if (v == 1) {
-      setVisibility(VISIBLE);
-    } else {
-      setVisibility(GONE);
-    }
-    mHintVisibility = v;
-  }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiHintListenerConstants.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiHintListenerConstants.java
deleted file mode 100644
index 420033d..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiHintListenerConstants.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2019 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.quickstep.hints;
-
-public final class UiHintListenerConstants {
-
-    private UiHintListenerConstants() {}
-
-    // Operations
-    public static final int ON_HINTS_RETURNED_CODE = 5;
-
-    // Keys
-    public static final String SESSION_ID_KEY = "session_id";
-    public static final String HINTS_KEY = "hints";
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiInterfaceConstants.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiInterfaceConstants.java
deleted file mode 100644
index 0140613..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/hints/UiInterfaceConstants.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 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.quickstep.hints;
-
-public final class UiInterfaceConstants {
-
-    private UiInterfaceConstants() {}
-
-    // Operations
-    public static final int ON_HINT_TAP_CODE = 4;
-
-    public static final int REQUEST_HINTS_CODE = 7;
-
-    // Keys
-    public static final String SESSION_ID_KEY = "session_id";
-    public static final String HINT_ID_KEY = "hint_id";
-    public static final String WIDTH_PX_KEY = "width_px";
-    public static final String HEIGHT_PX_KEY = "height_px";
-    public static final String HINT_SPACE_WIDTH_PX_KEY = "hint_space_width_px";
-    public static final String HINT_SPACE_HEIGHT_PX_KEY = "hint_space_height_px";
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
index 6e7cb8f..489eb27 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
@@ -31,6 +31,7 @@
     int TYPE_DEVICE_LOCKED = 1 << 4;
     int TYPE_ACCESSIBILITY = 1 << 5;
     int TYPE_SCREEN_PINNED = 1 << 6;
+    int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
 
     InputConsumer NO_OP = () -> TYPE_NO_OP;
 
@@ -78,6 +79,8 @@
                 return "ACCESSIBILITY";
             case TYPE_SCREEN_PINNED:
                 return "SCREEN_PINNED";
+            case TYPE_OVERVIEW_WITHOUT_FOCUS:
+                return "TYPE_OVERVIEW_WITHOUT_FOCUS";
             default:
                 return "NO_OP";
         }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 0ed4c99..69b25db 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -28,7 +28,6 @@
 import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE;
 import static com.android.launcher3.util.RaceConditionTracker.ENTER;
 import static com.android.launcher3.util.RaceConditionTracker.EXIT;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
 import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 
@@ -43,10 +42,8 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.view.MotionEvent;
-import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
-import android.view.WindowManager;
 
 import androidx.annotation.UiThread;
 
@@ -65,6 +62,7 @@
 import com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget;
 import com.android.quickstep.util.CachedEventDispatcher;
 import com.android.quickstep.util.MotionPauseDetector;
+import com.android.quickstep.util.NavBarPosition;
 import com.android.quickstep.util.RecentsAnimationListenerSet;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.BackgroundExecutor;
@@ -95,7 +93,7 @@
     private final SysUINavigationMode.Mode mMode;
     private final RectF mSwipeTouchRegion;
 
-    private final int mDisplayRotation;
+    private final NavBarPosition mNavBarPosition;
 
     private final Consumer<OtherActivityInputConsumer> mOnCompleteCallback;
     private final MotionPauseDetector mMotionPauseDetector;
@@ -157,7 +155,7 @@
         mInputConsumer = inputConsumer;
         mSwipeSharedState = swipeSharedState;
 
-        mDisplayRotation = getSystemService(WindowManager.class).getDefaultDisplay().getRotation();
+        mNavBarPosition = new NavBarPosition(base);
         mDragSlop = QuickStepContract.getQuickStepDragSlopPx();
         float slop = QuickStepContract.getQuickStepTouchSlopPx();
         mSquaredTouchSlop = slop * slop;
@@ -188,9 +186,7 @@
         if (mPassedDragSlop && mInteractionHandler != null
                 && !mRecentsViewDispatcher.hasConsumer()) {
             mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher(
-                    isNavBarOnLeft()
-                            ? ROTATION_SEASCAPE
-                            : (isNavBarOnRight() ? ROTATION_LANDSCAPE : RotationMode.NORMAL)));
+                    mNavBarPosition.getRotationMode()));
         }
         int edgeFlags = ev.getEdgeFlags();
         ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
@@ -329,14 +325,6 @@
         mInteractionHandler.onGestureStarted();
     }
 
-    private boolean isNavBarOnRight() {
-        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90;
-    }
-
-    private boolean isNavBarOnLeft() {
-        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270;
-    }
-
     private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
         TOUCH_INTERACTION_LOG.addLog("startRecentsAnimation");
 
@@ -382,8 +370,8 @@
                         ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
                 float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
                 float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
-                float velocity = isNavBarOnRight() ? velocityX
-                        : isNavBarOnLeft() ? -velocityX
+                float velocity = mNavBarPosition.isRightEdge() ? velocityX
+                        : mNavBarPosition.isLeftEdge() ? -velocityX
                                 : velocityY;
 
                 mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
@@ -444,9 +432,9 @@
     }
 
     private float getDisplacement(MotionEvent ev) {
-        if (isNavBarOnRight()) {
+        if (mNavBarPosition.isRightEdge()) {
             return ev.getX() - mDownPos.x;
-        } else if (isNavBarOnLeft()) {
+        } else if (mNavBarPosition.isLeftEdge()) {
             return mDownPos.x - ev.getX();
         } else {
             return ev.getY() - mDownPos.y;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index bab3c71..4851e67 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -51,7 +51,7 @@
     private final boolean mStartingInActivityBounds;
     private boolean mTargetHandledTouch;
 
-    OverviewInputConsumer(T activity, @Nullable InputMonitorCompat inputMonitor,
+    public OverviewInputConsumer(T activity, @Nullable InputMonitorCompat inputMonitor,
             boolean startingInActivityBounds) {
         mActivity = activity;
         mInputMonitor = inputMonitor;
@@ -115,12 +115,12 @@
         }
     }
 
-    public static InputConsumer newInstance(ActivityControlHelper activityHelper,
-            @Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) {
+    public static InputConsumer newInstanceWithinActivityBounds(
+            ActivityControlHelper activityHelper) {
         BaseDraggingActivity activity = activityHelper.getCreatedActivity();
         if (activity == null) {
             return InputConsumer.NO_OP;
         }
-        return new OverviewInputConsumer(activity, inputMonitor, startingInActivityBounds);
+        return new OverviewInputConsumer(activity, null, true);
     }
 }
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
new file mode 100644
index 0000000..425b8b6
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 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.quickstep.inputconsumers;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
+import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.Utilities;
+import com.android.quickstep.OverviewCallbacks;
+import com.android.quickstep.util.NavBarPosition;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+public class OverviewWithoutFocusInputConsumer implements InputConsumer {
+
+    private final InputMonitorCompat mInputMonitor;
+    private final boolean mDisableHorizontalSwipe;
+    private final PointF mDownPos = new PointF();
+    private final float mSquaredTouchSlop;
+    private final Context mContext;
+    private final NavBarPosition mNavBarPosition;
+
+    private boolean mInterceptedTouch;
+    private VelocityTracker mVelocityTracker;
+
+
+    public OverviewWithoutFocusInputConsumer(Context context, InputMonitorCompat inputMonitor,
+            boolean disableHorizontalSwipe) {
+        mInputMonitor = inputMonitor;
+        mDisableHorizontalSwipe = disableHorizontalSwipe;
+        mContext = context;
+        mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
+        mNavBarPosition = new NavBarPosition(context);
+
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    @Override
+    public int getType() {
+        return TYPE_OVERVIEW_WITHOUT_FOCUS;
+    }
+
+    @Override
+    public boolean allowInterceptByParent() {
+        return !mInterceptedTouch;
+    }
+
+    private void endTouchTracking() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            return;
+        }
+
+        mVelocityTracker.addMovement(ev);
+        switch (ev.getActionMasked()) {
+            case ACTION_DOWN: {
+                mDownPos.set(ev.getX(), ev.getY());
+                break;
+            }
+            case ACTION_MOVE: {
+                if (!mInterceptedTouch) {
+                    float displacementX = ev.getX() - mDownPos.x;
+                    float displacementY = ev.getY() - mDownPos.y;
+                    if (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop) {
+                        if (mDisableHorizontalSwipe
+                                && Math.abs(displacementX) > Math.abs(displacementY)) {
+                            // Horizontal gesture is not allowed in this region
+                            endTouchTracking();
+                            break;
+                        }
+
+                        mInterceptedTouch = true;
+
+                        if (mInputMonitor != null) {
+                            mInputMonitor.pilferPointers();
+                        }
+                    }
+                }
+                break;
+            }
+
+            case ACTION_CANCEL:
+                endTouchTracking();
+                break;
+
+            case ACTION_UP: {
+                finishTouchTracking(ev);
+                endTouchTracking();
+                break;
+            }
+        }
+    }
+
+    private void finishTouchTracking(MotionEvent ev) {
+        mVelocityTracker.computeCurrentVelocity(100);
+        float velocityX = mVelocityTracker.getXVelocity();
+        float velocityY = mVelocityTracker.getYVelocity();
+        float velocity = mNavBarPosition.isRightEdge()
+                ? -velocityX : (mNavBarPosition.isLeftEdge() ? velocityX : -velocityY);
+
+        final boolean triggerQuickstep;
+        if (Math.abs(velocity) >= ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) {
+            triggerQuickstep = velocity > 0;
+        } else {
+            float displacementX = mDisableHorizontalSwipe ? 0 : (ev.getX() - mDownPos.x);
+            float displacementY = ev.getY() - mDownPos.y;
+            triggerQuickstep = squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop;
+        }
+
+        if (triggerQuickstep) {
+            OverviewCallbacks.get(mContext).closeAllWindows();
+            ActivityManagerWrapper.getInstance()
+                    .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+            TOUCH_INTERACTION_LOG.addLog("startQuickstep");
+        } else {
+            // ignore
+        }
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java
new file mode 100644
index 0000000..3ce341d
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 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.quickstep.util;
+
+import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_LANDSCAPE;
+import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+
+import android.content.Context;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import com.android.launcher3.graphics.RotationMode;
+import com.android.quickstep.SysUINavigationMode;
+
+/**
+ * Utility class to check nav bar position
+ */
+public class NavBarPosition {
+
+    private final SysUINavigationMode.Mode mMode;
+    private final int mDisplayRotation;
+
+    public NavBarPosition(Context context) {
+        mMode = SysUINavigationMode.getMode(context);
+        mDisplayRotation = context.getSystemService(WindowManager.class)
+                .getDefaultDisplay().getRotation();
+    }
+
+    public boolean isRightEdge() {
+        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90;
+    }
+
+    public boolean isLeftEdge() {
+        return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270;
+    }
+
+    public RotationMode getRotationMode() {
+        return isLeftEdge() ? ROTATION_SEASCAPE
+                : (isRightEdge() ? ROTATION_LANDSCAPE : RotationMode.NORMAL);
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 837c2dc..9eda2f9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -28,13 +28,20 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.anim.SpringObjectAnimator;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 
 /**
@@ -56,7 +63,7 @@
     private final float mSpringTransY;
     private final View mViewToIgnore;
 
-    private final List<ValueAnimator> mAnimators = new ArrayList<>();
+    private final List<Animator> mAnimators = new ArrayList<>();
 
     /**
      * @param floatingViewOriginalView The FloatingIconView's original view.
@@ -104,6 +111,9 @@
             View qsb = launcher.findViewById(R.id.search_container_all_apps);
             addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
         }
+
+        addWorkspaceScrimAnimationForState(launcher, BACKGROUND_APP, 0);
+        addWorkspaceScrimAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
     }
 
     /**
@@ -150,4 +160,14 @@
         alpha.setStartDelay(startDelay);
         mAnimators.add(alpha);
     }
+
+    private void addWorkspaceScrimAnimationForState(Launcher launcher, LauncherState state,
+            long duration) {
+        AnimatorSetBuilder scrimAnimBuilder = new AnimatorSetBuilder();
+        AnimationConfig scrimAnimConfig = new AnimationConfig();
+        scrimAnimConfig.duration = duration;
+        PropertySetter scrimPropertySetter = scrimAnimConfig.getPropertySetter(scrimAnimBuilder);
+        launcher.getWorkspace().getStateTransitionAnimation().setScrim(scrimPropertySetter, state);
+        mAnimators.add(scrimAnimBuilder.build());
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 4162845..5b2e27e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -35,8 +35,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
@@ -45,11 +43,8 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.appprediction.PredictionUiStateManager;
 import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
-import com.android.launcher3.util.PendingAnimation;
-import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.hints.ProactiveHintsContainer;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
 import com.android.quickstep.util.LayoutUtils;
@@ -61,8 +56,6 @@
 public class LauncherRecentsView extends RecentsView<Launcher> implements StateListener {
 
     private final TransformParams mTransformParams = new TransformParams();
-    private final int mChipOverhang;
-    @Nullable private ProactiveHintsContainer mProactiveHintsContainer;
 
     public LauncherRecentsView(Context context) {
         this(context, null);
@@ -75,20 +68,10 @@
     public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         setContentAlpha(0);
-        mChipOverhang = (int) context.getResources().getDimension(R.dimen.chip_hint_overhang);
         mActivity.getStateManager().addStateListener(this);
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        View hintContainer = mActivity.findViewById(R.id.hints);
-        mProactiveHintsContainer =
-                hintContainer instanceof ProactiveHintsContainer
-                        ? (ProactiveHintsContainer) hintContainer : null;
-    }
-
-    @Override
     public void startHome() {
         mActivity.getStateManager().goToState(NORMAL);
     }
@@ -104,11 +87,6 @@
         }
     }
 
-    @Nullable
-    public ProactiveHintsContainer getProactiveHintsContainer() {
-        return mProactiveHintsContainer;
-    }
-
     @Override
     public void draw(Canvas canvas) {
         maybeDrawEmptyMessage(canvas);
@@ -162,23 +140,6 @@
     @Override
     protected void getTaskSize(DeviceProfile dp, Rect outRect) {
         LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
-        if (mProactiveHintsContainer != null) {
-            BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) mProactiveHintsContainer.getLayoutParams();
-            params.bottomMargin = getHeight() - outRect.bottom - mChipOverhang;
-            params.width = outRect.width();
-        }
-    }
-
-    @Override
-    public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) {
-        PendingAnimation anim = super.createTaskLauncherAnimation(tv, duration);
-
-        if (mProactiveHintsContainer != null) {
-            anim.anim.play(ObjectAnimator.ofFloat(
-                    mProactiveHintsContainer, ProactiveHintsContainer.HINT_VISIBILITY, 0));
-        }
-
-        return anim;
     }
 
     @Override
@@ -197,31 +158,6 @@
     }
 
     @Override
-    public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
-            boolean shouldRemoveTask, long duration) {
-        PendingAnimation anim = super.createTaskDismissAnimation(taskView, animateTaskView,
-                shouldRemoveTask, duration);
-
-        if (mProactiveHintsContainer != null) {
-            anim.anim.play(ObjectAnimator.ofFloat(
-                    mProactiveHintsContainer, ProactiveHintsContainer.HINT_VISIBILITY, 0));
-            anim.addEndListener(onEndListener -> {
-                if (!onEndListener.isSuccess) {
-                    mProactiveHintsContainer.setHintVisibility(1);
-                }
-            });
-        }
-
-        return anim;
-    }
-
-    public void setHintVisibility(float v) {
-        if (mProactiveHintsContainer != null) {
-            mProactiveHintsContainer.setHintVisibility(v);
-        }
-    }
-
-    @Override
     protected void onTaskLaunched(boolean success) {
         if (success) {
             mActivity.getStateManager().goToState(NORMAL, false /* animate */);
@@ -291,6 +227,7 @@
     @Override
     public void onStateTransitionStart(LauncherState toState) {
         setOverviewStateEnabled(toState.overviewUi);
+        setFreezeViewVisibility(true);
     }
 
     @Override
@@ -300,6 +237,7 @@
             reset();
         }
         setOverlayEnabled(finalState == OVERVIEW);
+        setFreezeViewVisibility(false);
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 38bd461..e38a315 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -188,6 +188,7 @@
     private boolean mDwbToastShown;
     private boolean mDisallowScrollToClearAll;
     private boolean mOverlayEnabled;
+    private boolean mFreezeViewVisibility;
 
     /**
      * TODO: Call reloadIdNeeded in onTaskStackChanged.
@@ -1302,7 +1303,25 @@
         mEmptyMessagePaint.setAlpha(alphaInt);
         mEmptyIcon.setAlpha(alphaInt);
 
-        setVisibility(alpha > 0 ? VISIBLE : GONE);
+        if (alpha > 0) {
+            setVisibility(VISIBLE);
+        } else if (!mFreezeViewVisibility) {
+            setVisibility(GONE);
+        }
+    }
+
+    /**
+     * Freezes the view visibility change. When frozen, the view will not change its visibility
+     * to gone due to alpha changes.
+     */
+    public void setFreezeViewVisibility(boolean freezeViewVisibility) {
+        if (mFreezeViewVisibility != freezeViewVisibility) {
+            mFreezeViewVisibility = freezeViewVisibility;
+
+            if (!mFreezeViewVisibility) {
+                setVisibility(mContentAlpha > 0 ? VISIBLE : GONE);
+            }
+        }
     }
 
     @Override
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index c77726e..c2c568b 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -26,6 +26,5 @@
  */
 public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
     @Rule
-    public TestRule mQuickstepOnOffExecutor =
-            new NavigationModeSwitchRule(mLauncher);
+    public TestRule mNavigationModeSwitcher = new NavigationModeSwitchRule(mLauncher);
 }
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 9cab9c2..cca899b 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -48,11 +48,6 @@
             layout="@layout/overview_panel"
             android:visibility="gone" />
 
-        <include
-            android:id="@+id/hints"
-            layout="@layout/proactive_hints_container"
-            android:visibility="gone"/>
-
         <!-- Keep these behind the workspace so that they are not visible when
          we go into AllApps -->
         <com.android.launcher3.pageindicators.WorkspacePageIndicator
diff --git a/res/layout/proactive_hints_container.xml b/res/layout/proactive_hints_container.xml
deleted file mode 100644
index 2637f03..0000000
--- a/res/layout/proactive_hints_container.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<Space
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="0dp"
-    android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0da56da..4bcb8a7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -232,11 +232,6 @@
     <dimen name="snackbar_min_text_size">12sp</dimen>
     <dimen name="snackbar_max_text_size">14sp</dimen>
 
-<!-- Hints -->
-    <dimen name="chip_hint_height">26dp</dimen>
-    <dimen name="chip_hint_bottom_margin">194dp</dimen>
-    <dimen name="chip_hint_overhang">15dp</dimen>
-
 <!-- Theming related -->
     <dimen name="default_dialog_corner_radius">8dp</dimen>
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c1f898c..883e8c6 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -99,10 +99,6 @@
     public int folderChildTextSizePx;
     public int folderChildDrawablePaddingPx;
 
-    // Hints
-    public int chipHintHeightPx;
-    public int chipHintBottomMarginPx;
-
     // Hotseat
     public int hotseatCellHeightPx;
     // In portrait: size = height, in landscape: size = width
@@ -200,9 +196,6 @@
 
         workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
 
-        chipHintHeightPx = res.getDimensionPixelSize(R.dimen.chip_hint_height);
-        chipHintBottomMarginPx = res.getDimensionPixelSize(R.dimen.chip_hint_bottom_margin);
-
         hotseatBarTopPaddingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
         hotseatBarBottomPaddingPx = (isTallDevice ? 0
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f784226..9f846bb 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1394,6 +1394,10 @@
         builder.play(stepAnimator);
     }
 
+    public WorkspaceStateTransitionAnimation getStateTransitionAnimation() {
+        return mStateTransitionAnimation;
+    }
+
     public void updateAccessibilityFlags() {
         // TODO: Update the accessibility flags appropriately when dragging.
         int accessibilityFlag = mLauncher.getStateManager().getState().workspaceAccessibilityFlag;
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 8d0259d..065d065 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -130,7 +130,10 @@
         propertySetter.setFloat(mWorkspace.getPageIndicator(), View.TRANSLATION_Y,
                 hotseatScaleAndTranslation.translationY, translationInterpolator);
 
-        // Set scrim
+        setScrim(propertySetter, state);
+    }
+
+    public void setScrim(PropertySetter propertySetter, LauncherState state) {
         WorkspaceAndHotseatScrim scrim = mLauncher.getDragLayer().getScrim();
         propertySetter.setFloat(scrim, SCRIM_PROGRESS, state.getWorkspaceScrimAlpha(mLauncher),
                 LINEAR);
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index 4fea2e9..c24bb67 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -27,16 +27,17 @@
 import com.android.launcher3.config.FeatureFlags;
 
 /**
- * A wrapper around {@link Trace} to allow easier proguarding for production builds.
+ * A wrapper around {@link Trace} with some utility information.
  *
  * To enable any tracing log, execute the following command:
+ * $ adb shell setprop log.tag.LAUNCHER_TRACE VERBOSE
  * $ adb shell setprop log.tag.TAGNAME VERBOSE
  */
 public class TraceHelper {
 
-    private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD;
+    private static final boolean ENABLED = isLoggable("LAUNCHER_TRACE", VERBOSE);
 
-    private static final boolean SYSTEM_TRACE = false;
+    private static final boolean SYSTEM_TRACE = ENABLED;
     private static final ArrayMap<String, MutableLong> sUpTimes = ENABLED ? new ArrayMap<>() : null;
 
     public static void beginSection(String sectionName) {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 95c9681..339681c 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -124,6 +124,7 @@
 
     private boolean mIsVerticalBarLayout = false;
     private boolean mIsAdaptiveIcon = false;
+    private boolean mIsOpening;
 
     private @Nullable Drawable mBadge;
     private @Nullable Drawable mForeground;
@@ -178,8 +179,10 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        getViewTreeObserver().addOnGlobalLayoutListener(this);
-        mLauncher.getRotationHelper().setCurrentTransitionRequest(REQUEST_LOCK);
+        if (!mIsOpening) {
+            getViewTreeObserver().addOnGlobalLayoutListener(this);
+            mLauncher.getRotationHelper().setCurrentTransitionRequest(REQUEST_LOCK);
+        }
     }
 
     @Override
@@ -326,7 +329,7 @@
      * - For BubbleTextView, we return the icon bounds.
      */
     private float getLocationBoundsForView(View v, RectF outRect) {
-        boolean ignoreTransform = true;
+        boolean ignoreTransform = !mIsOpening;
         if (v instanceof DeepShortcutView) {
             v = ((DeepShortcutView) v).getBubbleText();
             ignoreTransform = false;
@@ -627,6 +630,7 @@
         view.recycle();
 
         view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
+        view.mIsOpening = isOpening;
 
         view.mOriginalIcon = originalView;
         view.mPositionOut = positionOut;
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index c7c36b0..e5cc858 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -58,6 +58,7 @@
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.tapl.TestHelpers;
 import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.FailureWatcher;
 import com.android.launcher3.util.rule.LauncherActivityRule;
 import com.android.launcher3.util.rule.ShellCommandRule;
 
@@ -66,11 +67,8 @@
 import org.junit.Rule;
 import org.junit.rules.TestRule;
 import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.IOException;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -93,7 +91,6 @@
     public static final long SHORT_UI_TIMEOUT = 300;
     public static final long DEFAULT_UI_TIMEOUT = 10000;
     private static final String TAG = "AbstractLauncherUiTest";
-    private static int sScreenshotCount = 0;
 
     protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
     protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
@@ -167,42 +164,11 @@
             } : base;
 
     @Rule
-    public TestWatcher mFailureWatcher = new TestWatcher() {
-        private void dumpViewHierarchy() {
-            final ByteArrayOutputStream stream = new ByteArrayOutputStream();
-            try {
-                mDevice.dumpWindowHierarchy(stream);
-                stream.flush();
-                stream.close();
-                for (String line : stream.toString().split("\\r?\\n")) {
-                    Log.e(TAG, line.trim());
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "error dumping XML to logcat", e);
-            }
-        }
+    public TestWatcher mFailureWatcher = new FailureWatcher(this);
 
-        @Override
-        protected void failed(Throwable e, Description description) {
-            if (mDevice == null) return;
-            final String pathname = getInstrumentation().getTargetContext().
-                    getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
-            Log.e(TAG, "Failed test " + description.getMethodName() +
-                    ", screenshot will be saved to " + pathname +
-                    ", track trace is below, UI object dump is further below:\n" +
-                    Log.getStackTraceString(e));
-            dumpViewHierarchy();
-
-            try {
-                final String dumpsysResult = mDevice.executeShellCommand(
-                                "dumpsys activity service TouchInteractionService");
-                Log.d(TAG, "TouchInteractionService: " + dumpsysResult);
-            } catch (IOException ex) {
-            }
-
-            mDevice.takeScreenshot(new File(pathname));
-        }
-    };
+    public UiDevice getDevice() {
+        return mDevice;
+    }
 
     @Before
     public void setUp() throws Exception {
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
new file mode 100644
index 0000000..09cc98d
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -0,0 +1,59 @@
+package com.android.launcher3.util.rule;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.util.Log;
+
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+public class FailureWatcher extends TestWatcher {
+    private static final String TAG = "FailureWatcher";
+    private static int sScreenshotCount = 0;
+    private AbstractLauncherUiTest mAbstractLauncherUiTest;
+
+    public FailureWatcher(AbstractLauncherUiTest abstractLauncherUiTest) {
+        mAbstractLauncherUiTest = abstractLauncherUiTest;
+    }
+
+    private void dumpViewHierarchy() {
+        final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        try {
+            mAbstractLauncherUiTest.getDevice().dumpWindowHierarchy(stream);
+            stream.flush();
+            stream.close();
+            for (String line : stream.toString().split("\\r?\\n")) {
+                Log.e(TAG, line.trim());
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "error dumping XML to logcat", e);
+        }
+    }
+
+    @Override
+    protected void failed(Throwable e, Description description) {
+        if (mAbstractLauncherUiTest.getDevice() == null) return;
+        final String pathname = getInstrumentation().getTargetContext().
+                getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
+        Log.e(TAG, "Failed test " + description.getMethodName() +
+                ", screenshot will be saved to " + pathname +
+                ", track trace is below, UI object dump is further below:\n" +
+                Log.getStackTraceString(e));
+        dumpViewHierarchy();
+
+        try {
+            final String dumpsysResult = mAbstractLauncherUiTest.getDevice().executeShellCommand(
+                    "dumpsys activity service TouchInteractionService");
+            Log.d(TAG, "TouchInteractionService: " + dumpsysResult);
+        } catch (IOException ex) {
+        }
+
+        mAbstractLauncherUiTest.getDevice().takeScreenshot(new File(pathname));
+    }
+}