Merge "Re-try binding to TouchInteractionService if service is killed" into sc-v2-dev
diff --git a/go/quickstep/res/drawable/arrow_toast_rounded_background.xml b/go/quickstep/res/drawable/arrow_toast_rounded_background.xml
new file mode 100644
index 0000000..9c815fd
--- /dev/null
+++ b/go/quickstep/res/drawable/arrow_toast_rounded_background.xml
@@ -0,0 +1,19 @@
+<!--
+    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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="@color/arrow_tip_view_bg" />
+    <corners android:radius="@dimen/tooltip_corner_radius" />
+</shape>
diff --git a/go/quickstep/res/layout/niu_actions_confirmation_dialog.xml b/go/quickstep/res/layout/niu_actions_confirmation_dialog.xml
index db1531a..5dbcca5 100644
--- a/go/quickstep/res/layout/niu_actions_confirmation_dialog.xml
+++ b/go/quickstep/res/layout/niu_actions_confirmation_dialog.xml
@@ -76,12 +76,12 @@
             <Button
                 style="@style/ModalDialogButton"
                 android:id="@+id/niu_actions_confirmation_reject"
-                android:text="@string/niu_actions_confirmation_no"/>
+                android:text="@string/dialog_cancel"/>
 
             <Button
                 style="@style/ModalDialogButton"
                 android:id="@+id/niu_actions_confirmation_accept"
-                android:text="@string/niu_actions_confirmation_yes"/>
+                android:text="@string/dialog_acknowledge"/>
         </LinearLayout>
 
     </LinearLayout>
diff --git a/go/quickstep/res/values/colors.xml b/go/quickstep/res/values/colors.xml
index 8034be2..4ce7669 100644
--- a/go/quickstep/res/values/colors.xml
+++ b/go/quickstep/res/values/colors.xml
@@ -23,4 +23,8 @@
     <!-- Modal Dialogs -->
     <color name="go_modal_dialog_background">#FFFFFF</color>
     <color name="go_modal_dialog_background_dark">#424242</color>
+
+    <!-- Tooltip Color -->
+    <color name="arrow_tip_view_bg">#1A73E8</color>
+    <color name="arrow_tip_view_content">#FFFFFF</color>
 </resources>
diff --git a/go/quickstep/res/values/dimens.xml b/go/quickstep/res/values/dimens.xml
index 0a7ac45..c14df50 100644
--- a/go/quickstep/res/values/dimens.xml
+++ b/go/quickstep/res/values/dimens.xml
@@ -36,4 +36,8 @@
     <dimen name="modal_dialog_vertical_spacer">12dp</dimen>
     <dimen name="modal_dialog_corner_radius">8dp</dimen>
     <dimen name="confirmation_dialog_text_height">216dp</dimen>
+
+    <!-- Tooltip -->
+    <dimen name="tooltip_corner_radius">8dp</dimen>
+    <dimen name="tooltip_top_margin">3dp</dimen>
 </resources>
diff --git a/go/quickstep/res/values/strings.xml b/go/quickstep/res/values/strings.xml
index 6e9e63e..8429f6a 100644
--- a/go/quickstep/res/values/strings.xml
+++ b/go/quickstep/res/values/strings.xml
@@ -11,13 +11,34 @@
     <string name="action_translate">Translate</string>
     <!-- Label for a button that triggers Search on a screenshot of the current app. [CHAR_LIMIT=40] -->
     <string name="action_search">Lens</string>
+
+    <!-- ******* Dialogs ******* -->
+    <!-- Label for a button that acknowledges the contents of the dialog. [CHAR_LIMIT=40] -->
+    <string name="dialog_acknowledge">GOT IT</string>
+    <!-- Label for a button that cancels the dialog. [CHAR_LIMIT=40] -->
+    <string name="dialog_cancel">CANCEL</string>
+    <!-- Label for a button that redirects the user to Settings. [CHAR_LIMIT=40] -->
+    <string name="dialog_settings">SETTINGS</string>
+
     <!-- ******* NIU Actions First-Run Confirmation Dialog ******* -->
     <!-- Dialog title -->
     <string name="niu_actions_confirmation_title">Translate or listen to text on screen</string>
     <!-- Dialog content -->
     <string name="niu_actions_confirmation_text">Information such as text on your screen, web addresses, and screenshots may be shared with Google.\n\nTo change what information you share, go to <b>Settings > Apps > Default apps > Digital assistant app</b>.</string>
-    <!-- Label for a button that rejects the feature. [CHAR_LIMIT=40] -->
-    <string name="niu_actions_confirmation_no">CANCEL</string>
-    <!-- Label for a button that accepts the feature. [CHAR_LIMIT=40] -->
-    <string name="niu_actions_confirmation_yes">GOT IT</string>
+
+    <!-- ******* NIU Actions Default Assistant Error Dialogs ******* -->
+    <!-- Assistant not selected: Dialog title -->
+    <string name="assistant_not_selected_title">Choose an assistant to use this feature</string>
+    <!-- Assistant not selected: Dialog content -->
+    <string name="assistant_not_selected_text">To listen to or translate text on your screen, choose a digital assistant app in Settings</string>
+    <!-- Assistant not supported: Dialog title -->
+    <string name="assistant_not_supported_title">Change your assistant to use this feature</string>
+    <!-- Assistant not supported: Dialog content -->
+    <string name="assistant_not_supported_text">To listen to or translate text on your screen, change your digital assistant app in Settings</string>
+
+    <!-- ******* NIU Actions Tooltip ******* -->
+    <!-- Tooltip to highlight and explain the Listen button -->
+    <string name="tooltip_listen">Tap here to listen to text on this screen</string>
+    <!-- Tooltip to highlight and explain the Translate button -->
+    <string name="tooltip_translate">Tap here to translate text on this screen</string>
 </resources>
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 37f5352..f3c7a02 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -16,6 +16,8 @@
 
 package com.android.quickstep;
 
+import static android.view.Surface.ROTATION_0;
+
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
 
@@ -30,6 +32,7 @@
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.drawable.ColorDrawable;
+import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -46,7 +49,8 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.quickstep.util.AssistContentRequester;
-import com.android.quickstep.views.OverviewActionsView;
+import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.views.GoOverviewActionsView;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -67,6 +71,9 @@
     private static final String NIU_ACTIONS_CONFIRMED = "launcher_go.niu_actions_confirmed";
     private static final String TAG = "TaskOverlayFactoryGo";
 
