Merge "Fix NPE inside REcyclerViewFastScroller" 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/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 6852642..0e85ec3 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -353,7 +353,8 @@
     public void startHome() {
         if (LIVE_TILE.get()) {
             RecentsView recentsView = getOverviewPanel();
-            recentsView.switchToScreenshotAndFinishAnimationToRecents(this::startHomeInternal);
+            recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true,
+                    this::startHomeInternal));
         } else {
             startHomeInternal();
         }
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/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/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/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/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-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 06bdd49..430a1ab 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -122,8 +122,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..eceec8d 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
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/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/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/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/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index bf7984e..426af19 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();