Merge "Fix taskbar hotseat alignment"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3984890..b459b2d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -58,6 +58,7 @@
             android:enabled="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.SHOW_WORK_APPS" />
                 <category android:name="android.intent.category.HOME" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.MONKEY"/>
diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml
index 2848b0f..1ad20cc 100644
--- a/quickstep/res/layout/taskbar_all_apps.xml
+++ b/quickstep/res/layout/taskbar_all_apps.xml
@@ -30,6 +30,10 @@
         android:theme="?attr/allAppsTheme">
 
         <include
+            layout="@layout/all_apps_bottom_sheet_background"
+            android:visibility="gone" />
+
+        <include
             layout="@layout/all_apps_rv_layout"
             android:visibility="gone" />
 
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 49b2cc5..3eb1935e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
 
@@ -75,6 +76,7 @@
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Pair;
 import android.util.Size;
 import android.view.SurfaceControl;
@@ -683,6 +685,18 @@
         appAnimator.addListener(floatingView);
         appAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
+            public void onAnimationStart(Animator animation) {
+                LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
+                if (taskbarController != null && taskbarController.shouldShowEdu()) {
+                    // LAUNCHER_TASKBAR_EDUCATION_SHOWING is set to true here, when the education
+                    // flow is about to start, to avoid a race condition with other components
+                    // that would show something else to the user as soon as the app is opened.
+                    Settings.Secure.putInt(mLauncher.getContentResolver(),
+                            LAUNCHER_TASKBAR_EDUCATION_SHOWING, 1);
+                }
+            }
+
+            @Override
             public void onAnimationEnd(Animator animation) {
                 if (v instanceof BubbleTextView) {
                     ((BubbleTextView) v).setStayPressed(false);
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index d4bbfa2..3f29e43 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -138,12 +138,12 @@
             if (mLastDragItem == null) {
                 return;
             }
-            if (isTrackedForHotseatPrediction(atomInfo)) {
-                sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION);
-            }
             if (isTrackedForHotseatPrediction(mLastDragItem)) {
                 sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
             }
+            if (isTrackedForHotseatPrediction(atomInfo)) {
+                sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION);
+            }
             if (isTrackedForWidgetPrediction(atomInfo)) {
                 sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 4132c68..0f91aa2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -216,9 +216,7 @@
      * Starts the taskbar education flow, if the user hasn't seen it yet.
      */
     public void showEdu() {
-        if (!FeatureFlags.ENABLE_TASKBAR_EDU.get()
-                || Utilities.IS_RUNNING_IN_TEST_HARNESS
-                || mLauncher.getOnboardingPrefs().getBoolean(OnboardingPrefs.TASKBAR_EDU_SEEN)) {
+        if (!shouldShowEdu()) {
             return;
         }
         mLauncher.getOnboardingPrefs().markChecked(OnboardingPrefs.TASKBAR_EDU_SEEN);
@@ -227,6 +225,15 @@
     }
 
     /**
+     * Whether the taskbar education should be shown.
+     */
+    public boolean shouldShowEdu() {
+        return FeatureFlags.ENABLE_TASKBAR_EDU.get()
+                && !Utilities.IS_RUNNING_IN_TEST_HARNESS
+                && !mLauncher.getOnboardingPrefs().getBoolean(OnboardingPrefs.TASKBAR_EDU_SEEN);
+    }
+
+    /**
      * Manually ends the taskbar education flow.
      */
     public void hideEdu() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index e152915..435eae4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -15,6 +15,11 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Intent;
@@ -27,7 +32,9 @@
 import android.os.UserHandle;
 import android.view.DragEvent;
 import android.view.MotionEvent;
+import android.view.SurfaceControl;
 import android.view.View;
+import android.view.ViewRootImpl;
 
 import androidx.annotation.Nullable;
 
@@ -39,20 +46,25 @@
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragDriver;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ClipDescriptionCompat;
 import com.android.systemui.shared.system.LauncherAppsCompat;
@@ -66,6 +78,8 @@
 public class TaskbarDragController extends DragController<TaskbarActivityContext> implements
         TaskbarControllers.LoggableTaskbarController {
 
+    private static boolean DEBUG_DRAG_SHADOW_SURFACE = false;
+
     private final int mDragIconSize;
     private final int[] mTempXY = new int[2];
 
@@ -78,6 +92,9 @@
 
     private boolean mIsSystemDragInProgress;
 
+    // Animation for the drag shadow back into position after an unsuccessful drag
+    private ValueAnimator mReturnAnimator;
+
     public TaskbarDragController(TaskbarActivityContext activity) {
         super(activity);
         Resources resources = mActivity.getResources();
@@ -279,6 +296,9 @@
             @Override
             public void onDrawShadow(Canvas canvas) {
                 canvas.save();
+                if (DEBUG_DRAG_SHADOW_SURFACE) {
+                    canvas.drawColor(0xffff0000);
+                }
                 float scale = mDragObject.dragView.getScaleX();
                 canvas.scale(scale, scale);
                 mDragObject.dragView.draw(canvas);
@@ -337,8 +357,9 @@
 
             ClipData clipData = new ClipData(clipDescription, new ClipData.Item(intent));
             if (btv.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
-                    View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE)) {
-                onSystemDragStarted();
+                    View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE
+                            | View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION)) {
+                onSystemDragStarted(btv);
 
                 mActivity.getStatsLogManager().logger().withItemInfo(mDragObject.dragInfo)
                         .withInstanceId(launcherInstanceId)
@@ -347,7 +368,7 @@
         }
     }
 
-    private void onSystemDragStarted() {
+    private void onSystemDragStarted(BubbleTextView btv) {
         mIsSystemDragInProgress = true;
         mActivity.getDragLayer().setOnDragListener((view, dragEvent) -> {
             switch (dragEvent.getAction()) {
@@ -356,7 +377,12 @@
                     return true;
                 case DragEvent.ACTION_DRAG_ENDED:
                     mIsSystemDragInProgress = false;
-                    maybeOnDragEnd();
+                    if (dragEvent.getResult()) {
+                        maybeOnDragEnd();
+                    } else {
+                        // This will take care of calling maybeOnDragEnd() after the animation
+                        animateGlobalDragViewToOriginalPosition(btv, dragEvent);
+                    }
                     return true;
             }
             return false;
@@ -382,6 +408,93 @@
         maybeOnDragEnd();
     }
 
+    private void animateGlobalDragViewToOriginalPosition(BubbleTextView btv,
+            DragEvent dragEvent) {
+        SurfaceControl dragSurface = dragEvent.getDragSurface();
+
+        // For top level icons, the target is the icon itself
+        View target = btv;
+        Object tag = btv.getTag();
+        if (tag instanceof ItemInfo) {
+            ItemInfo item = (ItemInfo) tag;
+            TaskbarViewController taskbarViewController = mControllers.taskbarViewController;
+            if (item.container == CONTAINER_ALL_APPS) {
+                // Since all apps closes when the drag starts, target the all apps button instead
+                target = taskbarViewController.getAllAppsButtonView();
+            } else if (item.container >= 0) {
+                // Since folders close when the drag starts, target the folder icon instead
+                LauncherBindableItemsContainer.ItemOperator op = (info, v) -> {
+                    if (info instanceof FolderInfo && v instanceof FolderIcon) {
+                        FolderInfo fi = (FolderInfo) info;
+                        for (WorkspaceItemInfo si : fi.contents) {
+                            if (si.id == item.id) {
+                                // Found the parent
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                };
+                target = taskbarViewController.mapOverItems(op);
+            }
+        }
+
+        // Finish any pending return animation before starting a new drag
+        if (mReturnAnimator != null) {
+            mReturnAnimator.end();
+        }
+
+        float fromX = dragEvent.getX() - dragEvent.getOffsetX();
+        float fromY = dragEvent.getY() - dragEvent.getOffsetY();
+        int[] toPosition = target.getLocationOnScreen();
+        float toScale = (float) target.getWidth() / mDragIconSize;
+        float toAlpha = (target == btv) ? 1f : 0f;
+        final ViewRootImpl viewRoot = target.getViewRootImpl();
+        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+        mReturnAnimator = ValueAnimator.ofFloat(0f, 1f);
+        mReturnAnimator.setDuration(300);
+        mReturnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        mReturnAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = animation.getAnimatedFraction();
+                float accelT = Interpolators.ACCEL_2.getInterpolation(t);
+                float scale = 1f - t * (1f - toScale);
+                float alpha = 1f - accelT * (1f - toAlpha);
+                tx.setPosition(dragSurface, Utilities.mapRange(t, fromX, toPosition[0]),
+                        Utilities.mapRange(t, fromY, toPosition[1]));
+                tx.setScale(dragSurface, scale, scale);
+                tx.setAlpha(dragSurface, alpha);
+                tx.apply();
+            }
+        });
+        mReturnAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cleanUpSurface();
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                cleanUpSurface();
+            }
+
+            private void cleanUpSurface() {
+                maybeOnDragEnd();
+                // Synchronize removing the drag surface with the next draw after calling
+                // maybeOnDragEnd()
+                viewRoot.consumeNextDraw((transaction) -> {
+                    transaction.remove(dragSurface);
+                    transaction.apply();
+                    tx.close();
+                });
+                viewRoot.getView().invalidate();
+                mReturnAnimator = null;
+            }
+        });
+        mReturnAnimator.start();
+    }
+
     @Override
     protected float getX(MotionEvent ev) {
         // We will resize to fill the screen while dragging, so use screen coordinates. This ensures
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
index 8525427..89d67be 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
@@ -20,6 +20,7 @@
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.graphics.Rect;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.view.View;
@@ -92,6 +93,14 @@
         getPopupContainer().addView(this, 1);
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0);
+    }
+
     /** Show the Education flow. */
     public void show() {
         attachToContainer();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index fddd1ed..ade58a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -32,6 +32,7 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.FolderInfo;
@@ -214,7 +215,8 @@
         }
 
         if (mAllAppsButton != null) {
-            addView(mAllAppsButton);
+            int index = Utilities.isRtl(getResources()) ? 0 : getChildCount();
+            addView(mAllAppsButton, index);
         }
     }
 