+    public static final String LISTEN_TOOL_TIP_SEEN = "launcher.go_listen_tip_seen";
+    public static final String TRANSLATE_TOOL_TIP_SEEN = "launcher.go_translate_tip_seen";
+
     private AssistContentRequester mContentRequester;
 
     public TaskOverlayFactoryGo(Context context) {
@@ -84,7 +91,7 @@
      * Overlay on each task handling Overview Action Buttons.
      * @param <T> The type of View in which the overlay will be placed
      */
-    public static final class TaskOverlayGo<T extends OverviewActionsView> extends TaskOverlay {
+    public static final class TaskOverlayGo<T extends GoOverviewActionsView> extends TaskOverlay {
         private String mNIUPackageName;
         private String mTaskPackageName;
         private String mWebUrl;
@@ -99,6 +106,7 @@
                 AssistContentRequester assistContentRequester) {
             super(taskThumbnailView);
             mFactoryContentRequester = assistContentRequester;
+            mSharedPreferences = Utilities.getPrefs(mApplicationContext);
         }
 
         /**
@@ -134,6 +142,18 @@
 
             int taskId = task.key.id;
             mFactoryContentRequester.requestAssistContent(taskId, this::onAssistContentReceived);
+
+            RecentsOrientedState orientedState =
+                    mThumbnailView.getTaskView().getRecentsView().getPagedViewOrientedState();
+            boolean isInLandscape = orientedState.getDisplayRotation() != ROTATION_0;
+
+            // show tooltips in portrait mode only
+            // TODO: remove If check once b/183714277 is fixed
+            if (!isInLandscape) {
+                new Handler().post(() -> {
+                    showTooltipsIfUnseen();
+                });
+            }
         }
 
         /** Provide Assist Content to the overlay. */
@@ -149,6 +169,12 @@
             mWebUrl = null;
         }
 
+        @Override
+        public void updateOrientationState(RecentsOrientedState state) {
+            super.updateOrientationState(state);
+            ((GoOverviewActionsView) getActionsView()).updateOrientationState(state);
+        }
+
         /**
          * Creates and sends an Intent corresponding to the button that was clicked
          */
@@ -275,6 +301,20 @@
         private void onNiuActionsConfirmationReject(View v) {
             mConfirmationDialog.cancel();
         }
+
+        /**
+         * Checks and Shows the tooltip if they are not seen by user
+         * Order of tooltips are translate and then listen
+         */
+        private void showTooltipsIfUnseen() {
+            if (!mSharedPreferences.getBoolean(TRANSLATE_TOOL_TIP_SEEN, false)) {
+                ((GoOverviewActionsView) getActionsView()).showTranslateToolTip();
+                mSharedPreferences.edit().putBoolean(TRANSLATE_TOOL_TIP_SEEN, true).apply();
+            } else if (!mSharedPreferences.getBoolean(LISTEN_TOOL_TIP_SEEN, false)) {
+                ((GoOverviewActionsView) getActionsView()).showListenToolTip();
+                mSharedPreferences.edit().putBoolean(LISTEN_TOOL_TIP_SEEN, true).apply();
+            }
+        }
     }
 
     /**
diff --git a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
index 9997d16..5b535a2 100644
--- a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
@@ -21,14 +21,20 @@
 import android.view.View;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.Px;
 
 import com.android.launcher3.R;
+import com.android.launcher3.views.ArrowTipView;
 import com.android.quickstep.TaskOverlayFactoryGo.OverlayUICallbacksGo;
+import com.android.quickstep.util.RecentsOrientedState;
 
 /**
  * View for showing Go-specific action buttons in Overview
  */
-public final class GoOverviewActionsView extends OverviewActionsView<OverlayUICallbacksGo> {
+public class GoOverviewActionsView extends OverviewActionsView<OverlayUICallbacksGo> {
+
+    private ArrowTipView mArrowTipView;
+
     public GoOverviewActionsView(Context context) {
         this(context, null);
     }
@@ -72,4 +78,46 @@
             mCallbacks.onSearch();
         }
     }
+
+    /**
+     * Shows Tooltip for action icons
+     */
+    private void showToolTip(int viewId, int textResourceId) {
+        int[] location = new int[2];
+        @Px int topMargin = getResources().getDimensionPixelSize(R.dimen.tooltip_top_margin);
+        findViewById(viewId).getLocationOnScreen(location);
+        mArrowTipView = new ArrowTipView(getContext(),  /* isPointingUp= */ false)
+            .showAtLocation(getResources().getString(textResourceId),
+                /* arrowXCoord= */ location[0] + findViewById(viewId).getWidth() / 2,
+                /* yCoord= */ location[1] - topMargin);
+
+        mArrowTipView.bringToFront();
+    }
+
+    /**
+     * Shows Tooltip for listen action icon
+     */
+    public void showListenToolTip() {
+        showToolTip(/* viewId= */ R.id.action_listen,
+                /* textResourceId= */ R.string.tooltip_listen);
+    }
+
+    /**
+     * Shows Tooltip for translate action icon
+     */
+    public void showTranslateToolTip() {
+        showToolTip(/* viewId= */ R.id.action_translate,
+                /* textResourceId= */ R.string.tooltip_translate);
+    }
+
+    /**
+     * Called when device orientation is changed
+     */
+    public void updateOrientationState(RecentsOrientedState orientedState) {
+        // dismiss tooltip
+        boolean canLauncherRotate = orientedState.canRecentsActivityRotate();
+        if (mArrowTipView != null && !canLauncherRotate) {
+            mArrowTipView.close(/* animate= */ false);
+        }
+    }
 }
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index 3a47e99..a5c9445 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -40,7 +40,6 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        android:divider="@drawable/all_apps_divider"
         android:showDividers="middle" />
 
 </com.android.quickstep.views.TaskMenuView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9b402e3..1febc88 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -25,6 +25,7 @@
     <!--  Task Menu View  -->
     <dimen name="task_menu_corner_radius">22dp</dimen>
     <dimen name="task_menu_item_corner_radius">4dp</dimen>
