Merging ub-launcher3-qt-dev, build 5456758

Test: Manual

Bug:111142970 Icon display blur in all apps page
Bug:114136250 Have a more spartan RecentsActivity on android go
Bug:122609330 Update PIP animation for swiping up to home
Bug:123985787 Respect dialogCornerRadius for all apps / widgets / settings / shortcut menu / dwb / task / overview (everything)
Bug:126587956 Create an app to use with Launcher testing
Bug:126606858 In multiwindow mode, not able to switch between recent apps.
Bug:127766994 Gray app icons disappeared after completing cable transfer for a while
Bug:127987071 Create a proper contract for specifying default Launcher Layout
Bug:129033091 [Q-Preview] I would like the ability to swipe up anywhere on my screen to open up the app li.
Bug:129297464 [Gesture Nav] Exclude edges from most Launcher / Overview states.
Bug:129434166 Lab-only flake: drag to workspace doesn't happen
Bug:129746879 [Q-Preview] Quick search bar overlaying other app
Bug:129874298 Show different string (Wallpaper vs Style & Wallpaper) on Settings depending on device type
Bug:129947426 nexus launcher crash observed randomly during device boot up(NPE:Attempt to invoke virtual method 'android.app.ActivityManager$RunningTaskInfo com.android.systemui.shared.system.ActivityManagerWrapper.getRunningTask(int)' on a null object reference)
Bug:129976669 Implement returning to home from Widgets in 0-button mode Bug:130027168 Can't tap in nav region on home screen
Bug:130151609 Some tests in MultiDisplaySystemDecorationTests.java failing in pre-submit
Bug:130182878 Pixel launcher crashes on secondary display
Bug:130225926 Cannot unpin app while in gesture nav
Bug:130245920 Icons disappear from launcher when selected
Bug:130272454 [C1/B1] Message app crash when opening a video MMS.
Change-Id: I18aa35d2c75deaf5149358d96d4e1d7f26de2f02
diff --git a/go/quickstep/src/com/android/quickstep/TaskActionController.java b/go/quickstep/src/com/android/quickstep/TaskActionController.java
index 77b287b..71bee91 100644
--- a/go/quickstep/src/com/android/quickstep/TaskActionController.java
+++ b/go/quickstep/src/com/android/quickstep/TaskActionController.java
@@ -42,6 +42,9 @@
      * @param viewHolder the task view holder to launch
      */
     public void launchTask(TaskHolder viewHolder) {
+        if (viewHolder.getTask() == null) {
+            return;
+        }
         TaskItemView itemView = (TaskItemView) (viewHolder.itemView);
         View v = itemView.getThumbnailView();
         int left = 0;
@@ -60,6 +63,9 @@
      * @param viewHolder the task view holder to remove
      */
     public void removeTask(TaskHolder viewHolder) {
+        if (viewHolder.getTask() == null) {
+            return;
+        }
         int position = viewHolder.getAdapterPosition();
         Task task = viewHolder.getTask();
         ActivityManagerWrapper.getInstance().removeTask(task.key.id);
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index c98eca6..674fcae 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -28,6 +28,7 @@
 import com.android.systemui.shared.recents.model.Task;
 
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Recycler view adapter that dynamically inflates and binds {@link TaskHolder} instances with the
@@ -40,6 +41,7 @@
     private final TaskListLoader mLoader;
     private final ArrayMap<Integer, TaskItemView> mTaskIdToViewMap = new ArrayMap<>();
     private TaskActionController mTaskActionController;
+    private boolean mIsShowingLoadingUi;
 
     public TaskAdapter(@NonNull TaskListLoader loader) {
         mLoader = loader;
@@ -50,6 +52,18 @@
     }
 
     /**
+     * Sets all positions in the task adapter to loading views, binding new views if necessary.
+     * This changes the task adapter's view of the data, so the appropriate notify events should be
+     * called in addition to this method to reflect the changes.
+     *
+     * @param isShowingLoadingUi true to bind loading task views to all positions, false to return
+     *                           to the real data
+     */
+    public void setIsShowingLoadingUi(boolean isShowingLoadingUi) {
+        mIsShowingLoadingUi = isShowingLoadingUi;
+    }
+
+    /**
      * Get task item view for a given task id if it's attached to the view.
      *
      * @param taskId task id to search for
@@ -70,6 +84,10 @@
 
     @Override
     public void onBindViewHolder(TaskHolder holder, int position) {
+        if (mIsShowingLoadingUi) {
+            holder.bindEmptyUi();
+            return;
+        }
         List<Task> tasks = mLoader.getCurrentTaskList();
         if (position >= tasks.size()) {
             // Task list has updated.
@@ -79,13 +97,13 @@
         holder.bindTask(task);
         mLoader.loadTaskIconAndLabel(task, () -> {
             // Ensure holder still has the same task.
-            if (task.equals(holder.getTask())) {
+            if (Objects.equals(task, holder.getTask())) {
                 holder.getTaskItemView().setIcon(task.icon);
                 holder.getTaskItemView().setLabel(task.titleDescription);
             }
         });
         mLoader.loadTaskThumbnail(task, () -> {
-            if (task.equals(holder.getTask())) {
+            if (Objects.equals(task, holder.getTask())) {
                 holder.getTaskItemView().setThumbnail(task.thumbnail.thumbnail);
             }
         });
@@ -93,16 +111,27 @@
 
     @Override
     public void onViewAttachedToWindow(@NonNull TaskHolder holder) {
+        if (holder.getTask() == null) {
+            return;
+        }
         mTaskIdToViewMap.put(holder.getTask().key.id, (TaskItemView) holder.itemView);
     }
 
     @Override
     public void onViewDetachedFromWindow(@NonNull TaskHolder holder) {
+        if (holder.getTask() == null) {
+            return;
+        }
         mTaskIdToViewMap.remove(holder.getTask().key.id);
     }
 
     @Override
     public int getItemCount() {
-        return Math.min(mLoader.getCurrentTaskList().size(), MAX_TASKS_TO_DISPLAY);
+        if (mIsShowingLoadingUi) {
+            // Show loading version of all items.
+            return MAX_TASKS_TO_DISPLAY;
+        } else {
+            return Math.min(mLoader.getCurrentTaskList().size(), MAX_TASKS_TO_DISPLAY);
+        }
     }
 }
diff --git a/go/quickstep/src/com/android/quickstep/TaskHolder.java b/go/quickstep/src/com/android/quickstep/TaskHolder.java
index 744afd7..98dc989 100644
--- a/go/quickstep/src/com/android/quickstep/TaskHolder.java
+++ b/go/quickstep/src/com/android/quickstep/TaskHolder.java
@@ -15,7 +15,7 @@
  */
 package com.android.quickstep;
 
-import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
 
 import com.android.quickstep.views.TaskItemView;
@@ -50,11 +50,23 @@
     }
 
     /**
-     * Gets the task currently bound to this view
+     * Bind a generic empty UI to the holder to make it clear that the item is loading/unbound and
+     * should not be expected to react to user input.
+     */
+    public void bindEmptyUi() {
+        mTask = null;
+        // TODO: Set the task view to a loading, empty UI.
+        // Temporarily using the one below for visual confirmation but should be swapped out to new
+        // UI later.
+        mTaskItemView.resetTaskItemView();
+    }
+
+    /**
+     * Gets the task currently bound to this view. May be null if task holder is in a loading state.
      *
      * @return the current task
      */
-    public @NonNull Task getTask() {
+    public @Nullable Task getTask() {
         return mTask;
     }
 }
diff --git a/go/quickstep/src/com/android/quickstep/TaskListLoader.java b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
index 1234989..51b73f1 100644
--- a/go/quickstep/src/com/android/quickstep/TaskListLoader.java
+++ b/go/quickstep/src/com/android/quickstep/TaskListLoader.java
@@ -68,16 +68,26 @@
     }
 
     /**
+     * Whether or not the loader needs to load data to be up to date. This can return true if the
+     * task list is already up to date OR there is already a load in progress for the task list to
+     * become up to date.
+     *
+     * @return true if already up to date or load in progress, false otherwise
+     */
+    public boolean needsToLoad() {
+        return !mRecentsModel.isTaskListValid(mTaskListChangeId);
+    }
+
+    /**
      * Fetches the most recent tasks and updates the task list asynchronously. This call does not
      * provide guarantees the task content (icon, thumbnail, label) are loaded but will fill in
      * what it has. May run the callback immediately if there have been no changes in the task
-     * list.
+     * list since the start of the last load.
      *
      * @param onLoadedCallback callback to run when task list is loaded
      */
     public void loadTaskList(@Nullable Consumer<ArrayList<Task>> onLoadedCallback) {
-        if (mRecentsModel.isTaskListValid(mTaskListChangeId)) {
-            // Current task list is already up to date. No need to update.
+        if (!needsToLoad()) {
             if (onLoadedCallback != null) {
                 onLoadedCallback.accept(mTaskList);
             }
diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
index c579c8a..734425e 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -49,7 +49,6 @@
             ISystemUiProxy iSystemUiProxy = ISystemUiProxy.Stub
                     .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
             mRecentsModel.setSystemUiProxy(iSystemUiProxy);
-            mRecentsModel.onInitializeSystemUI(bundle);
         }
 
         @Override
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index 5bb4c5a..c06b6ec 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -28,6 +28,10 @@
 import android.util.FloatProperty;
 import android.view.View;
 import android.view.ViewDebug;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.LayoutAnimationController;
 import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
@@ -69,6 +73,8 @@
                 }
             };
     private static final long CROSSFADE_DURATION = 300;
+    private static final long LAYOUT_ITEM_ANIMATE_IN_DURATION = 150;
+    private static final long LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN = 40;
     private static final long ITEM_ANIMATE_OUT_DURATION = 150;
     private static final long ITEM_ANIMATE_OUT_DELAY_BETWEEN = 40;
     private static final float ITEM_ANIMATE_OUT_TRANSLATION_X_RATIO = .25f;
@@ -84,6 +90,7 @@
     private final TaskListLoader mTaskLoader;
     private final TaskAdapter mTaskAdapter;
     private final TaskActionController mTaskActionController;
+    private final LayoutAnimationController mLayoutAnimation;
 
     private RecentsToActivityHelper mActivityHelper;
     private RecyclerView mTaskRecyclerView;
@@ -99,6 +106,7 @@
         mTaskAdapter = new TaskAdapter(mTaskLoader);
         mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter);
         mTaskAdapter.setActionController(mTaskActionController);
+        mLayoutAnimation = createLayoutAnimation();
     }
 
     @Override
@@ -112,6 +120,7 @@
             ItemTouchHelper helper = new ItemTouchHelper(
                     new TaskSwipeCallback(mTaskActionController));
             helper.attachToRecyclerView(mTaskRecyclerView);
+            mTaskRecyclerView.setLayoutAnimation(mLayoutAnimation);
 
             mEmptyView = findViewById(R.id.recent_task_empty_view);
             mContentView = findViewById(R.id.recent_task_content_view);
@@ -131,7 +140,6 @@
         }
     }
 