@@ -316,6 +318,13 @@
         return icons;
     }
 
+    /**
+     * Returns the all apps button in the taskbar.
+     */
+    public View getAllAppsButtonView() {
+        return mAllAppsButton;
+    }
+
     // FolderIconParent implemented methods.
 
     @Override
@@ -357,13 +366,18 @@
         return getVisibility() == VISIBLE;
     }
 
-    protected void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
+    /**
+     * Maps {@code op} over all the child views, returning the view that {@code op} evaluates
+     * {@code true} for, or {@code null} if none satisfy {@code op}.
+     */
+    protected View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
         // map over all the shortcuts on the taskbar
         for (int i = 0; i < getChildCount(); i++) {
             View item = getChildAt(i);
             if (op.evaluate((ItemInfo) item.getTag(), item)) {
-                return;
+                return item;
             }
         }
+        return null;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 84367fa..8b6831b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -164,6 +164,10 @@
         return mTaskbarView.getIconViews();
     }
 
+    public View getAllAppsButtonView() {
+        return mTaskbarView.getAllAppsButtonView();
+    }
+
     public AnimatedFloat getTaskbarIconScaleForStash() {
         return mTaskbarIconScaleForStash;
     }
@@ -235,7 +239,9 @@
             if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() && i == count - 1) {
                 // Note that there is no All Apps button in the hotseat, this position is only used
                 // as its convenient for animation purposes.
-                positionInHotseat = mActivity.getDeviceProfile().inv.numShownHotseatIcons;
+                positionInHotseat = Utilities.isRtl(child.getResources())
+                        ? -1
+                        : mActivity.getDeviceProfile().inv.numShownHotseatIcons;
 
                 setter.setViewAlpha(child, 0, LINEAR);
             } else if (child.getTag() instanceof ItemInfo) {
@@ -268,8 +274,8 @@
         mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
     }
 