+    <dimen name="task_menu_spacing">2dp</dimen>
     <dimen name="overview_proactive_row_height">48dp</dimen>
     <dimen name="overview_proactive_row_bottom_margin">16dp</dimen>
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 4e85eb4..1edeba0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -86,6 +86,7 @@
     private TaskbarControllers mControllers;
     private View mA11yButton;
     private int mSysuiStateFlags;
+    private View mBackButton;
 
     public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
         mContext = context;
@@ -106,6 +107,26 @@
             return true;
         };
 
+        mPropertyHolders.add(new StatePropertyHolder(
+                mControllers.taskbarViewController.getTaskbarIconAlpha()
+                        .getProperty(ALPHA_INDEX_IME),
+                flags -> (flags & FLAG_IME_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
+
+        // IME switcher
+        View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
+                mEndContainer, mControllers.navButtonController, R.id.ime_switcher);
+        mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton,
+                flags -> ((flags & MASK_IME_SWITCHER_VISIBLE) == MASK_IME_SWITCHER_VISIBLE)
+                        && ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)
+                        && ((flags & FLAG_A11Y_VISIBLE) == 0)));
+
+        mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
+                mStartContainer, mControllers.navButtonController, R.id.back);
+        // Rotate when Ime visible
+        mPropertyHolders.add(new StatePropertyHolder(mBackButton,
+                flags -> (flags & FLAG_IME_VISIBLE) == 0, View.ROTATION, 0,
+                Utilities.isRtl(mContext.getResources()) ? 90 : -90));
+
         if (mContext.isThreeButtonNav()) {
             initButtons(mStartContainer, mEndContainer, mControllers.navButtonController);
 
@@ -116,10 +137,6 @@
                     AnimatedFloat.VALUE, 0, 1));
             mPropertyHolders.add(new StatePropertyHolder(
                     mControllers.taskbarViewController.getTaskbarIconAlpha()
-                            .getProperty(ALPHA_INDEX_IME),
-                    flags -> (flags & FLAG_IME_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
-            mPropertyHolders.add(new StatePropertyHolder(
-                    mControllers.taskbarViewController.getTaskbarIconAlpha()
                             .getProperty(ALPHA_INDEX_KEYGUARD),
                     flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
 
@@ -130,6 +147,9 @@
             mControllers.rotationButtonController.setRotationButton(rotationButton);
         } else {
             mControllers.rotationButtonController.setRotationButton(new RotationButton() {});
+            // Show when IME is visible
+            mPropertyHolders.add(new StatePropertyHolder(mBackButton,
+                    flags -> (flags & FLAG_IME_VISIBLE) != 0));
         }
 
         applyState();
@@ -139,13 +159,8 @@
     private void initButtons(ViewGroup startContainer, ViewGroup endContainer,
             TaskbarNavButtonController navButtonController) {
 
-        View backButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
-                startContainer, navButtonController, R.id.back);
-        // Rotate when Ime visible
-        mPropertyHolders.add(new StatePropertyHolder(backButton,
-                flags -> (flags & FLAG_IME_VISIBLE) == 0, View.ROTATION, 0,
-                Utilities.isRtl(mContext.getResources()) ? 90 : -90));
-        mPropertyHolders.add(new StatePropertyHolder(backButton,
+        // Hide when keyguard is showing, show when bouncer is showing
+        mPropertyHolders.add(new StatePropertyHolder(mBackButton,
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
                         (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
 
@@ -161,14 +176,6 @@
                 flags -> (flags & FLAG_IME_VISIBLE) == 0 &&
                         (flags & FLAG_KEYGUARD_VISIBLE) == 0));
 
-        // IME switcher
-        View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
-                endContainer, navButtonController, R.id.ime_switcher);
-        mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton,
-                flags -> ((flags & MASK_IME_SWITCHER_VISIBLE) == MASK_IME_SWITCHER_VISIBLE)
-                        && ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)
-                        && ((flags & FLAG_A11Y_VISIBLE) == 0)));
-
         // A11y button
         mA11yButton = addButton(R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
                 endContainer, navButtonController, R.id.accessibility_button);
@@ -193,7 +200,10 @@
         updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
         updateStateForFlag(FLAG_SWITCHER_SUPPORTED, isImeSwitcherShowing);
         updateStateForFlag(FLAG_A11Y_VISIBLE, a11yVisible);
-        mA11yButton.setLongClickable(a11yLongClickable);
+        if (mA11yButton != null) {
+            // Only used in 3 button
+            mA11yButton.setLongClickable(a11yLongClickable);
+        }
         applyState();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index f4703d3..e11f4c1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -218,9 +218,6 @@
     }
 
     public void updateSysuiStateFlags(int systemUiStateFlags, boolean forceUpdate) {
-        if (!isThreeButtonNav()) {
-            return;
-        }
         mControllers.navbarButtonsViewController.updateStateForSysuiFlags(
                 systemUiStateFlags, forceUpdate);
         mControllers.taskbarViewController.setImeIsVisible(
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index c04d15f..096ac6c 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -387,8 +387,11 @@
         mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> {
                 ThumbnailData snapshot = mGestureState.consumeRecentsAnimationCanceledSnapshot();
                 if (snapshot != null) {
-                    mRecentsView.switchToScreenshot(snapshot,
-                            () -> mRecentsAnimationController.cleanupScreenshot());
+                    mRecentsView.switchToScreenshot(snapshot, () -> {
+                        if (mRecentsAnimationController != null) {
+                            mRecentsAnimationController.cleanupScreenshot();
+                        }
+                    });
                     mRecentsView.onRecentsAnimationComplete();
                 }
             });
@@ -740,6 +743,8 @@
             mRecentsAnimationStartCallbacks.clear();
         }
 
+        TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, false);
+
         // Only add the callback to enable the input consumer after we actually have the controller
         mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
                 mRecentsAnimationController::enableInputConsumer);
@@ -754,6 +759,8 @@
         mActivityInitListener.unregister();
         mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
 
+        TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
+
         // Defer clearing the controller and the targets until after we've updated the state
         mRecentsAnimationController = null;
         mRecentsAnimationTargets = null;