-
     @Override
     public void setEnabled(boolean enabled) {
         super.setEnabled(enabled);
@@ -157,10 +165,17 @@
      * becomes visible.
      */
     public void onBeginTransitionToOverview() {
+        mTaskRecyclerView.scheduleLayoutAnimation();
+
         // Load any task changes
+        if (!mTaskLoader.needsToLoad()) {
+            return;
+        }
+        mTaskAdapter.setIsShowingLoadingUi(true);
+        mTaskAdapter.notifyDataSetChanged();
         mTaskLoader.loadTaskList(tasks -> {
-            // TODO: Put up some loading UI while task content is loading. May have to do something
-            // smarter when animating from app to overview.
+            mTaskAdapter.setIsShowingLoadingUi(false);
+            // TODO: Animate the loading UI out and the loaded data in.
             mTaskAdapter.notifyDataSetChanged();
         });
     }
@@ -322,4 +337,18 @@
                     }
                 });
     }
+
+    private static LayoutAnimationController createLayoutAnimation() {
+        AnimationSet anim = new AnimationSet(false /* shareInterpolator */);
+
+        Animation alphaAnim = new AlphaAnimation(0, 1);
+        alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION);
+        anim.addAnimation(alphaAnim);
+
+        LayoutAnimationController layoutAnim = new LayoutAnimationController(anim);
+        layoutAnim.setDelay(
+                (float) LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN / LAYOUT_ITEM_ANIMATE_IN_DURATION);
+
+        return layoutAnim;
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 225ae84..462e630 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -75,12 +75,4 @@
         return new ScaleAndTranslation(scale, 0f, 0f);
     }
 
