Merge "Update all apps divider to pill shape" into sc-dev
diff --git a/go/quickstep/res/values/config.xml b/go/quickstep/res/values/config.xml
index 402bf9a..796d14d 100644
--- a/go/quickstep/res/values/config.xml
+++ b/go/quickstep/res/values/config.xml
@@ -16,8 +16,6 @@
 <resources>
     <!-- The component to receive app sharing Intents -->
     <string name="app_sharing_component" translatable="false"/>
-    <!-- The package to receive Listen, Translate, and Search Intents -->
-    <string name="niu_actions_package" translatable="false"/>
 
     <!-- Feature Flags -->
     <bool name="enable_niu_actions">true</bool>
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 65cdcf0..3a6e9b5 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -21,6 +21,7 @@
 
 import android.annotation.SuppressLint;
 import android.app.assist.AssistContent;
+import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -29,10 +30,10 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.launcher3.R;
 import com.android.quickstep.util.AssistContentRequester;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.TaskThumbnailView;
@@ -90,9 +91,7 @@
         public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix,
                 boolean rotated) {
             getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null);
-            mNIUPackageName =
-                    mApplicationContext.getString(R.string.niu_actions_package);
-
+            checkSettings();
             if (thumbnail == null || TextUtils.isEmpty(mNIUPackageName)) {
                 return;
             }
@@ -105,7 +104,6 @@
             getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
             mTaskPackageName = task.key.getPackageName();
 
-            checkPermissions();
             if (!mAssistPermissionsEnabled) {
                 return;
             }
@@ -137,7 +135,11 @@
                 mImageApi.shareAsDataWithExplicitIntent(/* crop */ null, intent);
             } else {
                 intent.putExtra(ACTIONS_ERROR_CODE, ERROR_PERMISSIONS);
-                mApplicationContext.startActivity(intent);
+                try {
+                    mApplicationContext.startActivity(intent);
+                } catch (ActivityNotFoundException e) {
+                    Log.e(TAG, "No activity found to receive permission error intent");
+                }
             }
         }
 
@@ -160,13 +162,17 @@
          * Checks whether the Assistant has screen context permissions
          */
         @VisibleForTesting
-        public void checkPermissions() {
+        public void checkSettings() {
             ContentResolver contentResolver = mApplicationContext.getContentResolver();
             boolean structureEnabled = Settings.Secure.getInt(contentResolver,
                     Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1) != 0;
             boolean screenshotEnabled = Settings.Secure.getInt(contentResolver,
                     Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1) != 0;
             mAssistPermissionsEnabled = structureEnabled && screenshotEnabled;
+
+            String assistantPackage =
+                    Settings.Secure.getString(contentResolver, Settings.Secure.ASSISTANT);
+            mNIUPackageName = assistantPackage.split("/", 2)[0];
         }
 
         protected class OverlayUICallbacksGoImpl extends OverlayUICallbacksImpl
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index be98157..1090099 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -152,16 +152,18 @@
 
         @UiThread
         public void setAnimation(AnimatorSet animation, Context context) {
-            setAnimation(animation, context, null);
+            setAnimation(animation, context, null, true);
 
         }
 
         /**
          * Sets the animation to play for this app launch
+         * @param skipFirstFrame Iff true, we skip the first frame of the animation.
+         *                       We set to false when skipping first frame causes jank.
          */
         @UiThread
         public void setAnimation(AnimatorSet animation, Context context,
-                @Nullable Runnable onCompleteCallback) {
+                @Nullable Runnable onCompleteCallback, boolean skipFirstFrame) {
             if (mInitialized) {
                 throw new IllegalStateException("Animation already initialized");
             }
@@ -187,10 +189,12 @@
                 });
                 mAnimator.start();
 
-                // Because t=0 has the app icon in its original spot, we can skip the
-                // first frame and have the same movement one frame earlier.
-                mAnimator.setCurrentPlayTime(
-                        Math.min(getSingleFrameMs(context), mAnimator.getTotalDuration()));
+                if (skipFirstFrame) {
+                    // Because t=0 has the app icon in its original spot, we can skip the
+                    // first frame and have the same movement one frame earlier.
+                    mAnimator.setCurrentPlayTime(
+                            Math.min(getSingleFrameMs(context), mAnimator.getTotalDuration()));
+                }
             }
         }
     }
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 26d407f..65df237 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -38,6 +38,7 @@
 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
 import static com.android.launcher3.statehandlers.DepthController.DEPTH;
+import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
@@ -340,12 +341,17 @@
 
         final int rotationChange = getRotationChange(appTargets);
         // Note: the targetBounds are relative to the launcher
+        int startDelay = getSingleFrameMs(mLauncher);
         Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange);
-        anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, nonAppTargets,
-                windowTargetBounds, areAllTargetsTranslucent(appTargets), rotationChange));
+        Animator windowAnimator = getOpeningWindowAnimators(v, appTargets, wallpaperTargets,
+                nonAppTargets, windowTargetBounds, areAllTargetsTranslucent(appTargets),
+                rotationChange);
+        windowAnimator.setStartDelay(startDelay);
+        anim.play(windowAnimator);
         if (launcherClosing) {
+            // Delay animation by a frame to avoid jank.
             Pair<AnimatorSet, Runnable> launcherContentAnimator =
-                    getLauncherContentAnimator(true /* isAppOpening */);
+                    getLauncherContentAnimator(true /* isAppOpening */, startDelay);
             anim.play(launcherContentAnimator.first);
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
@@ -436,8 +442,10 @@
      *
      * @param isAppOpening True when this is called when an app is opening.
      *                     False when this is called when an app is closing.
+     * @param startDelay Start delay duration.
      */
-    private Pair<AnimatorSet, Runnable> getLauncherContentAnimator(boolean isAppOpening) {
+    private Pair<AnimatorSet, Runnable> getLauncherContentAnimator(boolean isAppOpening,
+            int startDelay) {
         AnimatorSet launcherAnimator = new AnimatorSet();
         Runnable endListener;
 
@@ -528,6 +536,8 @@
                 mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
             };
         }
+
+        launcherAnimator.setStartDelay(startDelay);
         return new Pair<>(launcherAnimator, endListener);
     }
 
@@ -633,7 +643,7 @@
                 ? 0 : getWindowCornerRadius(mLauncher.getResources());
         final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
 