@@ -882,6 +889,7 @@
                 break;
             case LAST_TASK:
                 mStateCallback.setState(STATE_RESUME_LAST_TASK);
+                TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
                 break;
         }
         ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + endTarget);
@@ -1723,6 +1731,9 @@
 
     @Override
     public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+        if (!controller.getFinishTargetIsLauncher()) {
+            TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
+        }
         mRecentsAnimationController = null;
         mRecentsAnimationTargets = null;
         if (mRecentsView != null) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index a21c714..239233b 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -19,6 +19,7 @@
 
 import android.graphics.Rect;
 import android.util.ArraySet;
+import android.view.RemoteAnimationTarget;
 
 import androidx.annotation.BinderThread;
 import androidx.annotation.UiThread;
@@ -39,6 +40,7 @@
         com.android.systemui.shared.system.RecentsAnimationListener {
 
     private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
+    private final SystemUiProxy mSystemUiProxy;
     private final boolean mAllowMinimizeSplitScreen;
 
     // TODO(141886704): Remove these references when they are no longer needed
@@ -46,7 +48,9 @@
 
     private boolean mCancelled;
 
-    public RecentsAnimationCallbacks(boolean allowMinimizeSplitScreen) {
+    public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
+            boolean allowMinimizeSplitScreen) {
+        mSystemUiProxy = systemUiProxy;
         mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
     }
 
@@ -89,8 +93,11 @@
             RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets,
             Rect homeContentInsets, Rect minimizedHomeBounds) {
+        RemoteAnimationTarget[] nonAppTargets =
+                mSystemUiProxy.onGoingToRecentsLegacy(mCancelled);
         RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
-                wallpaperTargets, homeContentInsets, minimizedHomeBounds);
+                wallpaperTargets, RemoteAnimationTargetCompat.wrap(nonAppTargets),
+                homeContentInsets, minimizedHomeBounds);
         mController = new RecentsAnimationController(animationController,
                 mAllowMinimizeSplitScreen, this::onAnimationFinished);
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 3861bab..b6d9016 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -31,9 +31,9 @@
     public final Rect minimizedHomeBounds;
 
     public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps,
-            RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets,
-            Rect minimizedHomeBounds) {
-        super(apps, wallpapers, new RemoteAnimationTargetCompat[0], MODE_CLOSING);
+            RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
+            Rect homeContentInsets, Rect minimizedHomeBounds) {
+        super(apps, wallpapers, nonApps, MODE_CLOSING);
         this.homeContentInsets = homeContentInsets;
         this.minimizedHomeBounds = minimizedHomeBounds;
     }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 090fd01..d6b95c1 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -33,6 +33,8 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 
 import com.android.launcher3.util.MainThreadInitializedObject;
@@ -562,6 +564,22 @@
         }
     }
 
+    /**
+     * Start multiple tasks in split-screen simultaneously.
+     */
+    public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
+            Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
+            RemoteAnimationAdapter adapter) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
+                        sideOptions, sidePosition, adapter);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startTasksWithLegacyTransition");
+            }
+        }
+    }
+
     public void startShortcut(String packageName, String shortcutId, int stage, int position,
             Bundle options, UserHandle user) {
         if (mSplitScreen != null) {
@@ -595,6 +613,24 @@
         }
     }
 
+    /**
+     * Call this when going to recents so that shell can set-up and provide appropriate leashes
+     * for animation (eg. DividerBar).
+     *
+     * @param cancel true if recents starting is being cancelled.
+     * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
+     */
+    public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel) {
+        if (mSplitScreen != null) {
+            try {
+                return mSplitScreen.onGoingToRecentsLegacy(cancel);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call onGoingToRecentsLegacy");
+            }
+        }
+        return null;
+    }
+
     //
     // One handed
     //
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 33718a3..fe07cbd 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -109,7 +109,8 @@
 
         final BaseActivityInterface activityInterface = gestureState.getActivityInterface();
         mLastGestureState = gestureState;
-        mCallbacks = new RecentsAnimationCallbacks(activityInterface.allowMinimizeSplitScreen());
+        mCallbacks = new RecentsAnimationCallbacks(SystemUiProxy.INSTANCE.get(mCtx),
+                activityInterface.allowMinimizeSplitScreen());
         mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
             @Override
             public void onRecentsAnimationStart(RecentsAnimationController controller,
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index ffa254d..080533b 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -266,6 +266,12 @@
             return mThumbnailView.getScaledInsets();
         }
 
+        /**
+         * Called when the device rotated.
+         */
+        public void updateOrientationState(RecentsOrientedState state) {
+        }
+
         protected void showBlockedByPolicyMessage() {
             Toast.makeText(
                     mThumbnailView.getContext(),
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 37fda73..f292f1a 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -15,6 +15,7 @@
  */
 package com.android.quickstep;
 
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
@@ -405,77 +406,39 @@
     }
 
     /** Legacy version (until shell transitions are enabled) */
-    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
+    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull TaskView initialView,
             @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
             @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
-            @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
-            @NonNull StateManager stateManager, @NonNull DepthController depthController,
-            int targetStage) {
-        PendingAnimation out = new PendingAnimation(RECENTS_LAUNCH_DURATION);
-        boolean isRunningTask = v.isRunningTask();
-        TransformParams params = null;
-        TaskViewSimulator tvs = null;
-        RecentsView recentsView = v.getRecentsView();
-        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask) {
-            params = recentsView.getLiveTileParams();
-            tvs = recentsView.getLiveTileTaskViewSimulator();
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
+            @NonNull Runnable finishCallback) {
+
+        final int[] splitRoots = new int[2];
+        for (int i = 0; i < appTargets.length; ++i) {
+            final int taskId = appTargets[i].taskInfo != null ? appTargets[i].taskInfo.taskId : -1;
+            final int mode = appTargets[i].mode;
+            if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
+                if (mode != MODE_OPENING) {
+                    throw new IllegalStateException(
+                            "Expected task to be opening, but it is " + mode);
+                }
+                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] = i;
+            }
         }
 
-        boolean inLiveTileMode =
-                ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1;
-        final RemoteAnimationTargets targets =
-                new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
-                        inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
+        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
 