-    @Override
-    public int getVisibleElements(Launcher launcher) {
-        if (SysUINavigationMode.getMode(launcher) == Mode.NO_BUTTON) {
-            return super.getVisibleElements(launcher);
-        }
-        // Hide shelf content (e.g. QSB) because we fade it in when swiping up.
-        return ALL_APPS_HEADER_EXTRA;
-    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 673beff..21ddfc0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -15,74 +15,131 @@
  */
 package com.android.launcher3.uioverrides.touchcontrollers;
 
+import static android.view.View.TRANSLATION_X;
+
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.view.MotionEvent;
-import android.view.View;
 import android.view.animation.Interpolator;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Command;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.TouchController;
 import com.android.quickstep.views.RecentsView;
 
 /**
- * Handles swiping up on the nav bar to go home from overview or all apps.
+ * Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
  */
-public class NavBarToHomeTouchController extends AbstractStateChangeTouchController {
+public class NavBarToHomeTouchController implements TouchController, SwipeDetector.Listener {
 
     private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3;
 
+    private final Launcher mLauncher;
+    private final SwipeDetector mSwipeDetector;
+    private final float mPullbackDistance;
+
+    private boolean mNoIntercept;
+    private LauncherState mStartState;
+    private LauncherState mEndState = NORMAL;
+    private AnimatorPlaybackController mCurrentAnimation;
+
     public NavBarToHomeTouchController(Launcher launcher) {
-        super(launcher, SwipeDetector.VERTICAL);
+        mLauncher = launcher;
+        mSwipeDetector = new SwipeDetector(mLauncher, this, SwipeDetector.VERTICAL);
+        mPullbackDistance = mLauncher.getResources().getDimension(R.dimen.home_pullback_distance);
     }
 
     @Override
-    protected boolean canInterceptTouch(MotionEvent ev) {
-        boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
-        return cameFromNavBar && (mLauncher.isInState(OVERVIEW) || mLauncher.isInState(ALL_APPS));
-    }
-
-    @Override
-    protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
-        return isDragTowardPositive ? NORMAL : fromState;
-    }
-
-    @Override
-    protected float initCurrentAnimation(int animComponents) {
-        long accuracy = (long) (getShiftRange() * 2);
-        final AnimatorSet anim;
-        if (mFromState == OVERVIEW) {
-            anim = new AnimatorSet();
-            RecentsView recentsView = mLauncher.getOverviewPanel();
-            float pullbackDistance = recentsView.getPaddingStart() / 2;
-            if (!recentsView.isRtl()) {
-                pullbackDistance = -pullbackDistance;
+    public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mStartState = mLauncher.getStateManager().getState();
+            mNoIntercept = !canInterceptTouch(ev);
+            if (mNoIntercept) {
+                return false;
             }
-            anim.play(ObjectAnimator.ofFloat(recentsView, View.TRANSLATION_X, pullbackDistance));
-            anim.setInterpolator(PULLBACK_INTERPOLATOR);
-        } else { // if (mFromState == ALL_APPS)
+            mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
+        }
+
+        if (mNoIntercept) {
+            return false;
+        }
+
+        onControllerTouchEvent(ev);
+        return mSwipeDetector.isDraggingOrSettling();
+    }
+
+    private boolean canInterceptTouch(MotionEvent ev) {
+        boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
+        if (!cameFromNavBar) {
+            return false;
+        }
+        if (mStartState == OVERVIEW || mStartState == ALL_APPS) {
+            return true;
+        }
+        if (!mLauncher.hasWindowFocus()) {
+            return true;
+        }
+        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public final boolean onControllerTouchEvent(MotionEvent ev) {
+        return mSwipeDetector.onTouchEvent(ev);
+    }
+
+    private float getShiftRange() {
+        return mLauncher.getDeviceProfile().heightPx;
+    }
+
+    @Override
+    public void onDragStart(boolean start) {
+        initCurrentAnimation();
+    }
+
+    private void initCurrentAnimation() {
+        long accuracy = (long) (getShiftRange() * 2);
+        final AnimatorSet anim = new AnimatorSet();
+        if (mStartState == OVERVIEW) {
+            RecentsView recentsView = mLauncher.getOverviewPanel();
+            float pullbackDist = mPullbackDistance;
+            if (!recentsView.isRtl()) {
+                pullbackDist = -pullbackDist;
+            }
+            Animator pullback = ObjectAnimator.ofFloat(recentsView, TRANSLATION_X, pullbackDist);
+            pullback.setInterpolator(PULLBACK_INTERPOLATOR);
+            anim.play(pullback);
+        } else if (mStartState == ALL_APPS) {
             AnimatorSetBuilder builder = new AnimatorSetBuilder();
             AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
-            final float pullbackDistance = mLauncher.getDeviceProfile().allAppsIconSizePx / 2;
             Animator allAppsProgress = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS,
-                    -pullbackDistance / allAppsController.getShiftRange());
+                    -mPullbackDistance / allAppsController.getShiftRange());
             allAppsProgress.setInterpolator(PULLBACK_INTERPOLATOR);
             builder.play(allAppsProgress);
             // Slightly fade out all apps content to further distinguish from scrolling.
@@ -90,52 +147,79 @@
                     .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
             AnimationConfig config = new AnimationConfig();
             config.duration = accuracy;
-            allAppsController.setAlphas(mToState.getVisibleElements(mLauncher), config, builder);
-            anim = builder.build();
+            allAppsController.setAlphas(mEndState.getVisibleElements(mLauncher), config, builder);
+            anim.play(builder.build());
+        }
+        AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
+        if (topView != null) {
+            Animator hintCloseAnim = topView.createHintCloseAnim(mPullbackDistance);
+            if (hintCloseAnim != null) {
+                hintCloseAnim.setInterpolator(PULLBACK_INTERPOLATOR);
+                anim.play(hintCloseAnim);
+            }
         }
         anim.setDuration(accuracy);
         mCurrentAnimation = AnimatorPlaybackController.wrap(anim, accuracy, this::clearState);
-        return -1 / getShiftRange();
+    }
+
+    private void clearState() {
+        mCurrentAnimation = null;
+        mSwipeDetector.finishedScrolling();
+        mSwipeDetector.setDetectableScrollConditions(0, false);
     }
 
     @Override
-    public void onDragStart(boolean start) {
-        super.onDragStart(start);
-        mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
+    public boolean onDrag(float displacement) {
+        // Only allow swipe up.
+        displacement = Math.min(0, displacement);
+        float progress = Utilities.getProgress(displacement, 0, getShiftRange());
+        mCurrentAnimation.setPlayFraction(progress);
+        return true;
     }
 
     @Override
     public void onDragEnd(float velocity, boolean fling) {
         final int logAction = fling ? Touch.FLING : Touch.SWIPE;
-        float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(
-                mCurrentAnimation.getProgressFraction());
-        if (interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS || velocity < 0 && fling) {
-            mLauncher.getStateManager().goToState(mToState, true,
-                    () -> onSwipeInteractionCompleted(mToState, logAction));
+        float progress = mCurrentAnimation.getProgressFraction();
+        float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(progress);
+        boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS
+                || (velocity < 0 && fling);
+        if (success) {
+            mLauncher.getStateManager().goToState(mEndState, true,
+                    () -> onSwipeInteractionCompleted(mEndState));
+            if (mStartState != mEndState) {
+                logStateChange(mStartState.containerType, logAction);
+            }
+            AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher);
+            if (topOpenView != null) {
+                AbstractFloatingView.closeAllOpenViews(mLauncher);
+                logStateChange(topOpenView.getLogContainerType(), logAction);
+            }
         } else {
             // Quickly return to the state we came from (we didn't move far).
-            AnimatorPlaybackController anim = mLauncher.getStateManager()
-                    .createAnimationToNewWorkspace(mFromState, 80);
-            anim.setEndAction(() -> onSwipeInteractionCompleted(mFromState, logAction));
-            anim.start();
+            ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+            anim.setFloatValues(progress, 0);
+            anim.addListener(new AnimationSuccessListener() {
+                @Override
+                public void onAnimationSuccess(Animator animator) {
+                    onSwipeInteractionCompleted(mStartState);
+                }
+            });
+            anim.setDuration(80).start();
         }
-        mCurrentAnimation.dispatchOnCancel();
     }
 
-    @Override
-    protected int getDirectionForLog() {
-        return LauncherLogProto.Action.Direction.UP;
+    private void onSwipeInteractionCompleted(LauncherState targetState) {
+        clearState();
+        mLauncher.getStateManager().goToState(targetState, false /* animated */);
     }
 
-    @Override
-    protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
-            LauncherState toState) {
-        // We don't want to create an atomic animation to/from overview.
-        return false;
-    }
-
-    @Override
-    protected int getLogContainerTypeForNormalState() {
-        return LauncherLogProto.ContainerType.NAVBAR;
+    private void logStateChange(int startContainerType, int logAction) {
+        mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
+                LauncherLogProto.Action.Direction.UP,
+                LauncherLogProto.ContainerType.NAVBAR,
+                startContainerType,
+                mEndState.containerType,
+                mLauncher.getWorkspace().getCurrentPage());
     }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index e903b6f..baef2eb 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -23,7 +23,6 @@
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO;
 import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 
 import android.animation.Animator;
@@ -44,11 +43,8 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherInitListener;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.SpringObjectAnimator;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -220,7 +216,7 @@
                         : mShelfState == ShelfAnimState.PEEK
                                 ? shelfPeekingProgress
                                 : shelfOverviewProgress;
-                mShelfAnim = createShelfProgressAnim(activity, toProgress);
+                mShelfAnim = createShelfAnim(activity, toProgress);
                 mShelfAnim.addListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
@@ -238,10 +234,10 @@
             LauncherState fromState, long transitionLength,
             Consumer<AnimatorPlaybackController> callback) {
         LauncherState endState = OVERVIEW;
-        DeviceProfile dp = activity.getDeviceProfile();
-        long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
         if (wasVisible && fromState != BACKGROUND_APP) {
             // If a translucent app was launched fom launcher, animate launcher states.
+            DeviceProfile dp = activity.getDeviceProfile();
+            long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
             callback.accept(activity.getStateManager()
                     .createAnimationToNewWorkspace(fromState, endState, accuracy));
             return;
@@ -254,11 +250,10 @@
         if (!activity.getDeviceProfile().isVerticalBarLayout()
                 && SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
             // Don't animate the shelf when the mode is NO_BUTTON, because we update it atomically.
-            Animator shiftAnim = createShelfProgressAnim(activity,
+            Animator shiftAnim = createShelfAnim(activity,
                     fromState.getVerticalProgress(activity),
                     endState.getVerticalProgress(activity));
             anim.play(shiftAnim);
-            anim.play(createShelfAlphaAnim(activity, endState, accuracy));
         }
         playScaleDownAnim(anim, activity, endState);
 
@@ -275,7 +270,7 @@
         callback.accept(controller);
     }
 
-    private Animator createShelfProgressAnim(Launcher activity, float ... progressValues) {
+    private Animator createShelfAnim(Launcher activity, float ... progressValues) {
         Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(),
                 "allAppsSpringFromACH", activity.getAllAppsController().getShiftRange(),
                 SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
@@ -284,19 +279,6 @@
     }
 
     /**
-     * Very quickly fade the alpha of shelf content.
-     */
-    private Animator createShelfAlphaAnim(Launcher activity, LauncherState toState, long accuracy) {
-        AllAppsTransitionController allAppsController = activity.getAllAppsController();
-        AnimatorSetBuilder animBuilder = new AnimatorSetBuilder();
-        animBuilder.setInterpolator(AnimatorSetBuilder.ANIM_ALL_APPS_FADE, DEACCEL_3);
-        LauncherStateManager.AnimationConfig config = new LauncherStateManager.AnimationConfig();
-        config.duration = accuracy;
-        allAppsController.setAlphas(toState.getVisibleElements(activity), config, animBuilder);
-        return animBuilder.build();
-    }
-
-    /**
      * Scale down recents from the center task being full screen to being in overview.
      */
     private void playScaleDownAnim(AnimatorSet anim, Launcher launcher,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
index 3ebe968..8bda3f6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewInputConsumer.java
@@ -136,17 +136,13 @@
     }
 
     private void sendEvent(MotionEvent ev) {
-        if (mInvalidated || !mTarget.verifyTouchDispatch(this, ev)) {
-            mInvalidated = true;
+        if (mInvalidated) {
             return;
         }
         int flags = ev.getEdgeFlags();
         ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
         ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
-        if (ev.getAction() == ACTION_DOWN) {
-            mTarget.onInterceptTouchEvent(ev);
-        }
-        mTarget.onTouchEvent(ev);
+        mInvalidated = !mTarget.dispatchTouchEvent(this, ev);
         ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
         ev.setEdgeFlags(flags);
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java
index 42a28fb..6e98a5a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java
@@ -290,6 +290,10 @@
             if (sysUiProxy == null) {
                 return null;
             }
+            if (SysUINavigationMode.getMode(activity) == SysUINavigationMode.Mode.NO_BUTTON) {
+                // TODO(b/130225926): Temporarily disable pinning while gesture nav is enabled
+                return null;
+            }
             if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) {
                 return null;
             }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index bcce937..3ea8de0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -101,7 +101,6 @@
             MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
             runWhenUserUnlocked(() -> {
                 mRecentsModel.setSystemUiProxy(mISystemUiProxy);
-                mRecentsModel.onInitializeSystemUI(bundle);
                 mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
             });
         }
@@ -426,7 +425,7 @@
 
     private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
         // TODO: this makes a binder call every touch down. we should move to a listener pattern.
-        if (mKM.isDeviceLocked()) {
+        if (!mIsUserUnlocked || mKM.isDeviceLocked()) {
             // This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched
             // while device is locked even after exiting direct boot mode (e.g. camera).
             return new DeviceLockedInputConsumer(this);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
index e1a39c6..32d510d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -16,6 +16,8 @@
 package com.android.quickstep.util;
 
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
+import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
@@ -33,6 +35,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.views.RecentsView;
@@ -97,12 +100,9 @@
             (t, a1) -> a1;
 
     public ClipAnimationHelper(Context context) {
-        mWindowCornerRadius = RecentsModel.INSTANCE.get(context).getWindowCornerRadius();
-        mSupportsRoundedCornersOnWindows = RecentsModel.INSTANCE.get(context)
-                .supportsRoundedCornersOnWindows();
-        int taskCornerRadiusRes = mSupportsRoundedCornersOnWindows ?
-                R.dimen.task_corner_radius : R.dimen.task_corner_radius_small;
-        mTaskCornerRadius = context.getResources().getDimension(taskCornerRadiusRes);
+        mWindowCornerRadius = getWindowCornerRadius(context.getResources());
+        mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources());
+        mTaskCornerRadius = Themes.getDialogCornerRadius(context);
     }
 
     private void updateSourceStack(RemoteAnimationTargetCompat target) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
index d15a392..c47e943 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java
@@ -40,6 +40,7 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.TaskSystemShortcut;
 import com.android.quickstep.TaskUtils;
@@ -270,7 +271,7 @@
     }
 
     private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
-        float radius = getResources().getDimension(R.dimen.task_corner_radius);
+        float radius = Themes.getDialogCornerRadius(getContext());
         Rect fromRect = new Rect(0, 0, getWidth(), 0);
         Rect toRect = new Rect(0, 0, getWidth(), getHeight());
         return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index a9f6311..7905230 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -46,11 +46,11 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
-import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.QuickStepContract;
 
 /**
  * A task in the Recents view.
@@ -108,7 +108,7 @@
 
     public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
+        mCornerRadius = Themes.getDialogCornerRadius(context);
         mOverlay = TaskOverlayFactory.INSTANCE.get(context).createOverlay(this);
         mPaint.setFilterBitmap(true);
         mBackgroundPaint.setColor(Color.WHITE);
@@ -116,7 +116,7 @@
         mDimmingPaintAfterClearing.setColor(Color.BLACK);
         mActivity = BaseActivity.fromContext(context);
         mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
-        mWindowCornerRadius = RecentsModel.INSTANCE.get(context).getWindowCornerRadius();
+        mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
     }
 
     public void bind(Task task) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 747c480..02a2ec6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -51,6 +51,7 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.util.PendingAnimation;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.ViewPool.Reusable;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskIconCache;
@@ -195,7 +196,7 @@
             fromContext(context).getStatsLogManager().logTaskLaunch(getRecentsView(),
                     TaskUtils.getLaunchComponentKeyForTask(getTask().key));
         });
-        setOutlineProvider(new TaskOutlineProvider(getResources()));
+        setOutlineProvider(new TaskOutlineProvider(context, getResources()));
     }
 
     @Override
@@ -513,9 +514,9 @@
         private final int mMarginTop;
         private final float mRadius;
 
-        TaskOutlineProvider(Resources res) {
+        TaskOutlineProvider(Context context, Resources res) {
             mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
-            mRadius = res.getDimension(R.dimen.task_corner_radius);
+            mRadius = Themes.getDialogCornerRadius(context);
         }
 
         @Override
diff --git a/quickstep/res/drawable/bg_wellbeing_toast.xml b/quickstep/res/drawable/bg_wellbeing_toast.xml
index 22d6f8a..65730f6 100644
--- a/quickstep/res/drawable/bg_wellbeing_toast.xml
+++ b/quickstep/res/drawable/bg_wellbeing_toast.xml
@@ -15,5 +15,5 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
     <solid android:color="#E61A73E8" />
-    <corners android:radius="@dimen/task_corner_radius" />
+    <corners android:radius="?android:attr/dialogCornerRadius" />
 </shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/task_menu_bg.xml b/quickstep/res/drawable/task_menu_bg.xml
index d5597a9..7334d98 100644
--- a/quickstep/res/drawable/task_menu_bg.xml
+++ b/quickstep/res/drawable/task_menu_bg.xml
@@ -28,8 +28,8 @@
         <!-- Background -->
         <shape>
             <corners
-                android:topLeftRadius="@dimen/task_corner_radius"
-                android:topRightRadius="@dimen/task_corner_radius"
+                android:topLeftRadius="?android:attr/dialogCornerRadius"
+                android:topRightRadius="?android:attr/dialogCornerRadius"
                 android:bottomLeftRadius="0dp"
                 android:bottomRightRadius="0dp" />
             <solid android:color="?attr/popupColorPrimary" />
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 97f2de7..6ec3bf6 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -19,9 +19,7 @@
     <dimen name="task_thumbnail_top_margin">24dp</dimen>
     <dimen name="task_thumbnail_half_top_margin">12dp</dimen>
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
-    <dimen name="task_corner_radius">8dp</dimen>
-    <!-- For screens without rounded corners -->
-    <dimen name="task_corner_radius_small">2dp</dimen>
+
     <dimen name="recents_page_spacing">10dp</dimen>
     <dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
     <dimen name="overview_peek_distance">32dp</dimen>
@@ -61,11 +59,13 @@
        docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
     <dimen name="multi_window_task_divider_size">10dp</dimen>
 
-    <dimen name="shelf_surface_radius">16dp</dimen>
     <!-- same as vertical_drag_handle_size -->
     <dimen name="shelf_surface_offset">24dp</dimen>
 
     <!-- Assistant Gestures -->
     <dimen name="gestures_assistant_size">28dp</dimen>
     <dimen name="gestures_assistant_drag_threshold">70dp</dimen>
+
+    <!-- Distance to move elements when swiping up to go home from launcher -->
+    <dimen name="home_pullback_distance">28dp</dimen>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index f77bd65..cda9d4f 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -31,6 +31,7 @@
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
+import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
@@ -63,12 +64,12 @@
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.views.FloatingIconView;
-import com.android.quickstep.RecentsModel;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.RemoteAnimationTargetSet;
 import com.android.systemui.shared.system.ActivityCompat;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -473,6 +474,10 @@
         });
 
         float shapeRevealDuration = APP_LAUNCH_DURATION * SHAPE_PROGRESS_DURATION;
+
+        final float windowRadius = mDeviceProfile.isMultiWindowMode
+                ? 0 :  getWindowCornerRadius(mLauncher.getResources());
+
         appAnimator.addUpdateListener(new MultiValueUpdateListener() {
             FloatProp mDx = new FloatProp(0, dX, 0, xDuration, AGGRESSIVE_EASE);
             FloatProp mDy = new FloatProp(0, dY, 0, yDuration, AGGRESSIVE_EASE);
@@ -514,13 +519,6 @@
                 float transX0 = temp.left - offsetX;
                 float transY0 = temp.top - offsetY;
 
-                float windowRadius = 0;
-                if (!mDeviceProfile.isMultiWindowMode &&
-                        RecentsModel.INSTANCE.get(mLauncher).supportsRoundedCornersOnWindows()) {
-                    windowRadius = RecentsModel.INSTANCE.get(mLauncher)
-                            .getWindowCornerRadius();
-                }
-
                 SurfaceParams[] params = new SurfaceParams[targets.length];
                 for (int i = targets.length - 1; i >= 0; i--) {
                     RemoteAnimationTargetCompat target = targets[i];
@@ -651,7 +649,7 @@
         ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
         unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
         float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
-                RecentsModel.INSTANCE.get(mLauncher).getWindowCornerRadius();
+                QuickStepContract.getWindowCornerRadius(mLauncher.getResources());
         unlockAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
@@ -677,8 +675,8 @@
         Matrix matrix = new Matrix();
         ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
         int duration = CLOSING_TRANSITION_DURATION_MS;
-        float windowCornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
-                RecentsModel.INSTANCE.get(mLauncher).getWindowCornerRadius();
+        float windowCornerRadius = mDeviceProfile.isMultiWindowMode
+                ? 0 : getWindowCornerRadius(mLauncher.getResources());
         closingAnimator.setDuration(duration);
         closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
             FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DEACCEL_1_7);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 482bbde..b263a4c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.QuickstepAppTransitionManagerImpl;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.quickstep.OverviewInteractionState;
 import com.android.quickstep.RecentsModel;
@@ -87,6 +86,9 @@
         }
         OverviewInteractionState.INSTANCE.get(launcher)
                 .setBackButtonAlpha(shouldBackButtonBeHidden ? 0 : 1, true /* animate */);
+        if (launcher != null && launcher.getDragLayer() != null) {
+            launcher.getDragLayer().setDisallowBackGesture(shouldBackButtonBeHidden);
+        }
     }
 
     public static void onCreate(Launcher launcher) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index ce50b68..0c29fcf 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -44,7 +44,6 @@
 import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.uioverrides.states.OverviewState;
-import com.android.launcher3.uioverrides.touchcontrollers.PortraitOverviewStateTouchHelper;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.quickstep.RecentsModel;
@@ -114,8 +113,10 @@
                 return false;
             }
         } else {
+            // If we are swiping to all apps instead of overview, allow it from anywhere.
+            boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
             // For all other states, only listen if the event originated below the hotseat height
-            if (!isTouchOverHotseat(mLauncher, ev)) {
+            if (!interceptAnywhere && !isTouchOverHotseat(mLauncher, ev)) {
                 return false;
             }
         }
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index a65bc33..675cfe2 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -35,6 +35,7 @@
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 
 import java.util.ArrayList;
@@ -62,9 +63,6 @@
     private final TaskIconCache mIconCache;
     private final TaskThumbnailCache mThumbnailCache;
 
-    private float mWindowCornerRadius = 0;
-    private boolean mSupportsRoundedCornersOnWindows;
-
     private RecentsModel(Context context) {
         mContext = context;
         HandlerThread loaderThread = new HandlerThread("TaskThumbnailIconCache",
@@ -76,12 +74,6 @@
         ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
     }
 
-    public void onInitializeSystemUI(Bundle params) {
-        mWindowCornerRadius = params.getFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, 0);
-        mSupportsRoundedCornersOnWindows =
-                params.getBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, false);
-    }
-
     public TaskIconCache getIconCache() {
         return mIconCache;
     }
@@ -182,14 +174,6 @@
         return mSystemUiProxy;
     }
 