-    public void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
-        mTaskbarView.mapOverItems(op);
+    public View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
+        return mTaskbarView.mapOverItems(op);
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e218db1..2cb7100 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1198,10 +1198,10 @@
             // We probably never received an animation controller, skip logging.
             return;
         }
-        int pageIndex = endTarget == LAST_TASK
+        int pageIndex = endTarget == LAST_TASK || mRecentsView == null
                 ? LOG_NO_OP_PAGE_INDEX
                 : mRecentsView.getNextPage();
-        // TODO: set correct container using the pageIndex
+        logger.withRank(pageIndex);
         logger.log(event);
     }
 
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index d2d3ba3..4d13253 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -23,6 +23,7 @@
 import static android.view.MotionEvent.ACTION_UP;
 
 import static com.android.launcher3.states.RotationHelper.deltaRotation;
+
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.RectF;
@@ -359,7 +360,7 @@
                 if (mLastRectTouched == null) {
                     return;
                 }
-                if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+                if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) {
                     if (event.getSurfaceRotation() != mActiveTouchRotation) {
                         // With Shell transitions, we should rotated to the orientation at the start
                         // of the gesture not the current display rotation which will happen early
@@ -378,7 +379,7 @@
                 if (mLastRectTouched == null) {
                     return;
                 }
-                if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+                if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) {
                     if (event.getSurfaceRotation() != mActiveTouchRotation) {
                         // With Shell transitions, we should rotated to the orientation at the start
                         // of the gesture not the current display rotation which will happen early
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 914c939..5e298f4 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -23,9 +23,9 @@
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
 
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Bundle;
 import android.os.SystemProperties;
 import android.util.Log;
 import android.view.RemoteAnimationTarget;
@@ -50,6 +50,8 @@
 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
     public static final boolean ENABLE_SHELL_TRANSITIONS =
             SystemProperties.getBoolean("persist.debug.shell_transit", false);
+    public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
+            && SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
 
     private RecentsAnimationController mController;
     private RecentsAnimationCallbacks mCallbacks;
@@ -196,9 +198,10 @@
             RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks,
                     mController != null ? mController.getController() : null,
                     mCtx.getIApplicationThread());
-            Bundle options = ActivityOptionsCompat.makeRemoteTransition(transition)
-                    .setTransientLaunch().toBundle();
-            UI_HELPER_EXECUTOR.execute(() -> mCtx.startActivity(intent, options));
+            final ActivityOptions options = ActivityOptionsCompat.makeRemoteTransition(transition)
+                    .setTransientLaunch();
+            options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
+            UI_HELPER_EXECUTOR.execute(() -> mCtx.startActivity(intent, options.toBundle()));
         } else {
             UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
                     .startRecentsActivity(intent, eventTime, mCallbacks, null, null));
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index ad52a66..12a638a 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -412,9 +412,8 @@
                     atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */,
                     atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
                     getCardinality(atomInfo) /* cardinality */,
-                    getFeatures(atomInfo) /* features */
-                    // TODO(b/217753033) : Add SearchAttributes field after necessary approval
-                    // getSearchAttributes(atomInfo) /* searchAttributes */
+                    getFeatures(atomInfo) /* features */,
+                    getSearchAttributes(atomInfo) /* searchAttributes */
             );
         }
     }