-        if (params == null) {
-            SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
-            targets.addReleaseCheck(applier);
-
-            params = new TransformParams()
-                    .setSyncTransactionApplier(applier)
-                    .setTargetSet(targets);
+        // This is where we should animate the split roots. For now, though, just make them visible.
+        for (int i = 0; i < 2; ++i) {
+            t.show(appTargets[splitRoots[i]].leash.getSurfaceControl());
+            t.setAlpha(appTargets[splitRoots[i]].leash.getSurfaceControl(), 1.f);
         }
 
-        Rect crop = new Rect();
-        Context context = v.getContext();
-        DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
-        if (tvs == null && targets.apps.length > 0) {
-            tvs = new TaskViewSimulator(recentsView.getContext(), recentsView.getSizeStrategy());
-            tvs.setDp(dp);
+        // This contains the initial state (before animation), so apply this at the beginning of
+        // the animation.
+        t.apply();
 
-            // RecentsView never updates the display rotation until swipe-up so the value may
-            // be stale. Use the display value instead.
-            int displayRotation = DisplayController.INSTANCE.get(recentsView.getContext())
-                    .getInfo().rotation;
-            tvs.getOrientationState().update(displayRotation, displayRotation);
-
-            tvs.setPreview(targets.apps[targets.apps.length - 1]);
-            tvs.fullScreenProgress.value = 0;
-            tvs.recentsViewScale.value = 1;
-//            tvs.setScroll(startScroll);
-
-            // Fade in the task during the initial 20% of the animation
-            out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1,
-                    clampToProgress(LINEAR, 0, 0.2f));
-        }
-
-        TaskViewSimulator topMostSimulator = null;
-
-        if (tvs != null) {
-            out.setFloat(tvs.fullScreenProgress,
-                    AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
-            out.setFloat(tvs.recentsViewScale,
-                    AnimatedFloat.VALUE, tvs.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
-            out.setFloat(tvs.recentsViewScroll,
-                    AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
-
-            TaskViewSimulator finalTsv = tvs;
-            TransformParams finalParams = params;
-            out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
-            topMostSimulator = tvs;
-        }
-
-        anim.play(out.buildAnim());
+        // Once there is an animation, this should be called AFTER the animation completes.
+        finishCallback.run();
     }
 
     public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
@@ -490,6 +453,10 @@
         PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
         createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
                 nonAppTargets, depthController, pa);
+        if (launcherClosing) {
+            // TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
+            TaskViewUtils.setDividerBarShown(nonAppTargets, true);
+        }
 
         Animator childStateAnimation = null;
         // Found a visible recents task that matches the opening app, lets launch the app from there
@@ -542,4 +509,19 @@
         stateManager.setCurrentAnimation(anim, childStateAnimation);
         anim.addListener(windowAnimEndListener);
     }
+
+    static void setDividerBarShown(RemoteAnimationTargetCompat[] nonApps, boolean shown) {
+        // TODO(b/182592057): make this part of the animations instead.
+        if (nonApps != null && nonApps.length > 0) {
+            for (int i = 0; i < nonApps.length; ++i) {
+                final RemoteAnimationTargetCompat targ = nonApps[i];
+                if (targ.windowType == TYPE_DOCK_DIVIDER) {
+                    SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+                    t.setVisibility(targ.leash.getSurfaceControl(), shown);
+                    t.apply();
+                    t.close();
+                }
+            }
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index bfd9008..c515bdf 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -65,7 +65,7 @@
  * This class has initial default state assuming the device and foreground app have
  * no ({@link Surface#ROTATION_0} rotation.
  */
-public final class RecentsOrientedState implements
+public class RecentsOrientedState implements
         SharedPreferences.OnSharedPreferenceChangeListener {
 
     private static final String TAG = "RecentsOrientedState";
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index a147b68..2351a4e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -22,33 +22,26 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 
-import android.animation.AnimatorSet;
-import android.app.ActivityOptions;
+import android.app.ActivityThread;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
-import android.util.Pair;
 import android.view.Gravity;
+import android.view.RemoteAnimationAdapter;
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.LauncherAnimationRunner;
-import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
 import com.android.launcher3.R;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.TaskViewUtils;
 import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -92,37 +85,27 @@
                     ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
                     : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
 
-            RemoteSplitLaunchAnimationRunner animationRunner =
-                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+            RemoteSplitLaunchTransitionRunner animationRunner =
+                    new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
             mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
                     null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
                     new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
-            return;
+        } else {
+            // Assume initial task is for top/left part of screen
+            final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
+                    ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
+                    : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
+
+            RemoteSplitLaunchAnimationRunner animationRunner =
+                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+            final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+                    RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
+                    300, 150,
+                    ActivityThread.currentActivityThread().getApplicationThread());
+
+            mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], null /* mainOptions */,
+                    taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, adapter);
         }
-        // Assume initial mInitialTaskId is for top/left part of screen
-        RemoteAnimationFactory initialSplitRunnerWrapped =  new SplitLaunchAnimationRunner(
-                mInitialTaskView, 0);
-        RemoteAnimationFactory secondarySplitRunnerWrapped =  new SplitLaunchAnimationRunner(
-                taskView, 1);
-        RemoteAnimationRunnerCompat initialSplitRunner = new LauncherAnimationRunner(
-                new Handler(Looper.getMainLooper()), initialSplitRunnerWrapped,
-                true /* startAtFrontOfQueue */);
-        RemoteAnimationRunnerCompat secondarySplitRunner = new LauncherAnimationRunner(
-                new Handler(Looper.getMainLooper()), secondarySplitRunnerWrapped,
-                true /* startAtFrontOfQueue */);
-        ActivityOptions initialOptions = ActivityOptionsCompat.makeRemoteAnimation(
-                new RemoteAnimationAdapterCompat(initialSplitRunner, 300, 150));
-        ActivityOptions secondaryOptions = ActivityOptionsCompat.makeRemoteAnimation(
-                new RemoteAnimationAdapterCompat(secondarySplitRunner, 300, 150));
-        mSystemUiProxy.startTask(mInitialTaskView.getTask().key.id, mInitialPosition.mStageType,
-                mInitialPosition.mStagePosition,
-                /*null*/ initialOptions.toBundle());
-        Pair<Integer, Integer> compliment = getComplimentaryStageAndPosition(mInitialPosition);
-        mSystemUiProxy.startTask(taskView.getTask().key.id, compliment.first,
-                compliment.second,
-                /*null*/ secondaryOptions.toBundle());
-        // After successful launch, call resetState
-        resetState();
     }
 
     /**
@@ -153,12 +136,12 @@
     /**
      * Requires Shell Transitions
      */
