Snap for 7339742 from 7ef54561828bb371b2eae2bc37941457fda19b4c to sc-v2-release

Change-Id: Ibb4e00821b01b0cb46d14b2bb2828115aa4f4154
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 842abc3..7ab09c5 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -103,16 +103,40 @@
              android:clearTaskOnLaunch="true"
              android:exported="false"/>
 
+        <!--
+        Activity for gesture nav onboarding.
+        It's protected by android.permission.REBOOT to ensure that only system apps can start it
+        (setup wizard already has this permission)
+        -->
         <activity android:name="com.android.quickstep.interaction.GestureSandboxActivity"
-             android:autoRemoveFromRecents="true"
-             android:excludeFromRecents="true"
-             android:screenOrientation="portrait"
-             android:exported="true">
+            android:autoRemoveFromRecents="true"
+            android:excludeFromRecents="true"
+            android:screenOrientation="portrait"
+            android:permission="android.permission.REBOOT"
+            android:exported="true">
             <intent-filter>
                 <action android:name="com.android.quickstep.action.GESTURE_SANDBOX"/>
                 <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
+
+        <!--
+        Activity following gesture nav onboarding.
+        It's protected by android.permission.REBOOT to ensure that only system apps can start it
+        (setup wizard already has this permission)
+        -->
+        <activity android:name="com.android.quickstep.interaction.AllSetActivity"
+            android:autoRemoveFromRecents="true"
+            android:excludeFromRecents="true"
+            android:screenOrientation="portrait"
+            android:permission="android.permission.REBOOT"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.quickstep.action.GESTURE_ONBOARDING_ALL_SET"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
         <activity
             android:name=".hybridhotseat.HotseatEduActivity"
             android:theme="@android:style/Theme.NoDisplay"
diff --git a/quickstep/res/drawable/ic_all_set.xml b/quickstep/res/drawable/ic_all_set.xml
new file mode 100644
index 0000000..a6852aa
--- /dev/null
+++ b/quickstep/res/drawable/ic_all_set.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2021 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="42dp"
+    android:height="40dp"
+    android:viewportWidth="42"
+    android:viewportHeight="40">
+    <path
+        android:pathData="M38,14H25.38L27.28,4.86L27.34,4.22C27.34,3.4 27,2.64 26.46,2.1L24.34,0C24.34,0 10.16,13.7 10,14H0V40H32C33.66,40 35.08,39 35.68,37.56L41.72,23.46C41.9,23 42,22.52 42,22V18C42,15.8 40.2,14 38,14ZM10,36H4V18H10V36ZM38,22L32,36H14V16L22.68,7.32L20,18H38V22Z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
new file mode 100644
index 0000000..a6a17e5
--- /dev/null
+++ b/quickstep/res/layout/activity_allset.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2021 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingStart="@dimen/allset_page_margin_horizontal"
+    android:paddingEnd="@dimen/allset_page_margin_horizontal"
+    android:layoutDirection="locale"
+    android:textDirection="locale"
+    android:background="?android:attr/colorBackground">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_gravity="start"
+        android:gravity="start"
+        android:orientation="vertical">
+
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/allset_title_icon_margin_top"
+            android:src="@drawable/ic_all_set"/>
+
+        <TextView
+            android:id="@+id/title"
+            style="@style/TextAppearance.GestureTutorial.Feedback.Title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/allset_title_margin_top"
+            android:gravity="start"
+            android:text="@string/allset_title"/>
+
+        <TextView
+            android:id="@+id/subtitle"
+            style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/allset_subtitle_margin_top"
+            android:gravity="start"
+            android:text="@string/allset_description"/>
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/navigation_settings"
+        style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+        android:textSize="14sp"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_above="@+id/hint"
+        android:gravity="center_horizontal"
+        android:layout_marginBottom="72dp"/>
+
+    <TextView
+        android:id="@id/hint"
+        style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+        android:textSize="14sp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/allset_hint_margin_bottom"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:text="@string/allset_hint"/>
+</RelativeLayout>
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index d7bcd9e..f303f31 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -15,12 +15,6 @@
 -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <com.android.quickstep.views.SplitPlaceholderView
-        android:id="@+id/split_placeholder"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/split_placeholder_size"
-        android:background="@android:color/darker_gray"
-        android:visibility="gone" />
 
     <com.android.quickstep.views.LauncherRecentsView
         android:id="@+id/overview_panel"
@@ -31,6 +25,13 @@
         android:clipToPadding="false"
         android:visibility="invisible" />
 
+    <com.android.quickstep.views.SplitPlaceholderView
+        android:id="@+id/split_placeholder"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/split_placeholder_size"
+        android:background="@android:color/darker_gray"
+        android:visibility="gone" />
+
     <include
         android:id="@+id/overview_actions_view"
         layout="@layout/overview_actions_container" />
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
new file mode 100644
index 0000000..336fb57
--- /dev/null
+++ b/quickstep/res/values/attrs.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2021 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.
+-->
+<resources>
+    <declare-styleable name="AllSetLinkSpan">
+        <attr name="android:textSize"/>
+        <attr name="android:fontFamily"/>
+    </declare-styleable>
+</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9c0a083..4f9b3eb 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -99,6 +99,13 @@
     <dimen name="gesture_tutorial_feedback_margin_start_end">24dp</dimen>
     <dimen name="gesture_tutorial_button_margin_start_end">18dp</dimen>
 
+    <!-- All Set page -->
+    <dimen name="allset_page_margin_horizontal">40dp</dimen>
+    <dimen name="allset_title_margin_top">28dp</dimen>
+    <dimen name="allset_title_icon_margin_top">80dp</dimen>
+    <dimen name="allset_hint_margin_bottom">52dp</dimen>
+    <dimen name="allset_subtitle_margin_top">24dp</dimen>
+
     <!-- All Apps Education tutorial -->
     <dimen name="swipe_edu_padding">8dp</dimen>
     <dimen name="swipe_edu_circle_size">64dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index a0f1638..7ada496 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -177,6 +177,15 @@
     <!-- Feedback subtext displaying the current step and the total number of steps for the tutorial. [CHAR LIMIT=30] -->
     <string name="gesture_tutorial_step">Tutorial <xliff:g id="current">%1$d</xliff:g>/<xliff:g id="total">%2$d</xliff:g></string>
 
+    <!-- Title of "All Set" page [CHAR LIMIT=NONE] -->
+    <string name="allset_title">All set!</string>
+    <!-- Hint string at the bottom of "All Set" page [CHAR LIMIT=NONE] -->
+    <string name="allset_hint">Swipe up to go home</string>
+    <!-- Description of "All Set" page [CHAR LIMIT=NONE] -->
+    <string name="allset_description">You\u2019re ready to start using your phone</string>
+    <!-- String linking to navigation settings on "All Set" page [CHAR LIMIT=NONE] -->
+    <string name="allset_navigation_settings"><annotation id="link">Navigation settings for accessibility</annotation></string>
+
     <!-- ******* Overview ******* -->
     <!-- Label for a button that causes the current overview app to be shared. [CHAR_LIMIT=40] -->
     <string name="action_share">Share</string>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 7c7d20a..0a8ecb8 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -59,7 +59,7 @@
         parent="TextAppearance.GestureTutorial">
         <item name="android:gravity">start</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:fontFamily">google-sans</item>
+        <item name="android:fontFamily">google-sans-text</item>
         <item name="android:letterSpacing">0.03</item>
         <item name="android:textSize">18sp</item>
         <item name="android:lineHeight">24sp</item>
@@ -99,6 +99,11 @@
         <item name="android:textColor">@color/gesture_tutorial_primary_color</item>
     </style>
 
+    <style name="TextAppearance.GestureTutorial.LinkText"
+        parent="TextAppearance.GestureTutorial.Feedback.Subtitle">
+        <item name="android:textSize">14sp</item>
+    </style>
+
     <!--
       Can be applied to views to color things like ripples and list highlights the workspace text
       color.
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 01616d4..b3374f3 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -22,12 +22,12 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
-import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_TRANSLATION;
+import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
 
 import android.util.FloatProperty;
@@ -97,10 +97,10 @@
         PagedOrientationHandler orientationHandler =
                 ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
         FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset(
-                TASK_PRIMARY_TRANSLATION, TASK_SECONDARY_TRANSLATION, mLauncher.getDeviceProfile());
+                TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
+                mLauncher.getDeviceProfile());
         setter.setFloat(mRecentsView, taskViewsFloat,
-                toState.getOverviewSecondaryTranslation(mLauncher),
-                config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
+                toState.getOverviewSecondaryTranslation(mLauncher), LINEAR);
 
         setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
                 config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 12de4a6..8278a5a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -36,11 +36,13 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
 import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
+import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -207,7 +209,7 @@
     /** Create state animation to control non-overview components. */
     private void updateNonOverviewAnim(LauncherState toState, StateAnimationConfig config) {
         config.duration = (long) (Math.max(mXRange, mYRange) * 2);
-        config.animFlags |= SKIP_OVERVIEW;
+        config.animFlags |= SKIP_OVERVIEW | SKIP_SCRIM;
         mNonOverviewAnim = mLauncher.getStateManager()
                 .createAnimationToNewWorkspace(toState, config);
         mNonOverviewAnim.getTarget().addListener(mClearStateOnCancelListener);
@@ -229,10 +231,14 @@
         // As we drag right, animate the following properties:
         //   - RecentsView translationX
         //   - OverviewScrim
+        //   - RecentsView fade (if it's empty)
         PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
         xAnim.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1], LINEAR);
         xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
                 toState.getWorkspaceScrimColor(mLauncher), LINEAR);