@@ -572,9 +571,14 @@
     }
 
     private static int getSearchAttributes(LauncherAtom.ItemInfo info) {
-        if (info.getContainerInfo().getExtendedContainers().getDeviceSearchResultContainer()
-                .hasSearchAttributes()) {
-            return searchAttributesToInt(info.getContainerInfo().getExtendedContainers()
+        ContainerInfo containerInfo = info.getContainerInfo();
+        if (containerInfo.getContainerCase() == EXTENDED_CONTAINERS
+                && containerInfo.getExtendedContainers().getContainerCase()
+                == DEVICE_SEARCH_RESULT_CONTAINER
+                && containerInfo.getExtendedContainers()
+                .getDeviceSearchResultContainer().hasSearchAttributes()
+        ) {
+            return searchAttributesToInt(containerInfo.getExtendedContainers()
                     .getDeviceSearchResultContainer().getSearchAttributes());
         }
         return 0;
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index ae8e45a..4f5c368 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -341,7 +341,7 @@
 
     @SurfaceRotation
     public int getDisplayRotation() {
-        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+        if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) {
             // When shell transitions are enabled, both the display and activity rotations should
             // be the same once the gesture starts
             return mRecentsActivityRotation;
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index f66a6de..5212755 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -305,7 +305,7 @@
             mOrientationStateId = mOrientationState.getStateId();
 
             getFullScreenScale();
-            if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+            if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) {
                 // With shell transitions, the display is rotated early so we need to actually use
                 // the rotation when the gesture starts
                 mThumbnailData.rotation = mOrientationState.getTouchRotation();
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 3757cd9..27a748d 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -144,7 +144,6 @@
 
     public void initialize(Task task) {
         mTask = task;
-
         THREAD_POOL_EXECUTOR.execute(() -> {
             final AppUsageLimit usageLimit = mLauncherApps.getAppUsageLimit(
                     task.getTopComponent().getPackageName(),
@@ -321,7 +320,7 @@
                 mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
         PagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
         Pair<Float, Float> translations = orientationHandler
-                .setDwbLayoutParamsAndGetTranslations(mTaskView.getMeasuredWidth(),
+                .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
                         mTaskView.getMeasuredHeight(), mStagedSplitBounds, deviceProfile,
                         mTaskView.getThumbnails(), mTask.key.id, mBanner);
         mSplitOffsetTranslationX = translations.first;
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 3ddec26..af9f818 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -242,6 +242,7 @@
         mIconView2.setDrawableSize(iconDrawableSize, iconDrawableSize);
         mIconView2.setRotation(getPagedOrientationHandler().getDegreesRotated());
         updateIconPlacement();
+        updateSecondaryDwbPlacement();
     }
 
     private void updateIconPlacement() {
@@ -258,6 +259,13 @@
                 isRtl, deviceProfile, mSplitBoundsConfig);
     }
 
+    private void updateSecondaryDwbPlacement() {
+        if (mSecondaryTask == null) {
+            return;
+        }
+        mDigitalWellBeingToast2.initialize(mSecondaryTask);
+    }
+
     @Override
     protected void updateSnapshotRadius() {
         super.updateSnapshotRadius();
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index e26bf73..cdb8082 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -897,6 +897,7 @@
         LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
         orientationHandler.setIconAndSnapshotParams(mIconView, taskIconMargin, taskIconHeight,
                 snapshotParams, isRtl);
+        updateDwbPlacement();
         mSnapshotView.setLayoutParams(snapshotParams);
         iconParams.width = iconParams.height = taskIconHeight;
         mIconView.setLayoutParams(iconParams);
@@ -909,6 +910,10 @@
         mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
     }
 
+    private void updateDwbPlacement() {
+        mDigitalWellBeingToast.initialize(mTask);
+    }
+
     /**
      * Returns whether the task is part of overview grid and not being focused.
      */
diff --git a/res/color-night-v31/accent_ripple_color.xml b/res/color-night-v31/accent_ripple_color.xml
new file mode 100644
index 0000000..cb149d6
--- /dev/null
+++ b/res/color-night-v31/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_accent1_300"/>
+</selector>
\ No newline at end of file
diff --git a/res/color-night/accent_ripple_color.xml b/res/color-night/accent_ripple_color.xml
new file mode 100644
index 0000000..4a37b00
--- /dev/null
+++ b/res/color-night/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#53BCAC"/>
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/accent_ripple_color.xml b/res/color-v31/accent_ripple_color.xml
new file mode 100644
index 0000000..a996228
--- /dev/null
+++ b/res/color-v31/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_accent2_50"/>
+</selector>
\ No newline at end of file
diff --git a/res/color/accent_ripple_color.xml b/res/color/accent_ripple_color.xml
new file mode 100644
index 0000000..697f415
--- /dev/null
+++ b/res/color/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#CDFAF1"/>
+</selector>
\ No newline at end of file
diff --git a/res/drawable/all_apps_tabs_background.xml b/res/drawable/all_apps_tabs_background.xml
index aea2e7a..8471cd4 100644
--- a/res/drawable/all_apps_tabs_background.xml
+++ b/res/drawable/all_apps_tabs_background.xml
@@ -13,23 +13,36 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:enterFadeDuration="100">
-    <item
-        android:id="@+id/unselected"
-        android:state_selected="false">
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/accent_ripple_color">
+
+    <item android:id="@android:id/mask">
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-            <solid android:color="@color/all_apps_tabs_background" />
+            <solid android:color="@color/accent_ripple_color" />
         </shape>
     </item>
 
-    <item
-        android:id="@+id/selected"
-        android:state_selected="true">
-        <shape android:shape="rectangle">
-            <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-            <solid android:color="@color/all_apps_tab_background_selected" />
-        </shape>
+    <item>
+        <selector android:enterFadeDuration="100">
+            <item
+                android:id="@+id/unselected"
+                android:state_selected="false">
+                <shape android:shape="rectangle">
+                    <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+                    <solid android:color="@color/all_apps_tabs_background" />
+                </shape>
+            </item>
+
+            <item
+                android:id="@+id/selected"
+                android:state_selected="true">
+                <shape android:shape="rectangle">
+                    <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+                    <solid android:color="@color/all_apps_tab_background_selected" />
+                </shape>
+            </item>
+        </selector>
     </item>
-</selector>
\ No newline at end of file
+
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/personal_work_tabs_ripple.xml b/res/drawable/personal_work_tabs_ripple.xml
deleted file mode 100644
index 2e57b80..0000000
--- a/res/drawable/personal_work_tabs_ripple.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
--->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
-    <shape android:shape="rectangle">
-        <solid android:color="@android:color/transparent" />
-        <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-    </shape>
-</ripple>
\ No newline at end of file
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 6df6212..2ac7e63 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -26,6 +26,10 @@
     android:saveEnabled="false">
 
     <include
+        layout="@layout/all_apps_bottom_sheet_background"
+        android:visibility="gone" />
+
+    <include
         layout="@layout/all_apps_rv_layout"
         android:visibility="gone" />
 
diff --git a/res/layout/all_apps_bottom_sheet_background.xml b/res/layout/all_apps_bottom_sheet_background.xml
new file mode 100644
index 0000000..ad10d68
--- /dev/null
+++ b/res/layout/all_apps_bottom_sheet_background.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/bottom_sheet_background"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/bg_all_apps_bottom_sheet">
+
+    <View
+        android:id="@+id/bottom_sheet_handle_area"
+        android:layout_width="match_parent"
+        android:layout_height="34dp" />
+
+    <View
+        android:id="@+id/bottom_sheet_handle"
+        android:layout_width="48dp"
+        android:layout_height="2dp"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="16dp"
+        android:layout_marginBottom="16dp"
+        android:background="?android:attr/textColorSecondary" />
+</FrameLayout>
diff --git a/res/layout/secondary_launcher.xml b/res/layout/secondary_launcher.xml
index 3ccd4f2..0fe05ee 100644
--- a/res/layout/secondary_launcher.xml
+++ b/res/layout/secondary_launcher.xml
@@ -42,7 +42,7 @@
         android:onClick="onAppsButtonClicked" />
 
     <view
-        class="com.android.launcher3.allapps.ActivityAllAppsContainerView"
+        class="com.android.launcher3.allapps.SecondaryLauncherAllAppsContainerView"
         android:id="@+id/apps_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -56,6 +56,10 @@
         android:visibility="invisible" >
 
         <include
+            layout="@layout/all_apps_bottom_sheet_background"
+            android:visibility="gone" />
+
+        <include
             layout="@layout/all_apps_rv_layout"
             android:visibility="gone" />
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index fb4a7fd..ebc0c75 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -125,6 +125,7 @@
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.allapps.BaseAllAppsContainerView;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.anim.PropertyListBuilder;
@@ -1579,6 +1580,7 @@
         boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
         boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this);
         hideKeyboard();
+
         if (isActionMain) {
             if (!internalStateHandled) {
                 // In all these cases, only animate if we're already on home
@@ -1607,6 +1609,8 @@
             handleGestureContract(intent);
         } else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) {
             showAllAppsFromIntent(alreadyOnHome);
+        } else if (Intent.ACTION_SHOW_WORK_APPS.equals(intent.getAction())) {
+            showAllAppsWorkTabFromIntent(alreadyOnHome);
         }
 
         TraceHelper.INSTANCE.endSection(traceToken);
@@ -1617,6 +1621,11 @@
         getStateManager().goToState(ALL_APPS, alreadyOnHome);
     }
 
+    private void showAllAppsWorkTabFromIntent(boolean alreadyOnHome) {
+        showAllAppsFromIntent(alreadyOnHome);
+        mAppsView.switchToTab(BaseAllAppsContainerView.AdapterHolder.WORK);
+    }
+
     /**
      * Handles gesture nav contract
      */
@@ -2392,6 +2401,10 @@
                     } else {
                         Log.d(TAG, desc);
                         getModelWriter().deleteItemFromDatabase(item);
+                        if (TestProtocol.sDebugTracing) {
+                            Log.d(TestProtocol.MISSING_PROMISE_ICON,
+                                    TAG + "bindItems failed for item=" + item);
+                        }
                         continue;
                     }
                 }
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 558538c..b81637f 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -24,12 +24,14 @@
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.Executors;
 
 /**
@@ -51,6 +53,9 @@
     private static void processIntent(Context context, Intent intent) {
         if (!isEnabled(context)) {
             // User has decided to not add icons on homescreen.
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + " not enabled");
+            }
             return;
         }
 
@@ -59,6 +64,9 @@
         if (!PackageInstaller.ACTION_SESSION_COMMITTED.equals(intent.getAction())
                 || info == null || user == null) {
             // Invalid intent.
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + " invalid intent");
+            }
             return;
         }
 
@@ -68,6 +76,15 @@
                 || info.getInstallReason() != PackageManager.INSTALL_REASON_USER
                 || packageInstallerCompat.promiseIconAddedForId(info.getSessionId())) {
             packageInstallerCompat.removePromiseIconId(info.getSessionId());
+            if (TestProtocol.sDebugTracing) {
+                int id = info.getSessionId();
+                Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG
+                        + ", TextUtils.isEmpty=" + TextUtils.isEmpty(info.getAppPackageName())
+                        + ", info.getInstallReason()=" + info.getInstallReason()
+                        + ", INSTALL_REASON_USER=" + PackageManager.INSTALL_REASON_USER
+                        + ", icon added=" + packageInstallerCompat.promiseIconAddedForId(id)
+                );
+            }
             return;
         }
 
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index e8dcdbd..a66ae78 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -110,6 +110,8 @@
     private AllAppsPagedView mViewPager;
 
     protected FloatingHeaderView mHeader;
+    private View mBottomSheetBackground;
+    private View mBottomSheetHandleArea;
 
     protected boolean mUsingTabs;
     private boolean mHasWorkApps;
@@ -146,8 +148,6 @@
         mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
 
         mAllAppsStore.addUpdateListener(this::onAppsUpdated);
-
-        updateBackground(mActivityContext.getDeviceProfile());
     }
 
     /** Creates the adapter provider for the main section. */
@@ -222,10 +222,8 @@
         updateBackground(dp);
     }
 
-    private void updateBackground(DeviceProfile deviceProfile) {
-        setBackground(deviceProfile.isTablet
-                ? getContext().getDrawable(R.drawable.bg_all_apps_bottom_sheet)
-                : null);
+    protected void updateBackground(DeviceProfile deviceProfile) {
+        mBottomSheetBackground.setVisibility(deviceProfile.isTablet ? View.VISIBLE : View.GONE);
     }
 
     private void onAppsUpdated() {
@@ -253,7 +251,9 @@
         if (!mActivityContext.getDragLayer().isEventOverView(this, ev)) {
             return true;
         }
-        // TODO(b/216203409) Support dragging down from bottom sheet divider, if present.
+        if (mActivityContext.getDragLayer().isEventOverView(mBottomSheetHandleArea, ev)) {
+            return true;
+        }
         AllAppsRecyclerView rv = getActiveRecyclerView();
         if (rv == null) {
             return true;
@@ -331,6 +331,16 @@
         return mViewPager.getNextPage() == 0;
     }
 
+    /**
+     * Switches the current page to the provided {@code tab} if tabs are supported, otherwise does
+     * nothing.
+     */
+    public void switchToTab(int tab) {
+        if (mUsingTabs) {
+            mViewPager.setCurrentPage(tab);
+        }
+    }
+
     public LayoutInflater getLayoutInflater() {
         return LayoutInflater.from(getContext());
     }
@@ -365,6 +375,11 @@
 
         mHeader = findViewById(R.id.all_apps_header);
         rebindAdapters(true /* force */);
+
+        mBottomSheetBackground = findViewById(R.id.bottom_sheet_background);
+        updateBackground(mActivityContext.getDeviceProfile());
+
+        mBottomSheetHandleArea = findViewById(R.id.bottom_sheet_handle_area);
     }
 
     @Override
@@ -382,7 +397,6 @@
         }
 
         MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
-        mlp.topMargin = grid.isTablet ? insets.top : 0;
         int leftRightMargin = grid.allAppsLeftRightMargin;
         mlp.leftMargin = insets.left + leftRightMargin;
         mlp.rightMargin = insets.right + leftRightMargin;
@@ -391,7 +405,7 @@
         if (grid.isVerticalBarLayout()) {
             setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
         } else {
-            setPadding(0, 0, 0, 0);
+            setPadding(0, grid.isTablet ? insets.top : 0, 0, 0);
         }
 
         InsettableFrameLayout.dispatchInsets(this, insets);
diff --git a/src/com/android/launcher3/allapps/SecondaryLauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/SecondaryLauncherAllAppsContainerView.java
new file mode 100644
index 0000000..0719c43
--- /dev/null
+++ b/src/com/android/launcher3/allapps/SecondaryLauncherAllAppsContainerView.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher;
+
+/**
+ * AllAppsContainerView for secondary launcher
+ */
+public class SecondaryLauncherAllAppsContainerView extends
+        ActivityAllAppsContainerView<SecondaryDisplayLauncher> {
+
+    public SecondaryLauncherAllAppsContainerView(Context context) {
+        this(context, null);
+    }
+
+    public SecondaryLauncherAllAppsContainerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SecondaryLauncherAllAppsContainerView(Context context, AttributeSet attrs,
+            int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void updateBackground(DeviceProfile deviceProfile) {}
+}
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 7793b16..2b621bd 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -27,14 +27,12 @@
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.IntSparseArrayMap;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.ResourceBasedOverride;
-import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -109,9 +107,7 @@
         Set<UserHandle> users = workspaceItemInfos.stream().map(w -> w.user)
                 .collect(Collectors.toSet());
         if (users.size() == 1 && !users.contains(Process.myUserHandle())) {
-            StringCache cache = ActivityContext.lookupContext(context).getStringCache();
-            String workFolderName = cache != null
-                    ? cache.workFolderName : context.getString(R.string.work_folder_name);
+            String workFolderName = context.getString(R.string.work_folder_name);
             setAsLastSuggestion(nameInfos, workFolderName);
         }
 
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index a13fa55..91fb44e 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -22,6 +22,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Pair;
 
@@ -39,6 +40,7 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
@@ -82,11 +84,19 @@
                         item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
                     // Short-circuit this logic if the icon exists somewhere on the workspace
                     if (shortcutExists(dataModel, item.getIntent(), item.user)) {
+                        if (TestProtocol.sDebugTracing) {
+                            Log.d(TestProtocol.MISSING_PROMISE_ICON,
+                                    LOG + " Item already on workspace.");
+                        }
                         continue;
                     }
 
                     // b/139663018 Short-circuit this logic if the icon is a system app
                     if (PackageManagerHelper.isSystemApp(app.getContext(), item.getIntent())) {
+                        if (TestProtocol.sDebugTracing) {
+                            Log.d(TestProtocol.MISSING_PROMISE_ICON,
+                                    LOG + " Item is a system app.");
+                        }
                         continue;
                     }
                 }
@@ -126,6 +136,9 @@
                     String packageName = item.getTargetComponent() != null
                             ? item.getTargetComponent().getPackageName() : null;
                     if (packageName == null) {
+                        if (TestProtocol.sDebugTracing) {
+                            Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + " Null packageName.");
+                        }
                         continue;
                     }
                     SessionInfo sessionInfo = packageInstaller.getActiveSessionInfo(item.user,
@@ -134,6 +147,9 @@
                     if (!packageInstaller.verifySessionInfo(sessionInfo)) {
                         FileLog.d(LOG, "Item info failed session info verification. "
                                 + "Skipping : " + workspaceInfo);
+                        if (TestProtocol.sDebugTracing) {
+                            Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + "Failed verification.");
+                        }
                         continue;
                     }
 