-    private class RemoteSplitLaunchAnimationRunner implements RemoteTransitionRunner {
+    private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {
 
         private final TaskView mInitialTaskView;
         private final TaskView mTaskView;
 
-        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+        RemoteSplitLaunchTransitionRunner(TaskView initialTaskView, TaskView taskView) {
             mInitialTaskView = initialTaskView;
             mTaskView = taskView;
         }
@@ -175,48 +158,34 @@
 
     /**
      * LEGACY
-     * @return the opposite stage and position from the {@param position} provided as first and
-     *         second object, respectively
-     * Ex. If position is has stage = Main and position = Top/Left, this will return
-     * Pair(stage=Side, position=Bottom/Left)
-     */
-    private Pair<Integer, Integer> getComplimentaryStageAndPosition(SplitPositionOption position) {
-        // Right now this is as simple as flipping between 0 and 1
-        int complimentStageType = position.mStageType ^ 1;
-        int complimentStagePosition = position.mStagePosition ^ 1;
-        return new Pair<>(complimentStageType, complimentStagePosition);
-    }
-
-    /**
-     * LEGACY
      * Remote animation runner for animation to launch an app.
      */
-    private class SplitLaunchAnimationRunner implements RemoteAnimationFactory {
+    private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {
 
-        private final TaskView mV;
-        private final int mTargetState;
+        private final TaskView mInitialTaskView;
+        private final TaskView mTaskView;
 
-        SplitLaunchAnimationRunner(TaskView v, int targetState) {
-            mV = v;
-            mTargetState = targetState;
+        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+            mInitialTaskView = initialTaskView;
+            mTaskView = taskView;
         }
 
         @Override
-        public void onCreateAnimation(int transit,
-                RemoteAnimationTargetCompat[] appTargets,
-                RemoteAnimationTargetCompat[] wallpaperTargets,
-                RemoteAnimationTargetCompat[] nonAppTargets,
-                LauncherAnimationRunner.AnimationResult result) {
-            AnimatorSet anim = new AnimatorSet();
-            BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
-            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(anim, mV,
-                    appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
-                    activity.getDepthController(), mTargetState);
-            result.setAnimation(anim, activity);
+        public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
+                RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
+                Runnable finishedCallback) {
+            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTaskView, mTaskView, apps,
+                    wallpapers, nonApps, finishedCallback);
+            // After successful launch, call resetState
+            resetState();
+        }
+
+        @Override
+        public void onAnimationCancelled() {
+            resetState();
         }
     }
 
-
     /**
      * To be called if split select was cancelled
      */
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 0103acf..897dfbe 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -82,6 +82,7 @@
 import android.text.TextPaint;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -128,8 +129,8 @@
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.ResourceBasedOverride.Overrides;
-import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TranslateEdgeEffect;
@@ -988,6 +989,7 @@
     @Override
     protected void onPageBeginTransition() {
         super.onPageBeginTransition();
+        Log.d("b/193125090", "Disabling ActionsView due to scrolling");
         mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true);
     }
 
@@ -995,7 +997,10 @@
     protected void onPageEndTransition() {
         super.onPageEndTransition();
         if (isClearAllHidden()) {
+            Log.d("b/193125090", "Enabling ActionsView due after scrolling");
             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
+        } else {
+            Log.d("b/193125090", "Not enabling ActionsView due to ClearAll not hidden");
         }
         if (getNextPage() > 0) {
             setSwipeDownShouldLaunchApp(true);
@@ -1159,6 +1164,7 @@
         }
         if (mFocusedTaskId == -1 && getTaskViewCount() > 0) {
             mFocusedTaskId = getTaskViewAt(0).getTaskId();
+            Log.d("b/193125090", "applyLoadPlan - mFocusedTaskId: " + mFocusedTaskId);
         }
         updateTaskSize();
 
@@ -1475,14 +1481,22 @@
     }
 
     private void updateActionsViewScrollAlpha() {
+        Log.d("b/193125090", "updateActionsViewScrollAlpha - showAsGrid: " + showAsGrid());
         float scrollAlpha = 1f;
         if (showAsGrid()) {
             TaskView focusedTaskView = getFocusedTaskView();
+            Log.d("b/193125090",
+                    "updateActionsViewScrollAlpha - focusedTaskView: " + focusedTaskView);
             if (focusedTaskView != null) {
                 float scrollDiff = Math.abs(getScrollForPage(indexOfChild(focusedTaskView))
                         - mOrientationHandler.getPrimaryScroll(this));
                 float delta = (mGridSideMargin - scrollDiff) / (float) mGridSideMargin;
                 scrollAlpha = Utilities.boundToRange(delta, 0, 1);
+                Log.d("b/193125090",
+                        "updateActionsViewScrollAlpha - focusedTaskScroll: " + getScrollForPage(
+                                indexOfChild(focusedTaskView)) + ", primaryScroll: "
+                                + mOrientationHandler.getPrimaryScroll(this) + ", mGridSideMargin: "
+                                + mGridSideMargin);
             }
         }
         mActionsView.getScrollAlpha().setValue(scrollAlpha);
@@ -2742,6 +2756,7 @@
 
     @Override
     public void setVisibility(int visibility) {
+        Log.d("b/193125090", "setVisibility: " + visibility);
         super.setVisibility(visibility);
         if (mActionsView != null) {
             mActionsView.updateHiddenFlags(HIDDEN_NO_RECENTS, visibility != VISIBLE);
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index cb51d66..1345a94 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -25,6 +25,8 @@
 import android.graphics.Outline;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RectShape;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -226,6 +228,8 @@
         PagedOrientationHandler orientationHandler = taskView.getPagedOrientationHandler();
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
         orientationHandler.setTaskMenuAroundTaskView(this, mTaskInsetMargin);
+
+        // Get Position
         mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
         Rect insets = mActivity.getDragLayer().getInsets();
         BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
@@ -237,8 +241,15 @@
         setLayoutParams(params);
         setScaleX(taskView.getScaleX());
         setScaleY(taskView.getScaleY());
+
+        // Set divider spacing
+        ShapeDrawable divider = new ShapeDrawable(new RectShape());
+        divider.getPaint().setColor(getResources().getColor(android.R.color.transparent));
+        int dividerSpacing = (int) getResources().getDimension(R.dimen.task_menu_spacing);
+        mOptionLayout.setShowDividers(SHOW_DIVIDER_MIDDLE);
+
         orientationHandler.setTaskOptionsMenuLayoutOrientation(
-                mActivity.getDeviceProfile(), mOptionLayout);
+                mActivity.getDeviceProfile(), mOptionLayout, dividerSpacing, divider);
         setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top, 0);
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index e236fc0..b272def 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -794,6 +794,7 @@
         mIconView.setRotation(orientationHandler.getDegreesRotated());
         snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
         mSnapshotView.setLayoutParams(snapshotParams);
+        getThumbnail().getTaskOverlay().updateOrientationState(orientationState);
     }
 
     private void setIconAndDimTransitionProgress(float progress, boolean invert) {
diff --git a/res/drawable/padded_rounded_action_button.xml b/res/drawable/padded_rounded_action_button.xml
new file mode 100644
index 0000000..900f5fc
--- /dev/null
+++ b/res/drawable/padded_rounded_action_button.xml
@@ -0,0 +1,30 @@
+<?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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item android:bottom="8dp" android:top="8dp">
+        <shape android:shape="rectangle">
+
+        <corners android:radius="@dimen/rounded_button_radius" />
+        <stroke android:width="1dp" android:color="?androidprv:attr/colorAccentPrimaryVariant" />
+        <padding
+            android:left="@dimen/rounded_button_padding"
+            android:right="@dimen/rounded_button_padding" />
+        </shape>
+    </item>
+</layer-list>
+
diff --git a/res/drawable/work_card.xml b/res/drawable/work_card.xml
index 7048955..4a66cac 100644
--- a/res/drawable/work_card.xml
+++ b/res/drawable/work_card.xml
@@ -19,6 +19,6 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="rectangle">
     <solid android:color="?androidprv:attr/colorSurface" />
-    <corners android:radius="@dimen/work_edu_card_margin" />
+    <corners android:radius="@dimen/work_edu_card_radius" />
 </shape>
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ef324e0..a4a562e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -120,14 +120,17 @@
 
 <!-- Floating action button inside work tab to toggle work profile -->
     <dimen name="work_fab_height">56dp</dimen>
-    <dimen name="work_fab_radius">24dp</dimen>
+    <dimen name="work_fab_radius">28dp</dimen>
     <dimen name="work_card_padding_horizontal">24dp</dimen>
     <dimen name="work_card_padding_vertical">32dp</dimen>
     <dimen name="work_fab_margin">16dp</dimen>
     <dimen name="work_profile_footer_padding">20dp</dimen>
     <dimen name="work_profile_footer_text_size">16sp</dimen>
     <dimen name="work_edu_card_margin">16dp</dimen>
+    <dimen name="work_edu_card_radius">28dp</dimen>
 
+    <!-- rounded button shown inside card views, and snack bars  -->
+    <dimen name="padded_rounded_button_height">48dp</dimen>
     <dimen name="rounded_button_height">32dp</dimen>
     <dimen name="rounded_button_radius">16dp</dimen>
     <dimen name="rounded_button_padding">8dp</dimen>
diff --git a/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java b/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
index c18e26c..1090d1e 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
@@ -52,15 +52,15 @@
 
 @RunWith(RobolectricTestRunner.class)
 public class CachingWidgetPreviewLoaderTest {
-    private static final Size SIZE_10_10 = new Size(10, 10);
-    private static final Size SIZE_20_20 = new Size(20, 20);
+    private final Size SIZE_10_10 = new Size(10, 10);
+    private final Size SIZE_20_20 = new Size(20, 20);
     private static final String TEST_PACKAGE = "com.example.test";
-    private static final ComponentName TEST_PROVIDER =
+    private final ComponentName TEST_PROVIDER =
             new ComponentName(TEST_PACKAGE, ".WidgetProvider");
-    private static final ComponentName TEST_PROVIDER2 =
+    private final ComponentName TEST_PROVIDER2 =
             new ComponentName(TEST_PACKAGE, ".WidgetProvider2");
-    private static final Bitmap BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
-    private static final Bitmap BITMAP2 = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888);
+    private final Bitmap BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+    private final Bitmap BITMAP2 = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888);
 
 
     @Mock private CancellationSignal mCancellationSignal;
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 11c9649..d047eca 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -29,6 +29,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.ShapeDrawable;
 import android.util.FloatProperty;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -269,8 +270,11 @@
 
     @Override
     public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
-        LinearLayout taskMenuLayout) {
+            LinearLayout taskMenuLayout, int dividerSpacing,
+            ShapeDrawable dividerDrawable) {
         taskMenuLayout.setOrientation(LinearLayout.HORIZONTAL);
+        dividerDrawable.setIntrinsicWidth(dividerSpacing);
+        taskMenuLayout.setDividerDrawable(dividerDrawable);
     }
 
     @Override
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index e0b89c7..266e05f 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -22,6 +22,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.ShapeDrawable;
 import android.util.FloatProperty;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -123,7 +124,8 @@
      * inside task menu view.
      */
     void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