-        appAnimator.addUpdateListener(new MultiValueUpdateListener() {
+        MultiValueUpdateListener listener = new MultiValueUpdateListener() {
             FloatProp mDx = new FloatProp(0, prop.dX, 0, prop.xDuration, AGGRESSIVE_EASE);
             FloatProp mDy = new FloatProp(0, prop.dY, 0, prop.yDuration, AGGRESSIVE_EASE);
 
@@ -662,7 +672,7 @@
                     ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
 
             @Override
-            public void onUpdate(float percent) {
+            public void onUpdate(float percent, boolean initOnly) {
                 // Calculate the size of the scaled icon.
                 float iconWidth = launcherIconBounds.width() * mIconScaleToFitScreen.value;
                 float iconHeight = launcherIconBounds.height() * mIconScaleToFitScreen.value;
@@ -707,6 +717,12 @@
                 floatingIconBounds.right += offsetX;
                 floatingIconBounds.bottom += offsetY;
 
+                if (initOnly) {
+                    floatingView.update(mIconAlpha.value, 255, floatingIconBounds, percent, 0f,
+                            mWindowRadius.value * scale, true /* isOpening */);
+                    return;
+                }
+
                 ArrayList<SurfaceParams> params = new ArrayList<>();
                 for (int i = appTargets.length - 1; i >= 0; i--) {
                     RemoteAnimationTargetCompat target = appTargets[i];
@@ -779,7 +795,10 @@
 
                 surfaceApplier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
             }
-        });
+        };
+        appAnimator.addUpdateListener(listener);
+        // Since we added a start delay, call update here to init the FloatingIconView properly.
+        listener.onUpdate(0, true /* initOnly */);
 
         animatorSet.playTogether(appAnimator, getBackgroundAnimator(appTargets));
         return animatorSet;
@@ -869,7 +888,7 @@
                     ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
 
             @Override
-            public void onUpdate(float percent) {
+            public void onUpdate(float percent, boolean initOnly) {
                 widgetBackgroundBounds.set(mDx.value - mWidth.value / 2f,
                         mDy.value - mHeight.value / 2f, mDx.value + mWidth.value / 2f,
                         mDy.value + mHeight.value / 2f);
@@ -1128,7 +1147,7 @@
                     DEACCEL_1_7);
 
             @Override
-            public void onUpdate(float percent) {
+            public void onUpdate(float percent, boolean initOnly) {
                 SurfaceParams[] params = new SurfaceParams[appTargets.length];
                 for (int i = appTargets.length - 1; i >= 0; i--) {
                     RemoteAnimationTargetCompat target = appTargets[i];
@@ -1278,8 +1297,7 @@
 
                     if (mLauncher.isInState(LauncherState.ALL_APPS)) {
                         Pair<AnimatorSet, Runnable> contentAnimator =
-                                getLauncherContentAnimator(false /* isAppOpening */);
-                        contentAnimator.first.setStartDelay(LAUNCHER_RESUME_START_DELAY);
+                                getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY);
                         anim.play(contentAnimator.first);
                         anim.addListener(new AnimatorListenerAdapter() {
                             @Override
@@ -1328,27 +1346,32 @@
 
             final boolean launchingFromWidget = mV instanceof LauncherAppWidgetHostView;
             final boolean launchingFromRecents = isLaunchingFromRecents(mV, appTargets);
+            final boolean skipFirstFrame;
             if (launchingFromWidget) {
                 composeWidgetLaunchAnimator(anim, (LauncherAppWidgetHostView) mV, appTargets,
                         wallpaperTargets, nonAppTargets);
                 addCujInstrumentation(
                         anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_WIDGET);
+                skipFirstFrame = true;
             } else if (launchingFromRecents) {
                 composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
                 addCujInstrumentation(
                         anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS);
+                skipFirstFrame = true;
             } else {
                 composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
                 addCujInstrumentation(anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_ICON);
+                skipFirstFrame = false;
             }
 
             if (launcherClosing) {
                 anim.addListener(mForceInvisibleListener);
             }
 
-            result.setAnimation(anim, mLauncher, mOnEndCallback::executeAllAndDestroy);
+            result.setAnimation(anim, mLauncher, mOnEndCallback::executeAllAndDestroy,
+                    skipFirstFrame);
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
index 3a1a2f7..3a7d821 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 
 import com.android.launcher3.BaseActivity;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.ActivityTracker;
 
@@ -37,7 +38,8 @@
                 .addCategory(Intent.CATEGORY_HOME)
                 .setPackage(getPackageName())
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        new HotseatActivityTracker<>().addToIntent(homeIntent);
+
+        Launcher.ACTIVITY_TRACKER.registerCallback(new HotseatActivityTracker());
         startActivity(homeIntent);
         finish();
     }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 8f42993..a9dacee 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -349,6 +349,13 @@
         }
 
         if (mActivity != null) {
+            if (mStateCallback.hasStates(STATE_GESTURE_COMPLETED)) {
+                // If the activity has restarted between setting the page scroll settling callback
+                // and actually receiving the callback, just mark the gesture completed
+                mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
+                return true;
+            }
+
             // The launcher may have been recreated as a result of device rotation.
             int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
             initStateCallbacks();
@@ -1717,13 +1724,12 @@
 
     /**
      * Registers a callback to run when the activity is ready.
-     * @param intent The intent that will be used to start the activity if it doesn't exist already.
      */
-    public void initWhenReady(Intent intent) {
+    public void initWhenReady() {
         // Preload the plan
         RecentsModel.INSTANCE.get(mContext).getTasks(null);
 
-        mActivityInitListener.register(intent);
+        mActivityInitListener.register();
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 47d94ba..19cad53 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -191,6 +191,12 @@
         return new FloatingViewHomeAnimationFactory(floatingWidgetView) {
 
             @Override
+            @Nullable
+            protected View getViewIgnoredInWorkspaceRevealAnimation() {
+                return hostView;
+            }
+
+            @Override
             public RectF getWindowTargetRect() {
                 super.getWindowTargetRect();
                 return backgroundLocation;
@@ -387,6 +393,16 @@
     }
 
     private class LauncherHomeAnimationFactory extends HomeAnimationFactory {
+
+        /**
+         * Returns a view which should be excluded from the Workspace animation, or null if there
+         * is no view to exclude.
+         */
+        @Nullable
+        protected View getViewIgnoredInWorkspaceRevealAnimation() {
+            return null;
+        }
+
         @NonNull
         @Override
         public AnimatorPlaybackController createActivityAnimationToHome() {
@@ -400,7 +416,8 @@
         @Override
         public void playAtomicAnimation(float velocity) {
             if (!PROTOTYPE_APP_CLOSE.get()) {
-                new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */)
+                new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
+                        getViewIgnoredInWorkspaceRevealAnimation())
                         .start();
             } else if (shouldPlayAtomicWorkspaceReveal()) {
                 new WorkspaceRevealAnim(mActivity, true).start();
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index dbdd75f..2beef0a 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -184,9 +184,7 @@
                 .newHandler(gestureState, cmd.createTime);
         interactionHandler.setGestureEndCallback(
                 () -> onTransitionComplete(cmd, interactionHandler));
-
-        Intent intent = new Intent(interactionHandler.getLaunchIntent());
-        interactionHandler.initWhenReady(intent);
+        interactionHandler.initWhenReady();
 
         RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() {
             @Override
@@ -212,6 +210,7 @@
             cmd.mActiveCallbacks.addListener(recentAnimListener);
             mTaskAnimationManager.notifyRecentsAnimationState(recentAnimListener);
         } else {
+            Intent intent = new Intent(interactionHandler.getLaunchIntent());
             intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, gestureState.getGestureId());
             cmd.mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(
                     gestureState, intent, interactionHandler);
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 6852642..3d66823 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -141,7 +141,7 @@
     @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
-        ACTIVITY_TRACKER.handleNewIntent(this, intent);
+        ACTIVITY_TRACKER.handleNewIntent(this);
     }
 
     /**
@@ -214,7 +214,8 @@
             AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
                     wallpaperTargets, nonAppTargets);
             anim.addListener(resetStateListener());
-            result.setAnimation(anim, RecentsActivity.this, onEndCallback::executeAllAndDestroy);
+            result.setAnimation(anim, RecentsActivity.this, onEndCallback::executeAllAndDestroy,
+                    true /* skipFirstFrame */);
         };
 
         final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner<>(
@@ -353,7 +354,8 @@
     public void startHome() {
         if (LIVE_TILE.get()) {
             RecentsView recentsView = getOverviewPanel();
-            recentsView.switchToScreenshotAndFinishAnimationToRecents(this::startHomeInternal);
+            recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true,
+                    this::startHomeInternal));
         } else {
             startHomeInternal();
         }
@@ -385,7 +387,8 @@
         anim.play(controller.getAnimationPlayer());
         anim.setDuration(HOME_APPEAR_DURATION);
         result.setAnimation(anim, this,
-                () -> getStateManager().goToState(RecentsState.HOME, false));
+                () -> getStateManager().goToState(RecentsState.HOME, false),
+                true /* skipFirstFrame */);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 59bd1ed..3293810 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -249,7 +249,7 @@
                             ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
 
                     @Override
-                    public void onUpdate(float percent) {
+                    public void onUpdate(float percent, boolean initOnly) {
                         final SurfaceParams.Builder navBuilder =
                                 new SurfaceParams.Builder(navBarTarget.leash);
                         if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 9878d45..725c7c4 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -389,8 +389,7 @@
         mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs);
         mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
         mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener());
-        Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
-        mInteractionHandler.initWhenReady(intent);
+        mInteractionHandler.initWhenReady();
 
         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
             mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
@@ -398,6 +397,7 @@
             mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler);
             notifyGestureStarted(true /*isLikelyToStartNewTask*/);
         } else {
+            Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
             intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
             mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent,
                     mInteractionHandler);
diff --git a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
index dfb8c1d..b9879ab 100644
--- a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
+++ b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
@@ -26,7 +26,8 @@
 
 import java.util.function.BiPredicate;
 
-public class ActivityInitListener<T extends BaseActivity> implements SchedulerCallback<T> {
+public class ActivityInitListener<T extends BaseActivity> implements
+        SchedulerCallback<T> {
 
     private BiPredicate<T, Boolean> mOnInitListener;
     private final ActivityTracker<T> mActivityTracker;
@@ -47,6 +48,7 @@
     @Override
     public final boolean init(T activity, boolean alreadyOnHome) {
         if (!mIsRegistered) {
+            // Don't receive any more updates
             return false;
         }
         return handleInit(activity, alreadyOnHome);
@@ -59,18 +61,17 @@
     /**
      * Registers the activity-created listener. If the activity is already created, then the
      * callback provided in the constructor will be called synchronously.
-     * @param intent The intent that will be used to initialize the activity, if the activity
-     *               doesn't already exist. We add the callback as an extra on this intent.
      */
-    public void register(Intent intent) {
+    public void register() {
         mIsRegistered = true;
-        mActivityTracker.runCallbackWhenActivityExists(this, intent);
+        mActivityTracker.registerCallback(this);
     }
 
     /**
      * After calling this, we won't {@link #init} even when the activity is ready.
      */
     public void unregister() {
+        mActivityTracker.unregisterCallback(this);
         mIsRegistered = false;
         mOnInitListener = null;
     }
@@ -82,9 +83,9 @@
      */
     public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
             Context context, Handler handler, long duration) {
-        mIsRegistered = true;
+        register();
 
         Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle();
-        context.startActivity(addToIntent(new Intent(intent)), options);
+        context.startActivity(new Intent(intent), options);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index 2285d74..de7dbd6 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -26,6 +26,7 @@
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.prediction.AppTarget;
+import android.content.ActivityNotFoundException;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.ComponentName;
@@ -68,6 +69,7 @@
     private static final long FILE_LIFE = 1000L /*ms*/ * 60L /*s*/ * 60L /*m*/ * 24L /*h*/;
     private static final String SUB_FOLDER = "Overview";
     private static final String BASE_NAME = "overview_image_";
+    private static final String TAG = "ImageActionUtils";
 
     /**
      * Saves screenshot to location determine by SystemUiProxy
@@ -154,11 +156,15 @@
             Intent intent, BiFunction<Uri, Intent, Intent[]> uriToIntentMap, String tag) {
         Intent[] intents = uriToIntentMap.apply(getImageUri(bitmap, crop, context, tag), intent);
 
-        // Work around b/159412574
-        if (intents.length == 1) {
-            context.startActivity(intents[0]);
-        } else {
-            context.startActivities(intents);
+        try {
+            // Work around b/159412574
+            if (intents.length == 1) {
+                context.startActivity(intents[0]);
+            } else {
+                context.startActivities(intents);
+            }
+        } catch (ActivityNotFoundException e) {
+            Log.e(TAG, "No activity found to receive image intent");
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
index b4ae1ca..1c3c9c2 100644
--- a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
+++ b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
@@ -40,10 +40,14 @@
             newPercent = prop.mInterpolator.getInterpolation(newPercent);
             prop.value = prop.mEnd * newPercent + prop.mStart * (1 - newPercent);
         }
-        onUpdate(percent);
+        onUpdate(percent, false /* initOnly */);
     }
 
-    public abstract void onUpdate(float percent);
+    /**
+     * @param percent The total animation progress.
+     * @param initOnly When true, only does enough work to initialize the animation.
+     */
+    public abstract void onUpdate(float percent, boolean initOnly);
 
     public final class FloatProp {
 
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
index 93b3482..c331a13 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
@@ -280,7 +280,7 @@
             }
 
             @Override
-            public void onUpdate(float percent) {}
+            public void onUpdate(float percent, boolean initOnly) {}
         };
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 49aec93..ccc587c 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -32,6 +32,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
@@ -68,15 +70,18 @@
     private final float mSpringTransY;
 
     private final AnimatorSet mAnimators = new AnimatorSet();
+    private final @Nullable View mIgnoredView;
 
-    public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim) {
-        this(launcher, velocity, animateOverviewScrim, true);
+    public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim,
+            @Nullable View ignoredView) {
+        this(launcher, velocity, animateOverviewScrim, ignoredView, true);
     }
 
     public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim,
-            boolean staggerWorkspace) {
+            @Nullable View ignoredView, boolean staggerWorkspace) {
         prepareToAnimate(launcher, animateOverviewScrim);
 
+        mIgnoredView = ignoredView;
         mVelocity = velocity;
 
         // Scale the translationY based on the initial velocity to better sync the workspace items
@@ -224,6 +229,7 @@
      * @param totalRows Total number of rows.
      */
     private void addStaggeredAnimationForView(View v, int row, int totalRows) {
+        if (mIgnoredView != null && mIgnoredView == v) return;
         // Invert the rows, because we stagger starting from the bottom of the screen.
         int invertedRow = totalRows - row;
         // Add 1 to the inverted row so that the bottom most row has a start delay.
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 1062652..61a2eaf 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -298,16 +298,16 @@
         final float degree, positionX, positionY;
         if (mFromRotation == Surface.ROTATION_90) {
             degree = -90 * fraction;
-            positionX = fraction * (mDestinationBoundsTransformed.left - mAppBounds.left)
-                    + mAppBounds.left;
-            positionY = fraction * (mDestinationBoundsTransformed.bottom - mAppBounds.top)
-                    + mAppBounds.top;
+            positionX = fraction * (mDestinationBoundsTransformed.left - mStartBounds.left)
+                    + mStartBounds.left;
+            positionY = fraction * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
+                    + mStartBounds.top;
         } else {
             degree = 90 * fraction;
-            positionX = fraction * (mDestinationBoundsTransformed.right - mAppBounds.left)
-                    + mAppBounds.left;
-            positionY = fraction * (mDestinationBoundsTransformed.top - mAppBounds.top)
-                    + mAppBounds.top;
+            positionX = fraction * (mDestinationBoundsTransformed.right - mStartBounds.left)
+                    + mStartBounds.left;
+            positionY = fraction * (mDestinationBoundsTransformed.top - mStartBounds.top)
+                    + mStartBounds.top;
         }
         return new RotatedPosition(degree, positionX, positionY);
     }
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
index 00993e3..f67940a 100644
--- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
+++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
@@ -173,7 +173,7 @@
             FloatProp mGradientAlpha = new FloatProp(0, 255, firstPart, secondPart * 0.3f, LINEAR);
 
             @Override
-            public void onUpdate(float progress) {
+            public void onUpdate(float progress, boolean initOnly) {
                 temp.set(circleBoundsOg);
                 temp.offset(0, (int) -mDeltaY.value);
                 Utilities.scaleRectAboutCenter(temp, mCircleScale.value);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7991614..df7f8b5 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2357,7 +2357,8 @@
             public void accept(Boolean success) {
                 if (LIVE_TILE.get() && mEnableDrawingLiveTile && taskView.isRunningTask()
                         && success) {
-                    finishRecentsAnimation(true /* toHome */, () -> onEnd(success));
+                    finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
+                            () -> onEnd(success));
                 } else {
                     onEnd(success);
                 }
@@ -2368,7 +2369,8 @@
                 if (success) {
                     if (shouldRemoveTask) {
                         if (taskView.getTask() != null) {
-                            switchToScreenshotAndFinishAnimationToRecents(() -> {
+                            finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
+                                    () -> {
                                 UI_HELPER_EXECUTOR.getHandler().postDelayed(() ->
                                         ActivityManagerWrapper.getInstance().removeTask(
                                                 taskView.getTask().key.id),
@@ -2478,7 +2480,7 @@
         mPendingAnimation.addEndListener(isSuccess -> {
             if (isSuccess) {
                 // Remove all the task views now
-                switchToScreenshotAndFinishAnimationToRecents(() -> {
+                finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, () -> {
                     UI_HELPER_EXECUTOR.getHandler().postDelayed(
                             ActivityManagerWrapper.getInstance()::removeAllRecentTasks,
                             REMOVE_TASK_WAIT_FOR_APP_STOP_MS);
@@ -2639,7 +2641,9 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         if (LIVE_TILE.get() && mEnableDrawingLiveTile && newConfig.orientation != mOrientation) {
-            switchToScreenshotAndFinishAnimationToRecents(this::updateRecentsRotation);
+            switchToScreenshot(
+                    () -> finishRecentsAnimation(true /* toRecents */, false /* showPip */,
+                            this::updateRecentsRotation));
             mEnableDrawingLiveTile = false;
         } else {
             updateRecentsRotation();
@@ -3632,10 +3636,6 @@
         }
     }
 
-    public void switchToScreenshotAndFinishAnimationToRecents(Runnable onFinishRunnable) {
-        switchToScreenshot(() -> finishRecentsAnimation(true /* toRecents */, onFinishRunnable));
-    }
-
     /**
      * Switch the current running task view to static snapshot mode,
      * capturing the snapshot at the same time.
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-night-v31/all_apps_tab_background_selected.xml
similarity index 76%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-night-v31/all_apps_tab_background_selected.xml
index e59e8d2..b7c9ff6 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-night-v31/all_apps_tab_background_selected.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_accent2_100"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-night-v31/all_apps_tab_text.xml
similarity index 75%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-night-v31/all_apps_tab_text.xml
index e59e8d2..83237b4 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-night-v31/all_apps_tab_text.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_50" android:state_selected="true"/>
+    <item android:color="@android:color/system_neutral2_700"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-night-v31/all_apps_tabs_background.xml
similarity index 76%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-night-v31/all_apps_tabs_background.xml
index e59e8d2..b396f33 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-night-v31/all_apps_tabs_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral2_100"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-night/all_apps_tab_background_selected.xml
similarity index 76%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-night/all_apps_tab_background_selected.xml
index e59e8d2..b22bc8b 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-night/all_apps_tab_background_selected.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#BFEBE3"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-night/all_apps_tab_text.xml
similarity index 76%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-night/all_apps_tab_text.xml
index e59e8d2..183af01 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-night/all_apps_tab_text.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#F0F0F0" android:state_selected="true"/>
+    <item android:color="#464646"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-night/all_apps_tabs_background.xml
similarity index 76%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-night/all_apps_tabs_background.xml
index e59e8d2..c0c1621 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-night/all_apps_tabs_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#E2E2E2"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-v31/all_apps_tab_background_selected.xml
similarity index 76%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-v31/all_apps_tab_background_selected.xml
index e59e8d2..dac8fa2 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-v31/all_apps_tab_background_selected.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_accent1_100"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-v31/all_apps_tab_text.xml
similarity index 75%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-v31/all_apps_tab_text.xml
index e59e8d2..c3520a7 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-v31/all_apps_tab_text.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_900" android:state_selected="true"/>
+    <item android:color="@android:color/system_neutral2_700"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color-v31/all_apps_tabs_background.xml
similarity index 76%
copy from res/color/all_apps_tab_bg.xml
copy to res/color-v31/all_apps_tabs_background.xml
index e59e8d2..30757b0 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color-v31/all_apps_tabs_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="97" />
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color/all_apps_tab_background_selected.xml
similarity index 83%
rename from res/color/all_apps_tab_bg.xml
rename to res/color/all_apps_tab_background_selected.xml
index e59e8d2..5cb9bd8 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color/all_apps_tab_background_selected.xml
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#8DF5E3"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_text.xml b/res/color/all_apps_tab_text.xml
index 2db0fb5..dace380 100644
--- a/res/color/all_apps_tab_text.xml
+++ b/res/color/all_apps_tab_text.xml
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/black" android:state_selected="true"/>
-    <item android:color="?android:attr/textColorTertiary"/>
+    <item android:color="#1B1B1B" android:state_selected="true"/>
+    <item android:color="#464646"/>
 </selector>
\ No newline at end of file
diff --git a/res/color/all_apps_tab_bg.xml b/res/color/all_apps_tabs_background.xml
similarity index 77%
copy from res/color/all_apps_tab_bg.xml
copy to res/color/all_apps_tabs_background.xml
index e59e8d2..a4b7d1f 100644
--- a/res/color/all_apps_tab_bg.xml
+++ b/res/color/all_apps_tabs_background.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2021 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?androidprv:attr/colorAccentPrimary"/>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#F6F6F6"/>
 </selector>
\ No newline at end of file
diff --git a/res/drawable/all_apps_tabs_background.xml b/res/drawable/all_apps_tabs_background.xml
index a345dd3..4e95315 100644
--- a/res/drawable/all_apps_tabs_background.xml
+++ b/res/drawable/all_apps_tabs_background.xml
@@ -13,14 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:top="@dimen/all_apps_tabs_vertical_padding"
-        android:bottom="@dimen/all_apps_tabs_vertical_padding
-">
+        android:bottom="@dimen/all_apps_tabs_vertical_padding">
         <shape android:shape="rectangle">
-            <solid android:color="?androidprv:attr/colorSurface" />
+            <solid android:color="@color/all_apps_tabs_background" />
             <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
         </shape>
     </item>
diff --git a/res/drawable/work_apps_toggle_background.xml b/res/drawable/work_apps_toggle_background.xml
index a04d269..b7115f8 100644
--- a/res/drawable/work_apps_toggle_background.xml
+++ b/res/drawable/work_apps_toggle_background.xml
@@ -24,7 +24,7 @@
     <item>
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/work_fab_radius" />
-            <solid android:color="?android:attr/colorAccent" />
+            <solid android:color="@color/all_apps_tab_background_selected" />
             <padding android:left="@dimen/work_fab_radius" android:right="@dimen/work_fab_radius" />
         </shape>
     </item>
diff --git a/res/drawable/work_card.xml b/res/drawable/work_card.xml
new file mode 100644
index 0000000..0e4b054
--- /dev/null
+++ b/res/drawable/work_card.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <solid android:color="?androidprv:attr/colorSurface" />
+    <corners android:radius="@dimen/work_edu_card_margin" />
+    <padding
+        android:left="@dimen/work_fab_radius"
+        android:right="@dimen/work_fab_radius" />
+</shape>
+
diff --git a/res/drawable/work_card_btn.xml b/res/drawable/work_card_btn.xml
new file mode 100644
index 0000000..3c93919
--- /dev/null
+++ b/res/drawable/work_card_btn.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <corners android:radius="@dimen/work_edu_card_margin" />
+    <stroke android:width="1dp" android:color="?androidprv:attr/colorAccentPrimaryVariant" />
+    <padding
+        android:left="@dimen/work_fab_radius"
+        android:right="@dimen/work_fab_radius" />
+</shape>
+
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index 9439baf..1aeda50 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -26,79 +26,82 @@
     android:importantForAccessibility="no">
 
     <com.android.launcher3.widget.AddItemWidgetsBottomSheet
-        xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/add_item_bottom_sheet"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@drawable/add_item_dialog_background"
-        android:paddingTop="24dp"
         android:theme="?attr/widgetsTheme"
         android:layout_gravity="bottom"
         android:orientation="vertical">
 
-        <TextView
-            style="@style/TextHeadline"
-            android:id="@+id/widget_appName"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_horizontal"
-            android:paddingHorizontal="24dp"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="24sp"
-            android:ellipsize="end"
-            android:fadingEdge="horizontal"
-            android:singleLine="true"
-            android:maxLines="1" />
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_horizontal"
-            android:paddingHorizontal="24dp"
-            android:paddingTop="8dp"
-            android:text="@string/add_item_request_drag_hint"
-            android:textSize="14sp"
-            android:textColor="?android:attr/textColorSecondary"
-            android:alpha="0.7"
-            android:importantForAccessibility="no"/>
-
-        <include layout="@layout/widget_cell"
-            android:id="@+id/widget_cell"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:layout_marginVertical="16dp" />
-
         <LinearLayout
+            android:id="@+id/add_item_bottom_sheet_content"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:gravity="center_vertical|end"
-            android:paddingHorizontal="24dp"
-            android:paddingVertical="8dp"
-            android:orientation="horizontal">
-            <Button
-                style="@style/Button.FullRounded.Colored"
-                android:layout_width="wrap_content"
-                android:layout_height="36dp"
-                android:paddingHorizontal="16dp"
-                android:textSize="14sp"
-                android:textColor="@color/button_text"
-                android:text="@android:string/cancel"
-                android:onClick="onCancelClick"/>
+            android:padding="24dp"
+            android:background="@drawable/add_item_dialog_background"
+            android:orientation="vertical" >
 
-            <Space
-                android:layout_width="8dp"
-                android:layout_height="wrap_content" />
+            <TextView
+                style="@style/TextHeadline"
+                android:id="@+id/widget_appName"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:textColor="?android:attr/textColorPrimary"
+                android:textSize="24sp"
+                android:ellipsize="end"
+                android:fadingEdge="horizontal"
+                android:singleLine="true"
+                android:maxLines="1" />
 
-            <Button
-                style="@style/Button.FullRounded.Colored"
-                android:layout_width="wrap_content"
-                android:layout_height="36dp"
-                android:paddingHorizontal="16dp"
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:paddingTop="8dp"
+                android:text="@string/add_item_request_drag_hint"
                 android:textSize="14sp"
-                android:textColor="@color/button_text"
-                android:text="@string/add_to_home_screen"
-                android:onClick="onPlaceAutomaticallyClick"/>
+                android:textColor="?android:attr/textColorSecondary"
+                android:alpha="0.7"
+                android:importantForAccessibility="no"/>
+
+            <include layout="@layout/widget_cell"
+                android:id="@+id/widget_cell"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:layout_marginVertical="16dp" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical|end"
+                android:paddingVertical="8dp"
+                android:orientation="horizontal">
+                <Button
+                    style="@style/Button.FullRounded.Colored"
+                    android:layout_width="wrap_content"
+                    android:layout_height="36dp"
+                    android:paddingHorizontal="16dp"
+                    android:textSize="14sp"
+                    android:textColor="@color/button_text"
+                    android:text="@android:string/cancel"
+                    android:onClick="onCancelClick"/>
+
+                <Space
+                    android:layout_width="8dp"
+                    android:layout_height="wrap_content" />
+
+                <Button
+                    style="@style/Button.FullRounded.Colored"
+                    android:layout_width="wrap_content"
+                    android:layout_height="36dp"
+                    android:paddingHorizontal="16dp"
+                    android:textSize="14sp"
+                    android:textColor="@color/button_text"
+                    android:text="@string/add_to_home_screen"
+                    android:onClick="onPlaceAutomaticallyClick"/>
+            </LinearLayout>
         </LinearLayout>
     </com.android.launcher3.widget.AddItemWidgetsBottomSheet>
 
diff --git a/res/layout/widgets_bottom_sheet.xml b/res/layout/widgets_bottom_sheet.xml
index 1859bd8..bbb08fa 100644
--- a/res/layout/widgets_bottom_sheet.xml
+++ b/res/layout/widgets_bottom_sheet.xml
@@ -19,8 +19,6 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingTop="16dp"
-    android:background="@drawable/widgets_bottom_sheet_background"
     android:layout_gravity="bottom"
     android:theme="?attr/widgetsTheme">
 
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index 85c6488..3b3ff8b 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -14,32 +14,40 @@
      limitations under the License.
 -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <View
-        android:id="@+id/collapse_handle"
-        android:layout_width="48dp"
-        android:layout_height="2dp"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginBottom="16dp"
-        android:visibility="gone"
-        android:background="?android:attr/textColorSecondary"/>
-    <TextView
-        style="@style/TextHeadline"
-        android:id="@+id/title"
+    <LinearLayout
+        android:id="@+id/widgets_bottom_sheet"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:textColor="?android:attr/textColorPrimary"
-        android:textSize="24sp"/>
-
-    <ScrollView
-        android:id="@+id/widgets_table_scroll_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:fadeScrollbars="false"
-        android:layout_marginVertical="16dp">
-        <include layout="@layout/widgets_table_container"
+        android:background="@drawable/widgets_bottom_sheet_background"
+        android:paddingTop="16dp"
+        android:orientation="vertical">
+        <View
+            android:id="@+id/collapse_handle"
+            android:layout_width="48dp"
+            android:layout_height="2dp"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginBottom="16dp"
+            android:visibility="gone"
+            android:background="?android:attr/textColorSecondary"/>
+        <TextView
+            style="@style/TextHeadline"
+            android:id="@+id/title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal" />
-    </ScrollView>
+            android:gravity="center_horizontal"
+            android:textColor="?android:attr/textColorPrimary"
+            android:textSize="24sp"/>
+
+        <ScrollView
+            android:id="@+id/widgets_table_scroll_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fadeScrollbars="false"
+            android:layout_marginVertical="16dp">
+            <include layout="@layout/widgets_table_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal" />
+        </ScrollView>
+    </LinearLayout>
 </merge>
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
new file mode 100644
index 0000000..2c58907
--- /dev/null
+++ b/res/layout/work_apps_edu.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 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.
+-->
+
+<com.android.launcher3.allapps.WorkEduCard xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="@dimen/work_edu_card_margin"
+    android:orientation="vertical"
+    android:background="@drawable/work_card"
+    android:gravity="center">
+
+    <TextView
+        style="@style/PrimaryHeadline"
+        android:textColor="?android:attr/textColorPrimary"
+        android:id="@+id/work_apps_paused_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp"
+        android:text="@string/work_profile_edu_work_apps"
+        android:textAlignment="center"
+        android:textSize="20sp" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/action_btn"
+        android:textColor="?attr/workProfileOverlayTextColor"
+        android:text="@string/work_profile_edu_accept"
+        android:textAlignment="center"
+        android:background="@drawable/work_card_btn"
+        android:textSize="14sp" />
+</com.android.launcher3.allapps.WorkEduCard>
\ No newline at end of file
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 21f269f..4209192 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2017 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.
@@ -13,8 +12,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.allapps.WorkModeSwitch
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.allapps.WorkModeSwitch xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/work_mode_toggle"
     android:layout_alignParentBottom="true"
     android:layout_alignParentEnd="true"
@@ -22,8 +20,8 @@
     android:layout_width="wrap_content"
     android:gravity="center"
     android:includeFontPadding="false"
-    android:drawableTint="@android:color/white"
-    android:textColor="@android:color/white"
+    android:drawableTint="@color/all_apps_tab_text"
+    android:textColor="@color/all_apps_tab_text"
     android:background="@drawable/work_apps_toggle_background"
     android:drawablePadding="16dp"
     android:drawableStart="@drawable/ic_corp_off"
diff --git a/res/layout/work_mode_switch.xml b/res/layout/work_mode_switch.xml
deleted file mode 100644
index 538a180..0000000
--- a/res/layout/work_mode_switch.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2017 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.
--->
-<com.android.launcher3.allapps.WorkModeSwitch xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    style="@style/PrimaryHeadline"
-    android:id="@+id/work_mode_toggle"
-    android:drawableStart="@drawable/ic_corp"
-    android:drawablePadding="16dp"
-    android:drawableTint="?attr/workProfileOverlayTextColor"
-    android:textColor="?attr/workProfileOverlayTextColor"
-    android:layout_alignParentBottom="true"
-    android:ellipsize="end"
-    android:elevation="10dp"
-    android:gravity="start"
-    android:lines="1"
-    android:showText="false"
-    android:textSize="@dimen/work_profile_footer_text_size"
-    android:background="?attr/allAppsScrimColor"
-    android:text="@string/work_profile_toggle_label"
-    android:paddingBottom="@dimen/work_profile_footer_padding"
-    android:paddingLeft="@dimen/work_profile_footer_padding"
-    android:paddingRight="@dimen/work_profile_footer_padding"
-    android:paddingTop="@dimen/work_profile_footer_padding" />
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index 427525b..d41eb7e 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -20,5 +20,6 @@
 <resources>
     <style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+        <item name="android:windowTranslucentStatus">true</item>
     </style>
 </resources>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 1434430..38a0894 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -16,7 +16,7 @@
 ** limitations under the License.
 */
 -->
-<resources>
+<resources  xmlns:android="http://schemas.android.com/apk/res/android">
     <color name="popup_color_primary_light">@android:color/system_accent2_50</color>
     <color name="popup_color_secondary_light">@android:color/system_neutral2_100</color>
     <color name="popup_color_tertiary_light">@android:color/system_neutral2_300</color>
@@ -36,7 +36,8 @@
     <color name="text_color_tertiary_dark">@android:color/system_neutral2_400</color>
 
     <color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
-
+    <color name="folder_background_light" android:lstar="98">@android:color/system_neutral1_50</color>
+    <color name="folder_background_dark" android:lstar="30">@android:color/system_neutral2_800</color>
+  
     <color name="folder_dot_color">@android:color/system_accent2_50</color>
-
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 7aab4fa..dac12ed 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -59,6 +59,9 @@
     <color name="folder_hint_text_color_light">#FFF</color>
     <color name="folder_hint_text_color_dark">#FF000000</color>
 
+    <color name="folder_background_light">#FFFFFF</color>
+    <color name="folder_background_dark">#FF3C4043</color>
+
     <color name="folder_dot_color">?attr/colorPrimary</color>
 
     <color name="text_color_primary_dark">#FFFFFFFF</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f0cc64e..e8d3212 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -123,8 +123,10 @@
     <dimen name="work_fab_margin">18dp</dimen>
     <dimen name="work_profile_footer_padding">20dp</dimen>
     <dimen name="work_profile_footer_text_size">16sp</dimen>
+    <dimen name="work_edu_card_margin">16dp</dimen>
 
-<!-- Widget tray -->
+
+    <!-- Widget tray -->
     <dimen name="widget_cell_vertical_padding">8dp</dimen>
     <dimen name="widget_cell_horizontal_padding">16dp</dimen>
     <dimen name="widget_cell_font_size">14sp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9cfe69a..9823df3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -389,7 +389,7 @@
     <!-- This string is in the work profile tab when a user has All Apps open on their phone. This is a label for a toggle to turn the work profile on and off. "Work profile" means a separate profile on a user's phone that's specifically for their work apps and managed by their company. "Work" is used as an adjective.-->
     <string name="work_profile_toggle_label">Work profile</string>
     <!--- User onboarding title for work profile apps -->
-    <string name="work_profile_edu_work_apps">Work apps are badged andare visible to your IT admin</string>
+    <string name="work_profile_edu_work_apps">Work apps are badged and visible to your IT admin</string>
     <!-- Action label to finish work profile edu-->
     <string name="work_profile_edu_accept">Got it</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 571377c..6f7d727 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -48,9 +48,9 @@
         <item name="workspaceStatusBarScrim">@drawable/workspace_bg</item>
         <item name="widgetsTheme">@style/WidgetContainerTheme</item>
         <item name="folderDotColor">@color/folder_dot_color</item>
-        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
+        <item name="folderFillColor">@color/folder_background_light</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
-        <item name="folderTextColor">?android:attr/textColorPrimary</item>
+        <item name="folderTextColor">@color/workspace_text_color_dark</item>
         <item name="isFolderDarkText">true</item>
         <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
         <item name="loadingIconColor">#CCFFFFFF</item>
@@ -71,10 +71,10 @@
     </style>
 
     <style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme">
-        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
-        <item name="folderTextColor">?attr/workspaceTextColor</item>
-        <item name="isFolderDarkText">?attr/isWorkspaceDarkText</item>
-        <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
+        <item name="folderFillColor">@color/folder_background_dark</item>
+        <item name="folderTextColor">@color/workspace_text_color_light</item>
+        <item name="isFolderDarkText">false</item>
+        <item name="folderHintColor">@color/folder_hint_text_color_light</item>
         <item name="disabledIconAlpha">.254</item>
 
     </style>
@@ -87,9 +87,9 @@
         <item name="isWorkspaceDarkText">true</item>
         <item name="workspaceStatusBarScrim">@null</item>
         <item name="folderDotColor">@color/folder_dot_color</item>
-        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
+        <item name="folderFillColor">@color/folder_background_light</item>
         <item name="folderIconBorderColor">#FF80868B</item>
-        <item name="folderTextColor">?attr/workspaceTextColor</item>
+        <item name="folderTextColor">@color/workspace_text_color_dark</item>
         <item name="isFolderDarkText">true</item>
         <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
     </style>
@@ -109,9 +109,9 @@
         <item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
         <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
         <item name="folderDotColor">@color/folder_dot_color</item>
-        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
+        <item name="folderFillColor">@color/folder_background_dark</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
-        <item name="folderTextColor">?android:attr/textColorPrimary</item>
+        <item name="folderTextColor">@color/workspace_text_color_light</item>
         <item name="isFolderDarkText">false</item>
         <item name="folderHintColor">@color/folder_hint_text_color_light</item>
         <item name="isMainColorDark">true</item>
@@ -123,8 +123,8 @@
     </style>
 
     <style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
-        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
-        <item name="folderTextColor">@android:color/white</item>
+        <item name="folderFillColor">@color/folder_background_dark</item>
+        <item name="folderTextColor">@color/workspace_text_color_light</item>
         <item name="isFolderDarkText">false</item>
         <item name="folderHintColor">@color/folder_hint_text_color_light</item>
         <item name="disabledIconAlpha">.54</item>
@@ -132,16 +132,16 @@
 
     <style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
         <item name="android:colorControlHighlight">#19212121</item>
-        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
-        <item name="folderTextColor">?attr/workspaceTextColor</item>
-        <item name="isFolderDarkText">?attr/isWorkspaceDarkText</item>
-        <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
+        <item name="folderFillColor">@color/folder_background_light</item>
         <item name="workspaceTextColor">@color/workspace_text_color_dark</item>
         <item name="workspaceShadowColor">@android:color/transparent</item>
         <item name="workspaceAmbientShadowColor">@android:color/transparent</item>
         <item name="workspaceKeyShadowColor">@android:color/transparent</item>
         <item name="isWorkspaceDarkText">true</item>
         <item name="workspaceStatusBarScrim">@null</item>
+        <item name="folderTextColor">@color/workspace_text_color_dark</item>
+        <item name="isFolderDarkText">true</item>
+        <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
     </style>
 
     <!-- A derivative project can extend these themes to customize the application theme without
@@ -316,5 +316,6 @@
     <style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="widgetsTheme">@style/WidgetContainerTheme</item>
         <item name="android:windowLightStatusBar">true</item>
+        <item name="android:windowTranslucentStatus">true</item>
     </style>
 </resources>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 578379b..c5d280d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1080,7 +1080,13 @@
                 // Making sure mAllAppsSessionLogId is not null to avoid double logging.
                 && mAllAppsSessionLogId != null) {
             getAppsView().getSearchUiManager().resetSearch();
-            getStatsLogManager().logger().log(LAUNCHER_ALLAPPS_EXIT);
+            getStatsLogManager().logger()
+                    .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+                            .setWorkspace(
+                                    LauncherAtom.WorkspaceContainer.newBuilder()
+                                            .setPageIndex(getWorkspace().getCurrentPage()))
+                            .build())
+                    .log(LAUNCHER_ALLAPPS_EXIT);
             mAllAppsSessionLogId = null;
         }
     }
@@ -1472,7 +1478,7 @@
         boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL)
                 && AbstractFloatingView.getTopOpenView(this) == null;
         boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
-        boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this, intent);
+        boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this);
         hideKeyboard();
         if (isActionMain) {
             if (!internalStateHandled) {
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 2c24c3a..4579705 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -18,6 +18,9 @@
 
 import static android.view.MotionEvent.ACTION_DOWN;
 
+import static com.android.launcher3.CellLayout.FOLDER;
+import static com.android.launcher3.CellLayout.WORKSPACE;
+
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Rect;
@@ -124,21 +127,27 @@
 
     public void measureChild(View child) {
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-        final DeviceProfile profile = mActivity.getDeviceProfile();
+        final DeviceProfile dp = mActivity.getDeviceProfile();
 
         if (child instanceof LauncherAppWidgetHostView) {
-            ((LauncherAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
+            ((LauncherAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
-                    profile.appWidgetScale.x, profile.appWidgetScale.y, mBorderSpacing, mTempRect);
+                    dp.appWidgetScale.x, dp.appWidgetScale.y, mBorderSpacing, mTempRect);
         } else {
             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
                     mBorderSpacing, null);
             // Center the icon/folder
             int cHeight = getCellContentHeight();
             int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
-            int cellPaddingX = mContainerType == CellLayout.WORKSPACE
-                    ? profile.workspaceCellPaddingXPx
-                    : (int) (profile.edgeMarginPx / 2f);
+
+            // No need to add padding when cell layout border spacing is present.
+            boolean noPadding = (dp.cellLayoutBorderSpacingPx > 0 && mContainerType == WORKSPACE)
+                    || (dp.folderCellLayoutBorderSpacingPx > 0 && mContainerType == FOLDER);
+            int cellPaddingX = noPadding
+                    ? 0
+                    : mContainerType == WORKSPACE
+                            ? dp.workspaceCellPaddingXPx
+                            : (int) (dp.edgeMarginPx / 2f);
             child.setPadding(cellPaddingX, cellPaddingY, cellPaddingX, 0);
         }
         int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 7249aaf..d749e02 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -50,7 +50,6 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.ColorUtils;
 import androidx.core.os.BuildCompat;
-import androidx.recyclerview.widget.DefaultItemAnimator;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -127,6 +126,7 @@
     private Rect mInsets = new Rect();
 
     private SearchAdapterProvider mSearchAdapterProvider;
+    private WorkAdapterProvider mWorkAdapterProvider;
     private final int mScrimColor;
     private final int mHeaderProtectionColor;
     private final float mHeaderThreshold;
@@ -159,6 +159,11 @@
         Selection.setSelection(mSearchQueryBuilder, 0);
 
         mAH = new AdapterHolder[2];
+        mWorkAdapterProvider = new WorkAdapterProvider(mLauncher, () -> {
+            if (mAH[AdapterHolder.WORK] != null) {
+                mAH[AdapterHolder.WORK].appsList.updateAdapterItems();
+            }
+        });
         mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
         mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
 
@@ -228,8 +233,9 @@
     }
 
     private void resetWorkProfile() {
-        mWorkModeSwitch.updateCurrentState(!mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED));
-        mAH[AdapterHolder.WORK].setupOverlay();
+        boolean isEnabled = !mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED);
+        mWorkModeSwitch.updateCurrentState(isEnabled);
+        mWorkAdapterProvider.updateCurrentState(isEnabled);
         mAH[AdapterHolder.WORK].applyPadding();
     }
 
@@ -392,7 +398,6 @@
             mAH[i].padding.bottom = insets.bottom;
             mAH[i].padding.left = mAH[i].padding.right = leftRightPadding;
             mAH[i].applyPadding();
-            mAH[i].setupOverlay();
         }
 
         ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
@@ -539,6 +544,9 @@
                     && mAllAppsStore.hasModelFlag(
                     FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
         }
+        if (mSearchUiManager != null && mSearchUiManager.getEditText() != null) {
+            mSearchUiManager.getEditText().hideKeyboard();
+        }
     }
 
     // Used by tests only
@@ -719,9 +727,15 @@
 
         AdapterHolder(boolean isWork) {
             mIsWork = isWork;
-            appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork);
+            appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore,
+                    isWork ? mWorkAdapterProvider : null);
+
+            BaseAdapterProvider[] adapterProviders =
+                    isWork ? new BaseAdapterProvider[]{mSearchAdapterProvider, mWorkAdapterProvider}
+                            : new BaseAdapterProvider[]{mSearchAdapterProvider};
+
             adapter = new AllAppsGridAdapter(mLauncher, getLayoutInflater(), appsList,
-                    mSearchAdapterProvider);
+                    adapterProviders);
             appsList.setAdapter(adapter);
             layoutManager = adapter.getLayoutManager();
         }
@@ -743,38 +757,11 @@
             adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
             applyVerticalFadingEdgeEnabled(verticalFadingEdge);
             applyPadding();
-            setupOverlay();
             if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
                 recyclerView.addItemDecoration(mSearchAdapterProvider.getDecorator());
             }
         }
 
-        void setupOverlay() {
-            if (!mIsWork || recyclerView == null) return;
-            boolean workDisabled = mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED);
-            if (mWorkDisabled == workDisabled) return;
-            recyclerView.setContentDescription(workDisabled ? mLauncher.getString(
-                    R.string.work_apps_paused_content_description) : null);
-            View overlayView = getOverlayView();
-            recyclerView.setItemAnimator(new DefaultItemAnimator());
-            if (workDisabled) {
-                overlayView.setAlpha(0);
-                recyclerView.addAutoSizedOverlay(overlayView);
-                overlayView.animate().alpha(1).withEndAction(
-                        () -> {
-                            appsList.updateItemFilter((info, cn) -> false);
-                            recyclerView.setItemAnimator(null);
-                        }).start();
-            } else if (mInfoMatcher != null) {
-                appsList.updateItemFilter(mInfoMatcher);
-                overlayView.animate().alpha(0).withEndAction(() -> {
-                    recyclerView.setItemAnimator(null);
-                    recyclerView.clearAutoSizedOverlays();
-                }).start();
-            }
-            mWorkDisabled = workDisabled;
-        }
-
         void applyPadding() {
             if (recyclerView != null) {
                 Resources res = getResources();
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 70588ea..874fe80 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -41,10 +41,10 @@
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.PackageManagerHelper;
 
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -72,7 +72,8 @@
     public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
     public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
 
-    private final SearchAdapterProvider mSearchAdapterProvider;
+
+    private final BaseAdapterProvider[] mAdapterProviders;
 
     /**
      * ViewHolder for each icon.
@@ -242,9 +243,12 @@
             int totalSpans = mGridLayoutMgr.getSpanCount();
             if (isIconViewType(viewType)) {
                 return totalSpans / mAppsPerRow;
-            } else if (mSearchAdapterProvider.isSearchView(viewType)) {
-                return totalSpans / mSearchAdapterProvider.getItemsPerRow(viewType, mAppsPerRow);
             } else {
+                BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
+                if (adapterProvider != null) {
+                    return totalSpans / adapterProvider.getItemsPerRow(viewType, mAppsPerRow);
+                }
+
                 // Section breaks span the full width
                 return totalSpans;
             }
@@ -270,7 +274,7 @@
     private Intent mMarketSearchIntent;
 
     public AllAppsGridAdapter(BaseDraggingActivity launcher, LayoutInflater inflater,
-            AlphabeticalAppsList apps, SearchAdapterProvider searchAdapterProvider) {
+            AlphabeticalAppsList apps, BaseAdapterProvider[] adapterProviders) {
         Resources res = launcher.getResources();
         mLauncher = launcher;
         mApps = apps;
@@ -282,16 +286,18 @@
 
         mOnIconClickListener = launcher.getItemOnClickListener();
 
-        mSearchAdapterProvider = searchAdapterProvider;
+        mAdapterProviders = adapterProviders;
         setAppsPerRow(mLauncher.getDeviceProfile().numShownAllAppsColumns);
     }
 
     public void setAppsPerRow(int appsPerRow) {
         mAppsPerRow = appsPerRow;
         int totalSpans = mAppsPerRow;
-        for (int itemPerRow : mSearchAdapterProvider.getSupportedItemsPerRowArray()) {
-            if (totalSpans % itemPerRow != 0) {
-                totalSpans *= itemPerRow;
+        for (BaseAdapterProvider adapterProvider : mAdapterProviders) {
+            for (int itemPerRow : adapterProvider.getSupportedItemsPerRowArray()) {
+                if (totalSpans % itemPerRow != 0) {
+                    totalSpans *= itemPerRow;
+                }
             }
         }
         mGridLayoutMgr.setSpanCount(totalSpans);
@@ -363,9 +369,9 @@
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.all_apps_divider, parent, false));
             default:
-                if (mSearchAdapterProvider.isSearchView(viewType)) {
-                    return mSearchAdapterProvider.onCreateViewHolder(mLayoutInflater, parent,
-                            viewType);
+                BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
+                if (adapterProvider != null) {
+                    return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
                 }
                 throw new RuntimeException("Unexpected view type");
         }
@@ -399,7 +405,10 @@
                 // nothing to do
                 break;
             default:
-                mSearchAdapterProvider.onBindView(holder, position);
+                BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
+                if (adapterProvider != null) {
+                    adapterProvider.onBindView(holder, position);
+                }
         }
     }
 
@@ -424,4 +433,11 @@
         AdapterItem item = mApps.getAdapterItems().get(position);
         return item.viewType;
     }
+
+    @Nullable
+    private BaseAdapterProvider getAdapterProvider(int viewType) {
+        return Arrays.stream(mAdapterProviders).filter(
+                adapterProvider -> adapterProvider.isViewSupported(viewType)).findFirst().orElse(
+                null);
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 88d95fa..ce5c589 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -44,6 +44,7 @@
     private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS = 1;
 
     private final int mFastScrollDistributionMode = FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS;
+    private final WorkAdapterProvider mWorkAdapterProvider;
 
     /**
      * Info about a fast scroller section, depending if sections are merged, the fast scroller
@@ -75,8 +76,6 @@
     private final ArrayList<AdapterItem> mAdapterItems = new ArrayList<>();
     // The set of sections that we allow fast-scrolling to (includes non-merged sections)
     private final List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
-    // Is it the work profile app list.
-    private final boolean mIsWork;
 
     // The of ordered component names as a result of a search query
     private ArrayList<AdapterItem> mSearchResults;
@@ -86,11 +85,12 @@
     private int mNumAppRowsInAdapter;
     private ItemInfoMatcher mItemFilter;
 
-    public AlphabeticalAppsList(Context context, AllAppsStore appsStore, boolean isWork) {
+    public AlphabeticalAppsList(Context context, AllAppsStore appsStore,
+            WorkAdapterProvider adapterProvider) {
         mAllAppsStore = appsStore;
         mLauncher = BaseDraggingActivity.fromContext(context);
         mAppNameComparator = new AppInfoComparator(context);
-        mIsWork = isWork;
+        mWorkAdapterProvider = adapterProvider;
         mNumAppsPerRow = mLauncher.getDeviceProfile().inv.numColumns;
         mAllAppsStore.addUpdateListener(this);
     }
@@ -265,7 +265,7 @@
      * Updates the set of filtered apps with the current filter. At this point, we expect
      * mCachedSectionNames to have been calculated for the set of all apps in mApps.
      */
-    private void updateAdapterItems() {
+    public void updateAdapterItems() {
         refillAdapterItems();
         refreshRecyclerView();
     }
@@ -292,6 +292,12 @@
 
         if (!hasFilter()) {
             mAccessibilityResultsCount = mApps.size();
+            if (mWorkAdapterProvider != null) {
+                position += mWorkAdapterProvider.addWorkItems(mAdapterItems);
+                if (!mWorkAdapterProvider.shouldShowWorkApps()) {
+                    return;
+                }
+            }
             for (AppInfo info : mApps) {
                 String sectionName = info.sectionName;
 
@@ -303,7 +309,8 @@
                 }
 
                 // Create an app item
-                AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info, appIndex++);
+                AdapterItem appItem = AdapterItem.asApp(position++, sectionName, info,
+                        appIndex++);
                 if (lastFastScrollerSectionInfo.fastScrollToItem == null) {
                     lastFastScrollerSectionInfo.fastScrollToItem = appItem;
                 }
diff --git a/src/com/android/launcher3/allapps/BaseAdapterProvider.java b/src/com/android/launcher3/allapps/BaseAdapterProvider.java
new file mode 100644
index 0000000..308294c
--- /dev/null
+++ b/src/com/android/launcher3/allapps/BaseAdapterProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+/**
+ * A UI expansion wrapper providing for providing dynamic recyclerview items
+ */
+public abstract class BaseAdapterProvider {
+
+    /**
+     * Returns whether or not viewType can be handled by searchProvider
+     */
+    public abstract boolean isViewSupported(int viewType);
+
+    /**
+     * Called from RecyclerView.Adapter#onBindViewHolder
+     */
+    public abstract void onBindView(AllAppsGridAdapter.ViewHolder holder, int position);
+
+    /**
+     * Called from RecyclerView.Adapter#onCreateViewHolder
+     */
+    public abstract AllAppsGridAdapter.ViewHolder onCreateViewHolder(LayoutInflater layoutInflater,
+            ViewGroup parent, int viewType);
+
+    /**
+     * Returns supported item per row combinations supported
+     */
+    public int[] getSupportedItemsPerRowArray() {
+        return new int[]{};
+    }
+
+    /**
+     * Returns how many cells a view should span
+     */
+    public int getItemsPerRow(int viewType, int appsPerRow) {
+        return appsPerRow;
+    }
+
+}
diff --git a/src/com/android/launcher3/allapps/WorkAdapterProvider.java b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
new file mode 100644
index 0000000..13444dd
--- /dev/null
+++ b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+import java.util.ArrayList;
+
+/**
+ * A UI expansion wrapper providing for providing work profile specific views
+ */
+public class WorkAdapterProvider extends BaseAdapterProvider {
+
+    public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
+
+    private static final int VIEW_TYPE_WORK_EDU_CARD = 1 << 20;
+    private static final int VIEW_TYPE_WORK_DISABLED_CARD = 1 << 21;
+    private final Runnable mRefreshCB;
+    private final BaseDraggingActivity mLauncher;
+    private boolean mEnabled;
+
+    WorkAdapterProvider(BaseDraggingActivity launcher, Runnable refreshCallback) {
+        mLauncher = launcher;
+        mRefreshCB = refreshCallback;
+    }
+
+    @Override
+    public void onBindView(AllAppsGridAdapter.ViewHolder holder, int position) {
+        if (holder.itemView instanceof WorkEduCard) {
+            ((WorkEduCard) holder.itemView).setPosition(position);
+        }
+    }
+
+    @Override
+    public AllAppsGridAdapter.ViewHolder onCreateViewHolder(LayoutInflater layoutInflater,
+            ViewGroup parent, int viewType) {
+        int viewId = viewType == VIEW_TYPE_WORK_DISABLED_CARD ? R.layout.work_apps_paused
+                : R.layout.work_apps_edu;
+        return new AllAppsGridAdapter.ViewHolder(layoutInflater.inflate(viewId, parent, false));
+    }
+
+    /**
+     * returns whether or not work apps should be visible in work tab.
+     */
+    public boolean shouldShowWorkApps() {
+        return mEnabled;
+    }
+
+    /**
+     * Adds work profile specific adapter items to adapterItems and returns number of items added
+     */
+    public int addWorkItems(ArrayList<AllAppsGridAdapter.AdapterItem> adapterItems) {
+        if (!mEnabled) {
+            //add disabled card here.
+            AllAppsGridAdapter.AdapterItem disabledCard = new AllAppsGridAdapter.AdapterItem();
+            disabledCard.viewType = VIEW_TYPE_WORK_DISABLED_CARD;
+            adapterItems.add(disabledCard);
+        } else if (!isEduSeen()) {
+            AllAppsGridAdapter.AdapterItem eduCard = new AllAppsGridAdapter.AdapterItem();
+            eduCard.viewType = VIEW_TYPE_WORK_EDU_CARD;
+            adapterItems.add(eduCard);
+        }
+
+        return adapterItems.size();
+    }
+
+    /**
+     * Sets the current state of work profile
+     */
+    public void updateCurrentState(boolean isEnabled) {
+        mEnabled = isEnabled;
+        mRefreshCB.run();
+    }
+
+    @Override
+    public boolean isViewSupported(int viewType) {
+        return viewType == VIEW_TYPE_WORK_DISABLED_CARD || viewType == VIEW_TYPE_WORK_EDU_CARD;
+    }
+
+    @Override
+    public int getItemsPerRow(int viewType, int appsPerRow) {
+        return 1;
+    }
+
+    private boolean isEduSeen() {
+        return Utilities.getPrefs(mLauncher).getInt(KEY_WORK_EDU_STEP, 0) != 0;
+    }
+}
diff --git a/src/com/android/launcher3/allapps/WorkEduCard.java b/src/com/android/launcher3/allapps/WorkEduCard.java
new file mode 100644
index 0000000..29a42f8
--- /dev/null
+++ b/src/com/android/launcher3/allapps/WorkEduCard.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.LinearLayout;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+
+/**
+ * Work profile toggle switch shown at the bottom of AllApps work tab
+ */
+public class WorkEduCard extends LinearLayout implements View.OnClickListener,
+        Animation.AnimationListener {
+
+    private final Launcher mLauncher;
+    Animation mDismissAnim;
+    private int mPosition = -1;
+
+    public WorkEduCard(Context context) {
+        this(context, null, 0);
+    }
+
+    public WorkEduCard(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WorkEduCard(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLauncher = Launcher.getLauncher(getContext());
+        mDismissAnim = AnimationUtils.loadAnimation(context, android.R.anim.fade_out);
+        mDismissAnim.setDuration(500);
+        mDismissAnim.setAnimationListener(this);
+    }
+
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        findViewById(R.id.action_btn).setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View view) {
+        startAnimation(mDismissAnim);
+        mLauncher.getSharedPrefs().edit().putInt(WorkAdapterProvider.KEY_WORK_EDU_STEP, 1).apply();
+    }
+
+    @Override
+    public void onAnimationEnd(Animation animation) {
+        removeCard();
+    }
+
+    @Override
+    public void onAnimationRepeat(Animation animation) {
+
+    }
+
+    @Override
+    public void onAnimationStart(Animation animation) {
+
+    }
+
+    private void removeCard() {
+        if (mPosition == -1) {
+            if (getParent() != null) ((ViewGroup) getParent()).removeView(WorkEduCard.this);
+        } else {
+            AllAppsRecyclerView rv = mLauncher.getAppsView()
+                    .mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView;
+            rv.getApps().getAdapterItems().remove(mPosition);
+            rv.getAdapter().notifyItemRemoved(mPosition);
+        }
+    }
+
+    public void setPosition(int position) {
+        mPosition = position;
+    }
+
+}
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index ef62da4..7abd555 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -57,7 +57,7 @@
     }
 
     @Override
-    public boolean isSearchView(int viewType) {
+    public boolean isViewSupported(int viewType) {
         return false;
     }
 
diff --git a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
index cefb8cb..7af0406 100644
--- a/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/SearchAdapterProvider.java
@@ -17,20 +17,18 @@
 package com.android.launcher3.allapps.search;
 
 import android.net.Uri;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.allapps.AllAppsGridAdapter;
+import com.android.launcher3.allapps.BaseAdapterProvider;
 
 /**
  * A UI expansion wrapper providing for search results
  */
-public abstract class SearchAdapterProvider {
+public abstract class SearchAdapterProvider extends BaseAdapterProvider {
 
     protected final BaseDraggingActivity mLauncher;
 
@@ -39,42 +37,12 @@
     }
 
     /**
-     * Called from RecyclerView.Adapter#onBindViewHolder
-     */
-    public abstract void onBindView(AllAppsGridAdapter.ViewHolder holder, int position);
-
-    /**
      * Called from LiveSearchManager to notify slice status updates.
      */
     public void onSliceStatusUpdate(Uri sliceUri) {
     }
 
     /**
-     * Returns whether or not viewType can be handled by searchProvider
-     */
-    public abstract boolean isSearchView(int viewType);
-
-    /**
-     * Called from RecyclerView.Adapter#onCreateViewHolder
-     */
-    public abstract AllAppsGridAdapter.ViewHolder onCreateViewHolder(LayoutInflater layoutInflater,
-            ViewGroup parent, int viewType);
-
-    /**
-     * Returns supported item per row combinations supported
-     */
-    public int[] getSupportedItemsPerRowArray() {
-        return new int[]{};
-    }
-
-    /**
-     * Returns how many cells a view should span
-     */
-    public int getItemsPerRow(int viewType, int appsPerRow) {
-        return appsPerRow;
-    }
-
-    /**
      * Handles selection event on search adapter item. Returns false if provider can not handle
      * event
      */
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index f6d1651..7d8b82a 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -290,7 +290,10 @@
         callAnimatorCommandRecursively(mAnim, a -> a.setInterpolator(interpolator));
     }
 
-    private static void callListenerCommandRecursively(
+    /**
+     * Recursively calls a command on all the listeners of the provided animation
+     */
+    public static void callListenerCommandRecursively(
             Animator anim, BiConsumer<AnimatorListener, Animator> command) {
         callAnimatorCommandRecursively(anim, a-> {
             for (AnimatorListener l : nonNullList(a.getListeners())) {
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index b4288ce..1503167 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -125,7 +125,6 @@
                 WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
         mDragLayer = findViewById(R.id.add_item_drag_layer);
         mDragLayer.recreateControllers();
-        mDragLayer.setInsets(mDeviceProfile.getInsets());
         mWidgetCell = findViewById(R.id.widget_cell);
 
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
@@ -213,7 +212,7 @@
                         .addCategory(Intent.CATEGORY_HOME)
                         .setPackage(getPackageName())
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        Launcher.ACTIVITY_TRACKER.runCallbackWhenActivityExists(listener, homeIntent);
+        Launcher.ACTIVITY_TRACKER.registerCallback(listener);
         startActivity(homeIntent,
                 ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out)
                         .toBundle());
@@ -322,7 +321,7 @@
     @Override
     public void onBackPressed() {
         logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_BACK);
-        super.onBackPressed();
+        mSlideInView.close(/* animate= */ true);
     }
 
     @Override
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index dc188f2..5dcd75a 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -30,17 +30,13 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Insets;
 import android.graphics.Path;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.Build;
@@ -50,7 +46,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
-import android.util.SparseIntArray;
 import android.util.TypedValue;
 import android.view.FocusFinder;
 import android.view.KeyEvent;
@@ -69,7 +64,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.core.content.res.ResourcesCompat;
-import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Alarm;
@@ -104,12 +98,10 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.util.Executors;
-import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.views.ClipPathView;
-import com.android.launcher3.widget.LocalColorExtractor;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 
 import java.util.ArrayList;
@@ -169,11 +161,6 @@
     private static final Rect sTempRect = new Rect();
     private static final int MIN_FOLDERS_FOR_HARDWARE_OPTIMIZATION = 10;
 
-    // Index used to get background color when using local wallpaper color extraction,
-    private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_neutral1_900;
-    private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_neutral2_500;
-    private static final int LIGHT_COLOR_L_STAR = 98;
-
     private final Alarm mReorderAlarm = new Alarm();
     private final Alarm mOnExitAlarm = new Alarm();
     private final Alarm mOnScrollHintAlarm = new Alarm();
@@ -241,17 +228,6 @@
 
     @Nullable private FolderWindowInsetsAnimationCallback mFolderWindowInsetsAnimationCallback;
 
-    // Wallpaper local color extraction
-    @Nullable private LocalColorExtractor mColorExtractor;
-    @Nullable private LocalColorExtractor.Listener mColorListener;
-
-    // For simplicity, we start the color change only after the open animation has started.
-    private Runnable mColorChangeRunnable;
-    private Animator mColorChangeAnimator;
-    // The background color animator used in the folder open animation. We keep a reference to this,
-    // so that we can cancel it when starting mColorChangeAnimator.
-    private ObjectAnimator mOpenAnimationColorChangeAnimator;
-
     private GradientDrawable mBackground;
 
     /**
@@ -315,64 +291,6 @@
 
             setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
         }
-
-        if (Utilities.ATLEAST_S) {
-            boolean isFolderDarkText = Themes.getAttrBoolean(getContext(), R.attr.isFolderDarkText);
-            mColorExtractor = LocalColorExtractor.newInstance(getContext());
-            mColorListener = (RectF rect, SparseIntArray extractedColors) -> {
-                mColorChangeRunnable = () -> {
-                    mColorChangeRunnable = null;
-                    int duration = FOLDER_COLOR_ANIMATION_DURATION;
-
-                    // Cancel the open animation color change animator.
-                    ObjectAnimator existingAnim = mOpenAnimationColorChangeAnimator;
-                    if (existingAnim != null && existingAnim.isRunning()) {
-                        duration = (int) Math.max(FOLDER_COLOR_ANIMATION_DURATION,
-                                existingAnim.getDuration() * (1f - existingAnim.getDuration()));
-                        existingAnim.cancel();
-                        mOpenAnimationColorChangeAnimator = null;
-                    }
-
-                    // Start a new animator to the extracted color. Clamp down on the alpha
-                    // to prevent folder from being transparent for too long.
-                    GradientDrawable bg = (GradientDrawable) getBackground();
-                    int currentColor = ColorUtils.setAlphaComponent(bg.getColor().getDefaultColor(),
-                            255);
-                    int newColor = getExtractedColor(extractedColors, isFolderDarkText);
-                    mColorChangeAnimator = ObjectAnimator.ofArgb(bg, "color", currentColor,
-                            newColor).setDuration(duration);
-                    mColorChangeAnimator.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mColorChangeAnimator = null;
-                        }
-                    });
-                    mColorChangeAnimator.start();
-                };
-
-                // If the folder open animation has started, we can start the color change now.
-                // Otherwise we wait for it to start.
-                if (mOpenAnimationColorChangeAnimator != null
-                        && mOpenAnimationColorChangeAnimator.isStarted()) {
-                    post(mColorChangeRunnable);
-                }
-            };
-        }
-    }
-
-    /**
-     * Returns an index used to query the color of interest from the list of extracted colors.
-     * @param hasDarkText True when dark index is wanted, False when light index is wanted.
-     */
-    @TargetApi(Build.VERSION_CODES.S)
-    private int getExtractedColor(SparseIntArray colors, boolean hasDarkText) {
-        int color = colors.get(hasDarkText
-                ? LIGHT_COLOR_EXTRACTION_INDEX
-                : DARK_COLOR_EXTRACTION_INDEX);
-        if (hasDarkText) {
-            color = ColorStateList.valueOf(color).withLStar(LIGHT_COLOR_L_STAR).getDefaultColor();
-        }
-        return color;
     }
 
     public boolean onLongClick(View v) {
@@ -753,15 +671,11 @@
         cancelRunningAnimations();
         FolderAnimationManager fam = new FolderAnimationManager(this, true /* isOpening */);
         AnimatorSet anim = fam.getAnimator();
-        mOpenAnimationColorChangeAnimator = fam.getBgColorAnimator();
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
                 mFolderIcon.setIconVisible(false);
                 mFolderIcon.drawLeaveBehindIfExists();
-                if (mColorChangeRunnable != null) {
-                    mColorChangeRunnable.run();
-                }
             }
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -857,9 +771,6 @@
         if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.cancel();
         }
-        if (mColorChangeAnimator != null && mColorChangeAnimator.isRunning()) {
-            mColorChangeAnimator.cancel();
-        }
     }
 
     private void animateClosed() {
@@ -945,19 +856,6 @@
         clearDragInfo();
         mState = STATE_SMALL;
         mContent.setCurrentPage(0);
-
-        mOpenAnimationColorChangeAnimator = null;
-        mColorChangeRunnable = null;
-        if (mColorChangeAnimator != null) {
-            mColorChangeAnimator.cancel();
-            mColorChangeAnimator = null;
-        }
-        if (mColorExtractor != null) {
-            mColorExtractor.removeLocations();
-            mColorExtractor.setListener(null);
-        }
-        GradientDrawable bg = (GradientDrawable) getBackground();
-        bg.setColor(Themes.getAttrColor(getContext(), R.attr.folderFillColor));
     }
 
     @Override
@@ -1227,12 +1125,6 @@
         lp.y = top;
 
         mBackground.setBounds(0, 0, width, height);
-
-        if (mColorExtractor != null) {
-            mColorExtractor.removeLocations();
-            mColorExtractor.setListener(mColorListener);
-            mLauncherDelegate.addRectForColorExtraction(lp, mColorExtractor);
-        }
     }
 
     protected int getContentAreaHeight() {
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index e66e2f6..57b289e 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -239,13 +239,13 @@
                 mFolder, startRect, endRect, finalRadius, !mIsOpening));
 
         // Create reveal animator for the folder content (capture the top 4 icons 2x2)
-        int width = mContent.getPaddingLeft() + mDeviceProfile.folderCellLayoutBorderSpacingPx
+        int width = mDeviceProfile.folderCellLayoutBorderSpacingPx
                 + mDeviceProfile.folderCellWidthPx * 2;
-        int height = mContent.getPaddingTop() + mDeviceProfile.folderCellLayoutBorderSpacingPx
+        int height = mDeviceProfile.folderCellLayoutBorderSpacingPx
                 + mDeviceProfile.folderCellHeightPx * 2;
         int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage();
-        int left = mContent.getPaddingLeft() + page * mContent.getWidth();
-        Rect contentStart = new Rect(left, 0, left + width, height);
+        int left = mContent.getPaddingLeft() + page * lp.width;
+        Rect contentStart = new Rect(0, 0, width, height);
         Rect contentEnd = new Rect(endRect.left + left, endRect.top, endRect.right + left,
                 endRect.bottom);
         play(a, getShape().createRevealAnimator(
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 915e140..dbd9c28 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -113,6 +113,12 @@
         Utilities.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
     }
 
+    @Override
+    protected void onStop() {
+        super.onStop();
+        finish();
+    }
+
     /**
      * Obtains the preference fragment to instantiate in this activity.
      *
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 03b6853..13d6568 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -18,6 +18,7 @@
 
 import static android.animation.ValueAnimator.areAnimatorsEnabled;
 
+import static com.android.launcher3.anim.AnimatorPlaybackController.callListenerCommandRecursively;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
 
 import android.animation.Animator;
@@ -514,8 +515,15 @@
                 playbackController.getAnimationPlayer().cancel();
                 playbackController.dispatchOnCancel();
             } else if (currentAnimation != null) {
-                currentAnimation.setDuration(0);
-                currentAnimation.cancel();
+                AnimatorSet anim = currentAnimation;
+                anim.setDuration(0);
+                if (!anim.isStarted()) {
+                    // If the animation is not started the listeners do not get notified,
+                    // notify manually.
+                    callListenerCommandRecursively(anim, AnimatorListener::onAnimationCancel);
+                    callListenerCommandRecursively(anim, AnimatorListener::onAnimationEnd);
+                }
+                anim.cancel();
             }
 
             currentAnimation = null;
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 5832711..87871b1 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.util.ActivityTracker;
 import com.android.launcher3.util.UiThreadHelper;
 
 /**
@@ -50,7 +51,7 @@
 
     /**
      * Rotation request made by
-     * {@link com.android.launcher3.util.ActivityTracker.SchedulerCallback}.
+     * {@link ActivityTracker.SchedulerCallback}.
      * This supersedes any other request.
      */
     private int mStateHandlerRequest = REQUEST_NONE;
diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java
index b5b9c2f..7af1a13 100644
--- a/src/com/android/launcher3/util/ActivityTracker.java
+++ b/src/com/android/launcher3/util/ActivityTracker.java
@@ -15,15 +15,14 @@
  */
 package com.android.launcher3.util;
 
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
-
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.BaseActivity;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * Helper class to statically track activity creation
@@ -32,8 +31,7 @@
 public final class ActivityTracker<T extends BaseActivity> {
 
     private WeakReference<T> mCurrentActivity = new WeakReference<>(null);
-
-    private static final String EXTRA_SCHEDULER_CALLBACK = "launcher.scheduler_callback";
+    private CopyOnWriteArrayList<SchedulerCallback<T>> mCallbacks = new CopyOnWriteArrayList<>();
 
     @Nullable
     public <R extends T> R getCreatedActivity() {
@@ -47,43 +45,50 @@
     }
 
     /**
-     * Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the activity is ready.
-     * If the activity is already created, this is called immediately, otherwise we add the
-     * callback as an extra on the intent, and will call init() when we get handleIntent().
+     * Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the
+     * activity is ready. If the activity is already created, this is called immediately.
+     *
+     * The tracker maintains a strong ref to the callback, so it is up to the caller to return
+     * {@code false} in the callback OR to unregister the callback explicitly.
+     *
      * @param callback The callback to call init() on when the activity is ready.
-     * @param intent The intent that will be used to initialize the activity, if the activity
-     *               doesn't already exist. We add the callback as an extra on this intent.
      */
-    public void runCallbackWhenActivityExists(SchedulerCallback<T> callback, Intent intent) {
+    public void registerCallback(SchedulerCallback<T> callback) {
         T activity = mCurrentActivity.get();
+        mCallbacks.add(callback);
         if (activity != null) {
-            callback.init(activity, activity.isStarted());
-        } else {
-            callback.addToIntent(intent);
+            if (!callback.init(activity, activity.isStarted())) {
+                unregisterCallback(callback);
+            }
         }
     }
 
+    /**
+     * Unregisters a registered callback.
+     */
+    public void unregisterCallback(SchedulerCallback<T> callback) {
+        mCallbacks.remove(callback);
+    }
+
     public boolean handleCreate(T activity) {
         mCurrentActivity = new WeakReference<>(activity);
-        return handleIntent(activity, activity.getIntent(), false);
+        return handleIntent(activity, false /* alreadyOnHome */);
     }
 
-    public boolean handleNewIntent(T activity, Intent intent) {
-        return handleIntent(activity, intent, activity.isStarted());
+    public boolean handleNewIntent(T activity) {
+        return handleIntent(activity, activity.isStarted());
     }
 
-    private boolean handleIntent(T activity, Intent intent, boolean alreadyOnHome) {
-        if (intent != null && intent.getExtras() != null) {
-            IBinder stateBinder = intent.getExtras().getBinder(EXTRA_SCHEDULER_CALLBACK);
-            SchedulerCallback<T> handler = ObjectWrapper.unwrap(stateBinder);
-            if (handler != null) {
-                if (!handler.init(activity, alreadyOnHome)) {
-                    intent.getExtras().remove(EXTRA_SCHEDULER_CALLBACK);
-                }
-                return true;
+    private boolean handleIntent(T activity, boolean alreadyOnHome) {
+        boolean handled = false;
+        for (SchedulerCallback<T> cb : mCallbacks) {
+            if (!cb.init(activity, alreadyOnHome)) {
+                // Callback doesn't want any more updates
+                unregisterCallback(cb);
             }
+            handled = true;
         }
-        return false;
+        return handled;
     }
 
     public interface SchedulerCallback<T extends BaseActivity> {
@@ -94,17 +99,5 @@
          * @return Whether to continue receiving callbacks (i.e. if the activity is recreated).
          */
         boolean init(T activity, boolean alreadyOnHome);
-
-        /**
-         * Adds this callback as an extra on the intent, so we can retrieve it in handleIntent() and
-         * call {@link #init}. The intent should be used to start the activity after calling this
-         * method in order for us to get handleIntent().
-         */
-        default Intent addToIntent(Intent intent) {
-            Bundle extras = new Bundle();
-            extras.putBinder(EXTRA_SCHEDULER_CALLBACK, ObjectWrapper.wrap(this));
-            intent.putExtras(extras);
-            return intent;
-        }
     }
 }
diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java
index b9387a8..cb721e6 100644
--- a/src/com/android/launcher3/util/UiThreadHelper.java
+++ b/src/com/android/launcher3/util/UiThreadHelper.java
@@ -25,11 +25,9 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.view.View;
-import android.view.WindowInsets;
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.launcher3.Launcher;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.views.ActivityContext;
 
 /**
@@ -48,14 +46,6 @@
     @SuppressLint("NewApi")
     public static void hideKeyboardAsync(ActivityContext activityContext, IBinder token) {
         View root = activityContext.getDragLayer();
-        if (Utilities.ATLEAST_R) {
-            WindowInsets rootInsets = root.getRootWindowInsets();
-            boolean isImeShown = rootInsets != null && rootInsets.isVisible(
-                    WindowInsets.Type.ime());
-            if (!isImeShown) {
-                return;
-            }
-        }
 
         Message.obtain(HANDLER.get(root.getContext()),
                 MSG_HIDE_KEYBOARD, token).sendToTarget();
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 25cce69..3027db6 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -376,6 +376,7 @@
             if (mIconLoadResult.isIconLoaded) {
                 setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
                         mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
+                setVisibility(VISIBLE);
                 setIconAndDotVisible(originalView, false);
             } else {
                 mIconLoadResult.onIconLoaded = () -> {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index f49d1b5..78916ac 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -344,7 +344,7 @@
             // swiping very close to the thumb area (not just within it's bound)
             // will also prevent back gesture
             SYSTEM_GESTURE_EXCLUSION_RECT.get(0).offset(mThumbDrawOffset.x, mThumbDrawOffset.y);
-            if (Utilities.ATLEAST_Q) {
+            if (Utilities.ATLEAST_Q && mSystemGestureInsets != null) {
                 SYSTEM_GESTURE_EXCLUSION_RECT.get(0).left =
                         SYSTEM_GESTURE_EXCLUSION_RECT.get(0).right - mSystemGestureInsets.right;
             }
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
index 804973f..1cc7f53 100644
--- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -16,17 +16,21 @@
 
 package com.android.launcher3.widget;
 
+import static com.android.launcher3.Utilities.ATLEAST_R;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 
 import android.animation.PropertyValuesHolder;
+import android.annotation.SuppressLint;
 import android.content.Context;
-import android.content.res.Configuration;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.WindowInsets;
 
-import com.android.launcher3.Insettable;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.dragndrop.AddItemActivity;
 import com.android.launcher3.views.AbstractSlideInView;
@@ -34,13 +38,12 @@
 /**
  * Bottom sheet for the pin widget.
  */
-public class AddItemWidgetsBottomSheet extends AbstractSlideInView<AddItemActivity>
-        implements Insettable {
+public class AddItemWidgetsBottomSheet extends AbstractSlideInView<AddItemActivity> implements
+        View.OnApplyWindowInsetsListener {
 
     private static final int DEFAULT_CLOSE_DURATION = 200;
 
-    private Rect mInsets;
-    private Configuration mCurrentConfiguration;
+    private final Rect mInsets;
 
     public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -48,9 +51,7 @@
 
     public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mContent = this;
         mInsets = new Rect();
-        mCurrentConfiguration = new Configuration(getResources().getConfiguration());
     }
 
     /**
@@ -62,15 +63,49 @@
             ((ViewGroup) parent).removeView(this);
         }
         attachToContainer();
+        setOnApplyWindowInsetsListener(this);
         animateOpen();
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
+        int width = r - l;
+        int height = b - t;
+
+        // Lay out content as center bottom aligned.
+        int contentWidth = mContent.getMeasuredWidth();
+        int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
+        mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
+                contentLeft + contentWidth, height);
+
         setTranslationShift(mTranslationShift);
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+        int widthUsed;
+        if (mInsets.bottom > 0) {
+            widthUsed = mInsets.left + mInsets.right;
+        } else {
+            Rect padding = deviceProfile.workspacePadding;
+            widthUsed = Math.max(padding.left + padding.right,
+                    2 * (mInsets.left + mInsets.right));
+        }
+
+        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
+        measureChildWithMargins(mContent, widthMeasureSpec,
+                widthUsed, heightMeasureSpec, heightUsed);
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mContent = findViewById(R.id.add_item_bottom_sheet_content);
+    }
+
     private void animateOpen() {
         if (mIsOpen || mOpenCloseAnimator.isRunning()) {
             return;
@@ -93,25 +128,24 @@
     }
 
     @Override
-    public void setInsets(Rect insets) {
-        // Extend behind left, right, and bottom insets.
-        int leftInset = insets.left - mInsets.left;
-        int rightInset = insets.right - mInsets.right;
-        int bottomInset = insets.bottom - mInsets.bottom;
-        mInsets.set(insets);
-        setPadding(leftInset, getPaddingTop(), rightInset, bottomInset);
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        if (mCurrentConfiguration.orientation != newConfig.orientation) {
-            mInsets.setEmpty();
-        }
-        mCurrentConfiguration.updateFrom(newConfig);
-    }
-
-    @Override
     protected int getScrimColor(Context context) {
         return context.getResources().getColor(R.color.widgets_picker_scrim);
     }
+
+    @SuppressLint("NewApi") // Already added API check.
+    @Override
+    public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
+        if (ATLEAST_R) {
+            Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars());
+            mInsets.set(insets.left, insets.top, insets.right, insets.bottom);
+        } else {
+            mInsets.set(windowInsets.getSystemWindowInsetLeft(),
+                    windowInsets.getSystemWindowInsetTop(),
+                    windowInsets.getSystemWindowInsetRight(),
+                    windowInsets.getSystemWindowInsetBottom());
+        }
+        mContent.setPadding(mContent.getPaddingStart(),
+                mContent.getPaddingTop(), mContent.getPaddingEnd(), mInsets.bottom);
+        return windowInsets;
+    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 81df100..d0e69fa 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -20,7 +20,6 @@
 
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.IntProperty;
@@ -71,10 +70,9 @@
     private static final long EDUCATION_TIP_DELAY_MS = 300;
 
     private ItemInfo mOriginalItemInfo;
-    private Rect mInsets;
+    private final Rect mInsets;
     private final int mMaxTableHeight;
     private int mMaxHorizontalSpan = 4;
-    private Configuration mCurrentConfiguration;
 
     private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
             new OnLayoutChangeListener() {
@@ -113,20 +111,38 @@
         super(context, attrs, defStyleAttr);
         setWillNotDraw(false);
         mInsets = new Rect();
-        mContent = this;
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         // Set the max table height to 2 / 3 of the grid height so that the bottom picker won't
         // take over the entire view vertically.
         mMaxTableHeight = deviceProfile.inv.numRows * 2 / 3  * deviceProfile.cellHeightPx;
-        mCurrentConfiguration = new Configuration(getResources().getConfiguration());
         if (!hasSeenEducationTip()) {
             addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
         }
     }
 
     @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mContent = findViewById(R.id.widgets_bottom_sheet);
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+        int widthUsed;
+        if (mInsets.bottom > 0) {
+            widthUsed = mInsets.left + mInsets.right;
+        } else {
+            Rect padding = deviceProfile.workspacePadding;
+            widthUsed = Math.max(padding.left + padding.right,
+                    2 * (mInsets.left + mInsets.right));
+        }
+
+        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
+        measureChildWithMargins(mContent, widthMeasureSpec,
+                widthUsed, heightMeasureSpec, heightUsed);
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
 
         int paddingPx = 2 * getResources().getDimensionPixelOffset(
                 R.dimen.widget_cell_horizontal_padding);
@@ -142,7 +158,15 @@
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
+        int width = r - l;
+        int height = b - t;
+
+        // Content is laid out as center bottom aligned.
+        int contentWidth = mContent.getMeasuredWidth();
+        int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
+        mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
+                contentLeft + contentWidth, height);
+
         setTranslationShift(mTranslationShift);
 
         // Ensure the scroll view height is not larger than mMaxTableHeight, which is a value
@@ -241,20 +265,14 @@
 
     @Override
     public void setInsets(Rect insets) {
-        // Extend behind left, right, and bottom insets.
-        int leftInset = insets.left - mInsets.left;
-        int rightInset = insets.right - mInsets.right;
-        int bottomInset = insets.bottom - mInsets.bottom;
         mInsets.set(insets);
-        setPadding(leftInset, getPaddingTop(), rightInset, bottomInset);
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        if (mCurrentConfiguration.orientation != newConfig.orientation) {
-            mInsets.setEmpty();
+        mContent.setPadding(mContent.getPaddingStart(),
+                mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
+        if (insets.bottom > 0) {
+            setupNavBarColor();
+        } else {
+            clearNavBarColor();
         }
-        mCurrentConfiguration.updateFrom(newConfig);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListLayoutManager.java b/src/com/android/launcher3/widget/picker/WidgetsListLayoutManager.java
new file mode 100644
index 0000000..2b7f544
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsListLayoutManager.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget.picker;
+
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.launcher3.widget.picker.SearchAndRecommendationsScrollController.OnContentChangeListener;
+
+/**
+ * A layout manager for the {@link WidgetsRecyclerView}.
+ *
+ * {@link #setOnContentChangeListener(OnContentChangeListener)} can be used to register a callback
+ * for when the content of the layout manager has changed, following measurement and animation.
+ */
+public final class WidgetsListLayoutManager extends LinearLayoutManager {
+    @Nullable
+    private OnContentChangeListener mOnContentChangeListener;
+
+    public WidgetsListLayoutManager(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onLayoutCompleted(RecyclerView.State state) {
+        super.onLayoutCompleted(state);
+        if (mOnContentChangeListener != null) {
+            mOnContentChangeListener.onContentChanged();
+        }
+    }
+
+    public void setOnContentChangeListener(@Nullable OnContentChangeListener listener) {
+        mOnContentChangeListener = listener;
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 4f4f1a3..3ee8b33 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -23,7 +23,6 @@
 import android.view.View;
 import android.widget.TableLayout;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
@@ -83,7 +82,9 @@
         super.onFinishInflate();
         // create a layout manager with Launcher's context so that scroll position
         // can be preserved during screen rotation.
-        setLayoutManager(new LinearLayoutManager(getContext()));
+        WidgetsListLayoutManager layoutManager = new WidgetsListLayoutManager(getContext());
+        layoutManager.setOnContentChangeListener(mOnContentChangeListener);
+        setLayoutManager(layoutManager);
     }
 
     @Override
@@ -92,22 +93,6 @@
         mAdapter = (WidgetsListAdapter) adapter;
     }
 
-    @Override
-    public void onChildAttachedToWindow(@NonNull View child) {
-        super.onChildAttachedToWindow(child);
-        if (mOnContentChangeListener != null) {
-            mOnContentChangeListener.onContentChanged();
-        }
-    }
-
-    @Override
-    public void onChildDetachedFromWindow(@NonNull View child) {
-        super.onChildDetachedFromWindow(child);
-        if (mOnContentChangeListener != null) {
-            mOnContentChangeListener.onContentChanged();
-        }
-    }
-
     /**
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      */
@@ -268,6 +253,10 @@
 
     public void setOnContentChangeListener(@Nullable OnContentChangeListener listener) {
         mOnContentChangeListener = listener;
+        WidgetsListLayoutManager layoutManager = (WidgetsListLayoutManager) getLayoutManager();
+        if (layoutManager != null) {
+            layoutManager.setOnContentChangeListener(listener);
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
index 59ada7b..b35c75b 100644
--- a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java
@@ -59,7 +59,8 @@
                 R.dimen.all_apps_header_pill_corner_radius);
 
         mSelectedIndicatorPaint = new Paint();
-        mSelectedIndicatorPaint.setColor(context.getColor(R.color.all_apps_tab_bg));
+        mSelectedIndicatorPaint.setColor(
+                context.getColor(R.color.all_apps_tab_background_selected));
 
         mIsRtl = Utilities.isRtl(getResources());
     }
diff --git a/tests/Android.mk b/tests/Android.mk
index 19b9656..6adc685 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -16,34 +16,6 @@
 LOCAL_PATH := $(call my-dir)
 
 #
-# Build rule for Tapl library.
-#
-include $(CLEAR_VARS)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	androidx.annotation_annotation \
-	androidx.test.runner \
-	androidx.test.rules \
-	androidx.preference_preference \
-	androidx.test.uiautomator_uiautomator
-
-ifneq (,$(wildcard frameworks/base))
-else
-    LOCAL_STATIC_JAVA_LIBRARIES += SystemUISharedLib
-
-    LOCAL_SRC_FILES := $(call all-java-files-under, tapl) \
-        ../src/com/android/launcher3/ResourceUtils.java \
-        ../src/com/android/launcher3/testing/TestProtocol.java
-endif
-
-LOCAL_MODULE := ub-launcher-aosp-tapl
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-LOCAL_SDK_VERSION := system_current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-#
 # Build rule for Launcher3Tests
 #
 include $(CLEAR_VARS)
@@ -56,14 +28,8 @@
     mockito-target-minus-junit4 \
     launcher_log_protos_lite
 
-ifneq (,$(wildcard frameworks/base))
-    LOCAL_PRIVATE_PLATFORM_APIS := true
-    LOCAL_STATIC_JAVA_LIBRARIES += launcher-aosp-tapl
-else
-    LOCAL_SDK_VERSION := system_28
-    LOCAL_MIN_SDK_VERSION := 21
-    LOCAL_STATIC_JAVA_LIBRARIES += ub-launcher-aosp-tapl
-endif
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_STATIC_JAVA_LIBRARIES += launcher-aosp-tapl
 
 LOCAL_SRC_FILES := \
 	$(call all-java-files-under, src) \
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 4a666b1..e86be2a 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -163,8 +163,8 @@
     @NonNull
     private void quickSwitch(boolean toRight) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
-            LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                    "want to quick switch to the previous app")) {
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to quick switch to the previous app")) {
             verifyActiveContainer();
             final boolean launcherWasVisible = mLauncher.isLauncherVisible();
             boolean transposeInLandscape = false;
@@ -177,33 +177,34 @@
                     final int startY;
                     final int endX;
                     final int endY;
+                    final int cornerRadius = (int) Math.ceil(mLauncher.getWindowCornerRadius());
                     if (toRight) {
                         if (mLauncher.getDevice().isNaturalOrientation() || !transposeInLandscape) {
                             // Swipe from the bottom left to the bottom right of the screen.
-                            startX = 0;
+                            startX = cornerRadius;
                             startY = getSwipeStartY();
-                            endX = mLauncher.getDevice().getDisplayWidth();
+                            endX = mLauncher.getDevice().getDisplayWidth() - cornerRadius;
                             endY = startY;
                         } else {
                             // Swipe from the bottom right to the top right of the screen.
                             startX = getSwipeStartX();
-                            startY = mLauncher.getRealDisplaySize().y - 1;
+                            startY = mLauncher.getRealDisplaySize().y - 1 - cornerRadius;
                             endX = startX;
-                            endY = 0;
+                            endY = cornerRadius;
                         }
                     } else {
                         if (mLauncher.getDevice().isNaturalOrientation() || !transposeInLandscape) {
                             // Swipe from the bottom right to the bottom left of the screen.
-                            startX = mLauncher.getDevice().getDisplayWidth();
+                            startX = mLauncher.getDevice().getDisplayWidth() - cornerRadius;
                             startY = getSwipeStartY();
-                            endX = 0;
+                            endX = cornerRadius;
                             endY = startY;
                         } else {
                             // Swipe from the bottom left to the top left of the screen.
                             startX = getSwipeStartX();
-                            startY = 0;
+                            startY = cornerRadius;
                             endX = startX;
-                            endY = mLauncher.getRealDisplaySize().y - 1;
+                            endY = mLauncher.getRealDisplaySize().y - 1 - cornerRadius;
                         }
                     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index bf7984e..f5c1efa 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1248,6 +1248,13 @@
         }
 
         final MotionEvent event = getMotionEvent(downTime, currentTime, action, point.x, point.y);
+        // b/190748682
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_UP:
+                log("b/190748682: injecting " + event);
+                break;
+        }
         assertTrue("injectInputEvent failed",
                 mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));
         event.recycle();
@@ -1443,4 +1450,33 @@
             return null;
         }
     }
+
+    float getWindowCornerRadius() {
+        final Resources resources = getResources();
+        if (!supportsRoundedCornersOnWindows(resources)) {
+            return 0f;
+        }
+
+        // Radius that should be used in case top or bottom aren't defined.
+        float defaultRadius = ResourceUtils.getDimenByName("rounded_corner_radius", resources, 0);
+
+        float topRadius = ResourceUtils.getDimenByName("rounded_corner_radius_top", resources, 0);
+        if (topRadius == 0f) {
+            topRadius = defaultRadius;
+        }
+        float bottomRadius = ResourceUtils.getDimenByName(
+                "rounded_corner_radius_bottom", resources, 0);
+        if (bottomRadius == 0f) {
+            bottomRadius = defaultRadius;
+        }
+
+        // Always use the smallest radius to make sure the rounded corners will
+        // completely cover the display.
+        return Math.min(topRadius, bottomRadius);
+    }
+
+    private static boolean supportsRoundedCornersOnWindows(Resources resources) {
+        return ResourceUtils.getBoolByName(
+                "config_supportsRoundedCornersOnWindows", resources, false);
+    }
 }
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 3624624..1ea0922 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -22,7 +22,6 @@
 
 import static junit.framework.TestCase.assertTrue;
 
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
@@ -61,34 +60,6 @@
         mHotseat = launcher.waitForLauncherObject("hotseat");
     }
 
-    private static boolean supportsRoundedCornersOnWindows(Resources resources) {
-        return ResourceUtils.getBoolByName(
-                "config_supportsRoundedCornersOnWindows", resources, false);
-    }
-
-    private static float getWindowCornerRadius(Resources resources) {
-        if (!supportsRoundedCornersOnWindows(resources)) {
-            return 0f;
-        }
-
-        // Radius that should be used in case top or bottom aren't defined.
-        float defaultRadius = ResourceUtils.getDimenByName("rounded_corner_radius", resources, 0);
-
-        float topRadius = ResourceUtils.getDimenByName("rounded_corner_radius_top", resources, 0);
-        if (topRadius == 0f) {
-            topRadius = defaultRadius;
-        }
-        float bottomRadius = ResourceUtils.getDimenByName(
-                "rounded_corner_radius_bottom", resources, 0);
-        if (bottomRadius == 0f) {
-            bottomRadius = defaultRadius;
-        }
-
-        // Always use the smallest radius to make sure the rounded corners will
-        // completely cover the display.
-        return Math.min(topRadius, bottomRadius);
-    }
-
     /**
      * Swipes up to All Apps.
      *
@@ -103,8 +74,7 @@
             final int deviceHeight = mLauncher.getDevice().getDisplayHeight();
             final int bottomGestureMargin = ResourceUtils.getNavbarSize(
                     ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources());
-            final int windowCornerRadius = (int) Math.ceil(getWindowCornerRadius(
-                    mLauncher.getResources()));
+            final int windowCornerRadius = (int) Math.ceil(mLauncher.getWindowCornerRadius());
             final int startY = deviceHeight - Math.max(bottomGestureMargin, windowCornerRadius) - 1;
             final int swipeHeight = mLauncher.getTestInfo(
                     TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).