-    public float getWindowCornerRadius() {
-        return mWindowCornerRadius;
-    }
-
-    public boolean supportsRoundedCornersOnWindows() {
-        return mSupportsRoundedCornersOnWindows;
-    }
-
     public void onTrimMemory(int level) {
         if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
             mThumbnailCache.getHighResLoadingState().setVisible(false);
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index bfe31d1..47f4f4d 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -27,8 +27,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
 
 import java.lang.annotation.Retention;
 
@@ -118,14 +116,10 @@
     }
 
     public static int getShelfTrackingDistance(Context context, DeviceProfile dp) {
-        if (SysUINavigationMode.getMode(context) == Mode.NO_BUTTON) {
-            // Track the bottom of the window rather than the top of the shelf.
-            int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
-            int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
-                    R.dimen.task_card_vert_space);
-            return shelfHeight + spaceBetweenShelfAndRecents;
-        }
-        // Start from a third of bottom inset to provide some shelf overlap.
-        return dp.hotseatBarSizePx + dp.getInsets().bottom / 3 - dp.edgeMarginPx * 2;
+        // Track the bottom of the window.
+        int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
+        int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
+                R.dimen.task_card_vert_space);
+        return shelfHeight + spaceBetweenShelfAndRecents;
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index d74e880..36521e5 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -53,6 +53,9 @@
     // cover the whole screen
     private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f;
 
+    // Temporarily needed until android.R.attr.bottomDialogCornerRadius becomes public
+    private static final float BOTTOM_CORNER_RADIUS_RATIO = 2f;
+
     // In transposed layout, we simply draw a flat color.
     private boolean mDrawingFlatColor;
 
@@ -87,7 +90,7 @@
         mMaxScrimAlpha = Math.round(OVERVIEW.getWorkspaceScrimAlpha(mLauncher) * 255);
 
         mEndAlpha = Color.alpha(mEndScrim);
-        mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius);
+        mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context);
         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
         mShelfOffset = context.getResources().getDimension(R.dimen.shelf_surface_offset);
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 895485d..6034791 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -32,7 +32,6 @@
 
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.tapl.TestHelpers;
-import com.android.systemui.shared.system.QuickStepContract;
 
 import org.junit.Assert;
 import org.junit.rules.TestRule;