@@ -144,6 +160,9 @@
                     if (sessionInfo == null) {
                         if (!hasActivity) {
                             // Session was cancelled, do not add.
+                            if (TestProtocol.sDebugTracing) {
+                                Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + "Session cancelled");
+                            }
                             continue;
                         }
                     } else {
@@ -163,6 +182,9 @@
                             // workspace items as promise icons. At this point we now have the
                             // correct intent to compare against existing workspace icons.
                             // Icon already exists on the workspace and should not be auto-added.
+                            if (TestProtocol.sDebugTracing) {
+                                Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + "shortcutExists");
+                            }
                             continue;
                         }
 
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 217f523..5a220f7 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -49,6 +49,7 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.PersistedItemArray;
 import com.android.launcher3.util.Preconditions;
@@ -118,10 +119,18 @@
         Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
         if (launcher == null) {
             // Launcher not loaded
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.MISSING_PROMISE_ICON,
+                        LOG + " flushQueueInBackground launcher not loaded");
+            }
             return;
         }
         ensureQueueLoaded();
         if (mItems.isEmpty()) {
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.MISSING_PROMISE_ICON,
+                        LOG + " flushQueueInBackground no items to load");
+            }
             return;
         }
 
@@ -131,6 +140,10 @@
 
         // Add the items and clear queue
         if (!installQueue.isEmpty()) {
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.MISSING_PROMISE_ICON,
+                        LOG + " flushQueueInBackground launcher addAndBindAddedWorkspaceItems");
+            }
             // add log
             launcher.getModel().addAndBindAddedWorkspaceItems(installQueue);
         }