+        if (mRecentsView.getTaskViewCount() == 0) {
+            xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
+        }
         mXOverviewAnim = xAnim.createPlaybackController();
         mXOverviewAnim.dispatchOnStart();
 
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index ecaac94..10384a8 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -47,7 +47,6 @@
 import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
 import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_END;
 import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_START;
-import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -55,7 +54,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
 import android.app.ActivityManager;
@@ -464,8 +462,6 @@
                     mDeviceState.getRotationTouchHelper()
                             .onEndTargetCalculated(mGestureState.getEndTarget(),
                                     mActivityInterface);
-
-                    mRecentsView.onGestureEndTargetCalculated(mGestureState.getEndTarget());
                 });
 
         notifyGestureStartedAsync();
@@ -1133,6 +1129,10 @@
             }
             homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
             mLauncherTransitionController = null;
+
+            if (mRecentsView != null) {
+                mRecentsView.onPrepareGestureEndAnimation(null, mGestureState.getEndTarget());
+            }
         } else {
             AnimatorSet animatorSet = new AnimatorSet();
             ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end);
@@ -1171,9 +1171,9 @@
                 }
             });
             animatorSet.play(windowAnim);
-            S state = mActivityInterface.stateFromGestureEndTarget(mGestureState.getEndTarget());
-            if (mRecentsView != null && state.displayOverviewTasksAsGrid(mDp)) {
-                animatorSet.play(ObjectAnimator.ofFloat(mRecentsView, RECENTS_GRID_PROGRESS, 1));
+            if (mRecentsView != null) {
+                mRecentsView.onPrepareGestureEndAnimation(
+                        animatorSet, mGestureState.getEndTarget());
             }
             animatorSet.setDuration(duration).setInterpolator(interpolator);
             animatorSet.start();
@@ -1701,7 +1701,7 @@
         // No need to apply any transform if there is ongoing swipe-pip-to-home animator since
         // that animator handles the leash solely.
         if (mRecentsAnimationTargets != null && !mIsSwipingPipToHome) {
-            if (mRecentsViewScrollLinked) {
+            if (mRecentsViewScrollLinked && mRecentsView != null) {
                 mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
             }
             mTaskViewSimulator.apply(mTransformParams);
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 9fa65d9..3c81d1b 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -163,7 +163,9 @@
 
     @Override
     public boolean isInLiveTileMode() {
-        return false;
+        RecentsActivity activity = getCreatedActivity();
+        return activity != null && activity.getStateManager().getState() == DEFAULT &&
+                activity.isStarted();
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 9398277..46cd8a2 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -260,6 +260,7 @@
             @Override
             public void setAnimation(RectFSpringAnim anim) {
                 anim.addAnimatorListener(floatingWidgetView);
+                floatingWidgetView.setOnTargetChangeListener(anim::onTargetPositionChanged);
                 floatingWidgetView.setFastFinishRunnable(anim::end);
             }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 3b92779..0e9e3ad 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -22,10 +22,13 @@
 import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION;
 import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY;
 import static com.android.launcher3.Utilities.createHomeIntent;
+import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
 import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
 import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -35,6 +38,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.view.SurfaceControl.Transaction;
 import android.view.View;
 
 import androidx.annotation.Nullable;
@@ -47,6 +51,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.WrappedAnimationRunnerImpl;
 import com.android.launcher3.WrappedLauncherAnimationRunner;
+import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -69,6 +74,7 @@
 import com.android.quickstep.util.RecentsAtomicAnimationFactory;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.quickstep.views.OverviewActionsView;
+import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.SplitPlaceholderView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
@@ -90,6 +96,8 @@
 
     private Handler mUiHandler = new Handler(Looper.getMainLooper());
 
+    private static final long HOME_APPEAR_DURATION = 250;
+
     private RecentsDragLayer mDragLayer;
     private ScrimView mScrimView;
     private FallbackRecentsView mFallbackRecentsView;
@@ -112,6 +120,7 @@
         mScrimView = findViewById(R.id.scrim_view);
         mFallbackRecentsView = findViewById(R.id.overview_panel);
         mActionsView = findViewById(R.id.overview_actions_view);
+        SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f);
 
         SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
         splitPlaceholderView.init(
@@ -291,6 +300,16 @@
         super.onConfigurationChanged(newConfig);
     }
 
+    @Override
+    public void onStateSetEnd(RecentsState state) {
+        super.onStateSetEnd(state);
+
+        if (state == RecentsState.DEFAULT) {
+            AccessibilityManagerCompat.sendStateEventToTest(getBaseContext(),
+                    OVERVIEW_STATE_ORDINAL);
+        }
+    }
+
     /**
      * Initialize/update the device profile.
      */
@@ -329,7 +348,42 @@
     }
 
     public void startHome() {
-        startActivity(createHomeIntent());
+        if (LIVE_TILE.get()) {
+            RecentsView recentsView = getOverviewPanel();
+            recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true,
+                    this::startHomeInternal));
+        } else {
+            startHomeInternal();
+        }
+    }
+
+    private void startHomeInternal() {
+        WrappedLauncherAnimationRunner runner = new WrappedLauncherAnimationRunner(
+                getMainThreadHandler(), this::onCreateAnimationToHome, true);
+        RemoteAnimationAdapterCompat adapterCompat =
+                new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0);
+        startActivity(createHomeIntent(),
+                ActivityOptionsCompat.makeRemoteAnimation(adapterCompat).toBundle());
+    }
+
+    private void onCreateAnimationToHome(
+            int transit, RemoteAnimationTargetCompat[] appTargets,
+            RemoteAnimationTargetCompat[] wallpaperTargets,
+            RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) {
+        AnimatorPlaybackController controller = getStateManager()
+                .createAnimationToNewWorkspace(RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
+        controller.dispatchOnStart();
+
+        RemoteAnimationTargets targets = new RemoteAnimationTargets(
+                appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
+        for (RemoteAnimationTargetCompat app : targets.apps) {
+            new Transaction().setAlpha(app.leash.getSurfaceControl(), 1).apply();
+        }
+        AnimatorSet anim = new AnimatorSet();
+        anim.play(controller.getAnimationPlayer());
+        anim.setDuration(HOME_APPEAR_DURATION);
+        result.setAnimation(anim, this,
+                () -> getStateManager().goToState(RecentsState.HOME, false));
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 4d4b6e1..1bb8e96 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -20,6 +20,7 @@
 import static com.android.quickstep.fallback.RecentsState.HOME;
 import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
 
+import android.animation.AnimatorSet;
 import android.annotation.TargetApi;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
@@ -27,6 +28,9 @@
 import android.util.AttributeSet;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statemanager.StateManager.StateListener;
 import com.android.launcher3.testing.TestProtocol;
@@ -67,7 +71,6 @@
     @Override
     public void startHome() {
         mActivity.startHome();
-        mActivity.getStateManager().goToState(RecentsState.HOME);
     }
 
     /**
@@ -86,14 +89,17 @@
      * to the center.
      */
     @Override
-    public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
-        super.onGestureEndTargetCalculated(endTarget);
-        if (mHomeTaskInfo != null && endTarget == RECENTS) {
+    public void onPrepareGestureEndAnimation(
+            @Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget) {
+        super.onPrepareGestureEndAnimation(animatorSet, endTarget);
+        if (mHomeTaskInfo != null && endTarget == RECENTS && animatorSet != null) {
             TaskView tv = getTaskView(mHomeTaskInfo.taskId);
             if (tv != null) {
                 PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150);
                 pa.addEndListener(e -> setCurrentTask(-1));
-                runDismissAnimation(pa);
+                AnimatorPlaybackController controller = pa.createPlaybackController();
+                controller.dispatchOnStart();
+                animatorSet.play(controller.getAnimationPlayer());
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index b3d6cfa..b6cfdce 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -39,15 +39,18 @@
     private static final int FLAG_OVERVIEW_ACTIONS = BaseState.getFlag(3);
     private static final int FLAG_SHOW_AS_GRID = BaseState.getFlag(4);
     private static final int FLAG_SCRIM = BaseState.getFlag(5);
+    private static final int FLAG_LIVE_TILE = BaseState.getFlag(6);
 
     public static final RecentsState DEFAULT = new RecentsState(0,
-            FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID | FLAG_SCRIM);
+            FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID | FLAG_SCRIM
+                    | FLAG_LIVE_TILE);
     public static final RecentsState MODAL_TASK = new ModalState(1,
             FLAG_DISABLE_RESTORE | FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_MODAL
-                    | FLAG_SHOW_AS_GRID | FLAG_SCRIM);
+                    | FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_LIVE_TILE);
     public static final RecentsState BACKGROUND_APP = new BackgroundAppState(2,
             FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN);
     public static final RecentsState HOME = new RecentsState(3, 0);
+    public static final RecentsState BG_LAUNCHER = new LauncherState(4, 0);
 
     public final int ordinal;
     private final int mFlags;
@@ -108,6 +111,13 @@
     }
 
     /**
+     * For this state, whether live tile should be shown.
+     */
+    public boolean hasLiveTile() {
+        return hasFlag(FLAG_LIVE_TILE);
+    }
+
+    /**
      * For this state, what color scrim should be drawn behind overview.
      */
     public int getScrimColor(RecentsActivity activity) {
@@ -152,4 +162,15 @@
             return getOverviewScaleAndOffsetForBackgroundState(activity);
         }
     }
+
+    private static class LauncherState extends RecentsState {
+        LauncherState(int id, int flags) {
+            super(id, flags);
+        }
+
+        @Override
+        public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
+            return new float[] { NO_SCALE, 1 };
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
index d7458d2..273d1f6 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep.fallback;
 
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
+
 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
 import com.android.quickstep.RecentsActivity;
 
@@ -26,7 +28,8 @@
 
     @Override
     protected boolean isRecentsInteractive() {
-        return mActivity.hasWindowFocus();
+        return mActivity.hasWindowFocus() || (LIVE_TILE.get()
+                && mActivity.getStateManager().getState().hasLiveTile());
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
new file mode 100644
index 0000000..76f43c9
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 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.interaction;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.text.TextPaint;
+import android.text.method.LinkMovementMethod;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+
+import java.net.URISyntaxException;
+
+/**
+ * A page shows after SUW flow to hint users to swipe up from the bottom of the screen to go home
+ * for the gestural system navigation.
+ */
+public class AllSetActivity extends Activity {
+
+    private static final String LOG_TAG = "AllSetActivity";
+    private static final String URI_SYSTEM_NAVIGATION_SETTING =
+            "#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S.:settings:fragment_args_key=gesture_system_navigation_input_summary;S.:settings:show_fragment=com.android.settings.gestures.SystemNavigationGestureSettings;end";
+    private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "accent_color_dark_mode";
+    private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "accent_color_light_mode";
+
+    private int mAccentColor;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_allset);
+        setTitle(R.string.allset_title);
+
+        final int mode =
+                getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        mAccentColor = getIntent().getIntExtra(
+                mode == Configuration.UI_MODE_NIGHT_YES
+                        ? EXTRA_ACCENT_COLOR_DARK_MODE : EXTRA_ACCENT_COLOR_LIGHT_MODE,
+                /* defValue= */ Color.BLACK);
+
+        ((ImageView) findViewById(R.id.icon)).getDrawable().mutate().setTint(mAccentColor);
+
+        TextView navigationSettings = findViewById(R.id.navigation_settings);
+        navigationSettings.setMovementMethod(LinkMovementMethod.getInstance());
+        AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
+                AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION,
+                new AllSetLinkSpan(
+                        /* context= */ this,
+                        view -> {
+                            try {
+                                startActivityForResult(
+                                        Intent.parseUri(URI_SYSTEM_NAVIGATION_SETTING, 0), 0);
+                            } catch (URISyntaxException e) {
+                                Log.e(LOG_TAG, "Failed to parse system nav settings intent", e);
+                            }
+                            finish();
+                        }));
+        navigationSettings.setText(
+                AnnotationSpan.linkify(getText(R.string.allset_navigation_settings), linkInfo));
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (hasFocus) {
+            hideSystemUI();
+        }
+    }
+
+    private void hideSystemUI() {
+        getWindow().getDecorView().setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                        | View.SYSTEM_UI_FLAG_FULLSCREEN);
+        getWindow().setNavigationBarColor(Color.TRANSPARENT);
+    }
+
+    private final class AllSetLinkSpan extends AnnotationSpan {
+
+        private final String mFontFamily;
+        private final int mTextSize;
+
+        AllSetLinkSpan(Context context, View.OnClickListener listener) {
+            super(listener);
+            TypedArray typedArray =
+                    context.obtainStyledAttributes(R.style.TextAppearance_GestureTutorial_LinkText,
+                            R.styleable.AllSetLinkSpan);
+            mFontFamily = typedArray.getString(R.styleable.AllSetLinkSpan_android_fontFamily);
+            mTextSize =
+                    typedArray.getDimensionPixelSize(
+                            R.styleable.AllSetLinkSpan_android_textSize, /* defValue= */ -1);
+            typedArray.recycle();
+        }
+
+        @Override
+        public void updateDrawState(TextPaint ds) {
+            super.updateDrawState(ds);
+            ds.setColor(mAccentColor);
+            ds.setTypeface(Typeface.create(mFontFamily, Typeface.NORMAL));
+            ds.setUnderlineText(false);
+            if (mTextSize != -1) {
+                ds.setTextSize(mTextSize);
+            }
+        }
+    }
+
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/AnnotationSpan.java b/quickstep/src/com/android/quickstep/interaction/AnnotationSpan.java
new file mode 100644
index 0000000..fea5078
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/AnnotationSpan.java
@@ -0,0 +1,143 @@
+/*
+ * 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.quickstep.interaction;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.text.Annotation;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.style.URLSpan;
+import android.util.Log;
+import android.view.View;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * This class is used to add {@link View.OnClickListener} for the text been wrapped by
+ * annotation.
+ *
+ * Copied from packages/apps/Settings/src/com/android/settings/utils/AnnotationSpan.java.
+ */
+public class AnnotationSpan extends URLSpan {
+
+    private final View.OnClickListener mClickListener;
+
+    AnnotationSpan(View.OnClickListener lsn) {
+        super((String) null);
+        mClickListener = lsn;
+    }
+
+    @Override
+    public void onClick(View widget) {
+        if (mClickListener != null) {
+            mClickListener.onClick(widget);
+        }
+    }
+
+    public static CharSequence linkify(CharSequence rawText, LinkInfo... linkInfos) {
+        SpannableString msg = new SpannableString(rawText);
+        Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
+        SpannableStringBuilder builder = new SpannableStringBuilder(msg);
+        for (Annotation annotation : spans) {
+            final String key = annotation.getValue();
+            int start = msg.getSpanStart(annotation);
+            int end = msg.getSpanEnd(annotation);
+            AnnotationSpan link = null;
+            for (LinkInfo linkInfo : linkInfos) {
+                if (linkInfo.mAnnotation.equals(key)) {
+                    link = linkInfo.mCustomizedSpan != null ? linkInfo.mCustomizedSpan
+                            : new AnnotationSpan(linkInfo.mClickListener);
+                    break;
+                }
+            }
+            if (link != null) {
+                builder.setSpan(link, start, end, msg.getSpanFlags(link));
+            }
+        }
+        return builder;
+    }
+
+    /**
+     * get the text part without having text for link part
+     */
+    public static CharSequence textWithoutLink(CharSequence encodedText) {
+        SpannableString msg = new SpannableString(encodedText);
+        Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
+        if (spans == null) {
+            return encodedText;
+        }
+        Arrays.sort(spans, Comparator.comparingInt(span -> -msg.getSpanStart(span)));
+        StringBuilder msgWithoutLink = new StringBuilder(msg.toString());
+        for (Annotation span : spans) {
+            msgWithoutLink.delete(msg.getSpanStart(span), msg.getSpanEnd(span));
+        }
+        return msgWithoutLink.toString();
+    }
+
+    /** Data class to store the annotation and the click action. */
+    public static class LinkInfo {
+        public static final String DEFAULT_ANNOTATION = "link";
+        private static final String TAG = "AnnotationSpan.LinkInfo";
+        private final String mAnnotation;
+        private final Boolean mActionable;
+        private final View.OnClickListener mClickListener;
+        private final AnnotationSpan mCustomizedSpan;
+
+        public LinkInfo(String annotation, View.OnClickListener listener) {
+            mAnnotation = annotation;
+            mClickListener = listener;
+            mActionable = true; // assume actionable
+            mCustomizedSpan = null;
+        }
+
+        public LinkInfo(String annotation, AnnotationSpan customizedSpan) {
+            mAnnotation = annotation;
+            mClickListener = null;
+            mActionable = customizedSpan != null;
+            mCustomizedSpan = customizedSpan;
+        }
+
+        public LinkInfo(Context context, String annotation, Intent intent) {
+            mAnnotation = annotation;
+            mCustomizedSpan = null;
+            if (intent != null) {
+                mActionable = context.getPackageManager().resolveActivity(intent, 0) != null;
+            } else {
+                mActionable = false;
+            }
+            if (mActionable) {
+                mClickListener =
+                        view -> {
+                            try {
+                                context.startActivity(intent);
+                            } catch (ActivityNotFoundException e) {
+                                Log.w(TAG, "Activity was not found for intent, " + intent);
+                            }
+                        };
+            } else {
+                mClickListener = null;
+            }
+        }
+
+        public boolean isActionable() {
+            return mActionable;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java b/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
index c527be3..60c7add 100644
--- a/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
+++ b/quickstep/src/com/android/quickstep/util/NavigationModeFeatureFlag.java
@@ -20,8 +20,6 @@
 
 import android.content.Context;
 
-import com.android.quickstep.OverviewComponentObserver;
-import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.SysUINavigationMode;
 
 import java.util.function.Predicate;
@@ -37,7 +35,6 @@
     private final Supplier<Boolean> mBasePredicate;
     private final Predicate<SysUINavigationMode.Mode> mModePredicate;
     private boolean mSupported;
-    private OverviewComponentObserver mObserver;
 
     private NavigationModeFeatureFlag(Supplier<Boolean> basePredicate,
             Predicate<SysUINavigationMode.Mode> modePredicate) {
@@ -46,17 +43,12 @@
     }
 
     public boolean get() {
-        return mBasePredicate.get() && mSupported && mObserver != null
-                && mObserver.isHomeAndOverviewSame();
+        return mBasePredicate.get() && mSupported;
     }
 
     public void initialize(Context context) {
         onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context).getMode());
         SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
-
-        // Temporary solution to disable live tile for the fallback launcher
-        RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(context);
-        mObserver = new OverviewComponentObserver(context, rads);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 01d51f8..3d33e57 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -25,6 +25,7 @@
 import android.animation.AnimatorSet;
 import android.app.ActivityOptions;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -64,6 +65,7 @@
     private final SystemUiProxy mSystemUiProxy;
     private TaskView mInitialTaskView;
     private SplitPositionOption mInitialPosition;
+    private Rect mInitialBounds;
     private final Handler mHandler;
 
     public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
@@ -74,9 +76,11 @@
     /**
      * To be called after first task selected
      */
-    public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption) {
+    public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption,
+            Rect initialBounds) {
         mInitialTaskView = taskView;
         mInitialPosition = positionOption;
+        mInitialBounds = initialBounds;
     }
 
     /**
@@ -220,9 +224,14 @@
     public void resetState() {
         mInitialTaskView = null;
         mInitialPosition = null;
+        mInitialBounds = null;
     }
 
     public boolean isSplitSelectActive() {
         return mInitialTaskView != null;
     }
+
+    public Rect getInitialBounds() {
+        return mInitialBounds;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index e63f8bb..f578ad1 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.util.TraceHelper;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
@@ -95,7 +96,9 @@
         mContext = context;
         mSizeStrategy = sizeStrategy;
 
-        mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
+        // TODO(b/187074722): Don't create this per-TaskViewSimulator
+        mOrientationState = TraceHelper.allowIpcs("",
+                () -> new RecentsOrientedState(context, sizeStrategy, i -> { }));
         mOrientationState.setGestureActive(true);
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
         mOrientationStateId = mOrientationState.getStateId();
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
index f74aa55..9ea2369 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
@@ -100,8 +100,8 @@
     /** Restores the drawables to the source view. */
     void finish() {
         if (isUninitialized()) return;
-        mSourceView.setForeground(mOriginalForeground);
-        mSourceView.setBackground(mOriginalBackground);
+        if (mOriginalForeground != null) mSourceView.setForeground(mOriginalForeground);
+        if (mOriginalBackground != null) mSourceView.setBackground(mOriginalBackground);
     }
 
     void recycle() {
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
index 8499902..ed54f10 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
@@ -27,6 +27,7 @@
 import android.view.GhostView;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.Launcher;
@@ -39,7 +40,8 @@
 
 /** A view that mimics an App Widget through a launch animation. */
 @TargetApi(Build.VERSION_CODES.S)
-public class FloatingWidgetView extends FrameLayout implements AnimatorListener {
+public class FloatingWidgetView extends FrameLayout implements AnimatorListener,
+        OnGlobalLayoutListener {
     private static final Matrix sTmpMatrix = new Matrix();
 
     private final Launcher mLauncher;
@@ -54,6 +56,7 @@
 
     private Runnable mEndRunnable;
     private Runnable mFastFinishRunnable;
+    private Runnable mOnTargetChangeRunnable;
 
     public FloatingWidgetView(Context context) {
         this(context, null);
@@ -93,6 +96,32 @@
     public void onAnimationRepeat(Animator animator) {
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        getViewTreeObserver().addOnGlobalLayoutListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        getViewTreeObserver().removeOnGlobalLayoutListener(this);
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onGlobalLayout() {
+        if (isUninitialized()) return;
+        positionViews();
+        if (mOnTargetChangeRunnable != null) {
+            mOnTargetChangeRunnable.run();
+        }
+    }
+
+    /** Sets a runnable that is called on global layout change. */
+    public void setOnTargetChangeListener(Runnable onTargetChangeListener) {
+        mOnTargetChangeRunnable = onTargetChangeListener;
+    }
+
     /** Sets a runnable that is called after a call to {@link #fastFinish()}. */
     public void setFastFinishRunnable(Runnable runnable) {
         mFastFinishRunnable = runnable;
@@ -205,6 +234,7 @@
     private void recycle() {
         mEndRunnable = null;
         mFastFinishRunnable = null;
+        mOnTargetChangeRunnable = null;
         mBackgroundPosition = null;
         mListenerView.setListener(null);
         mAppWidgetView = null;
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index f5a8ff8..2c5f661 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -245,8 +245,8 @@
         if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
             // We want to keep the tasks translations in this temporary state
             // after resetting the rest above
-            setTaskViewsResistanceTranslation(mTaskViewsSecondaryTranslation);
-            setTaskViewsPrimaryTranslation(mTaskViewsPrimaryTranslation);
+            setTaskViewsPrimarySplitTranslation(mTaskViewsPrimarySplitTranslation);
+            setTaskViewsSecondarySplitTranslation(mTaskViewsSecondarySplitTranslation);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index c9e7a73..63981b1 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -254,16 +254,29 @@
      * more specific, we'd want to create a similar FloatProperty just for a TaskView's
      * offsetX/Y property
      */
-    public static final FloatProperty<RecentsView> TASK_PRIMARY_TRANSLATION =
-            new FloatProperty<RecentsView>("taskPrimaryTranslation") {
+    public static final FloatProperty<RecentsView> TASK_PRIMARY_SPLIT_TRANSLATION =
+            new FloatProperty<RecentsView>("taskPrimarySplitTranslation") {
                 @Override
                 public void setValue(RecentsView recentsView, float v) {
-                    recentsView.setTaskViewsPrimaryTranslation(v);
+                    recentsView.setTaskViewsPrimarySplitTranslation(v);
                 }
 
                 @Override
                 public Float get(RecentsView recentsView) {
-                    return recentsView.mTaskViewsPrimaryTranslation;
+                    return recentsView.mTaskViewsPrimarySplitTranslation;
+                }
+            };
+
+    public static final FloatProperty<RecentsView> TASK_SECONDARY_SPLIT_TRANSLATION =
+            new FloatProperty<RecentsView>("taskSecondarySplitTranslation") {
+                @Override
+                public void setValue(RecentsView recentsView, float v) {
+                    recentsView.setTaskViewsSecondarySplitTranslation(v);
+                }
+
+                @Override
+                public Float get(RecentsView recentsView) {
+                    return recentsView.mTaskViewsSecondarySplitTranslation;
                 }
             };
 
@@ -279,7 +292,6 @@
                     view.mLiveTileTaskViewSimulator.recentsViewScale.value = scale;
                     view.updatePageOffsets();
                     view.setTaskViewsResistanceTranslation(view.mTaskViewsSecondaryTranslation);
-                    view.setTaskViewsPrimaryTranslation(view.mTaskViewsPrimaryTranslation);
                 }
 
                 @Override
@@ -363,7 +375,8 @@
 
     private float mAdjacentPageOffset = 0;
     protected float mTaskViewsSecondaryTranslation = 0;
-    protected float mTaskViewsPrimaryTranslation = 0;
+    protected float mTaskViewsPrimarySplitTranslation = 0;
+    protected float mTaskViewsSecondarySplitTranslation = 0;
     // Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
     private float mGridProgress = 0;
     private final IntSet mTopRowIdSet = new IntSet();
@@ -1631,7 +1644,16 @@
     /**
      * Called when a gesture from an app has finished, and an end target has been determined.
      */
-    public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
+    public void onPrepareGestureEndAnimation(
+            @Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget) {
+        if (mSizeStrategy.stateFromGestureEndTarget(endTarget)
+                .displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) {
+            if (animatorSet == null) {
+                setGridProgress(1);
+            } else {
+                animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
+            }
+        }
         mCurrentGestureEndTarget = endTarget;
         if (endTarget == GestureState.GestureEndTarget.NEW_TASK
                 || endTarget == GestureState.GestureEndTarget.LAST_TASK) {
@@ -1839,15 +1861,28 @@
         final int boxLength = Math.max(mLastComputedGridTaskSize.width(),
                 mLastComputedGridTaskSize.height());
         int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
-        float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
-        float taskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
+
+        /*
+         * taskGridVerticalDiff is used to position the top of a task in the top row of the grid
+         * heightOffset is the vertical space one grid task takes + space between top and
+         *   bottom row
+         * Summed together they provide the top position for bottom row of grid tasks
+         */
+        final float taskGridVerticalDiff =
+                mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
+        final float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
 
         int topRowWidth = 0;
         int bottomRowWidth = 0;
         float topAccumulatedTranslationX = 0;
         float bottomAccumulatedTranslationX = 0;
+
+        // Contains whether the child index is in top or bottom of grid (for non-focused task)
+        // Different from mTopRowIdSet, which contains the taskId of what task is in top row
         IntSet topSet = new IntSet();
         IntSet bottomSet = new IntSet();
+
+        // Horizontal grid translation for each task
         float[] gridTranslations = new float[taskCount];
 
         int focusedTaskIndex = Integer.MAX_VALUE;
@@ -1901,7 +1936,6 @@
                 boolean isTopRow = isTaskDismissal ? mTopRowIdSet.contains(taskId)
                         : topRowWidth <= bottomRowWidth;
                 if (isTopRow) {
-                    gridTranslations[i] += topAccumulatedTranslationX;
                     topRowWidth += taskWidthAndSpacing;
                     topSet.add(i);
                     mTopRowIdSet.add(taskId);
@@ -1917,11 +1951,10 @@
                         widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                     }
 
-                    float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
-                    gridTranslations[i] += gridTranslationX;
-                    topAccumulatedTranslationX += gridTranslationX;
+                    float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
+                    gridTranslations[i] += topAccumulatedTranslationX + currentTaskTranslationX;
+                    topAccumulatedTranslationX += currentTaskTranslationX;
                 } else {
-                    gridTranslations[i] += bottomAccumulatedTranslationX;
                     bottomRowWidth += taskWidthAndSpacing;
                     bottomSet.add(i);
 
@@ -1937,9 +1970,9 @@
                         widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                     }
 
-                    float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
-                    gridTranslations[i] += gridTranslationX;
-                    bottomAccumulatedTranslationX += gridTranslationX;
+                    float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
+                    gridTranslations[i] += bottomAccumulatedTranslationX + currentTaskTranslationX;
+                    bottomAccumulatedTranslationX += currentTaskTranslationX;
                 }
                 if (taskView == snappedTaskView) {
                     snappedTaskRowWidth = isTopRow ? topRowWidth : bottomRowWidth;
@@ -2130,18 +2163,43 @@
         // Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
         // alpha is set to 0 so that it can be recycled in the view pool properly
         anim.setFloat(taskView, VIEW_ALPHA, 0, ACCEL_2);
-        FloatProperty<TaskView> secondaryViewTranslate =
-                taskView.getSecondaryDissmissTranslationProperty();
-        int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
-        int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
+        SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
 
         ResourceProvider rp = DynamicResource.provider(mActivity);
         SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START)
                 .setDampingRatio(rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio))
                 .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness));
+        FloatProperty<TaskView> dismissingTaskViewTranslate =
+                taskView.getSecondaryDissmissTranslationProperty();;
+        // TODO(b/186800707) translate entire grid size distance
+        int translateDistance = mOrientationHandler.getSecondaryDimension(taskView);
+        int positiveNegativeFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
+        if (splitController.isSplitSelectActive()) {
+            // Have the task translate towards whatever side was just pinned
+            int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitController
+                    .getActiveSplitPositionOption(), mActivity.getDeviceProfile());
+            switch (dir) {
+                case PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE:
+                    dismissingTaskViewTranslate = taskView
+                            .getSecondaryDissmissTranslationProperty();
+                    positiveNegativeFactor = -1;
+                    break;
 
-        anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
-                verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp);
+                case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE:
+                    dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
+                    positiveNegativeFactor = 1;
+                    break;
+
+                case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_NEGATIVE:
+                    dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
+                    positiveNegativeFactor = -1;
+                    break;
+                default:
+                    throw new IllegalStateException("Invalid split task translation: " + dir);
+            }
+        }
+        anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate,
+                positiveNegativeFactor * translateDistance).setDuration(duration), LINEAR, sp);
 
         if (LIVE_TILE.get() && taskView.isRunningTask()) {
             anim.addOnFrameCallback(() -> {
@@ -2206,18 +2264,6 @@
                     }
                 }
 
-                // Additional offset for fake landscape, if the pinning happens to the right or
-                // left, we need to scroll all the tasks away from the direction of the splaceholder
-                // view
-                if (isSplitSelectionActive()) {
-                    int splitPosition = getSplitPlaceholder().getSplitController()
-                            .getActiveSplitPositionOption().mStagePosition;
-                    int direction = mOrientationHandler
-                            .getSplitTranslationDirectionFactor(splitPosition);
-                    int splitOffset = mOrientationHandler.getSplitAnimationTranslation(
-                            mSplitPlaceholderView.getHeight(), mActivity.getDeviceProfile());
-                    offset += direction * splitOffset;
-                }
                 int scrollDiff = newScroll[i] - oldScroll[i] + offset;
                 if (scrollDiff != 0) {
                     FloatProperty translationProperty = child instanceof TaskView
@@ -2249,7 +2295,8 @@
         mPendingAnimation.addEndListener(new Consumer<Boolean>() {
             @Override
             public void accept(Boolean success) {
-                if (LIVE_TILE.get() && taskView.isRunningTask() && success) {
+                if (LIVE_TILE.get() && mEnableDrawingLiveTile && taskView.isRunningTask()
+                        && success) {
                     finishRecentsAnimation(true /* toHome */, () -> onEnd(success));
                 } else {
                     onEnd(success);
@@ -2347,7 +2394,7 @@
         return true;
     }
 
-    protected void runDismissAnimation(PendingAnimation pendingAnim) {
+    private void runDismissAnimation(PendingAnimation pendingAnim) {
         AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
         controller.dispatchOnStart();
         controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
@@ -2759,13 +2806,20 @@
         mLiveTileTaskViewSimulator.recentsViewSecondaryTranslation.value = translation;
     }
 
-    protected void setTaskViewsPrimaryTranslation(float translation) {
-        mTaskViewsPrimaryTranslation = translation;
+    protected void setTaskViewsPrimarySplitTranslation(float translation) {
+        mTaskViewsPrimarySplitTranslation = translation;
         for (int i = 0; i < getTaskViewCount(); i++) {
             TaskView task = getTaskViewAt(i);
-            task.getPrimaryDismissTranslationProperty().set(task, translation / getScaleY());
+            task.getPrimarySplitTranslationProperty().set(task, translation);
         }
-        mLiveTileTaskViewSimulator.recentsViewPrimaryTranslation.value = translation;
+    }
+
+    protected void setTaskViewsSecondarySplitTranslation(float translation) {
+        mTaskViewsSecondarySplitTranslation = translation;
+        for (int i = 0; i < getTaskViewCount(); i++) {
+            TaskView task = getTaskViewAt(i);
+            task.getSecondarySplitTranslationProperty().set(task, translation);
+        }
     }
 
     /**
@@ -2788,8 +2842,9 @@
     public void initiateSplitSelect(TaskView taskView, SplitPositionOption splitPositionOption) {
         mSplitHiddenTaskView = taskView;
         SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
-        splitController.setInitialTaskSelect(taskView,
-                splitPositionOption);
+        Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
+                taskView.getBottom());
+        splitController.setInitialTaskSelect(taskView, splitPositionOption, initialBounds);
         mSplitHiddenTaskViewIndex = indexOfChild(taskView);
         mSplitPlaceholderView.setLayoutParams(
                 splitController.getLayoutParamsForActivePosition(getResources(),
@@ -2809,7 +2864,10 @@
     }
 
     public PendingAnimation cancelSplitSelect(boolean animate) {
-        mSplitPlaceholderView.getSplitController().resetState();
+        SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
+        SplitPositionOption splitOption = splitController.getActiveSplitPositionOption();
+        Rect initialBounds = splitController.getInitialBounds();
+        splitController.resetState();
         int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
         PendingAnimation pendingAnim = new PendingAnimation(duration);
         if (!animate) {
@@ -2824,8 +2882,6 @@
         getPageScrolls(oldScroll, false,
                 view -> view.getVisibility() != GONE && view != mSplitHiddenTaskView);
 
-        // x is correct, y is before tasks move up
-        int[] locationOnScreen = mSplitHiddenTaskView.getLocationOnScreen();
         int[] newScroll = new int[getChildCount()];
         getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC);
 
@@ -2833,20 +2889,42 @@
         for (int i = mSplitHiddenTaskViewIndex; i >= 0; i--) {
             View child = getChildAt(i);
             if (child == mSplitHiddenTaskView) {
+                TaskView taskView = (TaskView) child;
 
-                int left = newScroll[i] + getPaddingStart();
-                int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
-                int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1];
-                mSplitHiddenTaskView.layout(left, top,
-                        left + mSplitHiddenTaskView.getWidth(),
-                        top + mSplitHiddenTaskView.getHeight());
-                pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, TRANSLATION_Y,
-                        -top + mSplitPlaceholderView.getHeight() - topMargin));
+                int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitOption,
+                        mActivity.getDeviceProfile());
+                FloatProperty<TaskView> dismissingTaskViewTranslate;
+                Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(),
+                        taskView.getRight(), taskView.getBottom());
+                int distanceDelta = 0;
+                if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) {
+                    dismissingTaskViewTranslate = taskView
+                            .getSecondaryDissmissTranslationProperty();
+                    distanceDelta = initialBounds.top - hiddenBounds.top;
+                    taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right,
+                            hiddenBounds.bottom);
+                } else {
+                    dismissingTaskViewTranslate = taskView
+                            .getPrimaryDismissTranslationProperty();
+                    distanceDelta = initialBounds.left - hiddenBounds.left;
+                    taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right,
+                            initialBounds.bottom);
+                    if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) {
+                        distanceDelta *= -1;
+                    }
+                }
+                pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView,
+                        dismissingTaskViewTranslate,
+                        distanceDelta));
                 pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1));
             } else {
                 // If insertion is on last index (furthest from clear all), we directly add the view
                 // else we translate all views to the right of insertion index further right,
                 // ignore views to left
+                if (showAsGrid()) {
+                    // TODO(b/186800707) handle more elegantly for grid
+                    continue;
+                }
                 int scrollDiff = newScroll[i] - oldScroll[i];
                 if (scrollDiff != 0) {
                     FloatProperty translationProperty = child instanceof TaskView
@@ -2872,6 +2950,12 @@
         pendingAnim.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationSuccess(Animator animator) {
+                // TODO(b/186800707) Figure out how to undo for grid view
+                //  Need to handle cases where dismissed task is
+                //  * Top Row
+                //  * Bottom Row
+                //  * Focused Task
+                updateGridProperties();
                 resetFromSplitSelectionState();
             }
         });
@@ -2881,13 +2965,16 @@
 
     private void resetFromSplitSelectionState() {
         mSplitHiddenTaskView.setTranslationY(0);
-        int pageToSnapTo = mCurrentPage;
-        if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
-            pageToSnapTo += 1;
-        } else {
-            pageToSnapTo = mSplitHiddenTaskViewIndex;
+        if (!showAsGrid()) {
+            // TODO(b/186800707)
+            int pageToSnapTo = mCurrentPage;
+            if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
+                pageToSnapTo += 1;
+            } else {
+                pageToSnapTo = mSplitHiddenTaskViewIndex;
+            }
+            snapToPageImmediately(pageToSnapTo);
         }
-        snapToPageImmediately(pageToSnapTo);
         onLayout(false /*  changed */, getLeft(), getTop(), getRight(), getBottom());
         resetTaskVisuals();
         mSplitHiddenTaskView = null;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 45bcdc3..1477933 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -172,6 +172,32 @@
                 }
             };
 
+    private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_X =
+            new FloatProperty<TaskView>("splitSelectTranslationX") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setSplitSelectTranslationX(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.mSplitSelectTranslationX;
+                }
+            };
+
+    private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_Y =
+            new FloatProperty<TaskView>("splitSelectTranslationY") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setSplitSelectTranslationY(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.mSplitSelectTranslationY;
+                }
+            };
+
     private static final FloatProperty<TaskView> DISMISS_TRANSLATION_X =
             new FloatProperty<TaskView>("dismissTranslationX") {
                 @Override
@@ -345,6 +371,9 @@
     // The following grid translations scales with mGridProgress.
     private float mGridTranslationX;
     private float mGridTranslationY;
+    // Used when in SplitScreenSelectState
+    private float mSplitSelectTranslationY;
+    private float mSplitSelectTranslationX;
 
     private ObjectAnimator mIconAndDimAnimator;
     private float mIconScaleAnimStartProgress = 0;
@@ -553,6 +582,7 @@
 
                 @Override
                 public void onAnimationEnd(Animator animator) {
+                    recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(true);
                     mIsClickableAsLiveTile = true;
                 }
             });
@@ -825,8 +855,10 @@
     protected void resetViewTransforms() {
         // fullscreenTranslation and accumulatedTranslation should not be reset, as
         // resetViewTransforms is called during Quickswitch scrolling.
-        mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX = 0f;
-        mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = 0f;
+        mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX =
+                mSplitSelectTranslationX = 0f;
+        mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY =
+                mSplitSelectTranslationY = 0f;
         applyTranslationX();
         applyTranslationY();
         setTranslationZ(0);
@@ -956,6 +988,15 @@
         setScaleY(scale);
     }
 
+    private void setSplitSelectTranslationX(float x) {
+        mSplitSelectTranslationX = x;
+        applyTranslationX();
+    }
+
+    private void setSplitSelectTranslationY(float y) {
+        mSplitSelectTranslationY = y;
+        applyTranslationY();
+    }
     private void setDismissTranslationX(float x) {
         mDismissTranslationX = x;
         applyTranslationX();
@@ -1056,12 +1097,12 @@
 
     private void applyTranslationX() {
         setTranslationX(mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX
-                + getPersistentTranslationX());
+                + mSplitSelectTranslationX + getPersistentTranslationX());
     }
 
     private void applyTranslationY() {
         setTranslationY(mDismissTranslationY + mTaskOffsetTranslationY + mTaskResistanceTranslationY
-                + getPersistentTranslationY());
+                + mSplitSelectTranslationY + getPersistentTranslationY());
     }
 
     /**
@@ -1085,6 +1126,16 @@
                 + getGridTrans(mGridTranslationY);
     }
 
+    public FloatProperty<TaskView> getPrimarySplitTranslationProperty() {
+        return getPagedOrientationHandler().getPrimaryValue(
+                SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y);
+    }
+
+    public FloatProperty<TaskView> getSecondarySplitTranslationProperty() {
+        return getPagedOrientationHandler().getSecondaryValue(
+                SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y);
+    }
+
     public FloatProperty<TaskView> getPrimaryDismissTranslationProperty() {
         return getPagedOrientationHandler().getPrimaryValue(
                 DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y);
@@ -1417,9 +1468,10 @@
     }
 
     private void setColorTint(float amount) {
-        mSnapshotView.setDimAlpha(amount);
-        mIconView.setIconColorTint(mTintingColor, amount);
-        mDigitalWellBeingToast.setBannerColorTint(mTintingColor, amount);
+        mTintAmount = amount;
+        mSnapshotView.setDimAlpha(mTintAmount);
+        mIconView.setIconColorTint(mTintingColor, mTintAmount);
+        mDigitalWellBeingToast.setBannerColorTint(mTintingColor, mTintAmount);
     }
 
     private float getColorTint() {
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d6936ab..eae32b7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -221,7 +221,7 @@
     <!-- Text for wallpaper change button [CHAR LIMIT=30]-->
     <string name="wallpaper_button_text">Wallpapers</string>
     <!-- Text for wallpaper change button [CHAR LIMIT=30]-->
-    <string name="styles_wallpaper_button_text">Styles &amp; wallpapers</string>
+    <string name="styles_wallpaper_button_text">Wallpaper &amp; style</string>
     <!-- Text for settings button [CHAR LIMIT=30]-->
     <string name="settings_button_text">Home settings</string>
     <!-- Message shown when a feature is disabled by the administrator -->
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 20b4631..c1f3ac5 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -57,6 +57,22 @@
 
     private final View[] mDragHandles = new View[HANDLE_COUNT];
     private final List<Rect> mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT);
+    private final OnAttachStateChangeListener mWidgetViewAttachStateChangeListener =
+            new OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View view) {
+                    // Do nothing
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View view) {
+                    // When the app widget view is detached, we should close the resize frame.
+                    // An example is when the dragging starts, the widget view is detached from
+                    // CellLayout and then reattached to DragLayout.
+                    close(false);
+                }
+            };
+
 
     private LauncherAppWidgetHostView mWidgetView;
     private CellLayout mCellLayout;
@@ -177,7 +193,11 @@
     private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
             DragLayer dragLayer) {
         mCellLayout = cellLayout;
+        if (mWidgetView != null) {
+            mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
+        }
         mWidgetView = widgetView;
+        mWidgetView.addOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
         LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
                 widgetView.getAppWidgetInfo();
         mResizeMode = info.resizeMode;
@@ -628,6 +648,9 @@
     @Override
     protected void handleClose(boolean animate) {
         mDragLayer.removeView(this);
+        if (mWidgetView != null) {
+            mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 2f755e1..1df9df6 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -18,6 +18,7 @@
 
 import static android.animation.ValueAnimator.areAnimatorsEnabled;
 
+import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
 
 import android.animation.Animator;
@@ -193,6 +194,8 @@
     private static final int INVALID_DIRECTION = -100;
 
     private final Rect mTempRect = new Rect();
+    private final RectF mTempRectF = new RectF();
+    private final float[] mTmpFloatArray = new float[4];
 
     private static final Paint sPaint = new Paint();
 
@@ -1070,11 +1073,16 @@
         // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable.
         View view = dragObject.dragView.getContentView();
         if (view instanceof LauncherAppWidgetHostView) {
-            Workspace workspace =
-                    Launcher.getLauncher(dragObject.dragView.getContext()).getWorkspace();
+            Launcher launcher = Launcher.getLauncher(dragObject.dragView.getContext());
+            Workspace workspace = launcher.getWorkspace();
             int screenId = workspace.getIdForScreen(this);
             int pageId = workspace.getPageIndexForScreenId(screenId);
             cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect);
+
+            // Now get the rect in drag layer coordinates.
+            getBoundsForViewInDragLayer(launcher.getDragLayer(), workspace, mTempRect, false,
+                    mTmpFloatArray, mTempRectF);
+            Utilities.setRect(mTempRectF, mTempRect);
             ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, pageId);
         }
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index be5463e..972a6e8 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -33,6 +33,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
@@ -84,6 +85,7 @@
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 
 import java.lang.reflect.Method;
@@ -104,6 +106,8 @@
     private static final Pattern sTrimPattern =
             Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$");
 
+    private static final float[] sTmpFloatArray = new float[4];
+
     private static final int[] sLoc0 = new int[2];
     private static final int[] sLoc1 = new int[2];
     private static final Matrix sMatrix = new Matrix();
@@ -133,6 +137,15 @@
             Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") ||
             Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
 
+    /**
+     * Returns true if theme is dark.
+     */
+    public static boolean isDarkTheme(Context context) {
+        Configuration configuration = context.getResources().getConfiguration();
+        int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        return nightMode == Configuration.UI_MODE_NIGHT_YES;
+    }
+
     public static boolean isDevelopersOptionsEnabled(Context context) {
         return Settings.Global.getInt(context.getApplicationContext().getContentResolver(),
                         Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
@@ -219,6 +232,33 @@
     }
 
     /**
+     * Returns bounds for a child view of DragLayer, in drag layer coordinates.
+     *
+     * see {@link com.android.launcher3.dragndrop.DragLayer}.
+     *
+     * @param viewBounds Bounds of the view wanted in drag layer coordinates, relative to the view
+     *                   itself. eg. (0, 0, view.getWidth, view.getHeight)
+     * @param ignoreTransform If true, view transform is ignored
+     * @param outRect The out rect where we return the bounds of {@param view} in drag layer coords.
+     */
+    public static void getBoundsForViewInDragLayer(BaseDragLayer dragLayer, View view,
+            Rect viewBounds, boolean ignoreTransform, float[] recycle, RectF outRect) {
+        float[] points = recycle == null ? new float[4] : recycle;
+        points[0] = viewBounds.left;
+        points[1] = viewBounds.top;
+        points[2] = viewBounds.right;
+        points[3] = viewBounds.bottom;
+
+        Utilities.getDescendantCoordRelativeToAncestor(view, dragLayer, points,
+                false, ignoreTransform);
+        outRect.set(
+                Math.min(points[0], points[2]),
+                Math.min(points[1], points[3]),
+                Math.max(points[0], points[2]),
+                Math.max(points[1], points[3]));
+    }
+
+    /**
      * Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}.
      */
     public static void mapCoordInSelfToDescendant(View descendant, View root, float[] coord) {
@@ -273,6 +313,16 @@
         return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]};
     }
 
+    /**
+     * Helper method to set rectOut with rectFSrc.
+     */
+    public static void setRect(RectF rectFSrc, Rect rectOut) {
+        rectOut.left = (int) rectFSrc.left;
+        rectOut.top = (int) rectFSrc.top;
+        rectOut.right = (int) rectFSrc.right;
+        rectOut.bottom = (int) rectFSrc.bottom;
+    }
+
     public static void scaleRectFAboutCenter(RectF r, float scale) {
         if (scale != 1.0f) {
             float cx = r.centerX();
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index a5852ba..dbdfb2b 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -32,6 +32,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragController.DragListener;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.keyboard.KeyboardDragAndDropView;
 import com.android.launcher3.model.data.AppInfo;
@@ -290,7 +291,12 @@
             return actions;
         }
 
-        CellLayout layout = (CellLayout) host.getParent().getParent();
+        CellLayout layout;
+        if (host.getParent() instanceof DragView) {
+            layout = (CellLayout) ((DragView) host.getParent()).getContentViewParent().getParent();
+        } else {
+            layout = (CellLayout) host.getParent().getParent();
+        }
         if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) {
             if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) ||
                     layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 119a91f..b11b63e 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -75,7 +75,7 @@
 public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
         Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener {
 
-    private static final float FLING_VELOCITY_MULTIPLIER = 1800f;
+    private static final float FLING_VELOCITY_MULTIPLIER = 1000f;
 
     // Starts the springs after at least 25% of the animation has passed.
     private static final float FLING_ANIMATION_THRESHOLD = 0.25f;
@@ -611,7 +611,7 @@
             public void onAnimationUpdate(ValueAnimator valueAnimator) {
                 if (shouldSpring
                         && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) {
-                    absorbSwipeUpVelocity(-Math.abs(
+                    absorbSwipeUpVelocity(Math.abs(
                             Math.round(velocity * FLING_VELOCITY_MULTIPLIER)));
                     shouldSpring = false;
                 }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c61c0d6..c4c7891 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -15,13 +15,15 @@
  */
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
+import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_ALLAPPS;
 
@@ -154,9 +156,9 @@
             return;
         }
 
-        Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
-                ? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
-                : FAST_OUT_SLOW_IN;
+        Interpolator interpolator = toState.equals(ALL_APPS)
+                ? (config.userControlled ? ACCEL_2 : ACCEL_0_75) :
+                        (config.userControlled ? DEACCEL_2 : DEACCEL);
 
         Animator anim = createSpringAnimation(mProgress, targetProgress);
         anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index 13ae866..e45b8f7 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -21,7 +21,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
@@ -34,6 +33,7 @@
 import android.util.SparseArray;
 import android.view.ContextThemeWrapper;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.GraphicsUtils;
@@ -119,9 +119,7 @@
                 info,
                 IconPalette.getPreloadProgressColor(context, info.bitmap.color),
                 getPreloadColors(context),
-            (context.getResources().getConfiguration().uiMode
-                    & Configuration.UI_MODE_NIGHT_MASK
-                    & Configuration.UI_MODE_NIGHT_YES) != 0) /* isDarkMode */;
+                Utilities.isDarkTheme(context));
     }
 
     public PreloadIconDrawable(
diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
index b3057d5..0eea92c 100644
--- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java
+++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
@@ -94,6 +94,11 @@
                     "SearchActionItemInfo can only have either an Intent or a PendingIntent");
         }
         mIntent = intent;
+        // bandage fix for just one week
+        if (intent != null && "com.android.server.telecom".equals(intent.getPackage())) {
+            intent.setAction(Intent.ACTION_DIAL);
+            intent.setPackage(null);
+        }
     }
 
     public PendingIntent getPendingIntent() {
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index c19dfe9..c63d69d 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.popup;
 
-import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
 
@@ -31,6 +30,7 @@
 import android.content.res.Resources;
 import android.graphics.Outline;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
@@ -41,17 +41,21 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.InsettableFrameLayout;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.dragndrop.DragLayer;
@@ -59,9 +63,11 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.LocalColorExtractor;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 
 /**
  * A container for shortcuts to deep links and notifications associated with an app.
@@ -73,6 +79,9 @@
 
     // +1 for system shortcut view
     private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1;
+    // Index used to get background color when using local wallpaper color extraction,
+    private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50;
+    private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_800;
 
     private final Rect mTempRect = new Rect();
 
@@ -104,8 +113,14 @@
 
     private Runnable mOnCloseCallback = () -> { };
 
+    // The rect string of the view that the arrow is attached to, in screen reference frame.
+    private String mArrowColorRectString;
     private int mArrowColor;
     private final int[] mColors;
+    private final HashMap<String, View> mViewForRect = new HashMap<>();
+
+    private final int mColorExtractionIndex;
+    @Nullable private LocalColorExtractor mColorExtractor;
 
     public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -113,7 +128,9 @@
         mOutlineRadius = Themes.getDialogCornerRadius(context);
         mLauncher = BaseDraggingActivity.fromContext(context);
         mIsRtl = Utilities.isRtl(getResources());
-
+        mColorExtractionIndex = Utilities.isDarkTheme(context)
+                ? DARK_COLOR_EXTRACTION_INDEX
+                : LIGHT_COLOR_EXTRACTION_INDEX;
         setClipToOutline(true);
         setOutlineProvider(new ViewOutlineProvider() {
             @Override
@@ -158,6 +175,10 @@
                 mColors[i] =
                         (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor);
             }
+
+            if (Utilities.ATLEAST_S) {
+                setupColorExtraction();
+            }
         }
     }
 
@@ -342,6 +363,15 @@
             // so we centered it instead. In that case we don't want to showDefaultOptions the arrow.
             mArrow.setVisibility(INVISIBLE);
         } else {
+            updateArrowColor();
+        }
+
+        mArrow.setPivotX(mArrowWidth / 2.0f);
+        mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0);
+    }
+
+    private void updateArrowColor() {
+        if (!Gravity.isVertical(mGravity)) {
             mArrow.setBackground(new RoundedArrowDrawable(
                     mArrowWidth, mArrowHeight, mArrowPointRadius,
                     mOutlineRadius, getMeasuredWidth(), getMeasuredHeight(),
@@ -350,9 +380,6 @@
                     mArrowColor));
             mArrow.setElevation(getElevation());
         }
-
-        mArrow.setPivotX(mArrowWidth / 2.0f);
-        mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0);
     }
 
     /**
@@ -671,6 +698,12 @@
         getPopupContainer().removeView(this);
         getPopupContainer().removeView(mArrow);
         mOnCloseCallback.run();
+        mArrowColorRectString = null;
+        mViewForRect.clear();
+        if (mColorExtractor != null) {
+            mColorExtractor.removeLocations();
+            mColorExtractor.setListener(null);
+        }
     }
 
     /**
@@ -680,6 +713,68 @@
         mOnCloseCallback = callback;
     }
 
+    private void setupColorExtraction() {
+        Workspace workspace = mLauncher.findViewById(R.id.workspace);
+        if (workspace == null) {
+            return;
+        }
+
+        mColorExtractor = LocalColorExtractor.newInstance(mLauncher);
+        mColorExtractor.setListener((rect, extractedColors) -> {
+            String rectString = rect.toShortString();
+            View v = mViewForRect.get(rectString);
+            if (v != null) {
+                int newColor = extractedColors.get(mColorExtractionIndex);
+                setChildColor(v, newColor);
+                if (rectString.equals(mArrowColorRectString)) {
+                    mArrowColor = newColor;
+                    updateArrowColor();
+                }
+            }
+        });
+
+        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                getViewTreeObserver().removeOnPreDrawListener(this);
+
+                ArrayList<RectF> locations = new ArrayList<>();
+                Rect r = new Rect();
+
+                int count = getChildCount();
+                int numVisibleChild = 0;
+                for (int i = 0; i < count; i++) {
+                    View view = getChildAt(i);
+                    if (view.getVisibility() == VISIBLE) {
+                        RectF rf = new RectF();
+                        mColorExtractor.getExtractedRectForView(Launcher.getLauncher(getContext()),
+                                workspace.getCurrentPage(), view, rf);
+                        if (rf.isEmpty()) {
+                            numVisibleChild++;
+                            continue;
+                        }
+
+                        locations.add(rf);
+                        String rectString = rf.toShortString();
+                        mViewForRect.put(rectString, view);
+
+                        // Arrow color matches the first child or the last child.
+                        if (!mIsAboveIcon && numVisibleChild == 0) {
+                            mArrowColorRectString = rectString;
+                        } else if (mIsAboveIcon) {
+                            mArrowColorRectString = rectString;
+                        }
+
+                        numVisibleChild++;
+                    }
+                }
+
+                mColorExtractor.addLocation(locations);
+                return false;
+            }
+        });
+    }
+
     protected BaseDragLayer getPopupContainer() {
         return mLauncher.getDragLayer();
     }
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 2fd5efc..44e55e1 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -160,6 +160,19 @@
     }
 
     @Override
+    public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition,
+            DeviceProfile dp) {
+        // Don't use device profile here because we know we're in fake landscape, only split option
+        // available is top/left
+        if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+            // Top (visually left) side
+            return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
+        }
+        throw new IllegalStateException("Invalid split stage position: " +
+                splitPosition.mStagePosition);
+    }
+
+    @Override
     public int getPrimaryScroll(View view) {
         return view.getScrollY();
     }
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 6c2f17e..d8e5a48 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -42,6 +42,10 @@
  */
 public interface PagedOrientationHandler {
 
+    int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0;
+    int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1;
+    int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2;
+
     PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
     PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
     PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
@@ -71,6 +75,13 @@
     int getSecondaryDimension(View view);
     FloatProperty<View> getPrimaryViewTranslate();
     FloatProperty<View> getSecondaryViewTranslate();
+
+    /**
+     * @param splitPosition The position where the view to be split will go
+     * @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the
+     * dismissal should happen
+     */
+    int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, DeviceProfile dp);
     int getPrimaryScroll(View view);
     float getPrimaryScale(View view);
     int getChildStart(View view);
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index f6a6448..d3d77fd 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -156,6 +156,25 @@
     }
 
     @Override