@@ -78,9 +77,9 @@
                 @Override
                 public void evaluate() throws Throwable {
                     final Context context = getInstrumentation().getContext();
-                    final String prevOverlayPkg = QuickStepContract.isGesturalMode(context)
+                    final String prevOverlayPkg = LauncherInstrumentation.isGesturalMode(context)
                             ? NAV_BAR_MODE_GESTURAL_OVERLAY
-                            : QuickStepContract.isSwipeUpMode(context)
+                            : LauncherInstrumentation.isSwipeUpMode(context)
                                     ? NAV_BAR_MODE_2BUTTON_OVERLAY
                                     : NAV_BAR_MODE_3BUTTON_OVERLAY;
                     final LauncherInstrumentation.NavigationModel originalMode =
@@ -150,4 +149,4 @@
             return base;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/res/drawable-v28/round_rect_primary.xml b/res/drawable-v28/round_rect_primary.xml
new file mode 100644
index 0000000..53679ed
--- /dev/null
+++ b/res/drawable-v28/round_rect_primary.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="?android:attr/colorPrimary" />
+    <corners android:radius="?android:attr/dialogCornerRadius" />
+</shape>
diff --git a/res/drawable-v28/top_round_rect_primary.xml b/res/drawable-v28/top_round_rect_primary.xml
new file mode 100644
index 0000000..5c40df7
--- /dev/null
+++ b/res/drawable-v28/top_round_rect_primary.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="?android:attr/colorPrimary" />
+    <corners
+        android:topLeftRadius="?android:attr/dialogCornerRadius"
+        android:topRightRadius="?android:attr/dialogCornerRadius"
+        android:bottomLeftRadius="0dp"
+        android:bottomRightRadius="0dp"
+        />
+</shape>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index a471e50..008910d 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -33,7 +33,7 @@
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Tryk to gange, og hold fingeren nede for at vælge en widget eller bruge tilpassede handlinger."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i bredden og %2$d i højden"</string>
-    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tryk og hold fingeren nede for at placere manuelt"</string>
+    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tryk og hold nede for at placere manuelt"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Tilføj automatisk"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Søg efter apps"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Indlæser apps…"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index d4bfbc1..e03340b 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -33,7 +33,7 @@
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"വിജറ്റ് തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d വീതിയും %2$d ഉയരവും"</string>
-    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"സ്വമേധയാ സ്ഥാപിക്കുന്നതിന് സ്‌പർശിച്ചുപിടിക്കുക"</string>
+    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"നേരിട്ട് സ്ഥാപിക്കുന്നതിന് സ്‌പർശിച്ചുപിടിക്കുക"</string>
     <string name="place_automatically" msgid="8064208734425456485">"സ്വയമേവ ചേർക്കുക"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ആപ്പുകൾ തിരയുക"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ആപ്പുകൾ ലോഡുചെയ്യുന്നു..."</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 60dc9a6..f6eac53 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -34,7 +34,7 @@
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d रूंद बाय %2$d उंच"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"स्वतः ठेवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string>
-    <string name="place_automatically" msgid="8064208734425456485">"अापोआप जोडा"</string>
+    <string name="place_automatically" msgid="8064208734425456485">"आपोआप जोडा"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"अॅप्स शोधा"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"अॅप्स लोड करत आहे…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 0bd1911..d4cd5be 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -104,7 +104,7 @@
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
     <string name="widgets_list" msgid="796804551140113767">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ ਬੰਦ ਕੀਤੀ ਗਈ"</string>
-    <string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ਆਈਟਮ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
     <string name="item_removed" msgid="851119963877842327">"ਅਈਟਮ ਹਟਾਈ ਗਈ"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 1b74be1..528ce48 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -33,8 +33,8 @@
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"విడ్జెట్‌ను ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి, ఉంచండి."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d వెడల్పు X %2$d ఎత్తు"</string>
-    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"మాన్యువల్‌గా ఉంచడానికి నొక్కి &amp;amp పట్టుకోండి"</string>
-    <string name="place_automatically" msgid="8064208734425456485">"స్వయంచాలకంగా జోడించు"</string>
+    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"మాన్యువల్‌గా ఉంచడానికి నొక్కి, పట్టుకోండి"</string>
+    <string name="place_automatically" msgid="8064208734425456485">"ఆటోమేటిక్‌గా జోడించు"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"అప్లికేషన్‌లను శోధించండి"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"అప్లికేషన్‌లను లోడ్ చేస్తోంది…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అప్లికేషన్‌లేవీ కనుగొనబడలేదు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index fee76e6..03c02ad 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -104,7 +104,7 @@
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"วิดเจ็ตของ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_list" msgid="796804551140113767">"รายการวิดเจ็ต"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"ปิดรายการวิดเจ็ตแล้ว"</string>
-    <string name="action_add_to_workspace" msgid="8902165848117513641">"เพิ่มลงในหน้าแรก"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"เพิ่มลงในหน้าจอหลัก"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ย้ายรายการมาที่นี่"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"เพิ่มรายการไปยังหน้าจอหลักแล้ว"</string>
     <string name="item_removed" msgid="851119963877842327">"นำออกรายการออกแล้ว"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 359934e..f0c241e 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -33,7 +33,7 @@
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"I-double tap nang matagal upang pumili ng widget o gumamit ng mga custom na pagkilos."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ang lapad at %2$d ang taas"</string>
-    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pindutin nang matagal upang manual na ilagay"</string>
+    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Pindutin nang matagal para manual na ilagay"</string>
     <string name="place_automatically" msgid="8064208734425456485">"Awtomatikong idagdag"</string>
     <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Maghanap ng mga app"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Naglo-load ng mga app…"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7822e05..469b176 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -37,8 +37,6 @@
     <dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
 
     <!-- Hotseat/all-apps scrim -->
-    <dimen name="all_apps_scrim_radius">8dp</dimen>
-    <dimen name="all_apps_scrim_margin">8dp</dimen>
     <dimen name="all_apps_scrim_blur">4dp</dimen>
     <dimen name="vertical_drag_handle_size">24dp</dimen>
     <dimen name="vertical_drag_handle_overlap_workspace">0dp</dimen>
@@ -237,4 +235,8 @@
 <!-- Hints -->
     <dimen name="chip_hint_height">26dp</dimen>
     <dimen name="chip_hint_bottom_margin">194dp</dimen>
+
+<!-- Theming related -->
+    <dimen name="default_dialog_corner_radius">8dp</dimen>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 252cae1..ec63e35 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -44,7 +44,7 @@
         <item name="widgetsTheme">@style/WidgetContainerTheme</item>
         <item name="folderDotColor">?android:attr/colorPrimary</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
-        <item name="loadingIconColor">#FFF</item>
+        <item name="loadingIconColor">#CCFFFFFF</item>
 
         <item name="android:windowTranslucentStatus">false</item>
         <item name="android:windowTranslucentNavigation">false</item>
@@ -82,7 +82,7 @@
         <item name="folderDotColor">#FF464646</item>
         <item name="folderIconBorderColor">#FF80868B</item>
         <item name="isMainColorDark">true</item>
-        <item name="loadingIconColor">#000</item>
+        <item name="loadingIconColor">#99FFFFFF</item>
     </style>
 
     <style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
diff --git a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java
index 656d55c..ae81ff2 100644
--- a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java
+++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java
@@ -26,7 +26,6 @@
     @Test
     public void withFlagOn() {
         assertTrue(FeatureFlags.EXAMPLE_FLAG.get());
-        assertFalse(FeatureFlags.STYLE_WALLPAPER.get());
     }
 
 
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 599a353..e7d7a69 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -19,9 +19,11 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+
 import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
 
+import android.animation.Animator;
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.util.AttributeSet;
@@ -30,7 +32,11 @@
 import android.view.View;
 import android.widget.LinearLayout;
 
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
@@ -38,8 +44,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-import androidx.annotation.IntDef;
-
 /**
  * Base class for a View which shows a floating UI on top of the launcher UI.
  */
@@ -124,8 +128,20 @@
 
     protected abstract void handleClose(boolean animate);
 
+    /**
+     * Creates a user-controlled animation to hint that the view will be closed if completed.
+     * @param distanceToMove The max distance that elements should move from their starting point.
+     */
+    public @Nullable Animator createHintCloseAnim(float distanceToMove) {
+        return null;
+    }
+
     public abstract void logActionCommand(int command);
 
+    public int getLogContainerType() {
+        return ContainerType.DEFAULT_CONTAINERTYPE;
+    }
+
     public final boolean isOpen() {
         return mIsOpen;
     }
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 62bc53a..0d9bd31 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -50,6 +50,7 @@
 
 import java.io.IOException;
 import java.util.Locale;
+import java.util.function.Supplier;
 
 /**
  * Layout parsing code for auto installs layout
@@ -76,12 +77,8 @@
         if (customizationApkInfo == null) {
             return null;
         }
-        return get(context, customizationApkInfo.first, customizationApkInfo.second,
-                appWidgetHost, callback);
-    }
-
-    static AutoInstallsLayout get(Context context, String pkg, Resources targetRes,
-            AppWidgetHost appWidgetHost, LayoutParserCallback callback) {
+        String pkg = customizationApkInfo.first;
+        Resources targetRes = customizationApkInfo.second;
         InvariantDeviceProfile grid = LauncherAppState.getIDP(context);
 
         // Try with grid size and hotseat count
@@ -114,7 +111,7 @@
 
     // Object Tags
     private static final String TAG_INCLUDE = "include";
-    private static final String TAG_WORKSPACE = "workspace";
+    public static final String TAG_WORKSPACE = "workspace";
     private static final String TAG_APP_ICON = "appicon";
     private static final String TAG_AUTO_INSTALL = "autoinstall";
     private static final String TAG_FOLDER = "folder";
@@ -156,7 +153,7 @@
 
     protected final PackageManager mPackageManager;
     protected final Resources mSourceRes;
-    protected final int mLayoutId;
+    protected final Supplier<XmlPullParser> mInitialLayoutSupplier;
 
     private final InvariantDeviceProfile mIdp;
     private final int mRowCount;
@@ -171,6 +168,12 @@
     public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
             LayoutParserCallback callback, Resources res,
             int layoutId, String rootTag) {
+        this(context, appWidgetHost, callback, res, () -> res.getXml(layoutId), rootTag);
+    }
+
+    public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
+            LayoutParserCallback callback, Resources res,
+            Supplier<XmlPullParser> initialLayoutSupplier, String rootTag) {
         mContext = context;
         mAppWidgetHost = appWidgetHost;
         mCallback = callback;
@@ -180,7 +183,7 @@
         mRootTag = rootTag;
 
         mSourceRes = res;
-        mLayoutId = layoutId;
+        mInitialLayoutSupplier = initialLayoutSupplier;
 
         mIdp = LauncherAppState.getIDP(context);
         mRowCount = mIdp.numRows;
@@ -193,9 +196,9 @@
     public int loadLayout(SQLiteDatabase db, IntArray screenIds) {
         mDb = db;
         try {
-            return parseLayout(mLayoutId, screenIds);
+            return parseLayout(mInitialLayoutSupplier.get(), screenIds);
         } catch (Exception e) {
-            Log.e(TAG, "Error parsing layout: " + e);
+            Log.e(TAG, "Error parsing layout: ", e);
             return -1;
         }
     }
@@ -203,9 +206,8 @@
     /**
      * Parses the layout and returns the number of elements added on the homescreen.
      */
-    protected int parseLayout(int layoutId, IntArray screenIds)
+    protected int parseLayout(XmlPullParser parser, IntArray screenIds)
             throws XmlPullParserException, IOException {
-        XmlPullParser parser = mSourceRes.getXml(layoutId);
         beginDocument(parser, mRootTag);
         final int depth = parser.getDepth();
         int type;
@@ -248,7 +250,7 @@
             final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
             if (resId != 0) {
                 // recursively load some more favorites, why not?
-                return parseLayout(resId, screenIds);
+                return parseLayout(mSourceRes.getXml(resId), screenIds);
             } else {
                 return 0;
             }
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index 639c173..5424a8f 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -33,12 +33,20 @@
 
     class CheckForLongPress implements Runnable {
         public void run() {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                        "CheckForLongPress1");
+            }
             if ((mView.getParent() != null) && mView.hasWindowFocus()
                     && !mHasPerformedLongPress) {
                 boolean handled;
                 if (mListener != null) {
                     handled = mListener.onLongClick(mView);
                 } else {
+                    if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                        android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                                "CheckForLongPress2");
+                    }
                     handled = mView.performLongClick();
                 }
                 if (handled) {
@@ -73,11 +81,20 @@
         }
         mView.postDelayed(mPendingCheckForLongPress,
                 (long) (ViewConfiguration.getLongPressTimeout() * mLongPressTimeoutFactor));
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                    "postCheckForLongPress: " + ViewConfiguration.getLongPressTimeout() + " "
+                            + mLongPressTimeoutFactor);
+        }
     }
 
     public void cancelLongPress() {
         mHasPerformedLongPress = false;
         if (mPendingCheckForLongPress != null) {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                        "cancelLongPress");
+            }
             mView.removeCallbacks(mPendingCheckForLongPress);
             mPendingCheckForLongPress = null;
         }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index cbd3fc0..4da7907 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -20,6 +20,7 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
@@ -98,4 +99,10 @@
         setLayoutParams(lp);
         InsettableFrameLayout.dispatchInsets(this, insets);
     }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // Don't let if follow through to workspace
+        return true;
+    }
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f8d9959..c14512a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -974,7 +974,6 @@
         mDropTargetBar.setup(mDragController);
 
         mAllAppsController.setupViews(mAppsView);
-        mHotseat.setOnInterceptTouchListener(mWorkspace::onInterceptHotseatTouch);
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 39d93c8..f830301 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -34,6 +34,7 @@
 import android.content.OperationApplicationException;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ProviderInfo;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
@@ -51,8 +52,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.BaseColumns;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Xml;
 
 import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -63,15 +66,21 @@
 import com.android.launcher3.provider.LauncherDbUtils;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
 import com.android.launcher3.provider.RestoreDbTask;
+import com.android.launcher3.util.IOUtils;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.NoLocaleSQLiteHelper;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.Thunk;
 
+import org.xmlpull.v1.XmlPullParser;
+
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
+import java.io.StringReader;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -93,8 +102,6 @@
 
     static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
 
-    private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name";
-
     private final ChangeListenerWrapper mListenerWrapper = new ChangeListenerWrapper();
     private Handler mListenerHandler;
 
@@ -505,25 +512,40 @@
      */
     private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) {
         Context ctx = getContext();
-        UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
-        Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName());
-        if (bundle == null) {
+        InvariantDeviceProfile grid = LauncherAppState.getIDP(ctx);
+
+        String authority = Settings.Secure.getString(ctx.getContentResolver(),
+                "launcher3.layout.provider");
+        if (TextUtils.isEmpty(authority)) {
             return null;
         }
 
-        String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME);
-        if (packageName != null) {
-            try {
-                Resources targetResources = ctx.getPackageManager()
-                        .getResourcesForApplication(packageName);
-                return AutoInstallsLayout.get(ctx, packageName, targetResources,
-                        widgetHost, mOpenHelper);
-            } catch (NameNotFoundException e) {
-                Log.e(TAG, "Target package for restricted profile not found", e);
-                return null;
-            }
+        ProviderInfo pi = ctx.getPackageManager().resolveContentProvider(authority, 0);
+        if (pi == null) {
+            Log.e(TAG, "No provider found for authority " + authority);
+            return null;
         }
-        return null;
+        Uri uri = new Uri.Builder().scheme("content").authority(authority).path("launcher_layout")
+                .appendQueryParameter("version", "1")
+                .appendQueryParameter("gridWidth", Integer.toString(grid.numColumns))
+                .appendQueryParameter("gridHeight", Integer.toString(grid.numRows))
+                .appendQueryParameter("hotseatSize", Integer.toString(grid.numHotseatIcons))
+                .build();
+
+        try (InputStream in = ctx.getContentResolver().openInputStream(uri)) {
+            // Read the full xml so that we fail early in case of any IO error.
+            String layout = new String(IOUtils.toByteArray(in));
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(new StringReader(layout));
+
+            Log.d(TAG, "Loading layout from " + authority);
+            return new AutoInstallsLayout(ctx, widgetHost, mOpenHelper,
+                    ctx.getPackageManager().getResourcesForApplication(pi.applicationInfo),
+                    () -> parser, AutoInstallsLayout.TAG_WORKSPACE);
+        } catch (Exception e) {
+            Log.e(TAG, "Error getting layout stream from: " + authority , e);
+            return null;
+        }
     }
 
     private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 7fa1aa0..ed77786 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -133,9 +133,6 @@
     @Thunk int mPageIndicatorViewId;
     protected T mPageIndicator;
 
-    // Convenience/caching
-    private static final Rect sTmpRect = new Rect();
-
     protected final Rect mInsets = new Rect();
     protected boolean mIsRtl;
 
@@ -805,12 +802,6 @@
         super.requestDisallowInterceptTouchEvent(disallowIntercept);
     }
 