-            LinearLayout taskMenuLayout);
+            LinearLayout taskMenuLayout, int dividerSpacing,
+            ShapeDrawable dividerDrawable);
     /**
      * Sets layout param attributes for {@link com.android.launcher3.popup.SystemShortcut} child
      * views inside task menu view.
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index dcbb7ca..dd97af5 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -27,6 +27,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.ShapeDrawable;
 import android.util.FloatProperty;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -274,14 +275,18 @@
 
     @Override
     public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
-        LinearLayout taskMenuLayout) {
+            LinearLayout taskMenuLayout, int dividerSpacing,
+            ShapeDrawable dividerDrawable) {
         if (deviceProfile.isLandscape && !deviceProfile.isTablet) {
             // Phone landscape
             taskMenuLayout.setOrientation(LinearLayout.HORIZONTAL);
+            dividerDrawable.setIntrinsicWidth(dividerSpacing);
         } else {
             // Phone Portrait, LargeScreen Landscape/Portrait
             taskMenuLayout.setOrientation(LinearLayout.VERTICAL);
+            dividerDrawable.setIntrinsicHeight(dividerSpacing);
         }
+        taskMenuLayout.setDividerDrawable(dividerDrawable);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index a5c142d..12fd026 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -51,6 +51,8 @@
 public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
         implements OnClickListener, OnLongClickListener, DragSource,
         PopupDataProvider.PopupDataChangeListener, Insettable {
+    /** The default number of cells that can fit horizontally in a widget sheet. */
+    protected static final int DEFAULT_MAX_HORIZONTAL_SPANS = 4;
     /**
      * The maximum scale, [0, 1], of the device screen width that the widgets picker can consume
      * on large screen devices.
@@ -152,6 +154,17 @@
                 MeasureSpec.getSize(heightMeasureSpec));
     }
 
+    /** Returns the number of cells that can fit horizontally in a given {@code content}. */
+    protected int computeMaxHorizontalSpans(View content, int contentHorizontalPaddingPx) {
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+        int availableWidth = content.getMeasuredWidth() - contentHorizontalPaddingPx;
+        Point cellSize = deviceProfile.getCellSize();
+        if (cellSize.x > 0) {
+            return availableWidth / cellSize.x;
+        }
+        return DEFAULT_MAX_HORIZONTAL_SPANS;
+    }
+
     private boolean beginDraggingWidget(WidgetCell v) {
         // Get the widget preview as the drag representation
         WidgetImageView image = v.getWidgetView();
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index c045cf1..14aeaf6 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -70,9 +70,11 @@
     private static final int DEFAULT_CLOSE_DURATION = 200;
     private static final long EDUCATION_TIP_DELAY_MS = 300;
 
+    private final int mWidgetSheetContentHorizontalPadding;
+
     private ItemInfo mOriginalItemInfo;
     private final int mMaxTableHeight;
-    private int mMaxHorizontalSpan = 4;
+    private int mMaxHorizontalSpan = DEFAULT_MAX_HORIZONTAL_SPANS;
 
     private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
             new OnLayoutChangeListener() {
@@ -117,6 +119,9 @@
         if (!hasSeenEducationTip()) {
             addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
         }
+
+        mWidgetSheetContentHorizontalPadding = getResources().getDimensionPixelSize(
+                R.dimen.widget_list_horizontal_margin);
     }
 
     @Override
@@ -137,10 +142,8 @@
     private boolean updateMaxSpansPerRow() {
         if (getMeasuredWidth() == 0) return false;
 
-        int paddingPx = 2 * getResources().getDimensionPixelOffset(
-                R.dimen.widget_cell_horizontal_padding);
-        int maxHorizontalSpan = findViewById(R.id.widgets_table).getMeasuredWidth()
-                / (mActivityContext.getDeviceProfile().cellWidthPx + paddingPx);
+        int maxHorizontalSpan = computeMaxHorizontalSpans(mContent,
+                mWidgetSheetContentHorizontalPadding);
         if (mMaxHorizontalSpan != maxHorizontalSpan) {
             // Ensure the table layout is showing widgets in the right column after measure.
             mMaxHorizontalSpan = maxHorizontalSpan;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 6c2cca6..5e1a534 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.pm.LauncherApps;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Process;
 import android.os.UserHandle;
@@ -148,13 +149,13 @@
     private final int mTabsHeight;
     private final int mViewPagerTopPadding;
     private final int mSearchAndRecommendationContainerBottomMargin;
-    private final int mWidgetCellHorizontalPadding;
+    private final int mWidgetSheetContentHorizontalPadding;
 
     @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
     @Nullable private PersonalWorkPagedView mViewPager;
     private boolean mIsInSearchMode;
     private boolean mIsNoWidgetsViewNeeded;
-    private int mMaxSpansPerRow = 4;
+    private int mMaxSpansPerRow = DEFAULT_MAX_HORIZONTAL_SPANS;
     private View mTabsView;
     private TextView mNoWidgetsView;
     private SearchAndRecommendationViewHolder mSearchAndRecommendationViewHolder;
@@ -166,19 +167,20 @@
         mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
         mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
         mAdapters.put(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
+
+        Resources resources = getResources();
         mTabsHeight = mHasWorkProfile
-                ? getContext().getResources()
-                        .getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
+                ? resources.getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
                 : 0;
         mViewPagerTopPadding = mHasWorkProfile
                 ? getContext().getResources()
                     .getDimensionPixelSize(R.dimen.widget_picker_view_pager_top_padding)
                 : 0;
-        mSearchAndRecommendationContainerBottomMargin = getContext().getResources()
-                .getDimensionPixelSize(mHasWorkProfile
+        mSearchAndRecommendationContainerBottomMargin = resources.getDimensionPixelSize(
+                mHasWorkProfile
                         ? R.dimen.search_and_recommended_widgets_container_small_bottom_margin
                         : R.dimen.search_and_recommended_widgets_container_bottom_margin);
-        mWidgetCellHorizontalPadding = 2 * getResources().getDimensionPixelOffset(
+        mWidgetSheetContentHorizontalPadding = 2 * resources.getDimensionPixelSize(
                 R.dimen.widget_cell_horizontal_padding);
     }
 
@@ -375,11 +377,10 @@
     private boolean updateMaxSpansPerRow() {
         if (getMeasuredWidth() == 0) return false;
 
-        int previousMaxSpansPerRow = mMaxSpansPerRow;
-        mMaxSpansPerRow = getMeasuredWidth()
-                / (mActivityContext.getDeviceProfile().cellWidthPx + mWidgetCellHorizontalPadding);
-
-        if (previousMaxSpansPerRow != mMaxSpansPerRow) {
+        int maxHorizontalSpans = computeMaxHorizontalSpans(mContent,
+                mWidgetSheetContentHorizontalPadding);
+        if (mMaxSpansPerRow != maxHorizontalSpans) {
+            mMaxSpansPerRow = maxHorizontalSpans;
             mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
                     mMaxSpansPerRow);
             mAdapters.get(AdapterHolder.SEARCH).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(