@@ -191,6 +204,10 @@
         // Queue the item up for adding if launcher has not loaded properly yet
         MODEL_EXECUTOR.post(() -> {
             Pair<ItemInfo, Object> itemInfo = info.getItemInfo(mContext);
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + " queuePendingShortcutInfo"
+                        + ", itemInfo=" + itemInfo);
+            }
             if (itemInfo == null) {
                 FileLog.d(LOG,
                         "Adding PendingInstallShortcutInfo with no attached info to queue.",
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 4b86f65..618f926 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -27,6 +27,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
@@ -38,6 +39,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.ItemInstallQueue;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.MainThreadInitializedObject;
@@ -142,6 +144,16 @@
         if (sessionInfo == null
                 || sessionInfo.getInstallerPackageName() == null
                 || TextUtils.isEmpty(sessionInfo.getAppPackageName())) {
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + " verify"
+                        + ", info=" + (sessionInfo == null)
+                        + ", info install name" + (sessionInfo == null
+                                ? null
+                                : sessionInfo.getInstallerPackageName())
+                        + ", empty pkg name" + TextUtils.isEmpty((sessionInfo == null
+                                ? null
+                                : sessionInfo.getAppPackageName())));
+            }
             return null;
         }
         String pkg = sessionInfo.getInstallerPackageName();