-    /** Returns whether x and y originated within the buffered viewport */
-    private boolean isTouchPointInViewportWithBuffer(float x, float y) {
-        sTmpRect.set(-getMeasuredWidth() / 2, 0, 3 * getMeasuredWidth() / 2, getMeasuredHeight());
-        return sTmpRect.contains((int) x, (int) y);
-    }
-
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         /*
@@ -876,7 +867,7 @@
                         pageEndTransition();
                     }
                 } else {
-                    mIsBeingDragged = isTouchPointInViewportWithBuffer(mDownMotionX, mDownMotionY);
+                    mIsBeingDragged = true;
                 }
 
                 break;
@@ -917,13 +908,8 @@
         final int pointerIndex = ev.findPointerIndex(mActivePointerId);
         if (pointerIndex == -1) return;
 
-        // Disallow scrolling if we started the gesture from outside the viewport
         final float x = ev.getX(pointerIndex);
-        final float y = ev.getY(pointerIndex);
-        if (!isTouchPointInViewportWithBuffer(x, y)) return;
-
         final int xDiff = (int) Math.abs(x - mLastMotionX);
-
         final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
         boolean xMoved = xDiff > touchSlop;
 
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index d24a5a6..2ee537c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -475,13 +475,6 @@
         super.onViewAdded(child);
     }
 
-    protected boolean onInterceptHotseatTouch(View v, MotionEvent ev) {
-        // We don't want any clicks to go through to the hotseat unless the workspace is in
-        // the normal state or an accessible drag is in progress.
-        return !workspaceIconsCanBeDragged()
-                && !mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
-    }
-
     /**
      * Initializes and binds the first page
      * @param qsb an existing qsb to recycle or null.
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 5150b7c..a55ea82 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -90,10 +90,6 @@
     // trying to make them fit the orientation the device is in.
     public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
 
-    public static final ToggleableGlobalSettingsFlag STYLE_WALLPAPER
-            = new ToggleableGlobalSettingsFlag("STYLE_WALLPAPER", false,
-            "Direct users to the new ThemePicker based WallpaperPicker");
-
     /**
      * Feature flag to handle define config changes dynamically instead of killing the process.
      */
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 9f902ed..6cc49de 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -24,10 +24,12 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -43,6 +45,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.folder.Folder;
@@ -54,6 +57,8 @@
 import com.android.launcher3.views.BaseDragLayer;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * A ViewGroup that coordinates dragging across its descendants
@@ -68,6 +73,9 @@
     public static final int ANIMATION_END_DISAPPEAR = 0;
     public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
 
+    private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
+            Collections.singletonList(new Rect());
+
     @Thunk DragController mDragController;
 
     // Variables relating to animation of views after drop
@@ -86,6 +94,8 @@
     private final ViewGroupFocusHelper mFocusIndicatorHelper;
     private final WorkspaceAndHotseatScrim mScrim;
 
+    private boolean mDisallowBackGesture;
+
     /**
      * Used to create a new DragLayer from XML.
      *
@@ -552,6 +562,24 @@
         mScrim.onInsetsChanged(insets);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(l, t, r, b);
+        setDisallowBackGesture(mDisallowBackGesture);
+    }
+
+    @TargetApi(Build.VERSION_CODES.Q)
+    public void setDisallowBackGesture(boolean disallowBackGesture) {
+        if (!Utilities.ATLEAST_Q) {
+            return;
+        }
+        mDisallowBackGesture = disallowBackGesture;
+        setSystemGestureExclusionRects(mDisallowBackGesture
+                ? SYSTEM_GESTURE_EXCLUSION_RECT
+                : Collections.emptyList());
+    }
+
     public WorkspaceAndHotseatScrim getScrim() {
         return mScrim;
     }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index bcddd03..2ce6634 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1406,7 +1406,12 @@
     @Override
     public void logActionCommand(int command) {
         mLauncher.getUserEventDispatcher().logActionCommand(
-                command, getFolderIcon(), ContainerType.FOLDER);
+                command, getFolderIcon(), getLogContainerType());
+    }
+
+    @Override
+    public int getLogContainerType() {
+        return ContainerType.FOLDER;
     }
 
     @Override
diff --git a/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java b/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
index 5f2fb59..23745cb 100644
--- a/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.graphics;
 
+import static androidx.core.graphics.ColorUtils.compositeColors;
+
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -47,7 +49,8 @@
         super(b, iconColor);
 
         mProgressPath = progressPath;
-        mPaint.setColor(Themes.getAttrColor(context, R.attr.loadingIconColor));
+        mPaint.setColor(compositeColors(
+                Themes.getAttrColor(context, R.attr.loadingIconColor), iconColor));
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 2b20b08..cc8e92f 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -425,7 +425,8 @@
                                     } else if (installingPkgs.containsKey(targetPkg)) {
                                         // App restore has started. Update the flag
                                         c.restoreFlag |= ShortcutInfo.FLAG_RESTORE_STARTED;
-                                        c.updater().commit();
+                                        c.updater().put(LauncherSettings.Favorites.RESTORED,
+                                                c.restoreFlag).commit();
                                     } else {
                                         c.markDeleted("Unrestored app removed: " + targetPkg);
                                         continue;
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 0d499c1..28000b9 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -82,7 +82,7 @@
     public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mInflater = LayoutInflater.from(context);
-        mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
+        mOutlineRadius = Themes.getDialogCornerRadius(context);
         mLauncher = Launcher.getLauncher(context);
         mIsRtl = Utilities.isRtl(getResources());
 
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 080a0cb..593dbd4 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -157,7 +157,12 @@
     @Override
     public void logActionCommand(int command) {
         mLauncher.getUserEventDispatcher().logActionCommand(
-                command, mOriginalIcon, ContainerType.DEEPSHORTCUTS);
+                command, mOriginalIcon, getLogContainerType());
+    }
+
+    @Override
+    public int getLogContainerType() {
+        return ContainerType.DEEPSHORTCUTS;
     }
 
     public OnClickListener getItemClickListener() {
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 675e2f4..59fd859 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -25,11 +25,25 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 
+import com.android.launcher3.R;
+
 /**
  * Various utility methods associated with theming.
  */
 public class Themes {
 
+    public static float getDialogCornerRadius(Context context) {
+        return getDimension(context, android.R.attr.dialogCornerRadius,
+                context.getResources().getDimension(R.dimen.default_dialog_corner_radius));
+    }
+
+    public static float getDimension(Context context, int attr, float defaultValue) {
+        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+        float value = ta.getDimension(0, defaultValue);
+        ta.recycle();
+        return value;
+    }
+
     public static int getColorAccent(Context context) {
         return getAttrColor(context, android.R.attr.colorAccent);
     }
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index bd6bfd6..ab72bbe 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -223,14 +223,18 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
-        return verifyTouchDispatch(this, ev) && super.dispatchTouchEvent(ev);
+        return dispatchTouchEvent(this, ev);
+    }
+
+    public boolean dispatchTouchEvent(Object caller, MotionEvent ev) {
+        return verifyTouchDispatch(caller, ev) && super.dispatchTouchEvent(ev);
     }
 
     /**
      * Returns true if the {@param caller} is allowed to dispatch {@param ev} on this view,
      * false otherwise.
      */
-    public boolean verifyTouchDispatch(Object caller, MotionEvent ev) {
+    private boolean verifyTouchDispatch(Object caller, MotionEvent ev) {
         int action = ev.getAction();
         if (action == ACTION_DOWN) {
             if (mCurrentTouchOwner != null) {
diff --git a/src/com/android/launcher3/views/BottomUserEducationView.java b/src/com/android/launcher3/views/BottomUserEducationView.java
index a291fc6..bdc69af 100644
--- a/src/com/android/launcher3/views/BottomUserEducationView.java
+++ b/src/com/android/launcher3/views/BottomUserEducationView.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.views;
 
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.graphics.Rect;
@@ -28,8 +30,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.Interpolators;
-
-import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 
 public class BottomUserEducationView extends AbstractSlideInView implements Insettable {
 
@@ -71,6 +72,11 @@
     }
 
     @Override
+    public int getLogContainerType() {
+        return ContainerType.TIP;
+    }
+
+    @Override
     protected boolean isOfType(int type) {
         return (type & TYPE_ON_BOARD_POPUP) != 0;
     }
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 5889468..fab21fa 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -34,6 +34,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
 import android.view.View;
@@ -73,6 +74,7 @@
     private static final Rect sTmpRect = new Rect();
 
     private Runnable mEndRunnable;
+    private CancellationSignal mLoadIconSignal;
 
     private final int mBlurSizeOutline;
 
@@ -153,6 +155,9 @@
 
     @Override
     public void onAnimationEnd(Animator animator) {
+        if (mLoadIconSignal != null) {
+            mLoadIconSignal.cancel();
+        }
         if (mEndRunnable != null) {
             mEndRunnable.run();
         } else {
@@ -186,7 +191,7 @@
 
     @WorkerThread
     private void getIcon(Launcher launcher, View v, ItemInfo info, boolean isOpening,
-            Runnable onIconLoadedRunnable) {
+            Runnable onIconLoadedRunnable, CancellationSignal loadIconSignal) {
         final LayoutParams lp = (LayoutParams) getLayoutParams();
         Drawable drawable = null;
         boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get()
@@ -290,7 +295,9 @@
                 setBackground(finalDrawable);
             }
 
-            onIconLoadedRunnable.run();
+            if (!loadIconSignal.isCanceled()) {
+                onIconLoadedRunnable.run();
+            }
             invalidate();
             invalidateOutline();
         });
@@ -386,6 +393,7 @@
         // Get the drawable on the background thread
         // Must be called after matchPositionOf so that we know what size to load.
         if (originalView.getTag() instanceof ItemInfo) {
+            view.mLoadIconSignal = new CancellationSignal();
             Runnable onIconLoaded = () -> {
                 // Delay swapping views until the icon is loaded to prevent a flash.
                 view.setVisibility(VISIBLE);
@@ -393,9 +401,10 @@
                     originalView.setVisibility(INVISIBLE);
                 }
             };
+            CancellationSignal loadIconSignal = view.mLoadIconSignal;
             new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> {
                 view.getIcon(launcher, originalView, (ItemInfo) originalView.getTag(), isOpening,
-                        onIconLoaded);
+                        onIconLoaded, loadIconSignal);
             });
         }
 
@@ -461,6 +470,10 @@
         setScaleY(1);
         setAlpha(1);
         setBackground(null);
+        if (mLoadIconSignal != null) {
+            mLoadIconSignal.cancel();
+        }
+        mLoadIconSignal = null;
         mEndRunnable = null;
         mIsAdaptiveIcon = false;
         mForeground = null;
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 6a2f0ff..29866cf 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -152,7 +152,7 @@
         RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
 
         ArrayList<OptionItem> options = new ArrayList<>();
-        int res = FeatureFlags.STYLE_WALLPAPER.get() && existsStyleWallpapers(launcher) ?
+        int res = existsStyleWallpapers(launcher) ?
                 R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
         options.add(new OptionItem(res, R.drawable.ic_wallpaper,
                 ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
@@ -210,7 +210,7 @@
                 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                 .putExtra(EXTRA_WALLPAPER_OFFSET,
                         launcher.getWorkspace().getWallpaperOffsetForCenterPage());
-        if (!FeatureFlags.STYLE_WALLPAPER.get()) {
+        if (!existsStyleWallpapers(launcher)) {
             intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only");
         }
         String pickerPackage = launcher.getString(R.string.wallpaper_picker_package);
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 883cbee..5653801 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -24,6 +24,7 @@
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.util.Property;
 import android.view.MotionEvent;
@@ -31,13 +32,16 @@
 import android.view.ViewConfiguration;
 import android.widget.TextView;
 
+import androidx.recyclerview.widget.RecyclerView;
+
 import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.graphics.FastScrollThumbDrawable;
 import com.android.launcher3.util.Themes;
 
-import androidx.recyclerview.widget.RecyclerView;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * The track and scrollbar that shows when you scroll the list.
@@ -65,6 +69,9 @@
     private final static int SCROLL_BAR_VIS_DURATION = 150;
     private static final float FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR = 0.75f;
 
+    private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
+            Collections.singletonList(new Rect());
+
     private final int mMinWidth;
     private final int mMaxWidth;
     private final int mThumbPadding;
@@ -81,6 +88,8 @@
 
     private final Paint mThumbPaint;
     protected final int mThumbHeight;
+    private final RectF mThumbBounds = new RectF();
+    private final Point mThumbDrawOffset = new Point();
 
     private final Paint mTrackPaint;
 
@@ -292,15 +301,23 @@
         }
         int saveCount = canvas.save();
         canvas.translate(getWidth() / 2, mRv.getScrollBarTop());
+        mThumbDrawOffset.set(getWidth() / 2, mRv.getScrollBarTop());
         // Draw the track
         float halfW = mWidth / 2;
         canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
                 mWidth, mWidth, mTrackPaint);
 
         canvas.translate(0, mThumbOffsetY);
+        mThumbDrawOffset.y += mThumbOffsetY;
         halfW += mThumbPadding;
         float r = getScrollThumbRadius();
-        canvas.drawRoundRect(-halfW, 0, halfW, mThumbHeight, r, r, mThumbPaint);
+        mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
+        canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
+        if (Utilities.ATLEAST_Q) {
+            mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
+            SYSTEM_GESTURE_EXCLUSION_RECT.get(0).offset(mThumbDrawOffset.x, mThumbDrawOffset.y);
+            setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
+        }
         canvas.restoreToCount(saveCount);
     }
 
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index df82661..72cddc7 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -162,11 +162,16 @@
 
     @Override
     public final void logActionCommand(int command) {
-        Target target = newContainerTarget(ContainerType.WIDGETS);
+        Target target = newContainerTarget(getLogContainerType());
         target.cardinality = getElementsRowCount();
         mLauncher.getUserEventDispatcher().logActionCommand(command, target);
     }
 
+    @Override
+    public int getLogContainerType() {
+        return ContainerType.WIDGETS;
+    }
+
     protected abstract int getElementsRowCount();
 
     protected SystemUiController getSystemUiController() {
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 05368fa..3e2c0ae 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -16,10 +16,13 @@
 
 package com.android.launcher3.widget;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.IntProperty;
 import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -27,6 +30,8 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.Insettable;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppState;
@@ -43,6 +48,20 @@
  */
 public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
 
+    private static final IntProperty<View> PADDING_BOTTOM =
+            new IntProperty<View>("paddingBottom") {
+                @Override
+                public void setValue(View view, int paddingBottom) {
+                    view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
+                            view.getPaddingRight(), paddingBottom);
+                }
+
+                @Override
+                public Integer get(View view) {
+                    return view.getPaddingBottom();
+                }
+            };
+
     private static final int DEFAULT_CLOSE_DURATION = 200;
     private ItemInfo mOriginalItemInfo;
     private Rect mInsets;
@@ -158,8 +177,7 @@
         int rightInset = insets.right - mInsets.right;
         int bottomInset = insets.bottom - mInsets.bottom;
         mInsets.set(insets);
-        setPadding(getPaddingLeft() + leftInset, getPaddingTop(),
-                getPaddingRight() + rightInset, getPaddingBottom() + bottomInset);
+        setPadding(leftInset, getPaddingTop(), rightInset, bottomInset);
     }
 
     @Override