+    public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition,
+            DeviceProfile dp) {
+        if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+            if (dp.isLandscape) {
+                // Left side
+                return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
+            } else {
+                // Top side
+                return SPLIT_TRANSLATE_SECONDARY_NEGATIVE;
+            }
+        } else if (splitPosition.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
+            // We don't have a bottom option, so should be right
+            return SPLIT_TRANSLATE_PRIMARY_POSITIVE;
+        }
+        throw new IllegalStateException("Invalid split stage position: " +
+                splitPosition.mStagePosition);
+    }
+
+    @Override
     public int getPrimaryScroll(View view) {
         return view.getScrollX();
     }
@@ -277,7 +296,7 @@
         } else {
             // Phone Portrait, LargeScreen Landscape/Portrait
             viewGroup.setOrientation(LinearLayout.HORIZONTAL);
-            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
+            lp.width = LinearLayout.LayoutParams.MATCH_PARENT;
         }
 
         lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 99942aa..06cac08 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -22,7 +22,6 @@
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.ColorMatrix;
@@ -54,16 +53,12 @@
     }
 
     public static int getActivityThemeRes(Context context, int wallpaperColorHints) {
-        Configuration configuration = context.getResources().getConfiguration();
-        int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
-        boolean darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES;
-
         boolean supportsDarkText = Utilities.ATLEAST_S
                 && (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0;
         boolean isMainColorDark = Utilities.ATLEAST_S
                 && (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0;
 
-        if (darkTheme) {
+        if (Utilities.isDarkTheme(context)) {
             return supportsDarkText ? R.style.AppTheme_Dark_DarkText
                     : isMainColorDark ? R.style.AppTheme_Dark_DarkMainColor : R.style.AppTheme_Dark;
         } else {
diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java
index be14e01..f5e1234 100644
--- a/src/com/android/launcher3/util/UiThreadHelper.java
+++ b/src/com/android/launcher3/util/UiThreadHelper.java
@@ -48,7 +48,13 @@
             WindowInsets rootInsets = launcher.getRootView().getRootWindowInsets();
             boolean isImeShown = rootInsets != null && rootInsets.isVisible(
                     WindowInsets.Type.ime());
-            if (!isImeShown) return;
+            if (isImeShown) {
+                // this call is already asynchronous
+                launcher.getAppsView().getWindowInsetsController().hide(
+                        WindowInsets.Type.ime()
+                );
+            }
+            return;
         }
 
         Message.obtain(HANDLER.get(launcher), MSG_HIDE_KEYBOARD, token).sendToTarget();
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index d49320b..81581fa 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -233,15 +233,8 @@
             outViewBounds.set(0, 0, v.getWidth(), v.getHeight());
         }
 
-        float[] points = new float[] {outViewBounds.left, outViewBounds.top, outViewBounds.right,
-                outViewBounds.bottom};
-        Utilities.getDescendantCoordRelativeToAncestor(v, launcher.getDragLayer(), points,
-                false, ignoreTransform);
-        outRect.set(
-                Math.min(points[0], points[2]),
-                Math.min(points[1], points[3]),
-                Math.max(points[0], points[2]),
-                Math.max(points[1], points[3]));
+        Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, outViewBounds,
+                ignoreTransform, null /** recycle */, outRect);
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 620604a..5deecd4 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,6 +16,9 @@
 
 package com.android.launcher3.widget;
 
+import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer;
+import static com.android.launcher3.Utilities.setRect;
+
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -25,7 +28,6 @@
 import android.graphics.RectF;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.view.LayoutInflater;
@@ -95,11 +97,12 @@
     private RectF mLastLocationRegistered = null;
     @Nullable private AppWidgetHostViewDragListener mDragListener;
 
-    // Used to store the widget size during onLayout.
+    // Used to store the widget sizes in drag layer coordinates.
     private final Rect mCurrentWidgetSize = new Rect();
     private final Rect mWidgetSizeAtDrag = new Rect();
+
+    private final float[] mTmpFloatArray = new float[4];
     private final RectF mTempRectF = new RectF();
-    private final boolean mIsRtl;
     private final Rect mEnforcedRectangle = new Rect();
     private final float mEnforcedCornerRadius;
     private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
@@ -129,7 +132,6 @@
         if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
             setOnLightBackground(true);
         }
-        mIsRtl = Utilities.isRtl(context.getResources());
         mColorExtractor = LocalColorExtractor.newInstance(getContext());
         mColorExtractor.setListener(this);
 
@@ -319,13 +321,12 @@
         mIsScrollable = checkScrollableRecursively(this);
 
         if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
-            mCurrentWidgetSize.left = left;
-            mCurrentWidgetSize.top = top;
-            mCurrentWidgetSize.right = right;
-            mCurrentWidgetSize.bottom = bottom;
             LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
-            int pageId = mWorkspace.getPageIndexForScreenId(info.screenId);
-            updateColorExtraction(mCurrentWidgetSize, pageId);
+            getBoundsForViewInDragLayer(mLauncher.getDragLayer(), this, mCurrentWidgetSize, true,
+                    mTmpFloatArray, mTempRectF);
+            setRect(mTempRectF, mCurrentWidgetSize);
+            updateColorExtraction(mCurrentWidgetSize,
+                    mWorkspace.getPageIndexForScreenId(info.screenId));
         }
 
         enforceRoundedCorners();