@@ -211,6 +223,14 @@
      */
     @WorkerThread
     void tryQueuePromiseAppIcon(PackageInstaller.SessionInfo sessionInfo) {
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + " tryQueuePromiseAppIcon"
+                    + ", FeatureFlags=" + FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()
+                    + ", SessionCommitReceiveEnabled" + SessionCommitReceiver.isEnabled(mAppContext)
+                    + ", verifySessionInfo(sessionInfo)=" + verifySessionInfo(sessionInfo)
+                    + ", !promiseIconAdded=" + (sessionInfo != null
+                    && !promiseIconAddedForId(sessionInfo.getSessionId())));
+        }
         if (FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()
                 && SessionCommitReceiver.isEnabled(mAppContext)
                 && verifySessionInfo(sessionInfo)
@@ -227,6 +247,20 @@
     }
 
     public boolean verifySessionInfo(PackageInstaller.SessionInfo sessionInfo) {
+        if (TestProtocol.sDebugTracing) {
+            boolean appNotInstalled = sessionInfo == null
+                    || !new PackageManagerHelper(mAppContext)
+                    .isAppInstalled(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
+            boolean labelNotEmpty = sessionInfo != null
+                    && !TextUtils.isEmpty(sessionInfo.getAppLabel());
+            Log.d(TestProtocol.MISSING_PROMISE_ICON, LOG + " verifySessionInfo"
+                    + ", verify(sessionInfo)=" + verify(sessionInfo)
+                    + ", reason=" + (sessionInfo == null ? null : sessionInfo.getInstallReason())
+                    + ", PackageManager.INSTALL_REASON_USER=" + PackageManager.INSTALL_REASON_USER
+                    + ", hasIcon=" + (sessionInfo != null && sessionInfo.getAppIcon() != null)
+                    + ", label is ! empty=" + labelNotEmpty
+                    + " +, app not installed="  + appNotInstalled);
+        }
         return verify(sessionInfo) != null
                 && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
                 && sessionInfo.getAppIcon() != null
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index e1b3c1a..75cf7a8 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -25,10 +25,12 @@
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.os.Build;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.SparseArray;
 
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.PackageUserKey;
 
 import java.lang.ref.WeakReference;
@@ -57,10 +59,19 @@
     public void onCreated(int sessionId) {
         InstallSessionHelper helper = mWeakHelper.get();
         Callback callback = mWeakCallback.get();
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.MISSING_PROMISE_ICON, "Session created sessionId=" + sessionId
+                    + ", callback=" + callback
+                    + ", helper=" + helper);
+        }
         if (callback == null || helper == null) {
             return;
         }
         SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.MISSING_PROMISE_ICON, "Session created sessionId=" + sessionId
+                    + ", sessionInfo=" + sessionInfo);
+        }
         if (sessionInfo != null) {
             callback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo));
         }
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 7c6ad9f..78e9fe8 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -126,4 +126,5 @@
     public static final String TASK_VIEW_ID_CRASH = "b/195430732";
     public static final String NO_DROP_TARGET = "b/195031154";
     public static final String NULL_INT_SET = "b/200572078";