@@ -172,4 +190,10 @@
         return Pair.create(findViewById(R.id.title),  getContext().getString(
                 mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
     }
+
+    @Nullable
+    @Override
+    public Animator createHintCloseAnim(float distanceToMove) {
+        return ObjectAnimator.ofInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom));
+    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index ec06d1e..521f511 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -17,6 +17,8 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.graphics.Rect;
@@ -27,6 +29,9 @@
 import android.view.View;
 import android.view.animation.AnimationUtils;
 
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
@@ -35,8 +40,6 @@
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.TopRoundedCornerView;
 
-import androidx.annotation.VisibleForTesting;
-
 /**
  * Popup for showing the full list of available widgets
  */
@@ -235,4 +238,13 @@
     protected int getElementsRowCount() {
         return mAdapter.getItemCount();
     }
+
+    @Nullable
+    @Override
+    public Animator createHintCloseAnim(float distanceToMove) {
+        AnimatorSet anim = new AnimatorSet();
+        anim.play(ObjectAnimator.ofFloat(mRecyclerView, TRANSLATION_Y, -distanceToMove));
+        anim.play(ObjectAnimator.ofFloat(mRecyclerView, ALPHA, 0.5f));
+        return anim;
+    }
 }
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 46b463b..089d672 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -97,5 +97,13 @@
                 <category android:name="android.intent.category.LAUNCHER_APP" />
             </intent-filter>
         </activity>
+        <activity
+            android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
+            android:label="LauncherTestApp">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java b/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java
index 904590c..9c6d102 100644
--- a/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java
+++ b/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Color;
 import android.os.Bundle;
 import android.util.TypedValue;
 import android.view.View;
@@ -63,6 +64,7 @@
         mView = new LinearLayout(this);
         mView.setPadding(mMargin, mMargin, mMargin, mMargin);
         mView.setOrientation(LinearLayout.VERTICAL);
+        mView.setBackgroundColor(Color.BLUE);
         setContentView(mView);
 
         registerReceiver(mCommandReceiver, new IntentFilter(mAction + SUFFIX_COMMAND));
diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
index 0edb3d6..fa23b8d 100644
--- a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
+++ b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java
@@ -18,6 +18,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.content.pm.PackageManager.DONT_KILL_APP;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -28,6 +29,13 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.util.Base64;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -104,4 +112,19 @@
         Uri uri = Uri.parse("content://" + inst.getContext().getPackageName() + ".commands");
         return inst.getTargetContext().getContentResolver().call(uri, command, arg, null);
     }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        String path = Base64.encodeToString(uri.getPath().getBytes(),
+                Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP);
+        File file = new File(getContext().getCacheDir(), path);
+        if (!file.exists()) {
+            // Create an empty file so that we can pass its descriptor
+            try {
+                file.createNewFile();
+            } catch (IOException e) { }
+        }
+
+        return ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+    }
 }
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 8a2e816..9e77937 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -102,10 +102,6 @@
         }
         if (TestHelpers.isInLauncherProcess()) Utilities.enableRunningInTestHarnessForTests();
         mLauncher = new LauncherInstrumentation(instrumentation);
-        try {
-            mDevice.executeShellCommand("settings delete secure assistant");
-        } catch (IOException e) {
-        }
     }
 
     @Rule