@@ -338,8 +339,8 @@
     }
 
     /** Handles a drag event occurred on a workspace page, {@code pageId}. */
-    public void handleDrag(Rect rect, int pageId) {
-        mWidgetSizeAtDrag.set(rect);
+    public void handleDrag(Rect rectInDragLayer, int pageId) {
+        mWidgetSizeAtDrag.set(rectInDragLayer);
         updateColorExtraction(mWidgetSizeAtDrag, pageId);
     }
 
@@ -351,53 +352,14 @@
         requestLayout();
     }
 
-    private void updateColorExtraction(Rect widgetLocation, int pageId) {
-        // If the widget hasn't been measured and laid out, we cannot do this.
-        if (widgetLocation.isEmpty()) {
-            return;
-        }
-        int screenWidth = mLauncher.getDeviceProfile().widthPx;
-        int screenHeight = mLauncher.getDeviceProfile().heightPx;
-        int numScreens = mWorkspace.getNumPagesForWallpaperParallax();
-        pageId = mIsRtl ? numScreens - pageId - 1 : pageId;
-        float relativeScreenWidth = 1f / numScreens;
-        float absoluteTop = widgetLocation.top;
-        float absoluteBottom = widgetLocation.bottom;
-        View v = this;
-        while (v.getParent() instanceof View) {
-            v = (View) v.getParent();
-            if (v.getId() != R.id.launcher) {
-                break;
-            }
-            absoluteBottom += v.getTop();
-            absoluteTop += v.getTop();
-        }
-        float xOffset = 0;
-        View parentView = (View) getParent();
-        // The layout depends on the orientation.
-        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            int parentViewWidth = parentView == null ? 0 : parentView.getWidth();
-            xOffset = screenWidth - mWorkspace.getPaddingRight() - parentViewWidth;
-        } else {
-            int parentViewPaddingLeft = parentView == null ? 0 : parentView.getPaddingLeft();
-            xOffset = mWorkspace.getPaddingLeft() + parentViewPaddingLeft;
-        }
-        // This is the position of the widget relative to the wallpaper, as expected by the
-        // local color extraction of the WallpaperManager.
-        // The coordinate system is such that, on the horizontal axis, each screen has a
-        // distinct range on the [0,1] segment. So if there are 3 screens, they will have the
-        // ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be
-        // the position of the widget relative to the screen. For the vertical axis, this is
-        // simply the location of the widget relative to the screen.
-        mTempRectF.left = ((widgetLocation.left + xOffset) / screenWidth + pageId)
-                * relativeScreenWidth;
-        mTempRectF.right = ((widgetLocation.right + xOffset) / screenWidth + pageId)
-                * relativeScreenWidth;
-        mTempRectF.top = absoluteTop / screenHeight;
-        mTempRectF.bottom = absoluteBottom / screenHeight;
-        if (mTempRectF.left < 0 || mTempRectF.right > 1 || mTempRectF.top < 0
-                || mTempRectF.bottom > 1) {
-            Log.e(LOG_TAG, "   Error, invalid relative position");
+    /**
+     * @param rectInDragLayer Rect of widget in drag layer coordinates.
+     * @param pageId The workspace page the widget is on.
+     */
+    private void updateColorExtraction(Rect rectInDragLayer, int pageId) {
+        mColorExtractor.getExtractedRectForViewRect(mLauncher, pageId, rectInDragLayer, mTempRectF);
+
+        if (mTempRectF.isEmpty()) {
             return;
         }
         if (!mTempRectF.equals(mLastLocationRegistered)) {
diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java
index be4faea..8ae6b2e 100644
--- a/src/com/android/launcher3/widget/LocalColorExtractor.java
+++ b/src/com/android/launcher3/widget/LocalColorExtractor.java
@@ -19,11 +19,14 @@
 import android.app.WallpaperColors;
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.SparseIntArray;
+import android.view.View;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.util.ResourceBasedOverride;
 
@@ -71,4 +74,33 @@
      * Updates the base context to contain the colors override
      */
     public void applyColorsOverride(Context base, WallpaperColors colors) { }
+
+    /**
+     * Takes a view and returns its rect that can be used by the wallpaper local color extractor.
+     *
+     * @param launcher Launcher class class.
+     * @param pageId The page the workspace item is on.
+     * @param v The view.
+     * @param colorExtractionRectOut The location rect, but converted to a format expected by the
+     *                               wallpaper local color extractor.
+     */
+    public void getExtractedRectForView(Launcher launcher, int pageId, View v,
+            RectF colorExtractionRectOut) {
+        // no-op
+    }
+
+    /**
+     * Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper
+     * local color extractor.
+     *
+     * @param launcher Launcher class.
+     * @param pageId The page the workspace item is on.
+     * @param rectInDragLayer The relevant bounds of the view in drag layer coordinates.
+     * @param colorExtractionRectOut The location rect, but converted to a format expected by the
+     *                               wallpaper local color extractor.
+     */
+    public void getExtractedRectForViewRect(Launcher launcher, int pageId, Rect rectInDragLayer,
+            RectF colorExtractionRectOut) {
+        // no-op
+    }
 }