+    public static final String MISSING_PROMISE_ICON = "b/202985412";
 }
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index a6c9c4d..4a55d2e 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -310,9 +310,10 @@
     }
 
     @Override
-    public Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
             int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
             View[] thumbnailViews, int desiredTaskId, View banner) {
+        boolean isRtl = banner.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
         float translationX = 0;
         float translationY = 0;
         FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
@@ -323,7 +324,7 @@
         FrameLayout.LayoutParams snapshotParams =
                 (FrameLayout.LayoutParams) thumbnailViews[0]
                         .getLayoutParams();
-        bannerParams.gravity = TOP | START;
+        bannerParams.gravity = TOP | (isRtl ? END : START);
         if (splitBounds == null) {
             // Single, fullscreen case
             bannerParams.width = taskViewHeight - snapshotParams.topMargin;
@@ -339,9 +340,11 @@
 
         // Set translations
         if (desiredTaskId == splitBounds.rightBottomTaskId) {
-            translationY = (snapshotParams.topMargin + taskViewHeight)
-                    * (splitBounds.leftTaskPercent) +
-                    (taskViewHeight * splitBounds.dividerWidthPercent);
+            float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically
+                    ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)
+                    : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent);
+            translationY = snapshotParams.topMargin
+                    + ((taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent);
         }
         if (desiredTaskId == splitBounds.leftTopTaskId) {
             translationY = snapshotParams.topMargin;
@@ -440,7 +443,9 @@
             StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
         int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
         int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
-        int dividerBar = splitBoundsConfig.visualDividerBounds.width();
+        int dividerBar = splitBoundsConfig.appsStackedVertically
+                ? splitBoundsConfig.visualDividerBounds.height()
+                : splitBoundsConfig.visualDividerBounds.width();
         int primarySnapshotHeight;
         int primarySnapshotWidth;
         int secondarySnapshotHeight;
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 19c4639..923dcc6 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -191,7 +191,12 @@
      */
     PointF getAdditionalInsetForTaskMenu(float margin);
 
-    Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+    /**
+     * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
+     * TaskView.
+     * @return A Pair of Floats representing the proper x and y translations.
+     */
+    Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
             int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
             View[] thumbnailViews, int desiredTaskId, View banner);
 
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 01aea05..a308182 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -324,7 +324,7 @@
     }
 
     @Override
-    public Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
             int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
             View[] thumbnailViews, int desiredTaskId, View banner) {
         float translationX = 0;
@@ -360,8 +360,11 @@
                 FrameLayout.LayoutParams snapshotParams =
                         (FrameLayout.LayoutParams) thumbnailViews[0]
                                 .getLayoutParams();
+                float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
+                        ? (1f - splitBounds.topTaskPercent)
+                        : (1f - splitBounds.leftTaskPercent);
                 translationY = -((taskViewHeight - snapshotParams.topMargin)
-                        * (1f - splitBounds.topTaskPercent));
+                        * bottomRightTaskPlusDividerPercent);
             }
         }
         return new Pair<>(translationX, translationY);
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 80a7229..6dc0c9a 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -106,21 +106,25 @@
         return new PointF(-margin, margin);
     }
 
+
+
     @Override
-    public Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
             int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
             View[] thumbnailViews, int desiredTaskId, View banner) {
+        boolean isRtl = banner.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
         float translationX = 0;
         float translationY = 0;
         FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
         banner.setPivotX(0);
         banner.setPivotY(0);
         banner.setRotation(getDegreesRotated());
+        translationX = taskViewWidth - banner.getHeight();
         FrameLayout.LayoutParams snapshotParams =
                 (FrameLayout.LayoutParams) thumbnailViews[0]
                         .getLayoutParams();
-        bannerParams.gravity = BOTTOM | END;
-        translationX = taskViewWidth - banner.getHeight();
+        bannerParams.gravity = BOTTOM | (isRtl ? END : START);
+
         if (splitBounds == null) {
             // Single, fullscreen case
             bannerParams.width = taskViewHeight - snapshotParams.topMargin;
@@ -130,19 +134,22 @@
 
         // Set correct width
         if (desiredTaskId == splitBounds.leftTopTaskId) {
-            bannerParams.width = thumbnailViews[1].getMeasuredHeight();
-        } else {
             bannerParams.width = thumbnailViews[0].getMeasuredHeight();
+        } else {
+            bannerParams.width = thumbnailViews[1].getMeasuredHeight();
         }
 
         // Set translations
         if (desiredTaskId == splitBounds.rightBottomTaskId) {
-            translationY = -(taskViewHeight - snapshotParams.topMargin)
-                    * (1f - splitBounds.leftTaskPercent)
-                    + banner.getHeight();
+            translationY = banner.getHeight();
         }
         if (desiredTaskId == splitBounds.leftTopTaskId) {
-            translationY = banner.getHeight();
+            float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
+                    ? (1f - splitBounds.topTaskPercent)
+                    : (1f - splitBounds.leftTaskPercent);
+            translationY = banner.getHeight()
+                    - ((taskViewHeight - snapshotParams.topMargin)
+                    * bottomRightTaskPlusDividerPercent);
         }
         return new Pair<>(translationX, translationY);
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 5511770..c22b4da 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -98,7 +98,7 @@
 public final class LauncherInstrumentation {
 
     private static final String TAG = "Tapl";
-    private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
+    private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
     private static final int GESTURE_STEP_MS = 16;
     private static final long FORCE_PAUSE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2);