diff --git a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java
new file mode 100644
index 0000000..1efdee8
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.android.launcher3.ui;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
+
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.testcomponent.TestCommandReceiver;
+import com.android.launcher3.util.LauncherLayoutBuilder;
+import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.OutputStreamWriter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.UiSelector;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
+
+    @Rule
+    public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+
+    private static final String SETTINGS_APP = "com.android.settings";
+
+    private Context mContext;
+    private String mAuthority;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mContext = InstrumentationRegistry.getContext();
+
+        PackageManager pm = mTargetContext.getPackageManager();
+        ProviderInfo pi = pm.getProviderInfo(new ComponentName(mContext,
+                TestCommandReceiver.class), 0);
+        mAuthority = pi.authority;
+    }
+
+    @Test
+    public void testCustomProfileLoaded_with_icon_on_hotseat() throws Exception {
+        writeLayout(new LauncherLayoutBuilder().atHotseat(0).putApp(SETTINGS_APP, SETTINGS_APP));
+
+        // Launch the home activity
+        mActivityMonitor.startLauncher();
+        waitForModelLoaded();
+
+        // Verify widget present
+        UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
+                .description(getSettingsApp().getLabel().toString());
+        assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+    }
+
+    @Test
+    public void testCustomProfileLoaded_with_widget() throws Exception {
+        // A non-restored widget with no config screen gets restored automatically.
+        LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
+
+        writeLayout(new LauncherLayoutBuilder().atWorkspace(0, 1, 0)
+                .putWidget(info.getComponent().getPackageName(),
+                        info.getComponent().getClassName(), 2, 2));
+
+        // Launch the home activity
+        mActivityMonitor.startLauncher();
+        waitForModelLoaded();
+
+        // Verify widget present
+        UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
+                .className(LauncherAppWidgetHostView.class).description(info.label);
+        assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+    }
+
+    @Test
+    public void testCustomProfileLoaded_with_folder() throws Exception {
+        writeLayout(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
+                .addApp(SETTINGS_APP, SETTINGS_APP)
+                .addApp(SETTINGS_APP, SETTINGS_APP)
+                .addApp(SETTINGS_APP, SETTINGS_APP)
+                .build());
+
+        // Launch the home activity
+        mActivityMonitor.startLauncher();
+        waitForModelLoaded();
+
+        // Verify widget present
+        UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
+                .descriptionContains(mTargetContext.getString(android.R.string.copy));
+        assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+    }
+
+    @After
+    public void cleanup() throws Exception {
+        mDevice.executeShellCommand("settings delete secure launcher3.layout.provider");
+    }
+
+    private void writeLayout(LauncherLayoutBuilder builder) throws Exception {
+        mDevice.executeShellCommand("settings put secure launcher3.layout.provider " + mAuthority);
+        ParcelFileDescriptor pfd = mTargetContext.getContentResolver().openFileDescriptor(
+                Uri.parse("content://" + mAuthority + "/launcher_layout"), "w");
+
+        try (OutputStreamWriter writer = new OutputStreamWriter(new AutoCloseOutputStream(pfd))) {
+            builder.build(writer);
+        }
+        clearLauncherData();
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index c2e6749..e11e62e 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -330,9 +330,7 @@
     public void testDragAppIcon() throws Throwable {
         try {
             TestProtocol.sDebugTracing = true;
-            LauncherActivityInfo settingsApp = getSettingsApp();
-
-            final String appName = settingsApp.getLabel().toString();
+            final String appName = "LauncherTestApp";
             // 1. Open all apps and wait for load complete.
             // 2. Drag icon to homescreen.
             // 3. Verify that the icon works on homescreen.
@@ -341,7 +339,7 @@
                     getAppIcon(appName).
                     dragToWorkspace().
                     getWorkspaceAppIcon(appName).
-                    launch(settingsApp.getComponentName().getPackageName());
+                    launch(getInstrumentation().getContext().getPackageName());
         } finally {
             TestProtocol.sDebugTracing = false;
         }
diff --git a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java b/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
new file mode 100644
index 0000000..d3659eb
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.android.launcher3.util;
+
+
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Helper class to build xml for Launcher Layout
+ */
+public class LauncherLayoutBuilder {
+
+    // Object Tags
+    private static final String TAG_WORKSPACE = "workspace";
+    private static final String TAG_AUTO_INSTALL = "autoinstall";
+    private static final String TAG_FOLDER = "folder";
+    private static final String TAG_APPWIDGET = "appwidget";
+    private static final String TAG_EXTRA = "extra";
+
+    private static final String ATTR_CONTAINER = "container";
+    private static final String ATTR_RANK = "rank";
+
+    private static final String ATTR_PACKAGE_NAME = "packageName";
+    private static final String ATTR_CLASS_NAME = "className";
+    private static final String ATTR_TITLE = "title";
+    private static final String ATTR_SCREEN = "screen";
+
+    // x and y can be specified as negative integers, in which case -1 represents the
+    // last row / column, -2 represents the second last, and so on.
+    private static final String ATTR_X = "x";
+    private static final String ATTR_Y = "y";
+    private static final String ATTR_SPAN_X = "spanX";
+    private static final String ATTR_SPAN_Y = "spanY";
+
+    private static final String ATTR_CHILDREN = "children";
+
+
+    // Style attrs -- "Extra"
+    private static final String ATTR_KEY = "key";
+    private static final String ATTR_VALUE = "value";
+
+    private static final String CONTAINER_DESKTOP = "desktop";
+    private static final String CONTAINER_HOTSEAT = "hotseat";
+
+    private final ArrayList<Pair<String, HashMap<String, Object>>> mNodes = new ArrayList<>();
+
+    public Location atHotseat(int rank) {
+        Location l = new Location();
+        l.items.put(ATTR_CONTAINER, CONTAINER_HOTSEAT);
+        l.items.put(ATTR_RANK, Integer.toString(rank));
+        return l;
+    }
+
+    public Location atWorkspace(int x, int y, int screen) {
+        Location l = new Location();
+        l.items.put(ATTR_CONTAINER, CONTAINER_DESKTOP);
+        l.items.put(ATTR_X, Integer.toString(x));
+        l.items.put(ATTR_Y, Integer.toString(y));
+        l.items.put(ATTR_SCREEN, Integer.toString(screen));
+        return l;
+    }
+
+    public String build() throws IOException {
+        StringWriter writer = new StringWriter();
+        build(writer);
+        return writer.toString();
+    }
+
+    public void build(Writer writer) throws IOException {
+        XmlSerializer serializer = Xml.newSerializer();
+        serializer.setOutput(writer);
+
+        serializer.startDocument("UTF-8", true);
+        serializer.startTag(null, TAG_WORKSPACE);
+        writeNodes(serializer, mNodes);
+        serializer.endTag(null, TAG_WORKSPACE);
+        serializer.endDocument();
+        serializer.flush();
+    }
+
+    private static void writeNodes(XmlSerializer serializer,
+            ArrayList<Pair<String, HashMap<String, Object>>> nodes) throws IOException {
+        for (Pair<String, HashMap<String, Object>> node : nodes) {
+            ArrayList<Pair<String, HashMap<String, Object>>> children = null;
+
+            serializer.startTag(null, node.first);
+            for (Map.Entry<String, Object> attr : node.second.entrySet()) {
+                if (ATTR_CHILDREN.equals(attr.getKey())) {
+                    children = (ArrayList<Pair<String, HashMap<String, Object>>>) attr.getValue();
+                } else {
+                    serializer.attribute(null, attr.getKey(), (String) attr.getValue());
+                }
+            }
+
+            if (children != null) {
+                writeNodes(serializer, children);
+            }
+            serializer.endTag(null, node.first);
+        }
+    }
+
+    public class Location {
+
+        final HashMap<String, Object> items = new HashMap<>();
+
+        public LauncherLayoutBuilder putApp(String packageName, String className) {
+            items.put(ATTR_PACKAGE_NAME, packageName);
+            items.put(ATTR_CLASS_NAME, TextUtils.isEmpty(className) ? packageName : className);
+            mNodes.add(Pair.create(TAG_AUTO_INSTALL, items));
+            return LauncherLayoutBuilder.this;
+        }
+
+        public LauncherLayoutBuilder putWidget(String packageName, String className,
+                int spanX, int spanY) {
+            items.put(ATTR_PACKAGE_NAME, packageName);
+            items.put(ATTR_CLASS_NAME, className);
+            items.put(ATTR_SPAN_X, Integer.toString(spanX));
+            items.put(ATTR_SPAN_Y, Integer.toString(spanY));
+            mNodes.add(Pair.create(TAG_APPWIDGET, items));
+            return LauncherLayoutBuilder.this;
+        }
+
+        public FolderBuilder putFolder(int titleResId) {
+            FolderBuilder folderBuilder = new FolderBuilder();
+            items.put(ATTR_TITLE, Integer.toString(titleResId));
+            items.put(ATTR_CHILDREN, folderBuilder.mChildren);
+            mNodes.add(Pair.create(TAG_FOLDER, items));
+            return folderBuilder;
+        }
+    }
+
+    public class FolderBuilder {
+
+        final ArrayList<Pair<String, HashMap<String, Object>>> mChildren = new ArrayList<>();
+
+        public FolderBuilder addApp(String packageName, String className) {
+            HashMap<String, Object> items = new HashMap<>();
+            items.put(ATTR_PACKAGE_NAME, packageName);
+            items.put(ATTR_CLASS_NAME, TextUtils.isEmpty(className) ? packageName : className);
+            mChildren.add(Pair.create(TAG_AUTO_INSTALL, items));
+            return this;
+        }
+
+        public LauncherLayoutBuilder build() {
+            return LauncherLayoutBuilder.this;
+        }
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 7a2b7af..16ddba8 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -28,7 +28,6 @@
  * Ancestor for AppIcon and AppMenuItem.
  */
 class Launchable {
-    private static final int DRAG_SPEED = 500;
     protected final LauncherInstrumentation mLauncher;
 
     protected final UiObject2 mObject;
@@ -77,8 +76,7 @@
         Workspace.dragIconToWorkspace(
                 mLauncher,
                 this,
-                new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2),
-                DRAG_SPEED);
+                new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2));
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "dragged launchable to workspace")) {
             return new Workspace(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index c72f7d0..3a45e93 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -16,12 +16,16 @@
 
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
+import static com.android.launcher3.TestProtocol.NORMAL_STATE_ORDINAL;
+
 import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.graphics.Point;
 import android.net.Uri;
 import android.os.Build;
@@ -172,11 +176,11 @@
             // Workaround, use constructed context because both the instrumentation context and the
             // app context are not constructed with resources that take overlays into account
             final Context ctx = baseContext.createPackageContext("android", 0);
-            if (QuickStepContract.isGesturalMode(ctx)) {
+            if (isGesturalMode(ctx)) {
                 return NavigationModel.ZERO_BUTTON;
-            } else if (QuickStepContract.isSwipeUpMode(ctx)) {
+            } else if (isSwipeUpMode(ctx)) {
                 return NavigationModel.TWO_BUTTON;
-            } else if (QuickStepContract.isLegacyMode(ctx)) {
+            } else if (isLegacyMode(ctx)) {
                 return NavigationModel.THREE_BUTTON;
             } else {
                 fail("Can't detect navigation mode");
@@ -343,18 +347,33 @@
                 log(action = "0-button: already in workspace");
             } else if (hasLauncherObject(OVERVIEW_RES_ID)) {
                 log(action = "0-button: from overview");
-                mDevice.pressHome();
+                final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");
+
+                swipe(
+                        navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
+                        navBar.getVisibleBounds().centerX(), 0,
+                        NORMAL_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
             } else if (hasLauncherObject(WIDGETS_RES_ID)) {
                 log(action = "0-button: from widgets");
                 mDevice.pressHome();
             } else if (hasLauncherObject(APPS_RES_ID)) {
                 log(action = "0-button: from all apps");
-                mDevice.pressHome();
+                final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");
+
+                swipe(
+                        navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
+                        navBar.getVisibleBounds().centerX(), 0,
+                        NORMAL_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
             } else {
                 log(action = "0-button: from another app");
                 assertTrue("Launcher is visible, don't know how to go home",
                         !mDevice.hasObject(By.pkg(getLauncherPackageName())));
-                mDevice.pressHome();
+                final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");
+
+                swipe(
+                        navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
+                        navBar.getVisibleBounds().centerX(), 0,
+                        BACKGROUND_APP_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
             }
         } else {
             log(action = "clicking home button");
@@ -607,6 +626,46 @@
         }
     }
 
+    public static boolean isGesturalMode(Context context) {
+        return QuickStepContract.isGesturalMode(getCurrentInteractionMode(context));
+    }
+
+    public static boolean isSwipeUpMode(Context context) {
+        return QuickStepContract.isSwipeUpMode(getCurrentInteractionMode(context));
+    }
+
+    public static boolean isLegacyMode(Context context) {
+        return QuickStepContract.isLegacyMode(getCurrentInteractionMode(context));
+    }
+
+    private static int getCurrentInteractionMode(Context context) {
+        return getSystemIntegerRes(context, "config_navBarInteractionMode");
+    }
+
+    private static int getSystemIntegerRes(Context context, String resName) {
+        Resources res = context.getResources();
+        int resId = res.getIdentifier(resName, "integer", "android");
+
+        if (resId != 0) {
+            return res.getInteger(resId);
+        } else {
+            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+            return -1;
+        }
+    }
+
+    private static int getSystemDimensionResId(Context context, String resName) {
+        Resources res = context.getResources();
+        int resId = res.getIdentifier(resName, "dimen", "android");
+
+        if (resId != 0) {
+            return resId;
+        } else {
+            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+            return -1;
+        }
+    }
+
     static void sleep(int duration) {
         try {
             Thread.sleep(duration);
@@ -616,8 +675,10 @@
 
     int getEdgeSensitivityWidth() {
         try {
-            return QuickStepContract.getEdgeSensitivityWidth(
-                    mInstrumentation.getTargetContext().createPackageContext("android", 0)) + 1;
+            final Context context = mInstrumentation.getTargetContext().createPackageContext(
+                    "android", 0);
+            return context.getResources().getDimensionPixelSize(
+                    getSystemDimensionResId(context, "config_backGestureInset")) + 1;
         } catch (PackageManager.NameNotFoundException e) {
             fail("Can't get edge sensitivity: " + e);
             return 0;
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index f04afa0..943332e 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -21,7 +21,9 @@
 import static junit.framework.TestCase.assertTrue;
 
 import android.graphics.Point;
+import android.os.SystemClock;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -35,8 +37,8 @@
  */
 public final class Workspace extends Home {
     private static final float FLING_SPEED = 3500.0F;
+    private static final int DRAG_DURACTION = 2000;
     private final UiObject2 mHotseat;
-    private final int ICON_DRAG_SPEED = LauncherInstrumentation.needSlowGestures() ? 100 : 570;
 
     Workspace(LauncherInstrumentation launcher) {
         super(launcher);
@@ -116,8 +118,7 @@
                     mLauncher,
                     getHotseatAppIcon("Chrome"),
                     new Point(mLauncher.getDevice().getDisplayWidth(),
-                            workspace.getVisibleBounds().centerY()),
-                    (int) (ICON_DRAG_SPEED * mLauncher.getDisplayDensity()));
+                            workspace.getVisibleBounds().centerY()));
             verifyActiveContainer();
         }
         assertTrue("Home screen workspace didn't become scrollable",
@@ -134,10 +135,16 @@
                 mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
     }
 
-    static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
-            Point dest, int icon_drag_speed) {
+    static void dragIconToWorkspace(
+            LauncherInstrumentation launcher, Launchable launchable, Point dest) {
         LauncherInstrumentation.log("dragIconToWorkspace: begin");
-        launchable.getObject().drag(dest, icon_drag_speed);
+        final Point launchableCenter = launchable.getObject().getVisibleCenter();
+        final long downTime = SystemClock.uptimeMillis();
+        launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, launchableCenter);
+        launcher.waitForLauncherObject("deep_shortcuts_container");
+        launcher.movePointer(downTime, DRAG_DURACTION, launchableCenter, dest);
+        launcher.sendPointer(
+                downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);
         LauncherInstrumentation.log("dragIconToWorkspace: end");
         launcher.waitUntilGone("drop_target_bar");
     }