Merge "Move hideKeyboard call to end of the all apps transition controller animation" into tm-qpr-dev
diff --git a/go/quickstep/res/values-or/strings.xml b/go/quickstep/res/values-or/strings.xml
index 2e76e2d..36de437 100644
--- a/go/quickstep/res/values-or/strings.xml
+++ b/go/quickstep/res/values-or/strings.xml
@@ -6,7 +6,7 @@
     <string name="action_translate" msgid="8028378961867277746">"ଅନୁବାଦ କରନ୍ତୁ"</string>
     <string name="action_search" msgid="6269564710943755464">"Lens"</string>
     <string name="dialog_acknowledge" msgid="2804025517675853172">"ବୁଝିଗଲି"</string>
-    <string name="dialog_cancel" msgid="6464336969134856366">"ବାତିଲ୍ କରନ୍ତୁ"</string>
+    <string name="dialog_cancel" msgid="6464336969134856366">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="dialog_settings" msgid="6564397136021186148">"ସେଟିଂସ"</string>
     <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"ସ୍କିନରେ ଥିବା ଟେକ୍ସଟକୁ ଅନୁବାଦ କରନ୍ତୁ କିମ୍ବା ଶୁଣନ୍ତୁ"</string>
     <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଟେକ୍ସଟ, ୱେବ ଠିକଣା ଏବଂ ସ୍କ୍ରିନସଟଗୁଡ଼ିକ ପରି ସୂଚନାକୁ Google ସହ ସେୟାର କରାଯାଇପାରେ।\n\nଆପଣ କେଉଁ ସୂଚନାକୁ ସେୟାର କରନ୍ତି ତାହା ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, "<b>"ସେଟିଂସ &gt; ଆପ୍ସ &gt; ଡିଫଲ୍ଟ ଆପ୍ସ &gt; Digital assistant ଆପ"</b>"କୁ ଯାଆନ୍ତୁ।"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 643b1d5..c938e6b 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -45,18 +45,18 @@
     <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"सुझाए गए ऐप्लिकेशन की सुविधा चालू है"</string>
     <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"सुझाए गए ऐप्लिकेशन की सुविधा बंद है"</string>
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"सुझाया गया ऐप्लिकेशन: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"पक्का करें कि आप स्क्रीन की दाईं या बाईं ओर के बिल्कुल किनारे से स्वाइप कर रहे हों."</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"पक्का करें कि आप स्क्रीन की दाईं या बाईं ओर के बिलकुल किनारे से स्वाइप कर रहे हों."</string>
     <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"स्क्रीन के दाएं या बाएं किनारे से स्क्रीन के बीच तक स्वाइप करें और अपनी उंगली उठा लें."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"आपने स्क्रीन के दाएं किनारे से स्वाइप करके, पिछली स्क्रीन पर वापस जाने का तरीका सीख लिया है. अब, एक ऐप से दूसरे ऐप पर जाने का तरीका सीखें."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"आपने पेज पर पीछे ले जाने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है."</string>
-    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"देख लें कि आप स्क्रीन पर बिल्कुल नीचे तक स्वाइप न कर रहे हों."</string>
+    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"देख लें कि आप स्क्रीन पर बिलकुल नीचे तक स्वाइप न कर रहे हों."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\'सेटिंग\' में जाकर, पीछे जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) की संवेदनशीलता बदलें"</string>
     <string name="back_gesture_intro_title" msgid="19551256430224428">"पिछली स्क्रीन पर वापस जाने के लिए स्वाइप करें"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"पिछली स्क्रीन पर वापस जाने के लिए, स्क्रीन के बाएं या दाएं किनारे से बीचों-बीच तक स्वाइप करें."</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"पिछली स्क्रीन पर वापस जाने के लिए, स्क्रीन के बाएं या दाएं किनारे से स्क्रीन के बीच तक दो उंगलियों से स्वाइप करें."</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"देख लें कि आप स्क्रीन के निचले किनारे से ऊपर की ओर स्वाइप कर रहे हों."</string>
     <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"देख लें कि आप स्क्रीन से अपनी उंगली उठाने से पहले, इसे कहीं न रोक रहे हों."</string>
-    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"देख लें कि आप ऊपर की ओर बिल्कुल सीधे स्वाइप कर रहे हों."</string>
+    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"देख लें कि आप ऊपर की ओर बिलकुल सीधे स्वाइप कर रहे हों."</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"आपने होम स्क्रीन पर ले जाने वाले हाथ के जेस्चर के बारे में जान लिया है. अब, वापस जाने का तरीका जानें."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"आपने होम स्क्रीन पर ले जाने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है."</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"होम स्क्रीन पर जाने के लिए स्वाइप करें"</string>
@@ -64,7 +64,7 @@
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"स्क्रीन के सबसे नीचे से ऊपर की ओर 2 उंगलियों से स्वाइप करें. जेस्चर हमेशा होम स्क्रीन पर ले जाता है."</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"देख लें कि आप स्क्रीन के निचले किनारे से ऊपर की ओर स्वाइप कर रहे हों."</string>
     <string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"कोशिश करें कि स्क्रीन से उंगली उठाने से पहले, इसे कुछ देर स्क्रीन पर दबाकर रखें."</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"देख लें कि आप स्क्रीन पर ऊपर की तरफ़, बिल्कुल सीधे स्वाइप कर रहे हों और फिर रुकें."</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"देख लें कि आप स्क्रीन पर ऊपर की तरफ़, बिलकुल सीधे स्वाइप कर रहे हों और फिर रुकें."</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"आपने हाथ के जेस्चर इस्तेमाल करने सीख लिए हैं. जेस्चर बंद करने के लिए, सेटिंग में जाएं."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"आपने एक ऐप्लिकेशन से दूसरे पर जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर के बारे में जान लिया है."</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"एक ऐप्लिकेशन से दूसरे पर जाने के लिए स्वाइप करें"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 9398f52..6ab7c5e 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -89,7 +89,7 @@
     <string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ନାଭିଗେସନ୍ ଟ୍ୟୁଟୋରିଆଲକୁ ବାଦ୍ ଦେବେ?"</string>
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ଆପଣ ପରେ ଏହାକୁ <xliff:g id="NAME">%1$s</xliff:g> ଆପରେ ପାଇପାରିବେ"</string>
-    <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ବାତିଲ୍ କରନ୍ତୁ"</string>
+    <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ବାଦ୍ ଦିଅନ୍ତୁ"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"ସ୍କ୍ରିନ ଘୂରାନ୍ତୁ"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ଦେଖାଯାଇଛି"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 17a48a7..fa4eaed 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -36,6 +36,7 @@
     <dimen name="task_thumbnail_icon_drawable_size">44dp</dimen>
     <dimen name="overview_task_margin">16dp</dimen>
     <dimen name="overview_page_spacing">16dp</dimen>
+    <dimen name="task_icon_cache_default_icon_size">72dp</dimen>
 
     <item name="overview_max_scale" format="float" type="dimen">0.7</item>
     <item name="overview_modal_max_scale" format="float" type="dimen">1.1</item>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index e21dcba..ec497ef 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -337,7 +337,7 @@
                 new SplitSelectStateController(this, mHandler, getStateManager(),
                         getDepthController());
         overviewPanel.init(mActionsView, controller);
-        mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
+        mActionsView.updateDimension(getDeviceProfile());
         mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
 
         mAppTransitionManager = new QuickstepTransitionManager(this);
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index 119ae90..7b48332 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -41,7 +41,6 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.uioverrides.PredictedAppIcon;
 import com.android.launcher3.views.AbstractSlideInView;
 
@@ -107,8 +106,7 @@
         mDismissBtn.setOnClickListener(this::onDismiss);
 
         LinearLayout buttonContainer = findViewById(R.id.button_container);
-        int adjustedMarginEnd = ApiWrapper.getHotseatEndOffset(context)
-                - buttonContainer.getPaddingEnd();
+        int adjustedMarginEnd = grid.hotseatBarEndOffset - buttonContainer.getPaddingEnd();
         if (InvariantDeviceProfile.INSTANCE.get(context)
                 .getDeviceProfile(context).isTaskbarPresent && adjustedMarginEnd > 0) {
             ((LinearLayout.LayoutParams) buttonContainer.getLayoutParams()).setMarginEnd(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 439490e..6b12e9c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -839,6 +839,6 @@
         pw.println(String.format(
                 "%s\tmBindInProgress=%b", prefix, mBindingItems));
         mControllers.dumpLogs(prefix + "\t", pw);
-        mDeviceProfile.dump(prefix, pw);
+        mDeviceProfile.dump(this, prefix, pw);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index dc5c22d..48fde8f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -22,6 +22,7 @@
 import android.view.InsetsState
 import android.view.WindowManager
 import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD
+import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION
 import com.android.launcher3.AbstractFloatingView
 import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
 import com.android.launcher3.DeviceProfile
@@ -88,11 +89,17 @@
             }
         }
 
-        var imeInsetsSize = Insets.of(0, 0, 0, taskbarHeightForIme)
-        var insetsSizeOverride = arrayOf(
+        val imeInsetsSize = Insets.of(0, 0, 0, taskbarHeightForIme)
+        // Use 0 insets for the VoiceInteractionWindow (assistant) when gesture nav is enabled.
+        val visInsetsSize = Insets.of(0, 0, 0, if (context.isGestureNav) 0 else tappableHeight)
+        val insetsSizeOverride = arrayOf(
             InsetsFrameProvider.InsetsSizeOverride(
                 TYPE_INPUT_METHOD,
                 imeInsetsSize
+            ),
+            InsetsFrameProvider.InsetsSizeOverride(
+                TYPE_VOICE_INTERACTION,
+                visInsetsSize
             )
         )
         for (provider in windowLayoutParams.providedInsets) {
@@ -153,7 +160,8 @@
                     + " insetsSize=" + provider.insetsSize)
             if (provider.insetsSizeOverrides != null) {
                 pw.print(" insetsSizeOverrides={")
-                for (overrideSize in provider.insetsSizeOverrides) {
+                for ((i, overrideSize) in provider.insetsSizeOverrides.withIndex()) {
+                    if (i > 0) pw.print(", ")
                     pw.print(overrideSize)
                 }
                 pw.print("})")
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 6a43cc5..ea15acb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -42,7 +42,6 @@
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.AllAppsButton;
@@ -292,7 +291,7 @@
             countExcludingQsb--;
         }
         int spaceNeeded = countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
-        int navSpaceNeeded = ApiWrapper.getHotseatEndOffset(getContext());
+        int navSpaceNeeded = deviceProfile.hotseatBarEndOffset;
         boolean layoutRtl = isLayoutRtl();
         int iconEnd = right - (right - left - spaceNeeded) / 2;
         boolean needMoreSpaceForNav = layoutRtl ?
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 2f8e4d9..f450496 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -17,14 +17,9 @@
 package com.android.launcher3.uioverrides;
 
 import android.app.Person;
-import android.content.Context;
 import android.content.pm.ShortcutInfo;
-import android.content.res.Resources;
 
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.DisplayController.NavigationMode;
 
 public class ApiWrapper {
 
@@ -34,24 +29,4 @@
         Person[] persons = si.getPersons();
         return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons;
     }
-
-    /**
-     * Returns the minimum space that should be left empty at the end of hotseat
-     */
-    public static int getHotseatEndOffset(Context context) {
-        if (DisplayController.getNavigationMode(context) == NavigationMode.THREE_BUTTONS) {
-            Resources res = context.getResources();
-            /*
-            * 3 nav buttons +
-            * Little space at the end for contextual buttons +
-            * Little space between icons and nav buttons
-            */
-            return 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
-                    + res.getDimensionPixelSize(R.dimen.taskbar_contextual_button_margin)
-                    + res.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing);
-        } else {
-            return 0;
-        }
-
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 84b3839..7166a3e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -28,6 +28,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
+import static com.android.quickstep.views.RecentsView.OVERVIEW_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -74,6 +75,7 @@
         getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness());
         RECENTS_GRID_PROGRESS.set(mRecentsView,
                 state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f);
+        OVERVIEW_PROGRESS.set(mRecentsView, state == LauncherState.OVERVIEW ? 1f : 0f);
     }
 
     @Override
@@ -117,6 +119,10 @@
         boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile());
         setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
                 showAsGrid ? INSTANT : FINAL_FRAME);
+
+        boolean toOverview = toState == LauncherState.OVERVIEW;
+        setter.setFloat(mRecentsView, OVERVIEW_PROGRESS, toOverview ? 1f : 0f,
+                toOverview ? INSTANT : FINAL_FRAME);
     }
 
     abstract FloatProperty getTaskModalnessProperty();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index b733007..297a61a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -50,8 +50,7 @@
             return super.getVerticalProgress(launcher);
         }
         RecentsView recentsView = launcher.getOverviewPanel();
-        int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher,
-                launcher.getDeviceProfile(),
+        int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher.getDeviceProfile(),
                 recentsView.getPagedOrientationHandler());
         AllAppsTransitionController controller = launcher.getAllAppsController();
         float scrollRange = Math.max(controller.getShiftRange(), 1);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 0c49e5f..0f02e26 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -18,8 +18,6 @@
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
 
 import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.Launcher;
@@ -71,13 +69,6 @@
     }
 
     public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
-        Point taskSize = activity.<RecentsView>getOverviewPanel().getSelectedTaskSize();
-        Rect modalTaskSize = new Rect();
-        activity.<RecentsView>getOverviewPanel().getModalTaskSize(modalTaskSize);
-
-        float scale = Math.min((float) modalTaskSize.height() / taskSize.y,
-                (float) modalTaskSize.width() / taskSize.x);
-
-        return new float[] {scale, NO_OFFSET};
+        return new float[] {activity.getDeviceProfile().overviewModalTaskScale, NO_OFFSET};
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 6427e09..c0810b9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -65,12 +65,9 @@
 
     @Override
     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
-        RecentsView recentsView = launcher.getOverviewPanel();
-        float workspacePageHeight = launcher.getDeviceProfile().getCellLayoutHeight();
-        recentsView.getTaskSize(sTempRect);
-        float scale = (float) sTempRect.height() / workspacePageHeight;
         float parallaxFactor = 0.5f;
-        return new ScaleAndTranslation(scale, 0, -getDefaultSwipeHeight(launcher) * parallaxFactor);
+        return new ScaleAndTranslation(launcher.getDeviceProfile().overviewTaskWorkspaceScale, 0,
+                -getDefaultSwipeHeight(launcher) * parallaxFactor);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 53dc9dd..d06f64a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -120,8 +120,8 @@
         mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this);
         mRecentsView = mLauncher.getOverviewPanel();
         mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
-        mYRange = LayoutUtils.getShelfTrackingDistance(
-            mLauncher, mLauncher.getDeviceProfile(), mRecentsView.getPagedOrientationHandler());
+        mYRange = LayoutUtils.getShelfTrackingDistance(mLauncher.getDeviceProfile(),
+                mRecentsView.getPagedOrientationHandler());
         mMaxYProgress = mLauncher.getDeviceProfile().heightPx / mYRange;
         mMotionPauseDetector = new MotionPauseDetector(mLauncher);
         mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 9efbc34..7394945 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -144,8 +144,8 @@
                     .createPlaybackController();
             mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
             RecentsView recentsView = mLauncher.getOverviewPanel();
-            totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher,
-                    mLauncher.getDeviceProfile(), recentsView.getPagedOrientationHandler());
+            totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher.getDeviceProfile(),
+                    recentsView.getPagedOrientationHandler());
         } else {
             mCurrentAnimation = mLauncher.getStateManager()
                     .createAnimationToNewWorkspace(mToState, config);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9eb4d62..045530c 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -141,7 +141,7 @@
         RecentsAnimationCallbacks.RecentsAnimationListener {
     private static final String TAG = "AbsSwipeUpHandler";
 
-    private static final String[] STATE_NAMES = DEBUG_STATES ? new String[17] : null;
+    private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
 
     protected final BaseActivityInterface<S, T> mActivityInterface;
     protected final InputConsumerProxy mInputConsumerProxy;
@@ -172,59 +172,62 @@
                 }
             };
 
-    private static int getFlagForIndex(int index, String name) {
+    private static int FLAG_COUNT = 0;
+    private static int getNextStateFlag(String name) {
         if (DEBUG_STATES) {
-            STATE_NAMES[index] = name;
+            STATE_NAMES.add(name);
         }
-        return 1 << index;
+        int index = 1 << FLAG_COUNT;
+        FLAG_COUNT++;
+        return index;
     }
 
     // Launcher UI related states
     protected static final int STATE_LAUNCHER_PRESENT =
-            getFlagForIndex(0, "STATE_LAUNCHER_PRESENT");
+            getNextStateFlag("STATE_LAUNCHER_PRESENT");
     protected static final int STATE_LAUNCHER_STARTED =
-            getFlagForIndex(1, "STATE_LAUNCHER_STARTED");
+            getNextStateFlag("STATE_LAUNCHER_STARTED");
     protected static final int STATE_LAUNCHER_DRAWN =
-            getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
+            getNextStateFlag("STATE_LAUNCHER_DRAWN");
     // Called when the Launcher has connected to the touch interaction service (and the taskbar
     // ui controller is initialized)
     protected static final int STATE_LAUNCHER_BIND_TO_SERVICE =
-            getFlagForIndex(3, "STATE_LAUNCHER_BIND_TO_SERVICE");
+            getNextStateFlag("STATE_LAUNCHER_BIND_TO_SERVICE");
 
     // Internal initialization states
     private static final int STATE_APP_CONTROLLER_RECEIVED =
-            getFlagForIndex(4, "STATE_APP_CONTROLLER_RECEIVED");
+            getNextStateFlag("STATE_APP_CONTROLLER_RECEIVED");
 
     // Interaction finish states
     private static final int STATE_SCALED_CONTROLLER_HOME =
-            getFlagForIndex(5, "STATE_SCALED_CONTROLLER_HOME");
+            getNextStateFlag("STATE_SCALED_CONTROLLER_HOME");
     private static final int STATE_SCALED_CONTROLLER_RECENTS =
-            getFlagForIndex(6, "STATE_SCALED_CONTROLLER_RECENTS");
+            getNextStateFlag("STATE_SCALED_CONTROLLER_RECENTS");
 
     protected static final int STATE_HANDLER_INVALIDATED =
-            getFlagForIndex(7, "STATE_HANDLER_INVALIDATED");
+            getNextStateFlag("STATE_HANDLER_INVALIDATED");
     private static final int STATE_GESTURE_STARTED =
-            getFlagForIndex(8, "STATE_GESTURE_STARTED");
+            getNextStateFlag("STATE_GESTURE_STARTED");
     private static final int STATE_GESTURE_CANCELLED =
-            getFlagForIndex(9, "STATE_GESTURE_CANCELLED");
+            getNextStateFlag("STATE_GESTURE_CANCELLED");
     private static final int STATE_GESTURE_COMPLETED =
-            getFlagForIndex(10, "STATE_GESTURE_COMPLETED");
+            getNextStateFlag("STATE_GESTURE_COMPLETED");
 
     private static final int STATE_CAPTURE_SCREENSHOT =
-            getFlagForIndex(11, "STATE_CAPTURE_SCREENSHOT");
+            getNextStateFlag("STATE_CAPTURE_SCREENSHOT");
     protected static final int STATE_SCREENSHOT_CAPTURED =
-            getFlagForIndex(12, "STATE_SCREENSHOT_CAPTURED");
+            getNextStateFlag("STATE_SCREENSHOT_CAPTURED");
     private static final int STATE_SCREENSHOT_VIEW_SHOWN =
-            getFlagForIndex(13, "STATE_SCREENSHOT_VIEW_SHOWN");
+            getNextStateFlag("STATE_SCREENSHOT_VIEW_SHOWN");
 
     private static final int STATE_RESUME_LAST_TASK =
-            getFlagForIndex(14, "STATE_RESUME_LAST_TASK");
+            getNextStateFlag("STATE_RESUME_LAST_TASK");
     private static final int STATE_START_NEW_TASK =
-            getFlagForIndex(15, "STATE_START_NEW_TASK");
+            getNextStateFlag("STATE_START_NEW_TASK");
     private static final int STATE_CURRENT_TASK_FINISHED =
-            getFlagForIndex(16, "STATE_CURRENT_TASK_FINISHED");
+            getNextStateFlag("STATE_CURRENT_TASK_FINISHED");
     private static final int STATE_FINISH_WITH_NO_END =
-            getFlagForIndex(17, "STATE_FINISH_WITH_NO_END");
+            getNextStateFlag("STATE_FINISH_WITH_NO_END");
 
     private static final int LAUNCHER_UI_STATES =
             STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED |
@@ -318,7 +321,7 @@
     }
 
     private void initStateCallbacks() {
-        mStateCallback = new MultiStateCallback(STATE_NAMES);
+        mStateCallback = new MultiStateCallback(STATE_NAMES.toArray(new String[0]));
 
         mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
                 this::onLauncherPresentAndGestureStarted);
@@ -1626,7 +1629,8 @@
         // Cleanup when switching handlers
         mInputConsumerProxy.unregisterCallback();
         mActivityInitListener.unregister();
-        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mActivityRestartListener);
+        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
+                mActivityRestartListener);
         mTaskSnapshot = null;
     }
 
@@ -2045,8 +2049,8 @@
 
         float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage()));
         int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue(
-                mRecentsView.getLastComputedTaskSize().width(),
-                mRecentsView.getLastComputedTaskSize().height());
+                mActivity.getDeviceProfile().overviewTaskRect.width(),
+                mActivity.getDeviceProfile().overviewTaskRect.height());
         maxScrollOffset += mRecentsView.getPageSpacing();
 
         float maxScaleProgress =
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 52abb92..a922f58 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -33,12 +33,9 @@
 import android.animation.ObjectAnimator;
 import android.annotation.TargetApi;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Color;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Build;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -46,7 +43,6 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statehandlers.DepthController;
@@ -60,7 +56,6 @@
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
@@ -110,8 +105,8 @@
         activity.getStateManager().goToState(startState, activityVisible);
     }
 
-    public abstract int getSwipeUpDestinationAndLength(
-            DeviceProfile dp, Context context, Rect outRect,
+    /** Gets swipe-up destination and length. */
+    public abstract int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
             PagedOrientationHandler orientationHandler);
 
     /** Called when the animation to home has fully settled. */
@@ -216,138 +211,6 @@
     }
 
     /**
-     * Calculates the taskView size for the provided device configuration.
-     */
-    public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect) {
-        Resources res = context.getResources();
-        float maxScale = res.getFloat(R.dimen.overview_max_scale);
-        if (dp.isTablet) {
-            Rect gridRect = new Rect();
-            calculateGridSize(dp, gridRect);
-
-            calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect);
-        } else {
-            int taskMargin = dp.overviewTaskMarginPx;
-            calculateTaskSizeInternal(context, dp,
-                    dp.overviewTaskThumbnailTopMarginPx,
-                    dp.getOverviewActionsClaimedSpace(),
-                    res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
-                    maxScale,
-                    Gravity.CENTER,
-                    outRect);
-        }
-    }
-
-    private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove,
-            int claimedSpaceBelow, int minimumHorizontalPadding, float maxScale, int gravity,
-            Rect outRect) {
-        Rect insets = dp.getInsets();
-
-        Rect potentialTaskRect = new Rect(0, 0, dp.widthPx, dp.heightPx);
-        potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);
-        potentialTaskRect.inset(
-                minimumHorizontalPadding,
-                claimedSpaceAbove,
-                minimumHorizontalPadding,
-                claimedSpaceBelow);
-
-        calculateTaskSizeInternal(context, dp, potentialTaskRect, maxScale, gravity, outRect);
-    }
-
-    private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
-            Rect potentialTaskRect, float maxScale, int gravity, Rect outRect) {
-        PointF taskDimension = getTaskDimension(dp);
-
-        float scale = Math.min(
-                potentialTaskRect.width() / taskDimension.x,
-                potentialTaskRect.height() / taskDimension.y);
-        scale = Math.min(scale, maxScale);
-        int outWidth = Math.round(scale * taskDimension.x);
-        int outHeight = Math.round(scale * taskDimension.y);
-
-        Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
-    }
-
-    private static PointF getTaskDimension(DeviceProfile dp) {
-        PointF dimension = new PointF();
-        getTaskDimension(dp, dimension);
-        return dimension;
-    }
-
-    /**
-     * Gets the dimension of the task in the current system state.
-     */
-    public static void getTaskDimension(DeviceProfile dp, PointF out) {
-        out.x = dp.widthPx;
-        out.y = dp.heightPx;
-        if (TaskView.clipLeft(dp)) {
-            out.x -= dp.getInsets().left;
-        }
-        if (TaskView.clipRight(dp)) {
-            out.x -= dp.getInsets().right;
-        }
-        if (TaskView.clipTop(dp)) {
-            out.y -= dp.getInsets().top;
-        }
-        if (TaskView.clipBottom(dp)) {
-            out.y -= Math.max(dp.getInsets().bottom, dp.taskbarSize);
-        }
-    }
-
-    /**
-     * Calculates the overview grid size for the provided device configuration.
-     */
-    public final void calculateGridSize(DeviceProfile dp, Rect outRect) {
-        Rect insets = dp.getInsets();
-        int topMargin = dp.overviewTaskThumbnailTopMarginPx;
-        int bottomMargin = dp.getOverviewActionsClaimedSpace();
-        int sideMargin = dp.overviewGridSideMargin;
-
-        outRect.set(0, 0, dp.widthPx, dp.heightPx);
-        outRect.inset(Math.max(insets.left, sideMargin), insets.top + topMargin,
-                Math.max(insets.right, sideMargin), Math.max(insets.bottom, bottomMargin));
-    }
-
-    /**
-     * Calculates the overview grid non-focused task size for the provided device configuration.
-     */
-    public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
-            PagedOrientationHandler orientedState) {
-        Resources res = context.getResources();
-        Rect taskRect = new Rect();
-        calculateTaskSize(context, dp, taskRect);
-
-        float rowHeight =
-                (taskRect.height() + dp.overviewTaskThumbnailTopMarginPx - dp.overviewRowSpacing)
-                        / 2f;
-
-        PointF taskDimension = getTaskDimension(dp);
-        float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y;
-        int outWidth = Math.round(scale * taskDimension.x);
-        int outHeight = Math.round(scale * taskDimension.y);
-
-        int gravity = Gravity.TOP;
-        gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
-        Gravity.apply(gravity, outWidth, outHeight, taskRect, outRect);
-    }
-
-    /**
-     * Calculates the modal taskView size for the provided device configuration
-     */
-    public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
-        calculateTaskSize(context, dp, outRect);
-        float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
-        calculateTaskSizeInternal(
-                context, dp,
-                dp.overviewTaskMarginPx,
-                dp.heightPx - outRect.bottom - dp.getInsets().bottom,
-                Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2),
-                1f /*maxScale*/,
-                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
-                outRect);
-    }
-
-    /**
      * Called when the gesture ends and the animation starts towards the given target. Used to add
      * an optional additional animation with the same duration.
      */
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index ba61574..2ca5a2e 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -60,13 +60,13 @@
 
     /** 2 */
     @Override
-    public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
+    public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
             PagedOrientationHandler orientationHandler) {
-        calculateTaskSize(context, dp, outRect);
         if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) {
-            return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
+            return dp.isSeascape()
+                    ? dp.overviewTaskRect.left : (dp.widthPx - dp.overviewTaskRect.right);
         } else {
-            return dp.heightPx - outRect.bottom;
+            return dp.heightPx - dp.overviewTaskRect.bottom;
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 3b52e91..acdbbbd 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -38,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -82,11 +83,11 @@
 
     private static final String TAG = "GestureState";
 
-    private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
+    private static final List<String> STATE_NAMES = new ArrayList<>();
     public static final GestureState DEFAULT_STATE = new GestureState();
 
     private static int FLAG_COUNT = 0;
-    private static int getFlagForIndex(String name) {
+    private static int getNextStateFlag(String name) {
         if (DEBUG_STATES) {
             STATE_NAMES.add(name);
         }
@@ -97,36 +98,36 @@
 
     // Called when the end target as been set
     public static final int STATE_END_TARGET_SET =
-            getFlagForIndex("STATE_END_TARGET_SET");
+            getNextStateFlag("STATE_END_TARGET_SET");
 
     // Called when the end target animation has finished
     public static final int STATE_END_TARGET_ANIMATION_FINISHED =
-            getFlagForIndex("STATE_END_TARGET_ANIMATION_FINISHED");
+            getNextStateFlag("STATE_END_TARGET_ANIMATION_FINISHED");
 
     // Called when the recents animation has been requested to start
     public static final int STATE_RECENTS_ANIMATION_INITIALIZED =
-            getFlagForIndex("STATE_RECENTS_ANIMATION_INITIALIZED");
+            getNextStateFlag("STATE_RECENTS_ANIMATION_INITIALIZED");
 
     // Called when the recents animation is started and the TaskAnimationManager has been updated
     // with the controller and targets
     public static final int STATE_RECENTS_ANIMATION_STARTED =
-            getFlagForIndex("STATE_RECENTS_ANIMATION_STARTED");
+            getNextStateFlag("STATE_RECENTS_ANIMATION_STARTED");
 
     // Called when the recents animation is canceled
     public static final int STATE_RECENTS_ANIMATION_CANCELED =
-            getFlagForIndex("STATE_RECENTS_ANIMATION_CANCELED");
+            getNextStateFlag("STATE_RECENTS_ANIMATION_CANCELED");
 
     // Called when the recents animation finishes
     public static final int STATE_RECENTS_ANIMATION_FINISHED =
-            getFlagForIndex("STATE_RECENTS_ANIMATION_FINISHED");
+            getNextStateFlag("STATE_RECENTS_ANIMATION_FINISHED");
 
     // Always called when the recents animation ends (regardless of cancel or finish)
     public static final int STATE_RECENTS_ANIMATION_ENDED =
-            getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED");
+            getNextStateFlag("STATE_RECENTS_ANIMATION_ENDED");
 
     // Called when RecentsView stops scrolling and settles on a TaskView.
     public static final int STATE_RECENTS_SCROLLING_FINISHED =
-            getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
+            getNextStateFlag("STATE_RECENTS_SCROLLING_FINISHED");
 
     // Needed to interact with the current activity
     private final Intent mHomeIntent;
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index c13b95f..d3065bd 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -70,14 +70,14 @@
     }
 
     @Override
-    public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
+    public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
             PagedOrientationHandler orientationHandler) {
-        calculateTaskSize(context, dp, outRect);
         if (dp.isVerticalBarLayout()
                 && DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
-            return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
+            return dp.isSeascape()
+                    ? dp.overviewTaskRect.left : (dp.widthPx - dp.overviewTaskRect.right);
         } else {
-            return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler);
+            return LayoutUtils.getShelfTrackingDistance(dp, orientationHandler);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 528fb97..d216a6a 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -2,7 +2,6 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.graphics.Rect;
 import android.os.Bundle;
 
 import androidx.annotation.Nullable;
@@ -32,8 +31,7 @@
             }
 
             case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: {
-                final float swipeHeight =
-                        LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile,
+                final float swipeHeight = LayoutUtils.getShelfTrackingDistance(mDeviceProfile,
                                 PagedOrientationHandler.PORTRAIT);
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
                 return response;
@@ -43,10 +41,8 @@
                 if (!mDeviceProfile.isTablet) {
                     return null;
                 }
-                Rect focusedTaskRect = new Rect();
-                LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
-                        focusedTaskRect);
-                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
+                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        mDeviceProfile.overviewTaskRect.height());
                 return response;
             }
 
@@ -54,10 +50,10 @@
                 if (!mDeviceProfile.isTablet) {
                     return null;
                 }
-                Rect gridTaskRect = new Rect();
-                LauncherActivityInterface.INSTANCE.calculateGridTaskSize(mContext, mDeviceProfile,
-                        gridTaskRect, PagedOrientationHandler.PORTRAIT);
-                response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, gridTaskRect);
+                boolean isRecentsRtl = PagedOrientationHandler.PORTRAIT.getRecentsRtlSetting(
+                        mContext.getResources());
+                response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        mDeviceProfile.getOverviewGridTaskRect(isRecentsRtl));
                 return response;
             }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index b297973..fefef2f 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -220,7 +220,6 @@
      */
     public void enableInputConsumer() {
         UI_HELPER_EXECUTOR.submit(() -> {
-            mController.hideCurrentInputMethod();
             mController.setInputConsumerEnabled(true);
         });
     }
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index baeb514..3c15d0f 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -49,7 +49,6 @@
 public abstract class SwipeUpAnimationLogic implements
         RecentsAnimationCallbacks.RecentsAnimationListener{
 
-    protected static final Rect TEMP_RECT = new Rect();
     protected final RemoteTargetGluer mTargetGluer;
 
     protected DeviceProfile mDp;
@@ -92,7 +91,7 @@
     protected void initTransitionEndpoints(DeviceProfile dp) {
         mDp = dp;
         mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength(
-                dp, mContext, TEMP_RECT, mRemoteTargetHandles[0].getTaskViewSimulator()
+                dp, mContext, mRemoteTargetHandles[0].getTaskViewSimulator()
                         .getOrientationState().getOrientationHandler());
         mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
 
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 9ca5fc5..dc60875 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -263,7 +263,8 @@
         if (mIconFactory == null) {
             mIconFactory = new BaseIconFactory(mContext,
                     DisplayController.INSTANCE.get(mContext).getInfo().getDensityDpi(),
-                    mContext.getResources().getDimensionPixelSize(R.dimen.taskbar_icon_size));
+                    mContext.getResources().getDimensionPixelSize(
+                            R.dimen.task_icon_cache_default_icon_size));
         }
         return mIconFactory;
     }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index bf1c998..149af98 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1015,7 +1015,7 @@
             pw.println("ProtoTrace:");
             pw.println("  file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
             if (createdOverviewActivity != null) {
-                createdOverviewActivity.getDeviceProfile().dump("", pw);
+                createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
             }
             mTaskbarManager.dumpLogs("", pw);
         }
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index f68bbbc..c7c3441 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -27,6 +27,7 @@
 import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
+import static com.android.quickstep.views.RecentsView.OVERVIEW_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
@@ -105,6 +106,8 @@
         boolean showAsGrid = state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile());
         setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
                 showAsGrid ? INSTANT : FINAL_FRAME);
+        setter.setFloat(mRecentsView, OVERVIEW_PROGRESS, state == RecentsState.DEFAULT ? 1f : 0f,
+                INSTANT);
 
         setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
                 config.getInterpolator(ANIM_SCRIM_FADE, LINEAR));
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index aa52789..8ad17cb 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -83,6 +83,8 @@
 
     private static final int MAX_SWIPE_DURATION = 350;
 
+    private static final float ANIMATION_PAUSE_ALPHA_THRESHOLD = 0.1f;
+
     private TISBindHelper mTISBindHelper;
     private TISBinder mBinder;
 
@@ -145,6 +147,10 @@
     }
 
     private void runOnUiHelperThread(Runnable runnable) {
+        if (!isResumed()
+                || getContentViewAlphaForSwipeProgress() <= ANIMATION_PAUSE_ALPHA_THRESHOLD) {
+            return;
+        }
         Executors.UI_HELPER_EXECUTOR.execute(runnable);
     }
 
@@ -198,6 +204,7 @@
     @Override
     protected void onResume() {
         super.onResume();
+        maybeResumeOrPauseBackgroundAnimation();
         if (mBinder != null) {
             mBinder.getTaskbarManager().setSetupUIVisible(true);
             mBinder.setSwipeUpProxy(this::createSwipeUpProxy);
@@ -216,6 +223,7 @@
     protected void onPause() {
         super.onPause();
         clearBinderOverride();
+        maybeResumeOrPauseBackgroundAnimation();
         if (mSwipeProgress.value >= 1) {
             finishAndRemoveTask();
         }
@@ -250,10 +258,25 @@
         return mSwipeProgress;
     }
 
+    private float getContentViewAlphaForSwipeProgress() {
+        return Utilities.mapBoundToRange(
+                mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR, 1, 0, LINEAR);
+    }
+
+    private void maybeResumeOrPauseBackgroundAnimation() {
+        boolean shouldPlayAnimation =
+                getContentViewAlphaForSwipeProgress() > ANIMATION_PAUSE_ALPHA_THRESHOLD
+                        && isResumed();
+        if (mAnimatedBackground.isAnimating() && !shouldPlayAnimation) {
+            mAnimatedBackground.pauseAnimation();
+        } else if (!mAnimatedBackground.isAnimating() && shouldPlayAnimation) {
+            mAnimatedBackground.resumeAnimation();
+        }
+    }
+
     private void onSwipeProgressUpdate() {
         mBackground.setProgress(mSwipeProgress.value);
-        float alpha = Utilities.mapBoundToRange(
-                mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR, 1, 0, LINEAR);
+        float alpha = getContentViewAlphaForSwipeProgress();
         mContentView.setAlpha(alpha);
         mContentView.setTranslationY((alpha - 1) * mSwipeUpShift);
 
@@ -265,12 +288,7 @@
             mLauncherStartAnim.setPlayFraction(Utilities.mapBoundToRange(
                     mSwipeProgress.value, 0, 1, 0, 1, FAST_OUT_SLOW_IN));
         }
-
-        if (alpha == 0f) {
-            mAnimatedBackground.pauseAnimation();
-        } else if (!mAnimatedBackground.isAnimating()) {
-            mAnimatedBackground.resumeAnimation();
-        }
+        maybeResumeOrPauseBackgroundAnimation();
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index 7c83833..ded4fb0 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -36,7 +36,6 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.touch.PagedOrientationHandler;
-import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.views.RecentsView;
 
 /**
@@ -155,10 +154,9 @@
      */
     public static <SCALE, TRANSLATION> PendingAnimation createRecentsResistanceAnim(
             RecentsParams<SCALE, TRANSLATION> params) {
-        Rect startRect = new Rect();
+        Rect startRect = new Rect(params.dp.overviewTaskRect);
         PagedOrientationHandler orientationHandler = params.recentsOrientedState
                 .getOrientationHandler();
-        LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect);
         long distanceToCover = startRect.bottom;
         PendingAnimation resistAnim = params.resistAnim != null
                 ? params.resistAnim
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index d0856be..d4eb880 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -16,7 +16,6 @@
 package com.android.quickstep.util;
 
 import android.content.Context;
-import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -24,7 +23,6 @@
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.NavigationMode;
-import com.android.quickstep.LauncherActivityInterface;
 
 public class LayoutUtils {
 
@@ -39,12 +37,12 @@
         return swipeHeight;
     }
 
-    public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
+    /**
+     *  Returns the shelf tracking distance.
+     */
+    public static int getShelfTrackingDistance(DeviceProfile dp,
             PagedOrientationHandler orientationHandler) {
-        // Track the bottom of the window.
-        Rect taskSize = new Rect();
-        LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize);
-        return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
+        return orientationHandler.getDistanceToBottomOfRect(dp, dp.overviewTaskRect);
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index f2fcd06..39e3797 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -25,7 +25,6 @@
 import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SettingsCache.ROTATION_SETTING_URI;
-import static com.android.quickstep.BaseActivityInterface.getTaskDimension;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -53,7 +52,6 @@
 import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
-import com.android.quickstep.views.TaskView;
 
 import java.lang.annotation.Retention;
 import java.util.function.IntConsumer;
@@ -399,31 +397,10 @@
      * Returns the scale and pivot so that the provided taskRect can fit the provided full size
      */
     public float getFullScreenScaleAndPivot(Rect taskView, DeviceProfile dp, PointF outPivot) {
-        Rect insets = dp.getInsets();
-        float fullWidth = dp.widthPx;
-        float fullHeight = dp.heightPx;
-        if (TaskView.clipLeft(dp)) {
-            fullWidth -= insets.left;
-        }
-        if (TaskView.clipRight(dp)) {
-            fullWidth -= insets.right;
-        }
-        if (TaskView.clipTop(dp)) {
-            fullHeight -= insets.top;
-        }
-        if (TaskView.clipBottom(dp)) {
-            fullHeight -= insets.bottom;
-        }
-
-        getTaskDimension(dp, outPivot);
-        float scale = Math.min(outPivot.x / taskView.width(), outPivot.y / taskView.height());
-        // We also scale the preview as part of fullScreenParams, so account for that as well.
-        if (fullWidth > 0) {
-            scale = scale * dp.widthPx / fullWidth;
-        }
-
+        float scale = Math.min(dp.taskDimension.x / taskView.width(),
+                dp.taskDimension.y / taskView.height());
         if (scale == 1) {
-            outPivot.set(fullWidth / 2, fullHeight / 2);
+            outPivot.set(taskView.centerX(), taskView.centerY());
         } else {
             float factor = scale / (scale - 1);
             outPivot.set(taskView.left * factor, taskView.top * factor);
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index f1189c9..e89c842 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -42,6 +42,8 @@
 
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import com.android.quickstep.SystemUiProxy;
@@ -171,6 +173,8 @@
     public void launchTasks(int taskId1, @Nullable PendingIntent taskPendingIntent,
             @Nullable Intent fillInIntent, int taskId2, @StagePosition int stagePosition,
             Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
+        TestLogging.recordEvent(
+                TestProtocol.SEQUENCE_MAIN, "launchSplitTasks");
         // Assume initial task is for top/left part of screen
         final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
                 ? new int[]{taskId1, taskId2}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 8c48443..c626b0a 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -144,12 +144,8 @@
         if (mDp == null) {
             return 1;
         }
-        if (mIsGridTask) {
-            mSizeStrategy.calculateGridTaskSize(mContext, mDp, mTaskRect,
-                    mOrientationState.getOrientationHandler());
-        } else {
-            mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
-        }
+        mTaskRect.set(
+                mIsGridTask ? mDp.getOverviewGridTaskRect(mIsRecentsRtl) : mDp.overviewTaskRect);
 
         Rect fullTaskSize;
         if (mSplitBounds != null) {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index cb88068..2dff18e 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -1,5 +1,6 @@
 package com.android.quickstep.views;
 
+import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -313,4 +314,11 @@
         mSnapshotView2.setDimAlpha(amount);
         mDigitalWellBeingToast2.setBannerColorTint(tintColor, amount);
     }
+
+    @Override
+    protected void applyThumbnailSplashAlpha() {
+        super.applyThumbnailSplashAlpha();
+        mSnapshotView2.setSplashAlpha(
+                Utilities.mapToRange(mOverviewProgress, 0f, 1f, 1f, 0f, LINEAR));
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index bfb43c1..c178175 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -31,7 +31,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -94,7 +93,6 @@
 
     @Nullable
     protected DeviceProfile mDp;
-    private final Rect mTaskSize = new Rect();
 
     public OverviewActionsView(Context context) {
         this(context, null);
@@ -206,10 +204,13 @@
         if (mDp == null) {
             return;
         }
-        boolean alignFor3ButtonTaskbar = mDp.isTaskbarPresent && !mDp.isGestureMode;
-        if (alignFor3ButtonTaskbar) {
+        boolean largeScreenLandscape = mDp.isTablet && !mDp.isTwoPanels && mDp.isLandscape;
+        // If in 3-button mode, shift action buttons to accommodate 3-button layout.
+        // (Special exception for landscape tablets, where there is enough room and we don't need to
+        // shift the action buttons.)
+        if (mDp.areNavButtonsInline && !largeScreenLandscape) {
             // Add extra horizontal spacing
-            int additionalPadding = ApiWrapper.getHotseatEndOffset(getContext());
+            int additionalPadding = mDp.hotseatBarEndOffset;
             if (isLayoutRtl()) {
                 setPadding(mInsets.left + additionalPadding, 0, mInsets.right, 0);
             } else {
@@ -242,16 +243,15 @@
         }
 
         // Align to bottom of task Rect.
-        return mDp.heightPx - mTaskSize.bottom - mDp.overviewActionsTopMarginPx
+        return mDp.heightPx - mDp.overviewTaskRect.bottom - mDp.overviewActionsTopMarginPx
                 - mDp.overviewActionsHeight;
     }
 
     /**
-     * Updates device profile and task size for this view to draw with.
+     * Updates device profile for this view to draw with.
      */
-    public void updateDimension(DeviceProfile dp, Rect taskSize) {
+    public void updateDimension(DeviceProfile dp) {
         mDp = dp;
-        mTaskSize.set(taskSize);
         updateVerticalMargin(DisplayController.getNavigationMode(getContext()));
 
         requestLayout();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 274a691..dc886f6 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -363,6 +363,10 @@
                 }
             };
 
+    /**
+     * Progress of Recents view from carousel layout to grid layout. If Recents is not shown as a
+     * grid, then the value remains 0.
+     */
     public static final FloatProperty<RecentsView> RECENTS_GRID_PROGRESS =
             new FloatProperty<RecentsView>("recentsGrid") {
                 @Override
@@ -376,6 +380,23 @@
                 }
             };
 
+    /**
+     * Progress to and from the OVERVIEW state, where being in OverviewState has a value of 1, and
+     * being in any other LauncherState has a value of 0.
+     */
+    public static final FloatProperty<RecentsView> OVERVIEW_PROGRESS =
+            new FloatProperty<RecentsView>("overviewProgress") {
+                @Override
+                public void setValue(RecentsView view, float overviewProgress) {
+                    view.setOverviewProgress(overviewProgress);
+                }
+
+                @Override
+                public Float get(RecentsView view) {
+                    return view.mOverviewProgress;
+                }
+            };
+
     // OverScroll constants
     private static final int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
 
@@ -407,9 +428,6 @@
 
     @Nullable
     protected RemoteTargetHandle[] mRemoteTargetHandles;
-    protected final Rect mLastComputedTaskSize = new Rect();
-    protected final Rect mLastComputedGridSize = new Rect();
-    protected final Rect mLastComputedGridTaskSize = new Rect();
     // How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
     @Nullable
     protected Float mLastComputedTaskStartPushOutDistance = null;
@@ -466,6 +484,7 @@
     protected float mTaskViewsSecondarySplitTranslation = 0;
     // Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
     private float mGridProgress = 0;
+    private float mOverviewProgress = 0;
     private boolean mShowAsGridLastOnLayout = false;
     private final IntSet mTopRowIdSet = new IntSet();
 
@@ -1117,7 +1136,8 @@
         int targetScroll = getScrollForPage(indexOfChild(getFocusedTaskView()));
         if (!isClearAllHidden) {
             int clearAllWidth = mOrientationHandler.getPrimarySize(mClearAllButton);
-            int taskGridHorizontalDiff = mLastComputedTaskSize.right - mLastComputedGridSize.right;
+            int taskGridHorizontalDiff = mActivity.getDeviceProfile().overviewTaskRect.right
+                    - mActivity.getDeviceProfile().overviewGridRect.right;
             int clearAllFocusScrollDiff =  taskGridHorizontalDiff - clearAllWidth;
             targetScroll += mIsRtl ? clearAllFocusScrollDiff : -clearAllFocusScrollDiff;
         }
@@ -1656,7 +1676,7 @@
 
         // Update RecentsView and TaskView's DeviceProfile dependent layout.
         updateOrientationHandler();
-        mActionsView.updateDimension(dp, mLastComputedTaskSize);
+        mActionsView.updateDimension(dp);
     }
 
     private void updateOrientationHandler() {
@@ -1712,7 +1732,7 @@
     // Update task size and padding that are dependent on DeviceProfile and insets.
     private void updateSizeAndPadding() {
         DeviceProfile dp = mActivity.getDeviceProfile();
-        getTaskSize(mTempRect);
+        mTempRect.set(dp.overviewTaskRect);
         mTaskWidth = mTempRect.width();
         mTaskHeight = mTempRect.height();
 
@@ -1721,14 +1741,9 @@
                 dp.widthPx - mInsets.right - mTempRect.right,
                 dp.heightPx - mInsets.bottom - mTempRect.bottom);
 
-        mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(),
-                mLastComputedGridSize);
-        mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
-                mLastComputedGridTaskSize, mOrientationHandler);
-
-        mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
+        mTaskGridVerticalDiff = dp.getOverviewGridTaskRect(mIsRtl).top - dp.overviewTaskRect.top;
         mTopBottomRowHeightDiff =
-                mLastComputedGridTaskSize.height() + dp.overviewTaskThumbnailTopMarginPx
+                dp.overviewGridTaskDimension.y + dp.overviewTaskThumbnailTopMarginPx
                         + dp.overviewRowSpacing;
 
         // Force TaskView to update size from thumbnail
@@ -1770,34 +1785,6 @@
         updateGridProperties(isTaskDismissal);
     }
 
-    public void getTaskSize(Rect outRect) {
-        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
-        mLastComputedTaskSize.set(outRect);
-    }
-
-    /**
-     * Returns the size of task selected to enter modal state.
-     */
-    public Point getSelectedTaskSize() {
-        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(),
-                mTempRect);
-        return new Point(mTempRect.width(), mTempRect.height());
-    }
-
-    /** Gets the last computed task size */
-    public Rect getLastComputedTaskSize() {
-        return mLastComputedTaskSize;
-    }
-
-    public Rect getLastComputedGridTaskSize() {
-        return mLastComputedGridTaskSize;
-    }
-
-    /** Gets the task size for modal state. */
-    public void getModalTaskSize(Rect outRect) {
-        mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
-    }
-
     @Override
     protected boolean computeScrollHelper() {
         boolean scrolling = super.computeScrollHelper();
@@ -2212,6 +2199,11 @@
                 }
             }
         }
+        if (animatorSet == null) {
+            setOverviewProgress(1);
+        } else {
+            animatorSet.play(ObjectAnimator.ofFloat(this, OVERVIEW_PROGRESS, 1));
+        }
     }
 
     /**
@@ -2425,7 +2417,8 @@
             return;
         }
 
-        int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        int taskTopMargin = dp.overviewTaskThumbnailTopMarginPx;
 
         int topRowWidth = 0;
         int bottomRowWidth = 0;
@@ -2468,7 +2461,7 @@
                 gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
 
                 // Center view vertically in case it's from different orientation.
-                taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
+                taskView.setGridTranslationY((dp.overviewTaskRect.height() + taskTopMargin
                         - taskView.getLayoutParams().height) / 2f);
 
                 if (taskView == snappedTaskView) {
@@ -2584,11 +2577,11 @@
         // accordingly. Update longRowWidth if ClearAllButton has been moved.
         float clearAllShortTotalCompensation = 0;
         int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
-        if (longRowWidth < mLastComputedGridSize.width()) {
-            float shortTotalCompensation = mLastComputedGridSize.width() - longRowWidth;
+        if (longRowWidth < dp.overviewGridRect.width()) {
+            float shortTotalCompensation = dp.overviewGridRect.width() - longRowWidth;
             clearAllShortTotalCompensation =
                     mIsRtl ? -shortTotalCompensation : shortTotalCompensation;
-            longRowWidth = mLastComputedGridSize.width();
+            longRowWidth = dp.overviewGridRect.width();
         }
 
         float clearAllTotalTranslationX =
@@ -2605,9 +2598,8 @@
         if (snappedTaskView != null) {
             int distanceFromClearAll = longRowWidth - snappedTaskRowWidth + mPageSpacing;
             // ClearAllButton should be off screen when snapped task is in its snapped position.
-            int minimumDistance =
-                    mTaskWidth - snappedTaskView.getLayoutParams().width
-                            + (mLastComputedGridSize.width() - mTaskWidth) / 2;
+            int minimumDistance = mTaskWidth - snappedTaskView.getLayoutParams().width
+                    + (dp.overviewGridRect.width() - mTaskWidth) / 2;
             if (distanceFromClearAll < minimumDistance) {
                 int distanceDifference = minimumDistance - distanceFromClearAll;
                 snappedTaskGridTranslationX += mIsRtl ? distanceDifference : -distanceDifference;
@@ -2622,9 +2614,9 @@
 
         mClearAllButton.setGridTranslationPrimary(
                 clearAllTotalTranslationX - snappedTaskGridTranslationX);
-        mClearAllButton.setGridScrollOffset(
-                mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
-                        : mLastComputedTaskSize.right - mLastComputedGridSize.right);
+        mClearAllButton.setGridScrollOffset(mIsRtl
+                ? dp.overviewTaskRect.left - dp.overviewGridRect.left
+                : dp.overviewTaskRect.right - dp.overviewGridRect.right);
 
         setGridProgress(mGridProgress);
     }
@@ -2661,6 +2653,18 @@
         mClearAllButton.setGridProgress(gridProgress);
     }
 
+    private void setOverviewProgress(float overviewProgress) {
+        int taskCount = getTaskViewCount();
+        if (taskCount == 0) {
+            return;
+        }
+
+        mOverviewProgress = overviewProgress;
+        for (int i = 0; i < taskCount; i++) {
+            requireTaskViewAt(i).setOverviewProgress(overviewProgress);
+        }
+    }
+
     private void enableLayoutTransitions() {
         if (mLayoutTransition == null) {
             mLayoutTransition = new LayoutTransition();
@@ -2865,8 +2869,8 @@
         boolean closeGapBetweenClearAll = false;
         boolean isClearAllHidden = isClearAllHidden();
         boolean snapToLastTask = false;
-        boolean isLandscapeSplit =
-                mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        boolean isLandscapeSplit = dp.isLandscape && isSplitSelectionActive();
         boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
         boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
         TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
@@ -3057,7 +3061,7 @@
                         dismissTranslationInterpolationEnd);
                 if (taskView == nextFocusedTaskView) {
                     // Enlarge the task to be focused next, and translate into focus position.
-                    float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
+                    float scale = mTaskWidth / (float) dp.overviewGridTaskDimension.x;
                     anim.setFloat(taskView, TaskView.SNAPSHOT_SCALE, scale,
                             clampToProgress(LINEAR, animationStartProgress,
                                     dismissTranslationInterpolationEnd));
@@ -3313,7 +3317,7 @@
                         // Update various scroll-dependent UI.
                         dispatchScrollChanged();
                         updateActionsViewFocusedScroll();
-                        if (isClearAllHidden() && !mActivity.getDeviceProfile().isTablet) {
+                        if (isClearAllHidden() && !dp.isTablet) {
                             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING,
                                     false);
                         }
@@ -3711,7 +3715,6 @@
         updateEmptyStateUi(changed);
 
         // Update the pivots such that when the task is scaled, it fills the full page
-        getTaskSize(mTempRect);
         updatePivots();
         setTaskModalness(mTaskModalness);
         mLastComputedTaskStartPushOutDistance = null;
@@ -3725,12 +3728,13 @@
     }
 
     private void updatePivots() {
+        DeviceProfile dp = mActivity.getDeviceProfile();
         if (mOverviewSelectEnabled) {
-            setPivotX(mLastComputedTaskSize.centerX());
-            setPivotY(mLastComputedTaskSize.bottom);
+            setPivotX(dp.overviewTaskRect.centerX());
+            setPivotY(dp.overviewTaskRect.bottom);
         } else {
-            getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
-                    mActivity.getDeviceProfile(), mTempPointF);
+            getPagedViewOrientedState().getFullScreenScaleAndPivot(dp.overviewTaskRect, dp,
+                    mTempPointF);
             setPivotX(mTempPointF.x);
             setPivotY(mTempPointF.y);
         }
@@ -4003,8 +4007,8 @@
     }
 
     public void initiateSplitSelect(TaskView taskView) {
-        int defaultSplitPosition = mOrientationHandler
-                .getDefaultSplitPosition(mActivity.getDeviceProfile());
+        int defaultSplitPosition =
+                mOrientationHandler.getDefaultSplitPosition(mActivity.getDeviceProfile());
         initiateSplitSelect(taskView, defaultSplitPosition);
     }
 
@@ -4301,6 +4305,7 @@
                         properties));
             }
         }
+        anim.play(ObjectAnimator.ofFloat(recentsView, OVERVIEW_PROGRESS, 1, 0));
         return anim;
     }
 
@@ -4308,9 +4313,9 @@
      * Returns the scale up required on the view, so that it coves the screen completely
      */
     public float getMaxScaleForFullScreen() {
-        getTaskSize(mTempRect);
-        return getPagedViewOrientedState().getFullScreenScaleAndPivot(
-                mTempRect, mActivity.getDeviceProfile(), mTempPointF);
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        return getPagedViewOrientedState().getFullScreenScaleAndPivot(dp.overviewTaskRect,
+                dp, mTempPointF);
     }
 
     public PendingAnimation createTaskLaunchAnimation(
@@ -4360,6 +4365,8 @@
                     BACKGROUND_APP.getDepth(mActivity));
             anim.play(depthAnimator);
         }
+        anim.play(ObjectAnimator.ofFloat(this, OVERVIEW_PROGRESS, 1f, 0f));
+
         anim.play(progressAnim);
         anim.setInterpolator(interpolator);
 
@@ -4815,17 +4822,15 @@
         int lastGridTaskViewPosition =
                 getPositionInRow(lastGridTaskView, topRowIdArray, bottomRowIdArray);
         int taskViewPosition = getPositionInRow(taskView, topRowIdArray, bottomRowIdArray);
-        int gridTaskSizeAndSpacing = mLastComputedGridTaskSize.width() + mPageSpacing;
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        Rect gridTaskRect = dp.getOverviewGridTaskRect(mIsRtl);
+        int gridTaskSizeAndSpacing = gridTaskRect.width() + mPageSpacing;
         int positionDiff = gridTaskSizeAndSpacing * (lastGridTaskViewPosition - taskViewPosition);
 
-        int lastTaskEnd = (mIsRtl
-                ? mLastComputedGridSize.left
-                : mLastComputedGridSize.right)
+        int lastTaskEnd = (mIsRtl ? dp.overviewGridRect.left : dp.overviewGridRect.right)
                 + (mIsRtl ? mPageSpacing : -mPageSpacing);
         int taskEnd = lastTaskEnd + (mIsRtl ? positionDiff : -positionDiff);
-        int normalTaskEnd = mIsRtl
-                ? mLastComputedGridTaskSize.left
-                : mLastComputedGridTaskSize.right;
+        int normalTaskEnd = mIsRtl ? gridTaskRect.left : gridTaskRect.right;
         return taskEnd - normalTaskEnd;
     }
 
@@ -5131,14 +5136,12 @@
             while ((taskView == null || isTaskViewFullyVisible(taskView)) && targetPage - 1 >= 0) {
                 taskView = getTaskViewAt(--targetPage);
             }
+            DeviceProfile dp = mActivity.getDeviceProfile();
+            Rect gridTaskRect = dp.getOverviewGridTaskRect(mIsRtl);
             // Target a scroll where targetPage is on left of screen but still fully visible.
-            int lastTaskEnd = (mIsRtl
-                    ? mLastComputedGridSize.left
-                    : mLastComputedGridSize.right)
+            int lastTaskEnd = (mIsRtl ? dp.overviewGridRect.left : dp.overviewGridRect.right)
                     + (mIsRtl ? mPageSpacing : -mPageSpacing);
-            int normalTaskEnd = mIsRtl
-                    ? mLastComputedGridTaskSize.left
-                    : mLastComputedGridTaskSize.right;
+            int normalTaskEnd = mIsRtl ? gridTaskRect.left : gridTaskRect.right;
             int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - lastTaskEnd;
             // Find a page that is close to targetScroll while not over it.
             while (targetPage - 1 >= 0
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 32dc4d8..f4b3d98 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -36,12 +36,14 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Property;
 import android.view.Surface;
 import android.view.View;
+import android.widget.ImageView;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
@@ -50,6 +52,7 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
@@ -64,6 +67,7 @@
 public class TaskThumbnailView extends View {
     private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
             new MainThreadInitializedObject<>(FullscreenDrawParams::new);
+    private static final float MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT = 0.1f;
 
     public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
             new FloatProperty<TaskThumbnailView>("dimAlpha") {
@@ -83,6 +87,7 @@
     private TaskOverlay mOverlay;
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private final Paint mSplashBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mClearPaint = new Paint();
     private final Paint mDimmingPaintAfterClearing = new Paint();
     private final int mDimColor;
@@ -91,6 +96,8 @@
     private final Rect mPreviewRect = new Rect();
     private final PreviewPositionHelper mPreviewPositionHelper = new PreviewPositionHelper();
     private TaskView.FullscreenDrawParams mFullscreenParams;
+    private ImageView mSplashView;
+    private Drawable mSplashViewDrawable;
 
     @Nullable
     private Task mTask;
@@ -101,6 +108,8 @@
 
     /** How much this thumbnail is dimmed, 0 not dimmed at all, 1 totally dimmed. */
     private float mDimAlpha = 0f;
+    /** Controls visibility of the splash view, 0 is transparent, 255 fully opaque. */
+    private int mSplashAlpha = 0;
 
     private boolean mOverlayEnabled;
 
@@ -116,6 +125,7 @@
         super(context, attrs, defStyleAttr);
         mPaint.setFilterBitmap(true);
         mBackgroundPaint.setColor(Color.WHITE);
+        mSplashBackgroundPaint.setColor(Color.WHITE);
         mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
         mActivity = BaseActivity.fromContext(context);
         // Initialize with placeholder value. It is overridden later by TaskView
@@ -135,6 +145,8 @@
         int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000;
         mPaint.setColor(color);
         mBackgroundPaint.setColor(color);
+        mSplashBackgroundPaint.setColor(color);
+        updateSplashView(mTask.icon);
     }
 
     /**
@@ -152,6 +164,9 @@
         boolean thumbnailWasNull = mThumbnailData == null;
         mThumbnailData =
                 (thumbnailData != null && thumbnailData.thumbnail != null) ? thumbnailData : null;
+        if (mTask != null) {
+            updateSplashView(mTask.icon);
+        }
         if (refreshNow) {
             refresh(thumbnailWasNull && mThumbnailData != null);
         }
@@ -202,6 +217,18 @@
         updateThumbnailPaintFilter();
     }
 
+    /**
+     * Sets the alpha of the splash view.
+     */
+    public void setSplashAlpha(float splashAlpha) {
+        mSplashAlpha = (int) (Utilities.boundToRange(splashAlpha, 0f, 1f) * 255);
+        if (mSplashViewDrawable != null) {
+            mSplashViewDrawable.setAlpha(mSplashAlpha);
+        }
+        mSplashBackgroundPaint.setAlpha(mSplashAlpha);
+        invalidate();
+    }
+
     public TaskOverlay getTaskOverlay() {
         if (mOverlay == null) {
             mOverlay = getTaskView().getRecentsView().getTaskOverlayFactory().createOverlay(this);
@@ -238,13 +265,9 @@
         boundsToBitmapSpace.mapRect(boundsInBitmapSpace, viewRect);
 
         DeviceProfile dp = mActivity.getDeviceProfile();
-        int leftInset = TaskView.clipLeft(dp) ? Math.round(boundsInBitmapSpace.left) : 0;
-        int topInset = TaskView.clipTop(dp) ? Math.round(boundsInBitmapSpace.top) : 0;
-        int rightInset = TaskView.clipRight(dp) ? Math.round(
-                bitmapRect.right - boundsInBitmapSpace.right) : 0;
-        int bottomInset = TaskView.clipBottom(dp)
+        int bottomInset = dp.isTablet
                 ? Math.round(bitmapRect.bottom - boundsInBitmapSpace.bottom) : 0;
-        return Insets.of(leftInset, topInset, rightInset, bottomInset);
+        return Insets.of(0, 0, 0, bottomInset);
     }
 
 
@@ -264,6 +287,12 @@
     }
 
     @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        updateSplashView(mSplashViewDrawable);
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         RectF currentDrawnInsets = mFullscreenParams.mCurrentDrawnInsets;
         canvas.save();
@@ -313,6 +342,17 @@
         }
 
         canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
+
+        // Draw splash above thumbnail to hide inconsistencies in rotation and aspect ratios.
+        if (shouldShowSplashView()) {
+            if (mSplashView != null) {
+                canvas.drawRoundRect(x, y, width + 1, height + 1, cornerRadius,
+                        cornerRadius, mSplashBackgroundPaint);
+
+                mSplashView.layout((int) x, (int) (y + 1), (int) width, (int) height - 1);
+                mSplashView.draw(canvas);
+            }
+        }
     }
 
     public TaskView getTaskView() {
@@ -328,6 +368,78 @@
     }
 
     /**
+     * Determine if the splash should be shown over top of the thumbnail.
+     *
+     * <p>We want to show the splash if the aspect ratio or rotation of the thumbnail would be
+     * different from the task.
+     */
+    boolean shouldShowSplashView() {
+        return isThumbnailAspectRatioDifferentFromThumbnailData()
+                || isThumbnailRotationDifferentFromTask();
+    }
+
+    private void updateSplashView(Drawable icon) {
+        if (icon == null || icon.getConstantState() == null) {
+            return;
+        }
+        mSplashViewDrawable = icon.getConstantState().newDrawable().mutate();
+        mSplashViewDrawable.setAlpha(mSplashAlpha);
+        ImageView imageView = mSplashView == null ? new ImageView(getContext()) : mSplashView;
+        imageView.setImageDrawable(mSplashViewDrawable);
+
+        imageView.setScaleType(ImageView.ScaleType.MATRIX);
+        Matrix matrix = new Matrix();
+
+        float drawableWidth = mSplashViewDrawable.getIntrinsicWidth();
+        float drawableHeight = mSplashViewDrawable.getIntrinsicHeight();
+        float viewWidth = getMeasuredWidth();
+        float viewCenterX = viewWidth / 2f;
+        float viewHeight = getMeasuredHeight();
+        float viewCenterY = viewHeight / 2f;
+        float centeredDrawableLeft = (viewWidth - drawableWidth) / 2f;
+        float centeredDrawableTop = (viewHeight - drawableHeight) / 2f;
+        float nonGridScale = getTaskView() == null ? 1 : 1 / getTaskView().getNonGridScale();
+        float recentsMaxScale = getTaskView() == null || getTaskView().getRecentsView() == null
+                ? 1 : 1 / getTaskView().getRecentsView().getMaxScaleForFullScreen();
+        float scale = nonGridScale * recentsMaxScale;
+
+        // Center the image in the view.
+        matrix.setTranslate(centeredDrawableLeft, centeredDrawableTop);
+        // Apply scale transformation after translation, pivoting around center of view.
+        matrix.postScale(scale, scale, viewCenterX, viewCenterY);
+
+        imageView.setImageMatrix(matrix);
+        mSplashView = imageView;
+    }
+
+    private boolean isThumbnailAspectRatioDifferentFromThumbnailData() {
+        if (mThumbnailData == null || mThumbnailData.thumbnail == null) {
+            return false;
+        }
+
+        float thumbnailViewAspect = getWidth() / (float) getHeight();
+        float thumbnailDataAspect =
+                mThumbnailData.thumbnail.getWidth() / (float) mThumbnailData.thumbnail.getHeight();
+
+        return Utilities.isRelativePercentDifferenceGreaterThan(thumbnailViewAspect,
+                thumbnailDataAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
+    }
+
+    private boolean isThumbnailRotationDifferentFromTask() {
+        RecentsView recents = getTaskView().getRecentsView();
+        if (recents == null || mThumbnailData == null) {
+            return false;
+        }
+
+        if (recents.getPagedOrientationHandler() == PagedOrientationHandler.PORTRAIT) {
+            int currentRotation = recents.getPagedViewOrientedState().getRecentsActivityRotation();
+            return (currentRotation - mThumbnailData.rotation) % 2 != 0;
+        } else {
+            return recents.getPagedOrientationHandler().getRotation() != mThumbnailData.rotation;
+        }
+    }
+
+    /**
      * Potentially re-init the task overlay. Be cautious when calling this as the overlay may
      * do processing on initialization.
      */
@@ -435,18 +547,9 @@
             int thumbnailRotation = thumbnailData.rotation;
             int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
             RectF thumbnailClipHint = new RectF();
-            if (TaskView.clipLeft(dp)) {
-                thumbnailClipHint.left = thumbnailData.insets.left;
-            }
-            if (TaskView.clipRight(dp)) {
-                thumbnailClipHint.right = thumbnailData.insets.right;
-            }
-            if (TaskView.clipTop(dp)) {
-                thumbnailClipHint.top = thumbnailData.insets.top;
-            }
-            if (TaskView.clipBottom(dp)) {
-                thumbnailClipHint.bottom = thumbnailData.insets.bottom;
-            }
+            float canvasScreenRatio = canvasWidth / (float) dp.widthPx;
+            float scaledTaskbarSize = dp.taskbarSize * canvasScreenRatio;
+            thumbnailClipHint.bottom = dp.isTablet ? scaledTaskbarSize : 0;
 
             float scale = thumbnailData.scale;
             final float thumbnailScale;
@@ -476,8 +579,9 @@
                 float availableAspect = isRotated
                         ? availableHeight / availableWidth
                         : availableWidth / availableHeight;
-                boolean isAspectLargelyDifferent = Utilities.isRelativePercentDifferenceGreaterThan(
-                        canvasAspect, availableAspect, 0.1f);
+                boolean isAspectLargelyDifferent =
+                        Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect,
+                                availableAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
                 if (isRotated && isAspectLargelyDifferent) {
                     // Do not rotate thumbnail if it would not improve fit
                     isRotated = false;
@@ -486,18 +590,10 @@
 
                 if (isAspectLargelyDifferent) {
                     // Crop letterbox insets if insets isn't already clipped
-                    if (!TaskView.clipLeft(dp)) {
-                        thumbnailClipHint.left = thumbnailData.letterboxInsets.left;
-                    }
-                    if (!TaskView.clipRight(dp)) {
-                        thumbnailClipHint.right = thumbnailData.letterboxInsets.right;
-                    }
-                    if (!TaskView.clipTop(dp)) {
-                        thumbnailClipHint.top = thumbnailData.letterboxInsets.top;
-                    }
-                    if (!TaskView.clipBottom(dp)) {
-                        thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom;
-                    }
+                    thumbnailClipHint.left = thumbnailData.letterboxInsets.left;
+                    thumbnailClipHint.right = thumbnailData.letterboxInsets.right;
+                    thumbnailClipHint.top = thumbnailData.letterboxInsets.top;
+                    thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom;
                     availableWidth = surfaceWidth
                             - (thumbnailClipHint.left + thumbnailClipHint.right);
                     availableHeight = surfaceHeight
@@ -568,8 +664,7 @@
                 setThumbnailRotation(deltaRotate, thumbnailBounds);
             }
 
-            float canvasScreenRatio = canvasWidth / (float) dp.widthPx;
-            mClippedInsets.set(0, 0, 0, dp.taskbarSize * canvasScreenRatio);
+            mClippedInsets.set(0, 0, 0, scaledTaskbarSize);
 
             mMatrix.postScale(thumbnailScale, thumbnailScale);
             mIsOrientationChanged = isOrientationDifferent;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 68e9f5a..d2b85f6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -18,6 +18,7 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.widget.Toast.LENGTH_SHORT;
+import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR;
 
 import static com.android.launcher3.Utilities.comp;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
@@ -136,34 +137,6 @@
     /** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
     public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
 
-    /**
-     * Should the TaskView display clip off the left inset in RecentsView.
-     */
-    public static boolean clipLeft(DeviceProfile deviceProfile) {
-        return false;
-    }
-
-    /**
-     * Should the TaskView display clip off the top inset in RecentsView.
-     */
-    public static boolean clipTop(DeviceProfile deviceProfile) {
-        return false;
-    }
-
-    /**
-     * Should the TaskView display clip off the right inset in RecentsView.
-     */
-    public static boolean clipRight(DeviceProfile deviceProfile) {
-        return false;
-    }
-
-    /**
-     * Should the TaskView display clip off the bottom inset in RecentsView.
-     */
-    public static boolean clipBottom(DeviceProfile deviceProfile) {
-        return deviceProfile.isTablet;
-    }
-
     private static final float EDGE_SCALE_DOWN_FACTOR_CAROUSEL = 0.03f;
     private static final float EDGE_SCALE_DOWN_FACTOR_GRID = 0.00f;
 
@@ -361,6 +334,7 @@
     protected final DigitalWellBeingToast mDigitalWellBeingToast;
     private float mFullscreenProgress;
     private float mGridProgress;
+    protected float mOverviewProgress;
     private float mNonGridScale = 1;
     private float mDismissScale = 1;
     protected final FullscreenDrawParams mCurrentFullscreenParams;
@@ -420,7 +394,6 @@
 
     private boolean mIsClickableAsLiveTile = true;
 
-
     public TaskView(Context context) {
         this(context, null);
     }
@@ -688,6 +661,9 @@
             if (freezeTaskList) {
                 ActivityOptionsCompat.setFreezeRecentTasksList(opts);
             }
+            // TODO(b/202826469): Replace setSplashScreenStyle with setDisableStartingWindow.
+            opts.setSplashScreenStyle(mSnapshotView.shouldShowSplashView()
+                    ? SPLASH_SCREEN_STYLE_SOLID_COLOR : opts.getSplashScreenStyle());
             Task.TaskKey key = mTask.key;
             UI_HELPER_EXECUTOR.execute(() -> {
                 if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
@@ -1088,6 +1064,21 @@
         return scale;
     }
 
+    /**
+     * Updates progress of task view for entering/exiting overview on swipe up/down.
+     *
+     * <p>Updates the alpha of any splash screen over the thumbnail if it exists.
+     */
+    public void setOverviewProgress(float overviewProgress) {
+        mOverviewProgress = overviewProgress;
+        applyThumbnailSplashAlpha();
+    }
+
+    protected void applyThumbnailSplashAlpha() {
+        mSnapshotView.setSplashAlpha(
+                Utilities.mapToRange(mOverviewProgress, 0f, 1f, 1f, 0f, LINEAR));
+    }
+
     private void setSplitSelectTranslationX(float x) {
         mSplitSelectTranslationX = x;
         applyTranslationX();
@@ -1440,9 +1431,8 @@
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
         if (deviceProfile.isTablet) {
             final int thumbnailPadding = deviceProfile.overviewTaskThumbnailTopMarginPx;
-            final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
-            final int taskWidth = lastComputedTaskSize.width();
-            final int taskHeight = lastComputedTaskSize.height();
+            final int taskWidth = deviceProfile.overviewTaskRect.width();
+            final int taskHeight = deviceProfile.overviewTaskRect.height();
 
             int boxWidth;
             int boxHeight;
@@ -1453,10 +1443,9 @@
                 boxWidth = taskWidth;
                 boxHeight = taskHeight;
             } else {
-                // Otherwise task is in grid, and should use lastComputedGridTaskSize.
-                Rect lastComputedGridTaskSize = getRecentsView().getLastComputedGridTaskSize();
-                boxWidth = lastComputedGridTaskSize.width();
-                boxHeight = lastComputedGridTaskSize.height();
+                // Otherwise task is in grid.
+                boxWidth = deviceProfile.overviewGridTaskDimension.x;
+                boxHeight = deviceProfile.overviewGridTaskDimension.y;
             }
 
             // Bound width/height to the box size.
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfilePhone3ButtonTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfilePhone3ButtonTest.kt
new file mode 100644
index 0000000..588e346
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfilePhone3ButtonTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for phone with 3-Button navigation.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfilePhone3ButtonTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForPhone(isGestureMode = false)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(265)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(343)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.getCellSize().x).isEqualTo(265)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.getCellSize().y).isEqualTo(552)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(66)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(66)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(38)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(25)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(265)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(343)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(27)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(38)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1050)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(232)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(58)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(25)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(409)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(265)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(66)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(66)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(91)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(669)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(221)
+    }
+
+    @Test
+    fun hotseatBarBottomPaddingPx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(168)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(221)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(266)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(135)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(1189)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(false)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(0)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(91)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(53)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(53)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(573)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.182266f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(154)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(84)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(126)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(-112)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(112)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(56)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(84)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.74417657f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(2447)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(1334)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(364)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(2185)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(147)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(558)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(125)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(0)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(125)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(448)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(1440)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(2768)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(1440)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(3120)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(231)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(414)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(1209)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(2533)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(450)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(976)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(182)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(202)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(1258)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(2533)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(759)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(414)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(1209)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(1390)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.86595833f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1000472f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfilePhoneTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfilePhoneTest.kt
new file mode 100644
index 0000000..f91d03d
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfilePhoneTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for phone.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfilePhoneTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForPhone()
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(265)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(343)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.getCellSize().x).isEqualTo(265)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.getCellSize().y).isEqualTo(552)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(66)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(66)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(38)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(25)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(265)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(343)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(27)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(38)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1050)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(232)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(58)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(25)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(409)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(265)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(66)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(66)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(91)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(669)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(221)
+    }
+
+    @Test
+    fun hotseatBarBottomPaddingPx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(168)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(221)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(266)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(135)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(1189)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(false)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(0)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(91)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(53)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(53)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(573)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.182266f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(154)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(84)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(126)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(-112)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(112)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(56)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(84)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.74417657f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(2447)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(1334)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(364)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(2185)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(147)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(558)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(125)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(0)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(125)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(448)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(1440)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(2768)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(1440)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(3120)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(231)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(414)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(1209)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(2533)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(450)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(976)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(182)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(202)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(1258)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(2533)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(759)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(414)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(1209)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(1390)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.86595833f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1000472f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileQuickstepTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileQuickstepTest.kt
deleted file mode 100644
index 20b5a64..0000000
--- a/quickstep/tests/src/com/android/quickstep/DeviceProfileQuickstepTest.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.launcher3.DeviceProfileBaseTest
-import com.android.launcher3.InvariantDeviceProfile
-import com.android.launcher3.util.WindowBounds
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
-import org.mockito.Mockito.`when` as whenever
-
-/**
- * Test for [DeviceProfile] quickstep.
- */
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class DeviceProfileQuickstepTest : DeviceProfileBaseTest() {
-
-    @Test
-    fun getCellLayoutWidthAndHeight_twoPanelLandscapeScalable4By4GridTablet() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.densityDpi).thenReturn(320)
-        whenever(info.smallestSizeDp(ArgumentMatchers.any())).thenReturn(800f)
-        inv = newScalableInvariantDeviceProfile()
-
-        val dp = newDP()
-
-        assertThat(dp.cellLayoutWidth).isEqualTo(1237)
-        assertThat(dp.cellLayoutHeight).isEqualTo(1215)
-    }
-
-    @Test
-    fun getCellSize_twoPanelLandscapeScalable4By4GridTablet() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.densityDpi).thenReturn(320)
-        whenever(info.smallestSizeDp(ArgumentMatchers.any())).thenReturn(800f)
-        inv = newScalableInvariantDeviceProfile()
-
-        val dp = newDP()
-
-        assertThat(dp.getCellSize().y).isEqualTo(260)
-        assertThat(dp.getCellSize().x).isEqualTo(259)
-    }
-
-    @Test
-    fun getPanelCount_twoPanelLandscapeScalable4By4GridTablet() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.densityDpi).thenReturn(320)
-        whenever(info.smallestSizeDp(ArgumentMatchers.any())).thenReturn(800f)
-        inv = newScalableInvariantDeviceProfile()
-
-        val dp = newDP()
-
-        assertThat(dp.panelCount).isEqualTo(2)
-    }
-
-    @Test
-    fun getWorkspaceSpringLoadShrunkTopBottom_landscapePhoneVerticalBar() {
-        inv = newScalableInvariantDeviceProfile()
-        initializeVarsForPhone(true)
-        inv = newScalableInvariantDeviceProfile().apply {
-            deviceType = InvariantDeviceProfile.TYPE_PHONE
-            transposeLayoutWithOrientation = true
-        }
-
-        val dp = newDP()
-
-        assertThat(dp.isVerticalBarLayout).isEqualTo(true)
-        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(168)
-        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1358)
-    }
-
-    @Test
-    fun getWorkspaceSpringLoadShrunkTopBottom_portraitPhone() {
-        inv = newScalableInvariantDeviceProfile()
-        initializeVarsForPhone()
-        inv = newScalableInvariantDeviceProfile().apply {
-            deviceType = InvariantDeviceProfile.TYPE_PHONE
-        }
-
-        val dp = newDP()
-
-        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
-        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(364)
-        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(2185)
-    }
-}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscape3ButtonTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscape3ButtonTest.kt
new file mode 100644
index 0000000..2d9e263
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscape3ButtonTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for tablet in landscape with 3-Button navigation.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTabletLandscape3ButtonTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet(isLandscape = true, isGestureMode = false)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(227)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(294)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(558)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(294)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(57)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(57)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(59)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(59)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(59)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(227)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(294)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(48)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1600)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(199)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(50)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(351)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(227)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(57)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(57)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(64)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(1244)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(228)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(128)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(5)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(32)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(true)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(1237)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(78)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(19)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(19)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(93)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.7736843f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(64)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.7363184f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(1407)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(2522)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(208)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1244)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(109)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(1443)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(-7)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(428)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(428)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(2432)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(1340)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(2560)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(1480)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(384)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(232)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(2176)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(1268)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(723)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(418)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(294)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(2266)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(1268)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(1453)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(232)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(2176)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(650)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.7363184f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1003861f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscapeTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscapeTest.kt
new file mode 100644
index 0000000..3add2c7
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscapeTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for tablet in landscape.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTabletLandscapeTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet(isLandscape = true)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(227)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(294)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(558)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(294)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(57)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(57)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(59)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(59)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(59)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(227)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(294)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(48)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1600)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(199)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(50)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(351)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(227)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(57)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(57)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(64)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(1244)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(228)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(128)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(503)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(true)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(-503)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(78)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(19)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(19)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(93)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.7736843f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(64)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.7363184f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(1407)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(2522)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(208)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1244)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(109)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(301)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(-7)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(301)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(2432)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(1416)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(2560)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(1480)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(384)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(270)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(2176)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(1306)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(723)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(418)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(294)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(166)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(2266)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(1306)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(1453)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(270)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(2176)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(688)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.7363184f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1003861f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortrait3ButtonTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortrait3ButtonTest.kt
new file mode 100644
index 0000000..7f0d6ca
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortrait3ButtonTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for tablet in portrait with 3-Button navigation.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTabletPortrait3ButtonTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet(isGestureMode = false)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(294)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(382)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(294)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(482)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(74)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(74)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(72)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(72)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(72)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(294)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(382)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(77)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1960)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(257)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(64)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(456)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(294)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(74)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(74)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(56)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(781)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(386)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(216)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(32)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(1216)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(101)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(29)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(29)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(238)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(2.2988505f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(48)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(220)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(96)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.6741674f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(2222)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(1542)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(460)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1958)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(272)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(528)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(151)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(528)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(428)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(1472)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(2292)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(1600)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(2440)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(240)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(372)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(1360)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(2080)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(494)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(754)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(184)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(201)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(1416)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(2080)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(866)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(372)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(1360)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(1126)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.7686769f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortraitTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortraitTest.kt
new file mode 100644
index 0000000..1a709e6
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortraitTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for tablet in portrait.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTabletPortraitTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet()
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(294)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(382)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(294)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(482)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(74)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(74)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(72)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(72)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(72)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(294)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(382)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(77)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1960)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(257)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(64)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(456)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(294)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(74)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(74)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(56)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(781)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(386)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(216)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(256)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(1216)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(101)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(29)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(29)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(238)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(2.2988505f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(48)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(220)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(96)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.6741674f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(2222)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(1542)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(460)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1958)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(272)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(192)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(151)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(192)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(1472)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(2368)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(1600)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(2440)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(240)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(410)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(1360)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(2118)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(494)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(754)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(184)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(239)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(1416)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(2118)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(866)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(410)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(1360)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(1164)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.7686769f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscape3ButtonTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscape3ButtonTest.kt
new file mode 100644
index 0000000..0eeb23d
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscape3ButtonTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for two panel in landscape with 3-Button navigation.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTwoPanelLandscape3ButtonTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet(isLandscape = true, isTwoPanel = true, isGestureMode = false)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(200)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(260)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(259)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(260)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(50)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(50)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(25)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(25)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(25)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(200)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(260)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(36)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1600)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(175)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(44)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(310)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(200)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(50)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(50)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(64)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(1241)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(386)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(128)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(32)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(1039)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(68)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(43)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(43)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(285)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.5657895f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(64)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.7226337f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(1215)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(1237)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(2)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(208)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1086)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(272)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(864)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(151)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(864)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(428)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(2432)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(1340)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(2560)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(1480)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(384)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(232)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(2176)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(1268)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(723)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(418)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(294)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(2266)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(1268)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(1453)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(232)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(2176)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(650)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.8526749f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1003861f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscapeTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscapeTest.kt
new file mode 100644
index 0000000..7bf53d7
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscapeTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for two panel in landscape.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTwoPanelLandscapeTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet(isLandscape = true, isTwoPanel = true)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(200)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(260)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(259)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(260)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(50)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(50)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(25)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(25)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(25)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(200)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(260)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(36)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1600)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(175)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(44)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(310)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(200)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(50)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(50)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(64)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(1241)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(386)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(128)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(73)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(1039)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(68)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(43)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(43)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(285)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.5657895f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(64)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.7226337f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(1215)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(1237)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(2)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(208)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1086)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(272)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(761)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(151)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(761)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(2432)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(1416)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(2560)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(1480)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(384)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(270)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(2176)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(1306)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(723)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(418)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(294)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(166)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(2266)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(1306)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(1453)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(270)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(2176)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(688)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.8526749f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1003861f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortrait3ButtonTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortrait3ButtonTest.kt
new file mode 100644
index 0000000..9b6d7d5
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortrait3ButtonTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for two panel in portrait with 3-Button navigation.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTwoPanelPortrait3ButtonTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet(isTwoPanel = true, isGestureMode = false)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(153)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(199)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(153)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(509)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(19)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(19)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(19)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(153)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(199)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(16)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1960)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(134)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(34)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(237)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(153)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(38)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(38)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(56)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(763)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(386)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(216)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(32)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(685)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(52)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(33)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(33)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(291)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.1976048f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(48)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(220)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(96)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.69064087f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(2169)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(767)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(2)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(460)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1958)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(272)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(340)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(151)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(428)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(428)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(1472)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(2292)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(1600)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(2440)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(240)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(372)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(1360)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(2080)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(494)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(754)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(184)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(201)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(1416)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(2080)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(866)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(372)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(1360)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(1126)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.7874597f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortraitTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortraitTest.kt
new file mode 100644
index 0000000..6702eb5
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortraitTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for two panel in portrait.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileTwoPanelPortraitTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForTablet(isTwoPanel = true)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isTrue()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(153)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(199)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(153)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(509)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(38)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(19)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(19)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(19)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(153)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(199)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(112)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(28)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(16)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1960)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(600)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(134)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(34)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(237)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(153)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(38)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(38)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(56)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(763)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(386)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(116)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(126)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(216)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(2)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(685)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(true)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(120)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(52)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(33)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(33)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(291)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.1976048f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(32)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(48)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(96)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(72)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(88)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(40)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(128)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(220)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(144)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(96)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(48)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.69064087f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(2169)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(767)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(2)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(false)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(460)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1958)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(272)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(112)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(459)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(151)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(459)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(109)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(128)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(160)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(1472)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(2368)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(1600)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(2440)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(240)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(410)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(1360)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(2118)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(494)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(754)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(184)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(239)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(1416)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(2118)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(866)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(410)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(1360)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(1164)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.7874597f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBar3ButtonTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBar3ButtonTest.kt
new file mode 100644
index 0000000..7e0c5f3
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBar3ButtonTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for landscape phone with vertical bar and 3-Button navigation.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileVerticalBar3ButtonTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForPhone(isVerticalBar = true, isGestureMode = false)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isFalse()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(210)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(221)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(675)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(321)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(70)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(70)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(53)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(0)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(260)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(304)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(53)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1050)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(28)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(422)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(252)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(56)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(56)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(336)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(221)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(168)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(84)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(221)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(158)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(0)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(2221)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(false)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(0)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(14)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(266)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(0)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.0f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(154)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(42)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(126)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(-112)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(21)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(126)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(21)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(84)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.8880597f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(1340)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(2840)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(true)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(168)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1358)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(147)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(225)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(56)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(0)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(84)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(165)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(3120)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(1130)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(3120)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(1440)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(747)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(2372)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(1030)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(631)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(291)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(666)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(205)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(2454)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(1030)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(1741)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(280)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(2372)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(571)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.5597015f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBarTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBarTest.kt
new file mode 100644
index 0000000..9580458
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBarTest.kt
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfileBaseTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for DeviceProfile for landscape phone with vertical bar.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileVerticalBarTest : DeviceProfileBaseTest() {
+
+    lateinit var dp: DeviceProfile
+
+    @Before
+    fun before() {
+        initializeVarsForPhone(isVerticalBar = true)
+        dp = newDP()
+    }
+
+    @Test
+    fun isScalableGrid() {
+        assertThat(dp.isScalableGrid).isFalse()
+    }
+
+    @Test
+    fun cellWidthPx() {
+        assertThat(dp.cellWidthPx).isEqualTo(210)
+    }
+
+    @Test
+    fun cellHeightPx() {
+        assertThat(dp.cellHeightPx).isEqualTo(221)
+    }
+
+    @Test
+    fun getCellSizeX() {
+        assertThat(dp.cellSize.x).isEqualTo(675)
+    }
+
+    @Test
+    fun getCellSizeY() {
+        assertThat(dp.cellSize.y).isEqualTo(321)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxX() {
+        assertThat(dp.cellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutBorderSpacePxY() {
+        assertThat(dp.cellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxLeft() {
+        assertThat(dp.cellLayoutPaddingPx.left).isEqualTo(70)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxTop() {
+        assertThat(dp.cellLayoutPaddingPx.top).isEqualTo(0)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxRight() {
+        assertThat(dp.cellLayoutPaddingPx.right).isEqualTo(70)
+    }
+
+    @Test
+    fun cellLayoutPaddingPxBottom() {
+        assertThat(dp.cellLayoutPaddingPx.bottom).isEqualTo(53)
+    }
+
+    @Test
+    fun iconSizePx() {
+        assertThat(dp.iconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun iconTextSizePx() {
+        assertThat(dp.iconTextSizePx).isEqualTo(0)
+    }
+
+    @Test
+    fun iconDrawablePaddingPx() {
+        assertThat(dp.iconDrawablePaddingPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellWidthPx() {
+        assertThat(dp.folderCellWidthPx).isEqualTo(260)
+    }
+
+    @Test
+    fun folderCellHeightPx() {
+        assertThat(dp.folderCellHeightPx).isEqualTo(304)
+    }
+
+    @Test
+    fun folderChildIconSizePx() {
+        assertThat(dp.folderChildIconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun folderChildTextSizePx() {
+        assertThat(dp.folderChildTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun folderChildDrawablePaddingPx() {
+        assertThat(dp.folderChildDrawablePaddingPx).isEqualTo(14)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpaceOriginalPx() {
+        assertThat(dp.folderCellLayoutBorderSpaceOriginalPx).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxX() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.x).isEqualTo(0)
+    }
+
+    @Test
+    fun folderCellLayoutBorderSpacePxY() {
+        assertThat(dp.folderCellLayoutBorderSpacePx.y).isEqualTo(0)
+    }
+
+    @Test
+    fun bottomSheetTopPadding() {
+        assertThat(dp.bottomSheetTopPadding).isEqualTo(53)
+    }
+
+    @Test
+    fun allAppsShiftRange() {
+        assertThat(dp.allAppsShiftRange).isEqualTo(1050)
+    }
+
+    @Test
+    fun allAppsTopPadding() {
+        assertThat(dp.allAppsTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsIconSizePx() {
+        assertThat(dp.allAppsIconSizePx).isEqualTo(196)
+    }
+
+    @Test
+    fun allAppsIconTextSizePx() {
+        assertThat(dp.allAppsIconTextSizePx).isEqualTo(49)
+    }
+
+    @Test
+    fun allAppsIconDrawablePaddingPx() {
+        assertThat(dp.allAppsIconDrawablePaddingPx).isEqualTo(28)
+    }
+
+    @Test
+    fun allAppsCellHeightPx() {
+        assertThat(dp.allAppsCellHeightPx).isEqualTo(422)
+    }
+
+    @Test
+    fun allAppsCellWidthPx() {
+        assertThat(dp.allAppsCellWidthPx).isEqualTo(252)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxX() {
+        assertThat(dp.allAppsBorderSpacePx.x).isEqualTo(56)
+    }
+
+    @Test
+    fun allAppsBorderSpacePxY() {
+        assertThat(dp.allAppsBorderSpacePx.y).isEqualTo(56)
+    }
+
+    @Test
+    fun numShownAllAppsColumns() {
+        assertThat(dp.numShownAllAppsColumns).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightPadding() {
+        assertThat(dp.allAppsLeftRightPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun allAppsLeftRightMargin() {
+        assertThat(dp.allAppsLeftRightMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun hotseatBarSizePx() {
+        assertThat(dp.hotseatBarSizePx).isEqualTo(336)
+    }
+
+    @Test
+    fun hotseatCellHeightPx() {
+        assertThat(dp.hotseatCellHeightPx).isEqualTo(221)
+    }
+
+    @Test
+    fun hotseatBarBottomSpacePx() {
+        assertThat(dp.hotseatBarBottomSpacePx).isEqualTo(168)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingStartPx() {
+        assertThat(dp.hotseatBarSidePaddingStartPx).isEqualTo(84)
+    }
+
+    @Test
+    fun hotseatBarSidePaddingEndPx() {
+        assertThat(dp.hotseatBarSidePaddingEndPx).isEqualTo(56)
+    }
+
+    @Test
+    fun hotseatQsbSpace() {
+        assertThat(dp.hotseatQsbSpace).isEqualTo(126)
+    }
+
+    @Test
+    fun hotseatQsbHeight() {
+        assertThat(dp.hotseatQsbHeight).isEqualTo(221)
+    }
+
+    @Test
+    fun springLoadedHotseatBarTopMarginPx() {
+        assertThat(dp.springLoadedHotseatBarTopMarginPx).isEqualTo(158)
+    }
+
+    @Test
+    fun numShownHotseatIcons() {
+        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
+    }
+
+    @Test
+    fun hotseatBorderSpace() {
+        assertThat(dp.hotseatBorderSpace).isEqualTo(0)
+    }
+
+    @Test
+    fun isQsbInline() {
+        assertThat(dp.isQsbInline).isEqualTo(false)
+    }
+
+    @Test
+    fun qsbWidth() {
+        assertThat(dp.qsbWidth).isEqualTo(2221)
+    }
+
+    @Test
+    fun isTaskbarPresent() {
+        assertThat(dp.isTaskbarPresent).isEqualTo(false)
+    }
+
+    @Test
+    fun isTaskbarPresentInApps() {
+        assertThat(dp.isTaskbarPresentInApps).isEqualTo(false)
+    }
+
+    @Test
+    fun taskbarSize() {
+        assertThat(dp.taskbarSize).isEqualTo(0)
+    }
+
+    @Test
+    fun desiredWorkspaceHorizontalMarginPx() {
+        assertThat(dp.desiredWorkspaceHorizontalMarginPx).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingLeft() {
+        assertThat(dp.workspacePadding.left).isEqualTo(14)
+    }
+
+    @Test
+    fun workspacePaddingTop() {
+        assertThat(dp.workspacePadding.top).isEqualTo(0)
+    }
+
+    @Test
+    fun workspacePaddingRight() {
+        assertThat(dp.workspacePadding.right).isEqualTo(266)
+    }
+
+    @Test
+    fun workspacePaddingBottom() {
+        assertThat(dp.workspacePadding.bottom).isEqualTo(0)
+    }
+
+    @Test
+    fun iconScale() {
+        assertThat(dp.iconScale).isEqualTo(1)
+    }
+
+    @Test
+    fun cellScaleToFit() {
+        assertThat(dp.cellScaleToFit).isEqualTo(1.0f)
+    }
+
+    @Test
+    fun workspaceTopPadding() {
+        assertThat(dp.workspaceTopPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun workspaceBottomPadding() {
+        assertThat(dp.workspaceBottomPadding).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskMarginPx() {
+        assertThat(dp.overviewTaskMarginPx).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewTaskMarginGridPx() {
+        assertThat(dp.overviewTaskMarginGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskIconSizePx() {
+        assertThat(dp.overviewTaskIconSizePx).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizePx() {
+        assertThat(dp.overviewTaskIconDrawableSizePx).isEqualTo(154)
+    }
+
+    @Test
+    fun overviewTaskIconDrawableSizeGridPx() {
+        assertThat(dp.overviewTaskIconDrawableSizeGridPx).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewTaskThumbnailTopMarginPx() {
+        assertThat(dp.overviewTaskThumbnailTopMarginPx).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewActionsTopMarginPx() {
+        assertThat(dp.overviewActionsTopMarginPx).isEqualTo(42)
+    }
+
+    @Test
+    fun overviewActionsHeight() {
+        assertThat(dp.overviewActionsHeight).isEqualTo(168)
+    }
+
+    @Test
+    fun overviewActionsButtonSpacing() {
+        assertThat(dp.overviewActionsButtonSpacing).isEqualTo(126)
+    }
+
+    @Test
+    fun overviewPageSpacing() {
+        assertThat(dp.overviewPageSpacing).isEqualTo(56)
+    }
+
+    @Test
+    fun overviewRowSpacing() {
+        assertThat(dp.overviewRowSpacing).isEqualTo(-112)
+    }
+
+    @Test
+    fun overviewGridSideMargin() {
+        assertThat(dp.overviewGridSideMargin).isEqualTo(0)
+    }
+
+    @Test
+    fun dropTargetBarTopMarginPx() {
+        assertThat(dp.dropTargetBarTopMarginPx).isEqualTo(21)
+    }
+
+    @Test
+    fun dropTargetBarSizePx() {
+        assertThat(dp.dropTargetBarSizePx).isEqualTo(126)
+    }
+
+    @Test
+    fun dropTargetBarBottomMarginPx() {
+        assertThat(dp.dropTargetBarBottomMarginPx).isEqualTo(21)
+    }
+
+    @Test
+    fun workspaceSpringLoadedMinNextPageVisiblePx() {
+        assertThat(dp.workspaceSpringLoadedMinNextPageVisiblePx).isEqualTo(84)
+    }
+
+    @Test
+    fun getWorkspaceSpringLoadScale() {
+        assertThat(dp.workspaceSpringLoadScale).isEqualTo(0.8880597f)
+    }
+
+    @Test
+    fun getCellLayoutHeight() {
+        assertThat(dp.cellLayoutHeight).isEqualTo(1340)
+    }
+
+    @Test
+    fun getCellLayoutWidth() {
+        assertThat(dp.cellLayoutWidth).isEqualTo(2840)
+    }
+
+    @Test
+    fun getPanelCount() {
+        assertThat(dp.panelCount).isEqualTo(1)
+    }
+
+    @Test
+    fun isVerticalBarLayout() {
+        assertThat(dp.isVerticalBarLayout).isEqualTo(true)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkTop() {
+        assertThat(dp.cellLayoutSpringLoadShrunkTop).isEqualTo(168)
+    }
+
+    @Test
+    fun getCellLayoutSpringLoadShrunkBottom() {
+        assertThat(dp.cellLayoutSpringLoadShrunkBottom).isEqualTo(1358)
+    }
+
+    @Test
+    fun getQsbOffsetY() {
+        assertThat(dp.qsbOffsetY).isEqualTo(147)
+    }
+
+    @Test
+    fun getTaskbarOffsetY() {
+        assertThat(dp.taskbarOffsetY).isEqualTo(225)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingLeft() {
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(56)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingTop() {
+        assertThat(dp.getHotseatLayoutPadding(context).top).isEqualTo(0)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingRight() {
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(84)
+    }
+
+    @Test
+    fun getHotseatLayoutPaddingBottom() {
+        assertThat(dp.getHotseatLayoutPadding(context).bottom).isEqualTo(165)
+    }
+
+    @Test
+    fun hotseatBarEndOffset() {
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectLeft() {
+        assertThat(dp.overviewGridRect.left).isEqualTo(0)
+    }
+
+    @Test
+    fun overviewGridRectTop() {
+        assertThat(dp.overviewGridRect.top).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewGridRectRight() {
+        assertThat(dp.overviewGridRect.right).isEqualTo(3120)
+    }
+
+    @Test
+    fun overviewGridRectBottom() {
+        assertThat(dp.overviewGridRect.bottom).isEqualTo(1130)
+    }
+
+    @Test
+    fun taskDimensionX() {
+        assertThat(dp.taskDimension.x).isEqualTo(3120)
+    }
+
+    @Test
+    fun taskDimensionY() {
+        assertThat(dp.taskDimension.y).isEqualTo(1440)
+    }
+
+    @Test
+    fun overviewTaskRectLeft() {
+        assertThat(dp.overviewTaskRect.left).isEqualTo(747)
+    }
+
+    @Test
+    fun overviewTaskRectTop() {
+        assertThat(dp.overviewTaskRect.top).isEqualTo(280)
+    }
+
+    @Test
+    fun overviewTaskRectRight() {
+        assertThat(dp.overviewTaskRect.right).isEqualTo(2372)
+    }
+
+    @Test
+    fun overviewTaskRectBottom() {
+        assertThat(dp.overviewTaskRect.bottom).isEqualTo(1030)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionX() {
+        assertThat(dp.overviewGridTaskDimension.x).isEqualTo(631)
+    }
+
+    @Test
+    fun overviewGridTaskDimensionY() {
+        assertThat(dp.overviewGridTaskDimension.y).isEqualTo(291)
+    }
+
+    @Test
+    fun overviewModalTaskRectLeft() {
+        assertThat(dp.overviewModalTaskRect.left).isEqualTo(666)
+    }
+
+    @Test
+    fun overviewModalTaskRectTop() {
+        assertThat(dp.overviewModalTaskRect.top).isEqualTo(205)
+    }
+
+    @Test
+    fun overviewModalTaskRectRight() {
+        assertThat(dp.overviewModalTaskRect.right).isEqualTo(2454)
+    }
+
+    @Test
+    fun overviewModalTaskRectBottom() {
+        assertThat(dp.overviewModalTaskRect.bottom).isEqualTo(1030)
+    }
+
+    @Test
+    fun getGridTaskRectLeft() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).left).isEqualTo(1741)
+    }
+
+    @Test
+    fun getGridTaskRectTop() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).top).isEqualTo(280)
+    }
+
+    @Test
+    fun getGridTaskRectRight() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).right).isEqualTo(2372)
+    }
+
+    @Test
+    fun getGridTaskRectBottom() {
+        assertThat(dp.getOverviewGridTaskRect(isRecentsRtl).bottom).isEqualTo(571)
+    }
+
+    @Test
+    fun overviewTaskScale() {
+        assertThat(dp.overviewTaskWorkspaceScale).isEqualTo(0.5597015f)
+    }
+
+    @Test
+    fun overviewModalTaskScale() {
+        assertThat(dp.overviewModalTaskScale).isEqualTo(1.1f)
+    }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 4bf247c..81df3c0 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -179,6 +179,20 @@
         actionsView.clickAndDismissScreenshot();
     }
 
+    @Test
+    @PortraitLandscape
+    public void testSplitFromOverviewForTablet() {
+        assumeTrue(mLauncher.isTablet());
+
+        startTestActivity(2);
+        startTestActivity(3);
+
+        mLauncher.goHome().switchToOverview().getOverviewActions()
+                .clickSplit()
+                .getTestActivityTask(2)
+                .open();
+    }
+
     private int getCurrentOverviewPage(Launcher launcher) {
         return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
     }
diff --git a/quickstep/tests/src/com/android/quickstep/TaskThumbnailViewTest.kt b/quickstep/tests/src/com/android/quickstep/TaskThumbnailViewTest.kt
new file mode 100644
index 0000000..cf3c8c9
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaskThumbnailViewTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import android.graphics.Rect
+import android.graphics.RectF
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfileBaseTest
+import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+/**
+ * Test for TaskThumbnailView class.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TaskThumbnailViewTest : DeviceProfileBaseTest() {
+
+    private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java)
+
+    private val mPreviewPositionHelper = PreviewPositionHelper()
+
+    @Test
+    fun getInsetsToDrawInFullscreen_clipTaskbarSizeFromBottomForTablets() {
+        initializeVarsForTablet()
+        val dp = newDP()
+        val previewRect = Rect(0, 0, 100, 100)
+        val canvasWidth = dp.widthPx / 2
+        val canvasHeight = dp.heightPx / 2
+        val currentRotation = 0
+        val isRtl = false
+
+        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
+                canvasHeight, dp, currentRotation, isRtl)
+
+        val expectedClippedInsets = RectF(0f, 0f, 0f, dp.taskbarSize / 2f)
+        assertThat(mPreviewPositionHelper.getInsetsToDrawInFullscreen(dp))
+                .isEqualTo(expectedClippedInsets)
+    }
+
+    @Test
+    fun getInsetsToDrawInFullscreen_doNotClipTaskbarSizeFromBottomForPhones() {
+        initializeVarsForPhone()
+        val dp = newDP()
+        val previewRect = Rect(0, 0, 100, 100)
+        val canvasWidth = dp.widthPx / 2
+        val canvasHeight = dp.heightPx / 2
+        val currentRotation = 0
+        val isRtl = false
+
+        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
+                canvasHeight, dp, currentRotation, isRtl)
+
+        val expectedClippedInsets = RectF(0f, 0f, 0f, 0f)
+        assertThat(mPreviewPositionHelper.getInsetsToDrawInFullscreen(dp))
+                .isEqualTo(expectedClippedInsets)
+    }
+}
\ No newline at end of file
diff --git a/res/layout/all_apps_bottom_sheet_background.xml b/res/layout/all_apps_bottom_sheet_background.xml
index 12b6b7b..3e47690 100644
--- a/res/layout/all_apps_bottom_sheet_background.xml
+++ b/res/layout/all_apps_bottom_sheet_background.xml
@@ -22,7 +22,7 @@
     <View
         android:id="@+id/bottom_sheet_handle_area"
         android:layout_width="match_parent"
-        android:layout_height="36dp" />
+        android:layout_height="@dimen/bottom_sheet_handle_area_height" />
 
     <View
         android:id="@+id/bottom_sheet_handle"
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index e5a7356..474cd9f 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -81,7 +81,7 @@
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"መተግበሪያው ያለተጠቃሚ ጣልቃ ገብነት አቋራጭ እንዲያክል ያስችለዋል።"</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"የመነሻ ቅንብሮች እና አቋራጮችን ያነባል"</string>
     <string name="permdesc_read_settings" msgid="4208061150510996676">"ቅንብሮችን እና አቋራጮችን በመነሻ ለማንበብ ለትግበራ ይፈቅዳል።"</string>
-    <string name="permlab_write_settings" msgid="4820028712156303762">"መነሻ ቅንብሮች እና አቋራጮች ፃፍ"</string>
+    <string name="permlab_write_settings" msgid="4820028712156303762">"መነሻ ቅንብሮች እና አቋራጮች ጻፍ"</string>
     <string name="permdesc_write_settings" msgid="726859348127868466">"ቅንብሮችን እና አቋራጮችን በመነሻ ለመለወጥ ለመተግበሪያ ይፈቅዳል።"</string>
     <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> የስልክ ጥሪዎችን ለማድረግ አልተፈቀደለትም"</string>
     <string name="gadget_error_text" msgid="740356548025791839">"ምግብርን መጫን አልተቻለም"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 5a6cdd3..95fa000 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -88,7 +88,7 @@
     <string name="gadget_setup_text" msgid="8348374825537681407">"ୱିଜେଟ ସେଟିଂସ"</string>
     <string name="gadget_complete_setup_text" msgid="309040266978007925">"ସେଟଅପ ସମ୍ପୂର୍ଣ୍ଣ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ଏହା ଏକ ସିଷ୍ଟମ୍‌ ଆପ୍‌ ଅଟେ ଏବଂ ଏହା ଅନଇନଷ୍ଟଲ୍‌ କରାଯାଇ ପାରିବ ନାହିଁ।"</string>
-    <string name="folder_hint_text" msgid="5174843001373488816">"ନାମ ସମ୍ପାଦନ କରନ୍ତୁ"</string>
+    <string name="folder_hint_text" msgid="5174843001373488816">"ନାମ ଏଡିଟ କରନ୍ତୁ"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଅକ୍ଷମ କରାଗଲା"</string>
     <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name}ର #ଟି ବିଜ୍ଞପ୍ତି ଅଛି}other{{app_name}ର #ଟି ବିଜ୍ଞପ୍ତି ଅଛି}}"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"ମୋଟ %2$dରୁ %1$d ନମ୍ବର ପୃଷ୍ଠା"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a3a30e1..dc80bc3 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -22,8 +22,6 @@
     <dimen name="dynamic_grid_edge_margin">10.77dp</dimen>
     <dimen name="dynamic_grid_left_right_margin">8dp</dimen>
     <dimen name="dynamic_grid_icon_drawable_padding">7dp</dimen>
-    <!-- Minimum space between workspace and hotseat in spring loaded mode -->
-    <dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
     <!-- Minimum amount of next page visible in spring loaded mode -->
     <dimen name="dynamic_grid_spring_loaded_min_next_space_visible">24dp</dimen>
 
@@ -362,6 +360,9 @@
     <dimen name="taskbar_icon_size">44dp</dimen>
     <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
     <dimen name="taskbar_icon_spacing">8dp</dimen>
+    <dimen name="taskbar_nav_buttons_size">0dp</dimen>
+    <dimen name="taskbar_contextual_button_margin">0dp</dimen>
+    <dimen name="taskbar_hotseat_nav_spacing">0dp</dimen>
 
     <!-- Size of the maximum radius for the enforced rounded rectangles. -->
     <dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
@@ -382,6 +383,9 @@
     <dimen name="overview_grid_side_margin">0dp</dimen>
     <dimen name="overview_grid_row_spacing">0dp</dimen>
     <dimen name="overview_page_spacing">0dp</dimen>
+    <dimen name="overview_minimum_next_prev_size">0dp</dimen>
+    <item name="overview_max_scale" format="float" type="dimen">0.0</item>
+    <item name="overview_modal_max_scale" format="float" type="dimen">0.0</item>
     <dimen name="split_placeholder_size">72dp</dimen>
     <dimen name="split_placeholder_inset">16dp</dimen>
     <dimen name="split_placeholder_icon_size">44dp</dimen>
@@ -409,6 +413,7 @@
 
     <!-- Bottom sheet related parameters -->
     <dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
+    <dimen name="bottom_sheet_handle_area_height">36dp</dimen>
     <dimen name="bottom_sheet_handle_width">32dp</dimen>
     <dimen name="bottom_sheet_handle_height">4dp</dimen>
     <dimen name="bottom_sheet_handle_margin">16dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 65bba7b..a8cbf08 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -274,7 +274,7 @@
     </style>
 
     <!-- Drop targets -->
-    <style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault">
+    <style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault.Medium">
         <item name="android:drawablePadding">@dimen/drop_target_button_drawable_padding</item>
         <item name="android:padding">14dp</item>
         <item name="android:textColor">@color/drop_target_text</item>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 4b4a017..fbb0a57 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -24,6 +24,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 
@@ -68,22 +69,6 @@
 
     private final View[] mDragHandles = new View[HANDLE_COUNT];
     private final List<Rect> mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT);
-    private final OnAttachStateChangeListener mWidgetViewAttachStateChangeListener =
-            new OnAttachStateChangeListener() {
-                @Override
-                public void onViewAttachedToWindow(View view) {
-                    // Do nothing
-                }
-
-                @Override
-                public void onViewDetachedFromWindow(View view) {
-                    // When the app widget view is detached, we should close the resize frame.
-                    // An example is when the dragging starts, the widget view is detached from
-                    // CellLayout and then reattached to DragLayout.
-                    close(false);
-                }
-            };
-
 
     private LauncherAppWidgetHostView mWidgetView;
     private CellLayout mCellLayout;
@@ -221,11 +206,7 @@
     private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout,
             DragLayer dragLayer) {
         mCellLayout = cellLayout;
-        if (mWidgetView != null) {
-            mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
-        }
         mWidgetView = widgetView;
-        mWidgetView.addOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
         LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
                 widgetView.getAppWidgetInfo();
         mDragLayer = dragLayer;
@@ -423,6 +404,10 @@
      *  Based on the current deltas, we determine if and how to resize the widget.
      */
     private void resizeWidgetIfNeeded(boolean onDismiss) {
+        ViewGroup.LayoutParams wlp = mWidgetView.getLayoutParams();
+        if (!(wlp instanceof CellLayout.LayoutParams)) {
+            return;
+        }
         DeviceProfile dp = mLauncher.getDeviceProfile();
         float xThreshold = mCellLayout.getCellWidth() + dp.cellLayoutBorderSpacePx.x;
         float yThreshold = mCellLayout.getCellHeight() + dp.cellLayoutBorderSpacePx.y;
@@ -435,7 +420,7 @@
         mDirectionVector[0] = 0;
         mDirectionVector[1] = 0;
 
-        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) wlp;
 
         int spanX = lp.cellHSpan;
         int spanY = lp.cellVSpan;
@@ -687,9 +672,6 @@
     @Override
     protected void handleClose(boolean animate) {
         mDragLayer.removeView(this);
-        if (mWidgetView != null) {
-            mWidgetView.removeOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
-        }
     }
 
     private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 52dfcd4..52960a9 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -829,8 +829,8 @@
         final int hStartPadding = getPaddingLeft();
         final int vStartPadding = getPaddingTop();
 
-        result[0] = (x - hStartPadding) / mCellWidth;
-        result[1] = (y - vStartPadding) / mCellHeight;
+        result[0] = (x - hStartPadding) / (mCellWidth + mBorderSpace.x);
+        result[1] = (y - vStartPadding) / (mCellHeight + mBorderSpace.y);
 
         final int xAxis = mCountX;
         final int yAxis = mCountY;
@@ -842,16 +842,6 @@
     }
 
     /**
-     * Given a point, return the cell that most closely encloses that point
-     * @param x X coordinate of the point
-     * @param y Y coordinate of the point
-     * @param result Array of 2 ints to hold the x and y coordinate of the cell
-     */
-    void pointToCellRounded(int x, int y, int[] result) {
-        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
-    }
-
-    /**
      * Given a cell coordinate, return the point that represents the upper left corner of that cell
      *
      * @param cellX X coordinate of the cell
@@ -1240,7 +1230,7 @@
      */
     int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
             int spanY, int[] result, int[] resultSpan) {
-        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true,
+        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, false,
                 result, resultSpan);
     }
 
@@ -1262,9 +1252,10 @@
     /**
      * Find a vacant area that will fit the given bounds nearest the requested
      * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
+     * @param relativeXPos The X location relative to the Cell layout at which you want to search
+     *                     for a vacant area.
+     * @param relativeYPos The Y location relative to the Cell layout at which you want to search
+     *                     for a vacant area.
      * @param minSpanX The minimum horizontal span required
      * @param minSpanY The minimum vertical span required
      * @param spanX Horizontal span of the object.
@@ -1275,15 +1266,15 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
-            int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
+    private int[] findNearestArea(int relativeXPos, int relativeYPos, int minSpanX, int minSpanY,
+            int spanX, int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
         lazyInitTempRectStack();
 
-        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
-        // to the center of the item, but we are searching based on the top-left cell, so
-        // we translate the point over to correspond to the top-left.
-        pixelX -= mCellWidth * (spanX - 1) / 2f;
-        pixelY -= mCellHeight * (spanY - 1) / 2f;
+        // For items with a spanX / spanY > 1, the passed in point (relativeXPos, relativeYPos)
+        // corresponds to the center of the item, but we are searching based on the top-left cell,
+        // so we translate the point over to correspond to the top-left.
+        relativeXPos = (int) (relativeXPos - (mCellWidth + mBorderSpace.x) * (spanX - 1) / 2f);
+        relativeYPos = (int) (relativeYPos - (mCellHeight + mBorderSpace.y) * (spanY - 1) / 2f);
 
         // Keep track of best-scoring drop area
         final int[] bestXY = result != null ? result : new int[2];
@@ -1304,7 +1295,7 @@
             for (int x = 0; x < countX - (minSpanX - 1); x++) {
                 int ySize = -1;
                 int xSize = -1;
-                if (ignoreOccupied) {
+                if (!ignoreOccupied) {
                     // First, let's see if this thing fits anywhere
                     for (int i = 0; i < minSpanX; i++) {
                         for (int j = 0; j < minSpanY; j++) {
@@ -1368,7 +1359,7 @@
                     }
                 }
                 validRegions.push(currentRect);
-                double distance = Math.hypot(cellXY[0] - pixelX,  cellXY[1] - pixelY);
+                double distance = Math.hypot(cellXY[0] - relativeXPos,  cellXY[1] - relativeYPos);
 
                 if ((distance <= bestDistance && !contained) ||
                         currentRect.contains(bestRect)) {
@@ -2629,7 +2620,7 @@
      *         nearest the requested location.
      */
     public int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null);
+        return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, true, result, null);
     }
 
     boolean existsEmptyCell() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 673ab54..d09642a 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -34,6 +34,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
+import android.view.Gravity;
 import android.view.Surface;
 
 import com.android.launcher3.CellLayout.ContainerType;
@@ -41,6 +42,7 @@
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.icons.IconNormalizer;
+import com.android.launcher3.touch.PortraitPagedViewHandler;
 import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.Info;
@@ -108,9 +110,8 @@
 
     public final int edgeMarginPx;
     public final float workspaceContentScale;
-    public float workspaceSpringLoadShrunkTop;
-    public float workspaceSpringLoadShrunkBottom;
-    public final int workspaceSpringLoadedBottomSpace;
+    private float mWorkspaceSpringLoadShrunkTop;
+    private float mWorkspaceSpringLoadShrunkBottom;
     public final int workspaceSpringLoadedMinNextPageVisiblePx;
 
     private final int extraSpace;
@@ -159,10 +160,11 @@
     // Hotseat
     public final int numShownHotseatIcons;
     public int hotseatCellHeightPx;
-    private final boolean areNavButtonsInline;
+    public final boolean areNavButtonsInline;
     // In portrait: size = height, in landscape: size = width
     public int hotseatBarSizePx;
     public int hotseatBarBottomSpacePx;
+    public int hotseatBarEndOffset;
     public int hotseatQsbSpace;
     public int springLoadedHotseatBarTopMarginPx;
     // Start is the side next to the nav bar, end is the side next to the workspace
@@ -202,6 +204,12 @@
     public int overviewPageSpacing;
     public int overviewRowSpacing;
     public int overviewGridSideMargin;
+    public final Rect overviewGridRect = new Rect();
+    public final Rect overviewTaskRect = new Rect();
+    public final float overviewTaskWorkspaceScale;
+    public final Point overviewGridTaskDimension = new Point();
+    public final Rect overviewModalTaskRect = new Rect();
+    public final float overviewModalTaskScale;
 
     // Widgets
     public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
@@ -228,6 +236,9 @@
     public DotRenderer mDotRendererWorkSpace;
     public DotRenderer mDotRendererAllApps;
 
+    // Tasks
+    public final PointF taskDimension = new PointF();
+
     // Taskbar
     public boolean isTaskbarPresent;
     // Whether Taskbar will inset the bottom of apps by taskbarSize.
@@ -351,8 +362,6 @@
         dropTargetButtonWorkspaceEdgeGapPx = res.getDimensionPixelSize(
                 R.dimen.drop_target_button_workspace_edge_gap);
 
-        workspaceSpringLoadedBottomSpace =
-                res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
         workspaceSpringLoadedMinNextPageVisiblePx = res.getDimensionPixelSize(
                 R.dimen.dynamic_grid_spring_loaded_min_next_space_visible);
 
@@ -412,6 +421,18 @@
         // Add a bit of space between nav bar and hotseat in vertical bar layout.
         hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
         updateHotseatSizes(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
+        if (areNavButtonsInline) {
+            /*
+             * 3 nav buttons +
+             * Little space at the end for contextual buttons +
+             * Little space between icons and nav buttons
+             */
+            hotseatBarEndOffset = 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
+                    + res.getDimensionPixelSize(R.dimen.taskbar_contextual_button_margin)
+                    + res.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing);
+        } else {
+            hotseatBarEndOffset = 0;
+        }
 
         overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin);
         overviewTaskMarginGridPx = res.getDimensionPixelSize(R.dimen.overview_task_margin_grid);
@@ -471,6 +492,104 @@
         mDotRendererWorkSpace = new DotRenderer(iconSizePx, dotPath, DEFAULT_DOT_SIZE);
         mDotRendererAllApps = iconSizePx == allAppsIconSizePx ? mDotRendererWorkSpace :
                 new DotRenderer(allAppsIconSizePx, dotPath, DEFAULT_DOT_SIZE);
+
+        // Grid and Task size calculations
+        calculateGridSize();
+        getTaskDimension();
+        calculateTaskSize(res);
+        calculateGridTaskSize();
+        calculateModalTaskSize(res);
+        overviewModalTaskScale =
+                Math.min(overviewModalTaskRect.height() / (float) overviewTaskRect.height(),
+                        overviewModalTaskRect.width() / (float) overviewTaskRect.width());
+        overviewTaskWorkspaceScale = (float) overviewTaskRect.height() / getCellLayoutHeight();
+    }
+
+    private void calculateGridSize() {
+        int topMargin = overviewTaskThumbnailTopMarginPx;
+        int bottomMargin = getOverviewActionsClaimedSpace();
+        int sideMargin = overviewGridSideMargin;
+
+        overviewGridRect.set(0, 0, widthPx, heightPx);
+        overviewGridRect.inset(Math.max(mInsets.left, sideMargin), mInsets.top + topMargin,
+                Math.max(mInsets.right, sideMargin), Math.max(mInsets.bottom, bottomMargin));
+    }
+
+    private void calculateTaskSize(Resources res) {
+        int overviewMinNextPrevSize =
+                res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size);
+        float overviewMaxScale = res.getFloat(R.dimen.overview_max_scale);
+        Rect containerRect = new Rect();
+        if (isTablet) {
+            containerRect.set(overviewGridRect);
+        } else {
+            int taskMargin = overviewTaskMarginPx;
+            containerRect.set(0, 0, widthPx, heightPx);
+            containerRect.inset(mInsets.left, mInsets.top, mInsets.right, mInsets.bottom);
+            int minimumHorizontalPadding = overviewMinNextPrevSize + taskMargin;
+            containerRect.inset(minimumHorizontalPadding, overviewTaskThumbnailTopMarginPx,
+                    minimumHorizontalPadding, getOverviewActionsClaimedSpace());
+        }
+        float scale = Math.min(
+                containerRect.width() / taskDimension.x,
+                containerRect.height() / taskDimension.y);
+        scale = Math.min(scale, overviewMaxScale);
+        int outWidth = Math.round(scale * taskDimension.x);
+        int outHeight = Math.round(scale * taskDimension.y);
+        Gravity.apply(Gravity.CENTER, outWidth, outHeight, containerRect, overviewTaskRect);
+    }
+
+    private void calculateGridTaskSize() {
+        float rowHeight =
+                (overviewTaskRect.height() + overviewTaskThumbnailTopMarginPx - overviewRowSpacing)
+                        / 2f;
+
+        float scale = (rowHeight - overviewTaskThumbnailTopMarginPx) / taskDimension.y;
+        overviewGridTaskDimension.set(
+                Math.round(scale * taskDimension.x), Math.round(scale * taskDimension.y));
+    }
+
+    /**
+     * Returns a Rect the size of a grid task with the correct positioning within the screen.
+     *
+     * @param isRecentsRtl is true when device is in LTR, false when in RTL, as grid tasks are only
+     *                     supported on tablets, which use PortraitPagedViewHandler.
+     */
+    public Rect getOverviewGridTaskRect(boolean isRecentsRtl) {
+        Rect outRect = new Rect();
+        int gravity = Gravity.TOP;
+        gravity |= isRecentsRtl ? Gravity.RIGHT : Gravity.LEFT;
+        Gravity.apply(gravity, overviewGridTaskDimension.x, overviewGridTaskDimension.y,
+                overviewTaskRect, outRect);
+        return outRect;
+    }
+
+    private void calculateModalTaskSize(Resources res) {
+        float overviewModalMaxScale = res.getFloat(R.dimen.overview_modal_max_scale);
+        Rect potentialTaskRect = new Rect(0, 0, widthPx, heightPx);
+        potentialTaskRect.inset(mInsets.left, mInsets.top, mInsets.right, mInsets.bottom);
+        int minimumHorizontalPadding = Math.round(
+                (availableWidthPx - overviewTaskRect.width() * overviewModalMaxScale) / 2);
+        potentialTaskRect.inset(
+                minimumHorizontalPadding,
+                overviewTaskMarginPx,
+                minimumHorizontalPadding,
+                heightPx - overviewTaskRect.bottom - mInsets.bottom);
+        float scale = Math.min(
+                potentialTaskRect.width() / taskDimension.x,
+                potentialTaskRect.height() / taskDimension.y);
+        int outWidth = Math.round(scale * taskDimension.x);
+        int outHeight = Math.round(scale * taskDimension.y);
+        Gravity.apply(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, outWidth, outHeight,
+                potentialTaskRect, overviewModalTaskRect);
+    }
+
+    private void getTaskDimension() {
+        float taskHeight = heightPx;
+        if (isTablet) {
+            taskHeight -= taskbarSize;
+        }
+        taskDimension.set(widthPx, taskHeight);
     }
 
     /**
@@ -918,9 +1037,9 @@
      * Gets the scaled top of the workspace in px for the spring-loaded edit state.
      */
     public float getCellLayoutSpringLoadShrunkTop() {
-        workspaceSpringLoadShrunkTop = mInsets.top + dropTargetBarTopMarginPx + dropTargetBarSizePx
+        mWorkspaceSpringLoadShrunkTop = mInsets.top + dropTargetBarTopMarginPx + dropTargetBarSizePx
                 + dropTargetBarBottomMarginPx;
-        return workspaceSpringLoadShrunkTop;
+        return mWorkspaceSpringLoadShrunkTop;
     }
 
     /**
@@ -928,10 +1047,10 @@
      */
     public float getCellLayoutSpringLoadShrunkBottom() {
         int topOfHotseat = hotseatBarSizePx + springLoadedHotseatBarTopMarginPx;
-        workspaceSpringLoadShrunkBottom =
+        mWorkspaceSpringLoadShrunkBottom =
                 heightPx - (isVerticalBarLayout() ? getVerticalHotseatLastItemBottomOffset()
                         : topOfHotseat);
-        return workspaceSpringLoadShrunkBottom;
+        return mWorkspaceSpringLoadShrunkBottom;
     }
 
     /**
@@ -1054,8 +1173,7 @@
             int requiredWidth = iconSizePx * numShownHotseatIcons
                     + hotseatBorderSpace * (numShownHotseatIcons - 1)
                     + additionalQsbSpace;
-            int endOffset = ApiWrapper.getHotseatEndOffset(context);
-            int hotseatWidth = Math.min(requiredWidth, availableWidthPx - endOffset);
+            int hotseatWidth = Math.min(requiredWidth, availableWidthPx - hotseatBarEndOffset);
             int sideSpacing = (availableWidthPx - hotseatWidth) / 2;
 
             mHotseatBarPadding.set(sideSpacing, hotseatBarTopPadding, sideSpacing,
@@ -1068,10 +1186,10 @@
                 mHotseatBarPadding.left += additionalQsbSpace;
             }
 
-            if (endOffset > sideSpacing) {
+            if (hotseatBarEndOffset > sideSpacing) {
                 int diff = isRtl
-                        ? sideSpacing - endOffset
-                        : endOffset - sideSpacing;
+                        ? sideSpacing - hotseatBarEndOffset
+                        : hotseatBarEndOffset - sideSpacing;
                 mHotseatBarPadding.left -= diff;
                 mHotseatBarPadding.right += diff;
             }
@@ -1235,7 +1353,9 @@
         return "\t" + name + ": " + value + "px (" + dpiFromPx(value, mMetrics.densityDpi) + "dp)";
     }
 
-    public void dump(String prefix, PrintWriter writer) {
+    // LINT.IfChange
+    /** Dumps various DeviceProfile variables to the specified writer. */
+    public void dump(Context context, String prefix, PrintWriter writer) {
         writer.println(prefix + "DeviceProfile:");
         writer.println(prefix + "\t1 dp = " + mMetrics.density + " px");
 
@@ -1281,9 +1401,12 @@
                 cellLayoutBorderSpacePx.x));
         writer.println(prefix + pxToDpStr("cellLayoutBorderSpacePx Vertical",
                 cellLayoutBorderSpacePx.y));
-        writer.println(prefix + pxToDpStr("cellLayoutPaddingPx.left", cellLayoutPaddingPx.left));
-        writer.println(prefix + pxToDpStr("cellLayoutPaddingPx.top", cellLayoutPaddingPx.top));
-        writer.println(prefix + pxToDpStr("cellLayoutPaddingPx.right", cellLayoutPaddingPx.right));
+        writer.println(
+                prefix + pxToDpStr("cellLayoutPaddingPx.left", cellLayoutPaddingPx.left));
+        writer.println(
+                prefix + pxToDpStr("cellLayoutPaddingPx.top", cellLayoutPaddingPx.top));
+        writer.println(
+                prefix + pxToDpStr("cellLayoutPaddingPx.right", cellLayoutPaddingPx.right));
         writer.println(
                 prefix + pxToDpStr("cellLayoutPaddingPx.bottom", cellLayoutPaddingPx.bottom));
 
@@ -1314,27 +1437,34 @@
                 allAppsIconDrawablePaddingPx));
         writer.println(prefix + pxToDpStr("allAppsCellHeightPx", allAppsCellHeightPx));
         writer.println(prefix + pxToDpStr("allAppsCellWidthPx", allAppsCellWidthPx));
-        writer.println(prefix + pxToDpStr("allAppsBorderSpacePx", allAppsBorderSpacePx.x));
+        writer.println(prefix + pxToDpStr("allAppsBorderSpacePxX", allAppsBorderSpacePx.x));
+        writer.println(prefix + pxToDpStr("allAppsBorderSpacePxY", allAppsBorderSpacePx.y));
         writer.println(prefix + "\tnumShownAllAppsColumns: " + numShownAllAppsColumns);
-        writer.println(prefix + pxToDpStr("allAppsLeftRightPadding", allAppsLeftRightPadding));
+        writer.println(
+                prefix + pxToDpStr("allAppsLeftRightPadding", allAppsLeftRightPadding));
         writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
 
         writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
         writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]);
         writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
-        writer.println(prefix + pxToDpStr("hotseatBarBottomPaddingPx", hotseatBarBottomSpacePx));
+        writer.println(
+                prefix + pxToDpStr("hotseatBarBottomSpacePx", hotseatBarBottomSpacePx));
         writer.println(prefix + pxToDpStr("hotseatBarSidePaddingStartPx",
                 hotseatBarSidePaddingStartPx));
         writer.println(prefix + pxToDpStr("hotseatBarSidePaddingEndPx",
                 hotseatBarSidePaddingEndPx));
+        writer.println(prefix + pxToDpStr("hotseatBarEndOffset", hotseatBarEndOffset));
         writer.println(prefix + pxToDpStr("hotseatQsbSpace", hotseatQsbSpace));
         writer.println(prefix + pxToDpStr("hotseatQsbHeight", hotseatQsbHeight));
         writer.println(prefix + pxToDpStr("springLoadedHotseatBarTopMarginPx",
                 springLoadedHotseatBarTopMarginPx));
         writer.println(prefix + pxToDpStr("mHotseatBarPadding.top", mHotseatBarPadding.top));
-        writer.println(prefix + pxToDpStr("mHotseatBarPadding.bottom", mHotseatBarPadding.bottom));
-        writer.println(prefix + pxToDpStr("mHotseatBarPadding.left", mHotseatBarPadding.left));
-        writer.println(prefix + pxToDpStr("mHotseatBarPadding.right", mHotseatBarPadding.right));
+        writer.println(
+                prefix + pxToDpStr("mHotseatBarPadding.bottom", mHotseatBarPadding.bottom));
+        writer.println(
+                prefix + pxToDpStr("mHotseatBarPadding.left", mHotseatBarPadding.left));
+        writer.println(
+                prefix + pxToDpStr("mHotseatBarPadding.right", mHotseatBarPadding.right));
         writer.println(prefix + "\tnumShownHotseatIcons: " + numShownHotseatIcons);
         writer.println(prefix + pxToDpStr("hotseatBorderSpace", hotseatBorderSpace));
         writer.println(prefix + "\tisQsbInline: " + isQsbInline);
@@ -1349,12 +1479,14 @@
         writer.println(prefix + pxToDpStr("workspacePadding.left", workspacePadding.left));
         writer.println(prefix + pxToDpStr("workspacePadding.top", workspacePadding.top));
         writer.println(prefix + pxToDpStr("workspacePadding.right", workspacePadding.right));
-        writer.println(prefix + pxToDpStr("workspacePadding.bottom", workspacePadding.bottom));
+        writer.println(
+                prefix + pxToDpStr("workspacePadding.bottom", workspacePadding.bottom));
 
         writer.println(prefix + pxToDpStr("iconScale", iconScale));
         writer.println(prefix + pxToDpStr("cellScaleToFit ", cellScaleToFit));
         writer.println(prefix + pxToDpStr("extraSpace", extraSpace));
-        writer.println(prefix + pxToDpStr("unscaled extraSpace", extraSpace / iconScale));
+        writer.println(
+                prefix + pxToDpStr("unscaled extraSpace", extraSpace / iconScale));
 
         if (inv.devicePaddings != null) {
             int unscaledExtraSpace = (int) (extraSpace / iconScale);
@@ -1365,7 +1497,8 @@
         writer.println(prefix + pxToDpStr("workspaceBottomPadding", workspaceBottomPadding));
 
         writer.println(prefix + pxToDpStr("overviewTaskMarginPx", overviewTaskMarginPx));
-        writer.println(prefix + pxToDpStr("overviewTaskMarginGridPx", overviewTaskMarginGridPx));
+        writer.println(
+                prefix + pxToDpStr("overviewTaskMarginGridPx", overviewTaskMarginGridPx));
         writer.println(prefix + pxToDpStr("overviewTaskIconSizePx", overviewTaskIconSizePx));
         writer.println(prefix + pxToDpStr("overviewTaskIconDrawableSizePx",
                 overviewTaskIconDrawableSizePx));
@@ -1383,24 +1516,78 @@
         writer.println(prefix + pxToDpStr("overviewRowSpacing", overviewRowSpacing));
         writer.println(prefix + pxToDpStr("overviewGridSideMargin", overviewGridSideMargin));
 
-        writer.println(prefix + pxToDpStr("dropTargetBarTopMarginPx", dropTargetBarTopMarginPx));
+        writer.println(
+                prefix + pxToDpStr("dropTargetBarTopMarginPx", dropTargetBarTopMarginPx));
         writer.println(prefix + pxToDpStr("dropTargetBarSizePx", dropTargetBarSizePx));
-        writer.println(
-                prefix + pxToDpStr("dropTargetBarBottomMarginPx", dropTargetBarBottomMarginPx));
+        writer.println(prefix
+                + pxToDpStr("dropTargetBarBottomMarginPx", dropTargetBarBottomMarginPx));
 
-        writer.println(
-                prefix + pxToDpStr("workspaceSpringLoadShrunkTop", workspaceSpringLoadShrunkTop));
+        writer.println(prefix
+                + pxToDpStr("workspaceSpringLoadShrunkTop", mWorkspaceSpringLoadShrunkTop));
         writer.println(prefix + pxToDpStr("workspaceSpringLoadShrunkBottom",
-                workspaceSpringLoadShrunkBottom));
-        writer.println(prefix + pxToDpStr("workspaceSpringLoadedBottomSpace",
-                workspaceSpringLoadedBottomSpace));
+                mWorkspaceSpringLoadShrunkBottom));
         writer.println(prefix + pxToDpStr("workspaceSpringLoadedMinNextPageVisiblePx",
                 workspaceSpringLoadedMinNextPageVisiblePx));
-        writer.println(
-                prefix + pxToDpStr("getWorkspaceSpringLoadScale()", getWorkspaceSpringLoadScale()));
+        writer.println(prefix
+                + pxToDpStr("getWorkspaceSpringLoadScale()", getWorkspaceSpringLoadScale()));
         writer.println(prefix + pxToDpStr("getCellLayoutHeight()", getCellLayoutHeight()));
         writer.println(prefix + pxToDpStr("getCellLayoutWidth()", getCellLayoutWidth()));
+
+        writer.println(prefix + pxToDpStr("overviewGridRect.left", overviewGridRect.left));
+        writer.println(prefix + pxToDpStr("overviewGridRect.top", overviewGridRect.top));
+        writer.println(prefix + pxToDpStr("overviewGridRect.right", overviewGridRect.right));
+        writer.println(prefix
+                + pxToDpStr("overviewGridRect.bottom", overviewGridRect.bottom));
+        writer.println(prefix + pxToDpStr("taskDimension.x", taskDimension.x));
+        writer.println(prefix + pxToDpStr("taskDimension.y", taskDimension.y));
+        writer.println(prefix + pxToDpStr("overviewTaskRect.left", overviewTaskRect.left));
+        writer.println(prefix + pxToDpStr("overviewTaskRect.top", overviewTaskRect.top));
+        writer.println(prefix + pxToDpStr("overviewTaskRect.right", overviewTaskRect.right));
+        writer.println(prefix
+                + pxToDpStr("overviewTaskRect.bottom", overviewTaskRect.bottom));
+        writer.println(prefix
+                + pxToDpStr("overviewGridTaskDimension.x", overviewGridTaskDimension.x));
+        writer.println(prefix
+                + pxToDpStr("overviewGridTaskDimension.y", overviewGridTaskDimension.y));
+        writer.println(prefix
+                + pxToDpStr("overviewModalTaskRect.left", overviewModalTaskRect.left));
+        writer.println(prefix
+                + pxToDpStr("overviewModalTaskRect.top", overviewModalTaskRect.top));
+        writer.println(prefix
+                + pxToDpStr("overviewModalTaskRect.right", overviewModalTaskRect.right));
+        writer.println(prefix
+                + pxToDpStr("overviewModalTaskRect.bottom", overviewModalTaskRect.bottom));
+        boolean isRecentsRtl =
+                PortraitPagedViewHandler.PORTRAIT.getRecentsRtlSetting(context.getResources());
+        writer.println(prefix
+                + pxToDpStr("getOverviewGridTaskRect(" + isRecentsRtl + ").left",
+                getOverviewGridTaskRect(isRecentsRtl).left));
+        writer.println(prefix
+                + pxToDpStr("getOverviewGridTaskRect(" + isRecentsRtl + ").top",
+                getOverviewGridTaskRect(isRecentsRtl).top));
+        writer.println(prefix
+                + pxToDpStr("getOverviewGridTaskRect(" + isRecentsRtl + ").right",
+                getOverviewGridTaskRect(isRecentsRtl).right));
+        writer.println(prefix
+                + pxToDpStr("getOverviewGridTaskRect(" + isRecentsRtl + ").bottom",
+                getOverviewGridTaskRect(isRecentsRtl).bottom));
+        writer.println(
+                prefix + pxToDpStr("overviewTaskWorkspaceScale", overviewTaskWorkspaceScale));
+        writer.println(prefix + pxToDpStr("overviewModalTaskScale", overviewModalTaskScale));
     }
+    // LINT.ThenChange(
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfilePhoneTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBarTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfilePhone3ButtonTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileVerticalBar3ButtonTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscapeTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortraitTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletLandscape3ButtonTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTabletPortrait3ButtonTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscapeTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortraitTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelLandscape3ButtonTest.kt,
+    //     packages/apps/Launcher3/quickstep/tests/src/com/android/quickstep/DeviceProfileTwoPanelPortrait3ButtonTest.kt)
 
     private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) {
         Configuration config = new Configuration(c.getResources().getConfiguration());
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 9c62251..528613c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3024,7 +3024,7 @@
         mDragLayer.dump(prefix, writer);
         mStateManager.dump(prefix, writer);
         mPopupDataProvider.dump(prefix, writer);
-        mDeviceProfile.dump(prefix, writer);
+        mDeviceProfile.dump(this, prefix, writer);
 
         try {
             FileLog.flushAll(writer);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 45a567d..8bbe216 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -50,7 +50,7 @@
 
     public static final String TAG = "AlphabeticalAppsList";
 
-    private final WorkAdapterProvider mWorkAdapterProvider;
+    private final WorkProfileManager mWorkProviderManager;
 
     /**
      * Info about a fast scroller section, depending if sections are merged, the fast scroller
@@ -92,11 +92,11 @@
     private Predicate<ItemInfo> mItemFilter;
 
     public AlphabeticalAppsList(Context context, @Nullable AllAppsStore appsStore,
-            WorkAdapterProvider adapterProvider) {
+            WorkProfileManager workProfileManager) {
         mAllAppsStore = appsStore;
         mActivityContext = ActivityContext.lookupContext(context);
         mAppNameComparator = new AppInfoComparator(context);
-        mWorkAdapterProvider = adapterProvider;
+        mWorkProviderManager = workProfileManager;
         mNumAppsPerRowAllApps = mActivityContext.getDeviceProfile().inv.numAllAppsColumns;
         if (mAllAppsStore != null) {
             mAllAppsStore.addUpdateListener(this);
@@ -260,9 +260,9 @@
             }
         } else {
             int position = 0;
-            if (mWorkAdapterProvider != null) {
-                position += mWorkAdapterProvider.addWorkItems(mAdapterItems);
-                if (!mWorkAdapterProvider.shouldShowWorkApps()) {
+            if (mWorkProviderManager != null) {
+                position += mWorkProviderManager.addWorkItems(mAdapterItems);
+                if (!mWorkProviderManager.shouldShowWorkApps()) {
                     return;
                 }
             }
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index fcba246..459fa88 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -63,6 +63,11 @@
     // A divider that separates the apps list and the search market button
     public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;
 
+    public static final int VIEW_TYPE_WORK_EDU_CARD = 1 << 5;
+    public static final int VIEW_TYPE_WORK_DISABLED_CARD = 1 << 6;
+
+    public static final int NEXT_ID = 7;
+
     // Common view type masks
     public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
     public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
@@ -225,6 +230,12 @@
             case VIEW_TYPE_ALL_APPS_DIVIDER:
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.all_apps_divider, parent, false));
+            case VIEW_TYPE_WORK_EDU_CARD:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.work_apps_edu, parent, false));
+            case VIEW_TYPE_WORK_DISABLED_CARD:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.work_apps_paused, parent, false));
             default:
                 BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
                 if (adapterProvider != null) {
@@ -258,8 +269,12 @@
                 }
                 break;
             case VIEW_TYPE_ALL_APPS_DIVIDER:
+            case VIEW_TYPE_WORK_DISABLED_CARD:
                 // nothing to do
                 break;
+            case VIEW_TYPE_WORK_EDU_CARD:
+                ((WorkEduCard) holder.itemView).setPosition(position);
+                break;
             default:
                 BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
                 if (adapterProvider != null) {
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 72a9b14..f3c5dd6 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -147,8 +147,7 @@
 
         mWorkManager = new WorkProfileManager(
                 mActivityContext.getSystemService(UserManager.class),
-                this,
-                Utilities.getPrefs(mActivityContext), mActivityContext.getDeviceProfile());
+                this, Utilities.getPrefs(mActivityContext));
         mAH = Arrays.asList(null, null, null);
         mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN));
         mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
@@ -603,6 +602,8 @@
         if (mAH.get(currentActivePage).mRecyclerView != null) {
             mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
         }
+        // Header keeps track of active recycler view to properly render header protection.
+        mHeader.setActiveRV(currentActivePage);
         reset(true /* animate */);
 
         mWorkManager.onActivePageChanged(currentActivePage);
@@ -800,12 +801,9 @@
             mType = type;
             mAppsList = new AlphabeticalAppsList<>(mActivityContext,
                     isSearch() ? null : mAllAppsStore,
-                    isWork() ? mWorkManager.getAdapterProvider() : null);
-
+                    isWork() ? mWorkManager : null);
             BaseAdapterProvider[] adapterProviders =
-                    isWork() ? new BaseAdapterProvider[]{mMainAdapterProvider,
-                            mWorkManager.getAdapterProvider()}
-                            : new BaseAdapterProvider[]{mMainAdapterProvider};
+                    new BaseAdapterProvider[]{mMainAdapterProvider};
 
             mAdapter = createAdapter(mAppsList, adapterProviders);
             mAppsList.setAdapter(mAdapter);
diff --git a/src/com/android/launcher3/allapps/WorkAdapterProvider.java b/src/com/android/launcher3/allapps/WorkAdapterProvider.java
deleted file mode 100644
index 76d08c8..0000000
--- a/src/com/android/launcher3/allapps/WorkAdapterProvider.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.content.SharedPreferences;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.model.StringCache;
-import com.android.launcher3.views.ActivityContext;
-
-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;
-
-    @WorkProfileManager.WorkProfileState
-    private int mState;
-    private ActivityContext mActivityContext;
-    private SharedPreferences mPreferences;
-
-    WorkAdapterProvider(ActivityContext activityContext, SharedPreferences prefs) {
-        mActivityContext = activityContext;
-        mPreferences = prefs;
-    }
-
-    @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;
-        View view = layoutInflater.inflate(viewId, parent, false);
-        setDeviceManagementResources(view, viewType);
-        return new AllAppsGridAdapter.ViewHolder(view);
-    }
-
-    private void setDeviceManagementResources(View view, int viewType) {
-        StringCache cache = mActivityContext.getStringCache();
-        if (cache == null) {
-            return;
-        }
-        if (viewType == VIEW_TYPE_WORK_DISABLED_CARD) {
-            setWorkProfilePausedResources(view, cache);
-        } else {
-            setWorkProfileEduResources(view, cache);
-        }
-    }
-
-    private void setWorkProfilePausedResources(View view, StringCache cache) {
-        TextView title = view.findViewById(R.id.work_apps_paused_title);
-        title.setText(cache.workProfilePausedTitle);
-
-        TextView body = view.findViewById(R.id.work_apps_paused_content);
-        body.setText(cache.workProfilePausedDescription);
-
-        TextView button = view.findViewById(R.id.enable_work_apps);
-        button.setText(cache.workProfileEnableButton);
-    }
-
-    private void setWorkProfileEduResources(View view, StringCache cache) {
-        TextView title = view.findViewById(R.id.work_apps_paused_title);
-        title.setText(cache.workProfileEdu);
-
-    }
-
-    /**
-     * returns whether or not work apps should be visible in work tab.
-     */
-    public boolean shouldShowWorkApps() {
-        return mState != WorkProfileManager.STATE_DISABLED;
-    }
-
-    /**
-     * Adds work profile specific adapter items to adapterItems and returns number of items added
-     */
-    public int addWorkItems(ArrayList<AllAppsGridAdapter.AdapterItem> adapterItems) {
-        if (mState == WorkProfileManager.STATE_DISABLED) {
-            //add disabled card here.
-            adapterItems.add(new AdapterItem(VIEW_TYPE_WORK_DISABLED_CARD));
-        } else if (mState == WorkProfileManager.STATE_ENABLED && !isEduSeen()) {
-            adapterItems.add(new AdapterItem(VIEW_TYPE_WORK_EDU_CARD));
-        }
-
-        return adapterItems.size();
-    }
-
-    /**
-     * Sets the current state of work profile
-     */
-    public void updateCurrentState(@WorkProfileManager.WorkProfileState int state) {
-        mState = state;
-    }
-
-    @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 mPreferences.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
index 539cff1..968a556 100644
--- a/src/com/android/launcher3/allapps/WorkEduCard.java
+++ b/src/com/android/launcher3/allapps/WorkEduCard.java
@@ -24,9 +24,11 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.widget.FrameLayout;
+import android.widget.TextView;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
 
 /**
@@ -72,12 +74,18 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         findViewById(R.id.action_btn).setOnClickListener(this);
+
+        StringCache cache = mActivityContext.getStringCache();
+        if (cache != null) {
+            TextView title = findViewById(R.id.work_apps_paused_title);
+            title.setText(cache.workProfileEdu);
+        }
     }
 
     @Override
     public void onClick(View view) {
         startAnimation(mDismissAnim);
-        Utilities.getPrefs(getContext()).edit().putInt(WorkAdapterProvider.KEY_WORK_EDU_STEP,
+        Utilities.getPrefs(getContext()).edit().putInt(WorkProfileManager.KEY_WORK_EDU_STEP,
                 1).apply();
     }
 
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
index 729622f..26a7803 100644
--- a/src/com/android/launcher3/allapps/WorkPausedCard.java
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -23,9 +23,11 @@
 import android.view.View;
 import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
 
 /**
@@ -49,12 +51,27 @@
         mActivityContext = ActivityContext.lookupContext(getContext());
     }
 
-
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mBtn = findViewById(R.id.enable_work_apps);
         mBtn.setOnClickListener(this);
+
+        StringCache cache = mActivityContext.getStringCache();
+        if (cache != null) {
+            setWorkProfilePausedResources(cache);
+        }
+    }
+
+    private void setWorkProfilePausedResources(StringCache cache) {
+        TextView title = findViewById(R.id.work_apps_paused_title);
+        title.setText(cache.workProfilePausedTitle);
+
+        TextView body = findViewById(R.id.work_apps_paused_content);
+        body.setText(cache.workProfilePausedDescription);
+
+        TextView button = findViewById(R.id.enable_work_apps);
+        button.setText(cache.workProfileEnableButton);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 2f5b7a2..cfac985 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
@@ -31,13 +33,14 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.function.Predicate;
 
 /**
@@ -48,13 +51,12 @@
 public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
     private static final String TAG = "WorkProfileManager";
 
+    public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
 
     public static final int STATE_ENABLED = 1;
     public static final int STATE_DISABLED = 2;
     public static final int STATE_TRANSITION = 3;
 
-    private final UserManager mUserManager;
-
     /**
      * Work profile manager states
      */
@@ -64,26 +66,23 @@
             STATE_TRANSITION
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface WorkProfileState {
-    }
+    public @interface WorkProfileState { }
 
+    private final UserManager mUserManager;
     private final BaseAllAppsContainerView<?> mAllApps;
-    private final WorkAdapterProvider mAdapterProvider;
     private final Predicate<ItemInfo> mMatcher;
 
     private WorkModeSwitch mWorkModeSwitch;
-    private final DeviceProfile mDeviceProfile;
 
     @WorkProfileState
     private int mCurrentState;
+    private SharedPreferences mPreferences;
 
-
-    public WorkProfileManager(UserManager userManager, BaseAllAppsContainerView<?> allApps,
-            SharedPreferences preferences, DeviceProfile deviceProfile) {
+    public WorkProfileManager(
+            UserManager userManager, BaseAllAppsContainerView<?> allApps, SharedPreferences prefs) {
         mUserManager = userManager;
         mAllApps = allApps;
-        mDeviceProfile = deviceProfile;
-        mAdapterProvider = new WorkAdapterProvider(allApps.mActivityContext, preferences);
+        mPreferences = prefs;
         mMatcher = mAllApps.mPersonalMatcher.negate();
     }
 
@@ -120,7 +119,6 @@
 
     private void updateCurrentState(@WorkProfileState int currentState) {
         mCurrentState = currentState;
-        mAdapterProvider.updateCurrentState(currentState);
         if (getAH() != null) {
             getAH().mAppsList.updateAdapterItems();
         }
@@ -161,10 +159,6 @@
         mWorkModeSwitch = null;
     }
 
-    public WorkAdapterProvider getAdapterProvider() {
-        return mAdapterProvider;
-    }
-
     public Predicate<ItemInfo> getMatcher() {
         return mMatcher;
     }
@@ -181,4 +175,28 @@
     public int getCurrentState() {
         return mCurrentState;
     }
+
+    /**
+     * returns whether or not work apps should be visible in work tab.
+     */
+    public boolean shouldShowWorkApps() {
+        return mCurrentState != WorkProfileManager.STATE_DISABLED;
+    }
+
+    /**
+     * Adds work profile specific adapter items to adapterItems and returns number of items added
+     */
+    public int addWorkItems(ArrayList<AdapterItem> adapterItems) {
+        if (mCurrentState == WorkProfileManager.STATE_DISABLED) {
+            //add disabled card here.
+            adapterItems.add(new AdapterItem(VIEW_TYPE_WORK_DISABLED_CARD));
+        } else if (mCurrentState == WorkProfileManager.STATE_ENABLED && !isEduSeen()) {
+            adapterItems.add(new AdapterItem(VIEW_TYPE_WORK_EDU_CARD));
+        }
+        return adapterItems.size();
+    }
+
+    private boolean isEduSeen() {
+        return mPreferences.getInt(KEY_WORK_EDU_STEP, 0) != 0;
+    }
 }
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index d5bcb0c..a8546e8 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -43,6 +43,8 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
+import android.util.Size;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -53,6 +55,8 @@
 import android.view.WindowManager;
 import android.widget.TextClock;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
@@ -177,10 +181,12 @@
     private final Map<Integer, CellLayout> mWorkspaceScreens = new HashMap<>();
     private final AppWidgetHost mAppWidgetHost;
     private final SparseIntArray mWallpaperColorResources;
+    private final SparseArray<Size> mLauncherWidgetSpanInfo;
 
     public LauncherPreviewRenderer(Context context,
             InvariantDeviceProfile idp,
-            WallpaperColors wallpaperColorsOverride) {
+            WallpaperColors wallpaperColorsOverride,
+            @Nullable final SparseArray<Size> launcherWidgetSpanInfo) {
 
         super(context);
         mUiHandler = new Handler(Looper.getMainLooper());
@@ -224,6 +230,9 @@
         mHotseat = mRootView.findViewById(R.id.hotseat);
         mHotseat.resetLayout(false);
 
+        mLauncherWidgetSpanInfo = launcherWidgetSpanInfo == null ? new SparseArray<>() :
+                launcherWidgetSpanInfo;
+
         CellLayout firstScreen = mRootView.findViewById(R.id.workspace);
         firstScreen.setPadding(mDp.workspacePadding.left + mDp.cellLayoutPaddingPx.left,
                 mDp.workspacePadding.top + mDp.cellLayoutPaddingPx.top,
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index fd11b37..287b976 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -22,10 +22,13 @@
 import android.app.WallpaperColors;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.database.Cursor;
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.util.Log;
+import android.util.Size;
+import android.util.SparseArray;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.SurfaceControlViewHost;
@@ -34,6 +37,8 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.animation.AccelerateDecelerateInterpolator;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 import androidx.annotation.WorkerThread;
 
@@ -124,6 +129,45 @@
     }
 
     /**
+     * A function that queries for the launcher app widget span info
+     *
+     * @param context The context to get the content resolver from, should be related to launcher
+     * @return A SparseArray with the app widget id being the key and the span info being the values
+     */
+    @WorkerThread
+    @Nullable
+    public SparseArray<Size> getLoadedLauncherWidgetInfo(
+            @NonNull final Context context) {
+        final SparseArray<Size> widgetInfo = new SparseArray<>();
+        final String query = LauncherSettings.Favorites.ITEM_TYPE + " = "
+                + LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+
+        try (Cursor c = context.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
+                new String[] {
+                        LauncherSettings.Favorites.APPWIDGET_ID,
+                        LauncherSettings.Favorites.SPANX,
+                        LauncherSettings.Favorites.SPANY
+                }, query, null, null)) {
+            final int appWidgetIdIndex = c.getColumnIndexOrThrow(
+                    LauncherSettings.Favorites.APPWIDGET_ID);
+            final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
+            final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
+            while (c.moveToNext()) {
+                final int appWidgetId = c.getInt(appWidgetIdIndex);
+                final int spanX = c.getInt(spanXIndex);
+                final int spanY = c.getInt(spanYIndex);
+
+                widgetInfo.append(appWidgetId, new Size(spanX, spanY));
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error querying for launcher widget info", e);
+            return null;
+        }
+
+        return widgetInfo;
+    }
+
+    /**
      * Generates the preview in background
      */
     public void loadAsync() {
@@ -174,8 +218,11 @@
                     loadWorkspace(new ArrayList<>(), LauncherSettings.Favorites.PREVIEW_CONTENT_URI,
                             query);
 
+                    final SparseArray<Size> spanInfo =
+                            getLoadedLauncherWidgetInfo(previewContext.getBaseContext());
+
                     MAIN_EXECUTOR.execute(() -> {
-                        renderView(previewContext, mBgDataModel, mWidgetProvidersMap);
+                        renderView(previewContext, mBgDataModel, mWidgetProvidersMap, spanInfo);
                         mOnDestroyCallbacks.add(previewContext::onDestroy);
                     });
                 }
@@ -183,7 +230,8 @@
         } else {
             LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> {
                 if (dataModel != null) {
-                    MAIN_EXECUTOR.execute(() -> renderView(inflationContext, dataModel, null));
+                    MAIN_EXECUTOR.execute(() -> renderView(inflationContext, dataModel, null,
+                            null));
                 } else {
                     Log.e(TAG, "Model loading failed");
                 }
@@ -201,12 +249,13 @@
 
     @UiThread
     private void renderView(Context inflationContext, BgDataModel dataModel,
-            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
+            Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap,
+            @Nullable final SparseArray<Size> launcherWidgetSpanInfo) {
         if (mDestroyed) {
             return;
         }
-        View view = new LauncherPreviewRenderer(inflationContext, mIdp, mWallpaperColors)
-                .getRenderedView(dataModel, widgetProviderInfoMap);
+        View view = new LauncherPreviewRenderer(inflationContext, mIdp, mWallpaperColors,
+                launcherWidgetSpanInfo).getRenderedView(dataModel, widgetProviderInfoMap);
         // This aspect scales the view to fit in the surface and centers it
         final float scale = Math.min(mWidth / (float) view.getMeasuredWidth(),
                 mHeight / (float) view.getMeasuredHeight());
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 489bc38..a9d272e 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -57,7 +57,9 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * Handles updates due to changes in package manager (app installed/updated/removed)
@@ -343,7 +345,12 @@
                     .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
                     .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
             deleteAndBindComponentsRemoved(removeMatch,
-                    "removed because the corresponding package or component is removed");
+                    "removed because the corresponding package or component is removed. "
+                            + "mOp=" + mOp + " removedPackages=" + removedPackages.stream().collect(
+                                    Collectors.joining(",", "[", "]"))
+                            + " removedComponents=" + removedComponents.stream()
+                            .filter(Objects::nonNull).map(ComponentName::toShortString)
+                            .collect(Collectors.joining(",", "[", "]")));
 
             // Remove any queued items from the install queue
             ItemInstallQueue.INSTANCE.get(context)
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 6bae745..53cd416 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -38,6 +38,7 @@
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.views.BubbleTextHolder;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 /**
  * Class to handle long-clicks on workspace items and start drag as a result.
@@ -51,7 +52,11 @@
             ItemLongClickListener::onAllAppsItemLongClick;
 
     private static boolean onWorkspaceItemLongClick(View v) {
-        TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick");
+        if (v instanceof LauncherAppWidgetHostView) {
+            TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
+        } else {
+            TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick");
+        }
         Launcher launcher = Launcher.getLauncher(v.getContext());
         if (!canStartDrag(launcher)) return false;
         if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
index 0635d84..ba813c0 100644
--- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
@@ -23,6 +23,8 @@
 import org.junit.Before
 import org.mockito.ArgumentMatchers.any
 import org.mockito.Mockito.mock
+import java.io.PrintWriter
+import java.io.StringWriter
 import org.mockito.Mockito.`when` as whenever
 
 abstract class DeviceProfileBaseTest {
@@ -35,6 +37,7 @@
     protected var transposeLayoutWithOrientation: Boolean = false
     protected var useTwoPanels: Boolean = false
     protected var isGestureMode: Boolean = true
+    protected var isRecentsRtl: Boolean = true
 
     @Before
     fun setUp() {
@@ -55,8 +58,9 @@
         isGestureMode
     )
 
-    protected fun initializeVarsForPhone(isLandscape: Boolean = false) {
-        val (x, y) = if (isLandscape)
+    protected fun initializeVarsForPhone(isGestureMode: Boolean = true,
+                                         isVerticalBar: Boolean = false) {
+        val (x, y) = if (isVerticalBar)
             Pair(3120, 1440)
         else
             Pair(1440, 3120)
@@ -67,10 +71,17 @@
         whenever(info.getDensityDpi()).thenReturn(560)
         whenever(info.smallestSizeDp(any())).thenReturn(411f)
 
-        inv = newScalableInvariantDeviceProfile()
+        this.isGestureMode = isGestureMode
+
+        inv = newScalableInvariantDeviceProfile().apply {
+            deviceType = InvariantDeviceProfile.TYPE_PHONE
+            transposeLayoutWithOrientation = isVerticalBar
+        }
     }
 
-    protected fun initializeVarsForTablet(isLandscape: Boolean = false) {
+    protected fun initializeVarsForTablet(isLandscape: Boolean = false,
+                                          isTwoPanel: Boolean = false,
+                                          isGestureMode: Boolean = true) {
         val (x, y) = if (isLandscape)
             Pair(2560, 1600)
         else
@@ -82,7 +93,19 @@
         whenever(info.getDensityDpi()).thenReturn(320)
         whenever(info.smallestSizeDp(any())).thenReturn(800f)
 
-        inv = newScalableInvariantDeviceProfile()
+        this.isGestureMode = isGestureMode
+        useTwoPanels = isTwoPanel
+
+        inv = newScalableInvariantDeviceProfile().apply {
+            deviceType = if (isTwoPanel)
+                InvariantDeviceProfile.TYPE_MULTI_DISPLAY else InvariantDeviceProfile.TYPE_TABLET
+            inlineQsb = booleanArrayOf(
+                    false,
+                    isLandscape,
+                    false,
+                    false
+            )
+        }
     }
 
     /**
@@ -137,4 +160,12 @@
                 false
             )
         }
+
+    fun dump(dp: DeviceProfile): StringWriter {
+        val stringWriter = StringWriter()
+        val printWriter = PrintWriter(stringWriter)
+        dp.dump(context, "", printWriter)
+        printWriter.flush()
+        return stringWriter
+    }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/HotseatShownIconsTest.kt b/tests/src/com/android/launcher3/HotseatShownIconsTest.kt
index 593239d..5dabb33 100644
--- a/tests/src/com/android/launcher3/HotseatShownIconsTest.kt
+++ b/tests/src/com/android/launcher3/HotseatShownIconsTest.kt
@@ -32,33 +32,6 @@
 class HotseatShownIconsTest : DeviceProfileBaseTest() {
 
     @Test
-    fun hotseat_size_is_normal_for_handhelds() {
-        initializeVarsForPhone()
-        inv = newScalableInvariantDeviceProfile().apply {
-            deviceType = TYPE_PHONE
-        }
-
-        val dp = newDP()
-
-        assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.numShownHotseatIcons).isEqualTo(4)
-    }
-
-    @Test
-    fun hotseat_size_is_max_when_large_screen() {
-        initializeVarsForTablet(isLandscape = true)
-        inv = newScalableInvariantDeviceProfile().apply {
-            deviceType = TYPE_MULTI_DISPLAY
-        }
-        useTwoPanels = true
-
-        val dp = newDP()
-
-        assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-    }
-
-    @Test
     fun hotseat_size_is_shrunk_if_needed_when_large_screen() {
         initializeVarsForTablet(isLandscape = true)
         inv = newScalableInvariantDeviceProfile().apply {
diff --git a/tests/src/com/android/launcher3/InlineQsbTest.kt b/tests/src/com/android/launcher3/InlineQsbTest.kt
deleted file mode 100644
index 905c1e1..0000000
--- a/tests/src/com/android/launcher3/InlineQsbTest.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Test for [DeviceProfile]
- */
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class InlineQsbTest : DeviceProfileBaseTest() {
-
-    @Test
-    fun qsb_is_not_inline_for_phones() {
-        initializeVarsForPhone()
-
-        val dp = newDP()
-
-        assertThat(dp.isQsbInline).isFalse()
-    }
-
-    @Test
-    fun qsb_is_inline_for_tablet_portrait() {
-        initializeVarsForTablet()
-        inv = newScalableInvariantDeviceProfile().apply {
-            inlineQsb = booleanArrayOf(
-                false,
-                true, // landscape
-                false,
-                false
-            )
-        }
-
-        val dp = DeviceProfile(
-            context,
-            inv,
-            info,
-            windowBounds,
-            isMultiWindowMode,
-            transposeLayoutWithOrientation,
-            useTwoPanels,
-            isGestureMode
-        )
-
-        assertThat(dp.isQsbInline).isFalse()
-    }
-
-    @Test
-    fun qsb_is_inline_for_tablet_landscape() {
-        initializeVarsForTablet(isLandscape = true)
-        inv = newScalableInvariantDeviceProfile().apply {
-            inlineQsb = booleanArrayOf(
-                false,
-                true, // landscape
-                false,
-                false
-            )
-            numColumns = 6
-            numRows = 5
-            numShownHotseatIcons = 6
-        }
-
-        val dp = newDP()
-
-        if (dp.hotseatQsbHeight > 0) {
-            assertThat(dp.isQsbInline).isTrue()
-        } else { // Launcher3 doesn't have QSB height
-            assertThat(dp.isQsbInline).isFalse()
-        }
-    }
-
-    /**
-     * This test is to make sure that a tablet doesn't inline the QSB if the layout doesn't support
-     */
-    @Test
-    fun qsb_is_not_inline_for_tablet_landscape_without_inline() {
-        initializeVarsForTablet(isLandscape = true)
-        useTwoPanels = true
-
-        val dp = newDP()
-
-        assertThat(dp.isQsbInline).isFalse()
-    }
-
-}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
new file mode 100644
index 0000000..3ca05bc
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+
+public class CellLayoutBoard {
+
+    static final int INFINITE = 99999;
+
+    char[][] mBoard = new char[30][30];
+
+    List<TestBoardWidget> mWidgetsRects = new ArrayList<>();
+    Map<Character, TestBoardWidget> mWidgetsMap = new HashMap<>();
+
+    List<TestBoardAppIcon> mIconPoints = new ArrayList<>();
+    Map<Character, TestBoardAppIcon> mIconsMap = new HashMap<>();
+
+    Point mMain = new Point();
+
+    CellLayoutBoard() {
+        for (int x = 0; x < mBoard.length; x++) {
+            for (int y = 0; y < mBoard[0].length; y++) {
+                mBoard[x][y] = '-';
+            }
+        }
+    }
+
+    public List<TestBoardWidget> getWidgets() {
+        return mWidgetsRects;
+    }
+
+    public Point getMain() {
+        return mMain;
+    }
+
+    public TestBoardWidget getWidgetRect(char c) {
+        return mWidgetsMap.get(c);
+    }
+
+    public static TestBoardWidget getWidgetRect(int x, int y, Set<Point> used, char[][] board) {
+        char type = board[x][y];
+        Queue<Point> search = new ArrayDeque<Point>();
+        Point current = new Point(x, y);
+        search.add(current);
+        used.add(current);
+        List<Point> neighbors = new ArrayList<>(List.of(
+                new Point(-1, 0),
+                new Point(0, -1),
+                new Point(1, 0),
+                new Point(0, 1))
+        );
+        Rect widgetRect = new Rect(INFINITE, -INFINITE, -INFINITE, INFINITE);
+        while (!search.isEmpty()) {
+            current = search.poll();
+            widgetRect.top = Math.max(widgetRect.top, current.y);
+            widgetRect.right = Math.max(widgetRect.right, current.x);
+            widgetRect.bottom = Math.min(widgetRect.bottom, current.y);
+            widgetRect.left = Math.min(widgetRect.left, current.x);
+            for (Point p : neighbors) {
+                Point next = new Point(current.x + p.x, current.y + p.y);
+                if (next.x < 0 || next.x >= board.length) continue;
+                if (next.y < 0 || next.y >= board[0].length) continue;
+                if (board[next.x][next.y] == type && !used.contains(next)) {
+                    used.add(next);
+                    search.add(next);
+                }
+            }
+        }
+        return new TestBoardWidget(type, widgetRect);
+    }
+
+    public static boolean isWidget(char type) {
+        return type != 'i' && type != '-';
+    }
+
+    public static boolean isIcon(char type) {
+        return type == 'i';
+    }
+
+    private static List<TestBoardWidget> getRects(char[][] board) {
+        Set<Point> used = new HashSet<>();
+        List<TestBoardWidget> widgetsRects = new ArrayList<>();
+        for (int x = 0; x < board.length; x++) {
+            for (int y = 0; y < board[0].length; y++) {
+                if (!used.contains(new Point(x, y)) && isWidget(board[x][y])) {
+                    widgetsRects.add(getWidgetRect(x, y, used, board));
+                }
+            }
+        }
+        return widgetsRects;
+    }
+
+    private static List<TestBoardAppIcon> getIconPoints(char[][] board) {
+        List<TestBoardAppIcon> iconPoints = new ArrayList<>();
+        for (int x = 0; x < board.length; x++) {
+            for (int y = 0; y < board[0].length; y++) {
+                if (isIcon(board[x][y])) {
+                    iconPoints.add(new TestBoardAppIcon(new Point(x, y), board[x][y]));
+                }
+            }
+        }
+        return iconPoints;
+    }
+
+    public static CellLayoutBoard boardFromString(String boardStr) {
+        String[] lines = boardStr.split("\n");
+        CellLayoutBoard board = new CellLayoutBoard();
+
+        for (int y = 0; y < lines.length; y++) {
+            String line = lines[y];
+            for (int x = 0; x < line.length(); x++) {
+                char c = line.charAt(x);
+                if (c == 'm') {
+                    board.mMain = new Point(x, y);
+                }
+                if (c != '-') {
+                    board.mBoard[x][y] = line.charAt(x);
+                }
+            }
+        }
+        board.mWidgetsRects = getRects(board.mBoard);
+        board.mWidgetsRects.forEach(
+                widgetRect -> board.mWidgetsMap.put(widgetRect.mType, widgetRect));
+        board.mIconPoints = getIconPoints(board.mBoard);
+        return board;
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
new file mode 100644
index 0000000..ed0b71d
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout;
+
+import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
+
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.View;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.celllayout.testcases.FullReorderCase;
+import com.android.launcher3.celllayout.testcases.MoveOutReorderCase;
+import com.android.launcher3.celllayout.testcases.PushReorderCase;
+import com.android.launcher3.celllayout.testcases.ReorderTestCase;
+import com.android.launcher3.celllayout.testcases.SimpleReorderCase;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ReorderWidgets extends AbstractLauncherUiTest {
+
+    @Rule
+    public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+
+    private static final String TAG = ReorderWidgets.class.getSimpleName();
+
+    private View getViewAt(int cellX, int cellY) {
+        return getFromLauncher(l -> l.getWorkspace().getScreenWithId(
+                l.getWorkspace().getScreenIdForPageIndex(0)).getChildAt(cellX, cellY));
+    }
+
+    private Point getCellDimensions() {
+        return getFromLauncher(l -> {
+            CellLayout cellLayout = l.getWorkspace().getScreenWithId(
+                    l.getWorkspace().getScreenIdForPageIndex(0));
+            return new Point(cellLayout.getWidth() / cellLayout.getCountX(),
+                    cellLayout.getHeight() / cellLayout.getCountY());
+        });
+    }
+
+    @Before
+    public void setup() throws Throwable {
+        TaplTestsLauncher3.initialize(this);
+        clearHomescreen();
+    }
+
+    /**
+     * Validate if the given board represent the current CellLayout
+     **/
+    private boolean validateBoard(CellLayoutBoard board) {
+        boolean match = true;
+        Point cellDimensions = getCellDimensions();
+        for (TestBoardWidget widgetRect: board.getWidgets()) {
+            if (widgetRect.shouldIgnore()) {
+                continue;
+            }
+            View widget = getViewAt(widgetRect.getCellX(), widgetRect.getCellY());
+            match &= widgetRect.getSpanX()
+                    == Math.round(widget.getWidth() / (float) cellDimensions.x);
+            match &= widgetRect.getSpanY()
+                    == Math.round(widget.getHeight() / (float) cellDimensions.y);
+            if (!match) return match;
+        }
+        return match;
+    }
+
+    /**
+     * Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases.
+     */
+    private void fillWithWidgets(TestBoardWidget widgetRect) {
+        int initX = widgetRect.getCellX();
+        int initY = widgetRect.getCellY();
+        for (int x = 0; x < widgetRect.getSpanX(); x++) {
+            for (int y = 0; y < widgetRect.getSpanY(); y++) {
+                int auxX = initX + x;
+                int auxY = initY + y;
+                try {
+                    // this widgets are filling, we don't care if we can't place them
+                    addWidgetInCell(
+                            new TestBoardWidget('x',
+                                    new Rect(auxX, auxY, auxX, auxY))
+                    );
+                } catch (Exception e) {
+                    Log.d(TAG, "Unable to place filling widget at " + auxX + "," + auxY);
+                }
+            }
+        }
+    }
+
+    private void addWidgetInCell(TestBoardWidget widgetRect) {
+        LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
+        LauncherAppWidgetInfo item = createWidgetInfo(info,
+                ApplicationProvider.getApplicationContext(), true);
+        item.cellX = widgetRect.getCellX();
+        item.cellY = widgetRect.getCellY();
+
+        item.spanX = widgetRect.getSpanX();
+        item.spanY = widgetRect.getSpanY();
+        addItemToScreen(item);
+    }
+
+    private void addCorrespondingWidgetRect(TestBoardWidget widgetRect) {
+        if (widgetRect.mType == 'x') {
+            fillWithWidgets(widgetRect);
+        } else {
+            addWidgetInCell(widgetRect);
+        }
+    }
+
+    private void runTestCase(ReorderTestCase testCase) {
+        Point mainWidgetCellPos = testCase.mStart.getMain();
+
+        testCase.mStart.getWidgets().forEach(this::addCorrespondingWidgetRect);
+
+        mLauncher.getWorkspace()
+                .getWidgetAtCell(mainWidgetCellPos.x, mainWidgetCellPos.y)
+                .dragWidgetToWorkspace(testCase.moveMainTo.x, testCase.moveMainTo.y)
+                .dismiss(); // dismiss resize frame
+
+        boolean isValid = false;
+        for (CellLayoutBoard board : testCase.mEnd) {
+            isValid |= validateBoard(board);
+        }
+        assertTrue("None of the valid boards match with the current state", isValid);
+    }
+
+    /**
+     * Run only the test define for the current grid size if such test exist
+     *
+     * @param testCaseMap map containing all the tests per grid size (Point)
+     */
+    private void runTestCaseMap(Map<Point, ReorderTestCase> testCaseMap, String testName) {
+        Point iconGridDimensions = mLauncher.getWorkspace().getIconGridDimensions();
+        Log.d(TAG, "Running test " + testName + " for grid " + iconGridDimensions);
+        Assume.assumeTrue(
+                "The test " + testName + " doesn't support " + iconGridDimensions + " grid layout",
+                testCaseMap.containsKey(iconGridDimensions));
+        runTestCase(testCaseMap.get(iconGridDimensions));
+    }
+
+    @Test
+    public void simpleReorder() {
+        runTestCaseMap(SimpleReorderCase.TEST_BY_GRID_SIZE,
+                SimpleReorderCase.class.getSimpleName());
+    }
+
+    @Test
+    public void pushTest() {
+        runTestCaseMap(PushReorderCase.TEST_BY_GRID_SIZE, PushReorderCase.class.getSimpleName());
+    }
+
+    @Test
+    public void fullReorder() {
+        runTestCaseMap(FullReorderCase.TEST_BY_GRID_SIZE, FullReorderCase.class.getSimpleName());
+    }
+
+    @Test
+    public void moveOutReorder() {
+        runTestCaseMap(MoveOutReorderCase.TEST_BY_GRID_SIZE,
+                MoveOutReorderCase.class.getSimpleName());
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/TestBoardAppIcon.java b/tests/src/com/android/launcher3/celllayout/TestBoardAppIcon.java
new file mode 100644
index 0000000..04604d7
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/TestBoardAppIcon.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout;
+
+import android.graphics.Point;
+
+public class TestBoardAppIcon {
+    public Point coord;
+    public char mType;
+
+    public TestBoardAppIcon(Point coord, char type) {
+        this.coord = coord;
+        mType = type;
+    }
+
+    public char getType() {
+        return mType;
+    }
+
+    public void setType(char type) {
+        mType = type;
+    }
+
+    public Point getCoord() {
+        return coord;
+    }
+
+    public void setCoord(Point coord) {
+        this.coord = coord;
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/TestBoardWidget.java b/tests/src/com/android/launcher3/celllayout/TestBoardWidget.java
new file mode 100644
index 0000000..7f9aa95
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/TestBoardWidget.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout;
+
+import android.graphics.Rect;
+
+public class TestBoardWidget {
+    public char mType;
+    public Rect mBounds;
+
+    TestBoardWidget(char type, Rect bounds) {
+        this.mType = type;
+        this.mBounds = bounds;
+    }
+
+    int getSpanX() {
+        return mBounds.right - mBounds.left + 1;
+    }
+
+    int getSpanY() {
+        return mBounds.top - mBounds.bottom + 1;
+    }
+
+    int getCellX() {
+        return mBounds.left;
+    }
+
+    int getCellY() {
+        return mBounds.bottom;
+    }
+
+    boolean shouldIgnore() {
+        return this.mType == 'x';
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
new file mode 100644
index 0000000..ff03a50
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout.testcases;
+
+import android.graphics.Point;
+
+import java.util.Map;
+
+public class FullReorderCase {
+    private static final String START_BOARD_STR_5x5 = ""
+            + "xxxxx\n"
+            + "222mm\n"
+            + "222mm\n"
+            + "ad111\n"
+            + "bc111";
+
+    private static final Point MOVE_TO_5x5 = new Point(0, 4);
+
+    private static final String END_BOARD_STR_5x5 = ""
+            + "xxxxx\n"
+            + "222ad\n"
+            + "222bc\n"
+            + "mm111\n"
+            + "mm111";
+
+    private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_STR_5x5,
+            MOVE_TO_5x5,
+            END_BOARD_STR_5x5);
+
+    private static final String START_BOARD_STR_6x5 = ""
+            + "xxxxxx\n"
+            + "2222mm\n"
+            + "2222mm\n"
+            + "ad1111\n"
+            + "bc1111";
+
+    private static final Point MOVE_TO_6x5 = new Point(0, 4);
+
+    private static final String END_BOARD_STR_6x5 = ""
+            + "xxxxxx\n"
+            + "2222ad\n"
+            + "2222bc\n"
+            + "mm1111\n"
+            + "mm1111";
+
+    private static final ReorderTestCase TEST_CASE_6x5 = new ReorderTestCase(START_BOARD_STR_6x5,
+            MOVE_TO_6x5,
+            END_BOARD_STR_6x5);
+
+    public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+            Map.of(new Point(5, 5), TEST_CASE_5x5, new Point(6, 5), TEST_CASE_6x5);
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java
new file mode 100644
index 0000000..32bf05a
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout.testcases;
+
+import android.graphics.Point;
+
+import java.util.Map;
+
+public class MoveOutReorderCase {
+    private static final String START_BOARD_STR_5x5 = ""
+            + "xxxxx\n"
+            + "34-m-\n"
+            + "35111\n"
+            + "32111\n"
+            + "32111";
+
+    private static final Point MOVE_TO_5x5 = new Point(1, 2);
+
+    private static final String END_BOARD_STR_5x5 = ""
+            + "xxxxx\n"
+            + "345--\n"
+            + "3m111\n"
+            + "32111\n"
+            + "32111";
+
+    private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_STR_5x5,
+            MOVE_TO_5x5,
+            END_BOARD_STR_5x5);
+
+
+    private static final String START_BOARD_STR_6x5 = ""
+            + "xxxxxx\n"
+            + "34-m--\n"
+            + "351111\n"
+            + "321111\n"
+            + "321111";
+
+    private static final Point MOVE_TO_6x5 = new Point(1, 2);
+
+    private static final String END_BOARD_STR_6x5 = ""
+            + "xxxxxx\n"
+            + "345---\n"
+            + "3m1111\n"
+            + "321111\n"
+            + "321111";
+
+    private static final ReorderTestCase TEST_CASE_6x5 = new ReorderTestCase(START_BOARD_STR_6x5,
+            MOVE_TO_6x5,
+            END_BOARD_STR_6x5);
+
+    public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+            Map.of(new Point(5, 5), TEST_CASE_5x5, new Point(6, 5), TEST_CASE_6x5);
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java
new file mode 100644
index 0000000..b386946
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout.testcases;
+
+import android.graphics.Point;
+
+import com.android.launcher3.celllayout.CellLayoutBoard;
+
+import java.util.Map;
+
+public class PushReorderCase {
+    private static final String START_BOARD_STR_5x5 = ""
+            + "xxxxx\n"
+            + "222m-\n"
+            + "--111\n"
+            + "--333\n"
+            + "-----";
+    private static final CellLayoutBoard START_BOARD_5x5 = CellLayoutBoard.boardFromString(
+            START_BOARD_STR_5x5);
+
+    private static final Point MOVE_TO_5x5 = new Point(2, 1);
+
+    private static final String END_BOARD_STR_5x5 = ""
+            + "xxxxx\n"
+            + "--m--\n"
+            + "222--\n"
+            + "--111\n"
+            + "--333";
+    private static final CellLayoutBoard END_BOARD_5x5 = CellLayoutBoard.boardFromString(
+            END_BOARD_STR_5x5);
+
+    private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_5x5,
+            MOVE_TO_5x5,
+            END_BOARD_5x5);
+
+
+    private static final String START_BOARD_STR_6x5 = ""
+            + "xxxxxx\n"
+            + "2222m-\n"
+            + "--111-\n"
+            + "--333-\n"
+            + "------";
+    private static final CellLayoutBoard START_BOARD_6x5 = CellLayoutBoard.boardFromString(
+            START_BOARD_STR_6x5);
+
+    private static final Point MOVE_TO_6x5 = new Point(2, 1);
+
+    private static final String END_BOARD_STR_6x5 = ""
+            + "xxxxxx\n"
+            + "--m---\n"
+            + "2222--\n"
+            + "--111-\n"
+            + "--333-";
+    private static final CellLayoutBoard END_BOARD_6x5 = CellLayoutBoard.boardFromString(
+            END_BOARD_STR_6x5);
+
+    private static final ReorderTestCase TEST_CASE_6x5 = new ReorderTestCase(START_BOARD_6x5,
+            MOVE_TO_6x5,
+            END_BOARD_6x5);
+
+    public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+            Map.of(new Point(5, 5), TEST_CASE_5x5, new Point(6, 5), TEST_CASE_6x5);
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/ReorderTestCase.java b/tests/src/com/android/launcher3/celllayout/testcases/ReorderTestCase.java
new file mode 100644
index 0000000..0a28668
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/ReorderTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout.testcases;
+
+import android.graphics.Point;
+
+import com.android.launcher3.celllayout.CellLayoutBoard;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ReorderTestCase {
+    public CellLayoutBoard mStart;
+    public Point moveMainTo;
+    public List<CellLayoutBoard> mEnd;
+
+    ReorderTestCase(CellLayoutBoard start, Point moveMainTo, CellLayoutBoard ... end) {
+        mStart = start;
+        this.moveMainTo = moveMainTo;
+        mEnd = Arrays.asList(end);
+    }
+
+    ReorderTestCase(String start, Point moveMainTo, String ... end) {
+        mStart = CellLayoutBoard.boardFromString(start);
+        this.moveMainTo = moveMainTo;
+        mEnd = Arrays
+                .asList(end)
+                .stream()
+                .map(CellLayoutBoard::boardFromString)
+                .collect(Collectors.toList());
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java
new file mode 100644
index 0000000..57e1398
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.celllayout.testcases;
+
+import android.graphics.Point;
+
+import com.android.launcher3.celllayout.CellLayoutBoard;
+
+import java.util.Map;
+
+public class SimpleReorderCase {
+    private static final String START_BOARD_STR = ""
+            + "xxxxx\n"
+            + "--mm-\n"
+            + "--mm-\n"
+            + "-----\n"
+            + "-----";
+    private static final CellLayoutBoard START_BOARD_5x5 = CellLayoutBoard.boardFromString(
+            START_BOARD_STR);
+
+    private static final Point MOVE_TO_5x5 = new Point(4, 4);
+
+    private static final String END_BOARD_STR_5x5 = ""
+            + "xxxxx\n"
+            + "-----\n"
+            + "-----\n"
+            + "---mm\n"
+            + "---mm";
+    private static final CellLayoutBoard END_BOARD_5x5 = CellLayoutBoard.boardFromString(
+            END_BOARD_STR_5x5);
+
+    private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_5x5,
+            MOVE_TO_5x5,
+            END_BOARD_5x5);
+
+    public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+            Map.of(new Point(5, 5), TEST_CASE_5x5);
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 6f8b9d2..1f6e1ec 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -563,10 +563,13 @@
                     break;
                 }
                 case OVERVIEW: {
-                    checkLauncherStateInOverview(launcher, expectedContainerType, isStarted,
-                            isResumed);
-                    assertTrue(TestProtocol.stateOrdinalToString(ordinal),
-                            ordinal == TestProtocol.OVERVIEW_STATE_ORDINAL);
+                    verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
+                            ordinal, TestProtocol.OVERVIEW_STATE_ORDINAL);
+                    break;
+                }
+                case SPLIT_SCREEN_SELECT: {
+                    verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
+                            ordinal, TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL);
                     break;
                 }
                 case TASKBAR_ALL_APPS:
@@ -632,5 +635,9 @@
         return homeAppIcon;
     }
 
-
+    private void verifyOverviewState(Launcher launcher, ContainerType expectedContainerType,
+            boolean isStarted, boolean isResumed, int ordinal, int expectedOrdinal) {
+        checkLauncherStateInOverview(launcher, expectedContainerType, isStarted, isResumed);
+        assertEquals(TestProtocol.stateOrdinalToString(ordinal), ordinal, expectedOrdinal);
+    }
 }
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 35b4ca6..a7a17b1 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -30,7 +30,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsPagedView;
-import com.android.launcher3.allapps.WorkAdapterProvider;
 import com.android.launcher3.allapps.WorkEduCard;
 import com.android.launcher3.allapps.WorkPausedCard;
 import com.android.launcher3.allapps.WorkProfileManager;
@@ -155,7 +154,7 @@
     public void testEdu() {
         waitForWorkTabSetup();
         executeOnLauncher(l -> {
-            l.getSharedPrefs().edit().putInt(WorkAdapterProvider.KEY_WORK_EDU_STEP, 0).commit();
+            l.getSharedPrefs().edit().putInt(WorkProfileManager.KEY_WORK_EDU_STEP, 0).commit();
             ((AllAppsPagedView) l.getAppsView().getContentView()).setCurrentPage(WORK_PAGE);
             l.getAppsView().getWorkManager().reset();
         });
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index b7bca02..6a11336 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 
 import androidx.annotation.NonNull;
+import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.Direction;
 import androidx.test.uiautomator.UiObject2;
@@ -168,6 +169,27 @@
         return new OverviewTask(mLauncher, widestTask, this);
     }
 
+    /** Returns an overview task matching TestActivity {@param activityNumber}. */
+    @NonNull
+    public OverviewTask getTestActivityTask(int activityNumber) {
+        final List<UiObject2> taskViews = getTasks();
+        mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
+
+        final String activityName = "TestActivity" + activityNumber;
+        UiObject2 task = null;
+        for (UiObject2 taskView : taskViews) {
+            // TODO(b/239452415): Use equals instead of descEndsWith
+            if (taskView.getParent().hasObject(By.descEndsWith(activityName))) {
+                task = taskView;
+                break;
+            }
+        }
+        mLauncher.assertNotNull(
+                "Unable to find a task with " + activityName + " from the task list", task);
+
+        return new OverviewTask(mLauncher, task, this);
+    }
+
     /**
      * Returns a list of all tasks fully visible in the tablet grid overview.
      */
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index fa6141a..5f92097 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -121,8 +121,8 @@
     // Types for launcher containers that the user is interacting with. "Background" is a
     // pseudo-container corresponding to inactive launcher covered by another app.
     public enum ContainerType {
-        WORKSPACE, HOME_ALL_APPS, OVERVIEW, WIDGETS, FALLBACK_OVERVIEW, LAUNCHED_APP,
-        TASKBAR_ALL_APPS
+        WORKSPACE, HOME_ALL_APPS, OVERVIEW, SPLIT_SCREEN_SELECT, WIDGETS, FALLBACK_OVERVIEW,
+        LAUNCHED_APP, TASKBAR_ALL_APPS
     }
 
     public enum NavigationModel {ZERO_BUTTON, THREE_BUTTON}
@@ -744,7 +744,8 @@
 
                     return waitForLauncherObject(APPS_RES_ID);
                 }
-                case OVERVIEW: {
+                case OVERVIEW:
+                case SPLIT_SCREEN_SELECT: {
                     waitUntilLauncherObjectGone(APPS_RES_ID);
                     waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
                     waitUntilLauncherObjectGone(WIDGETS_RES_ID);
@@ -1091,6 +1092,14 @@
     }
 
     @NonNull
+    UiObject2 waitForSystemUiObject(BySelector selector) {
+        final UiObject2 object = TestHelpers.wait(
+                Until.findObject(selector), WAIT_TIME_MS);
+        assertNotNull("Can't find a systemui object with selector: " + selector, object);
+        return object;
+    }
+
+    @NonNull
     UiObject2 waitForNavigationUiObject(String resId) {
         String resPackage = getNavigationButtonResPackage();
         final UiObject2 object = mDevice.wait(
@@ -1221,6 +1230,13 @@
         return object;
     }
 
+    @NonNull
+    List<UiObject2> waitForObjectsBySelector(BySelector selector) {
+        final List<UiObject2> objects = mDevice.wait(Until.findObjects(selector), WAIT_TIME_MS);
+        assertNotNull("Can't find any view in Launcher, selector: " + selector, objects);
+        return objects;
+    }
+
     private UiObject2 waitForObjectBySelector(BySelector selector) {
         final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
         assertNotNull("Can't find a view in Launcher, selector: " + selector, object);
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 66a51a5..50c2136 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -21,7 +21,7 @@
 /**
  * Overview pane.
  */
-public final class Overview extends BaseOverview {
+public class Overview extends BaseOverview {
 
     Overview(LauncherInstrumentation launcher) {
         super(launcher);
@@ -29,7 +29,7 @@
 
     @Override
     protected ContainerType getContainerType() {
-        return LauncherInstrumentation.ContainerType.OVERVIEW;
+        return ContainerType.OVERVIEW;
     }
 
     @Override
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index d1b1a84..5710713 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -86,7 +86,6 @@
                     "clicked select button")) {
                 return getSelectModeButtons();
             }
-
         }
     }
 
@@ -103,4 +102,22 @@
             return new SelectModeButtons(selectModeButtons, mLauncher);
         }
     }
+
+    /**
+     * Clicks split button and enters split select mode.
+     */
+    @NonNull
+    public SplitScreenSelect clickSplit() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to click split button to enter split select mode")) {
+            UiObject2 split = mLauncher.waitForObjectInContainer(mOverviewActions,
+                    "action_split");
+            mLauncher.clickLauncherObject(split);
+            try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
+                    "clicked split")) {
+                return new SplitScreenSelect(mLauncher);
+            }
+        }
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index c8caa42..ac7424e 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -20,6 +20,8 @@
 
 import android.graphics.Rect;
 
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.UiObject2;
 
 import com.android.launcher3.testing.TestProtocol;
@@ -32,8 +34,12 @@
  * A recent task in the overview panel carousel.
  */
 public final class OverviewTask {
+    private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
     static final Pattern TASK_START_EVENT =
             Pattern.compile("startActivityFromRecentsAsync");
+    static final Pattern SPLIT_START_EVENT =
+            Pattern.compile("launchSplitTasks");
     private final LauncherInstrumentation mLauncher;
     private final UiObject2 mTask;
     private final BaseOverview mOverview;
@@ -125,7 +131,7 @@
     }
 
     /**
-     * Clicks at the task.
+     * Clicks the task.
      */
     public LaunchedAppState open() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
@@ -136,8 +142,21 @@
                     () -> "Launching task didn't open a new window: "
                             + mTask.getParent().getContentDescription(),
                     "clicking an overview task");
-            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
-            return new LaunchedAppState(mLauncher);
+            if (mOverview.getContainerType()
+                    == LauncherInstrumentation.ContainerType.SPLIT_SCREEN_SELECT) {
+                mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SPLIT_START_EVENT);
+
+                try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                        "launched splitscreen")) {
+
+                    BySelector divider = By.res(SYSTEMUI_PACKAGE, "docked_divider_handle");
+                    mLauncher.waitForSystemUiObject(divider);
+                    return new LaunchedAppState(mLauncher);
+                }
+            } else {
+                mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
+                return new LaunchedAppState(mLauncher);
+            }
         }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/SplitScreenSelect.java b/tests/tapl/com/android/launcher3/tapl/SplitScreenSelect.java
new file mode 100644
index 0000000..3cf3ed6
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/SplitScreenSelect.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
+
+/**
+ * Represents a special state in Overview where the initial split app is shoved to the side and a
+ * second split app can be selected.
+ */
+public class SplitScreenSelect extends Overview {
+
+    SplitScreenSelect(LauncherInstrumentation launcher) {
+        super(launcher);
+    }
+
+    @Override
+    protected ContainerType getContainerType() {
+        return ContainerType.SPLIT_SCREEN_SELECT;
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
index 2346249..e1a09af 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widget.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -69,7 +69,24 @@
      */
     @NonNull
     public WidgetResizeFrame dragWidgetToWorkspace() {
-        return dragWidgetToWorkspace(/* configurable= */ false, /* acceptsConfig= */ false);
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            return dragWidgetToWorkspace(/* configurable= */ false, /* acceptsConfig= */ false, -1,
+                    -1);
+        }
+    }
+
+    /**
+     * Drags a non-configurable widget from the widgets container to the workspace at cellX and
+     * cellY and returns the resize frame that is shown after the widget is added.
+     */
+    @NonNull
+    public WidgetResizeFrame dragWidgetToWorkspace(int cellX, int cellY) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "Dragging widget to workspace cell " + cellX + "," + cellY)) {
+            return dragWidgetToWorkspace(/* configurable= */ false, /* acceptsConfig= */ false,
+                    cellX, cellY);
+        }
     }
 
     /**
@@ -79,7 +96,32 @@
      */
     @Nullable
     public WidgetResizeFrame dragConfigWidgetToWorkspace(boolean acceptsConfig) {
-        return dragWidgetToWorkspace(/* configurable= */ true, acceptsConfig);
+        // TODO(b/239438337, fransebas) add correct event checking for this case
+        //try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+        return dragWidgetToWorkspace(/* configurable= */ true, acceptsConfig, -1, -1);
+        //}
+    }
+
+    /**
+     * Drags an object to the center of homescreen.
+     *
+     * @param startsActivity   whether it's expected to start an activity.
+     * @param isWidgetShortcut whether we drag a widget shortcut
+     * @param cellX            X position in the CellLayout
+     * @param cellY            Y position in the CellLayout
+     */
+    private void dragToWorkspace(boolean startsActivity, boolean isWidgetShortcut, int cellX,
+            int cellY) {
+        Launchable launchable = getLaunchable();
+        LauncherInstrumentation launcher = launchable.mLauncher;
+        Workspace.dragIconToWorkspace(
+                launcher,
+                launchable,
+                () -> Workspace.getCellCenter(launchable.mLauncher, cellX, cellY),
+                startsActivity,
+                isWidgetShortcut,
+                launchable::addExpectedEventsForLongClick);
+
     }
 
     /**
@@ -88,11 +130,28 @@
      *
      * <p> If {@code configurable} is true, then either accepts or cancels the configuration based
      * on {@code acceptsConfig}.
+     * <p> If either {@code cellX} or {@code cellY} are negative, then a default location would be
+     * chosen
+     *
+     * @param configurable  if the widget has a configuration activity.
+     * @param acceptsConfig if the widget has a configuration, then if we should accept it or
+     *                      cancel it
+     * @param cellX         X position to drop the widget in the workspace
+     * @param cellY         Y position to drop the widget in the workspace
+     * @return returns the given resize frame of the widget after being dropped, if
+     * configurable is true and acceptsConfig is false then the widget would not be places and will
+     * be cancel and it returns null.
      */
     @Nullable
-    private WidgetResizeFrame dragWidgetToWorkspace(
-            boolean configurable, boolean acceptsConfig) {
-        dragToWorkspace(/* startsActivity= */ configurable, /* isWidgetShortcut= */ false);
+    private WidgetResizeFrame dragWidgetToWorkspace(boolean configurable, boolean acceptsConfig,
+            int cellX, int cellY) {
+        if (cellX == -1 || cellY == -1) {
+            internalDragToWorkspace(/* startsActivity= */ configurable, /* isWidgetShortcut= */
+                    false);
+        } else {
+            dragToWorkspace(/* startsActivity= */ configurable, /* isWidgetShortcut= */ false,
+                    cellX, cellY);
+        }
 
         if (configurable) {
             // Configure the widget.
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 5e5fdec..6044b06 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -90,7 +90,7 @@
             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)
+                            TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT)
                     .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
             LauncherInstrumentation.log(
                     "switchToAllApps: deviceHeight = " + deviceHeight + ", startY = " + startY
@@ -271,7 +271,7 @@
 
     /**
      * @return map of text -> center of the view. In case of icons with the same name, the one with
-     *     lower x coordinate is selected.
+     * lower x coordinate is selected.
      */
     public Map<String, Point> getWorkspaceIconsPositions() {
         final UiObject2 workspace = verifyActiveContainer();
@@ -284,6 +284,7 @@
                                 /* valueMapper= */ UiObject2::getVisibleCenter,
                                 /* mergeFunction= */ (p1, p2) -> p1.x < p2.x ? p1 : p2));
     }
+
     /*
      * Get the center point of the delete/uninstall icon in the drop target bar.
      */
@@ -581,6 +582,32 @@
         }
     }
 
+    /**
+     * @param cellX X position of the widget trying to get.
+     * @param cellY Y position of the widget trying to get.
+     * @return returns the Widget in the given position in the Launcher or an Exception if no such
+     * widget is in that position.
+     */
+    @NonNull
+    public Widget getWidgetAtCell(int cellX, int cellY) {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "getting widget at cell position " + cellX + "," + cellY)) {
+            final List<UiObject2> widgets = mLauncher.waitForObjectsBySelector(
+                    By.clazz("com.android.launcher3.widget.LauncherAppWidgetHostView"));
+            Point coordinateInScreen = Workspace.getCellCenter(mLauncher, cellX, cellY);
+            for (UiObject2 widget : widgets) {
+                if (widget.getVisibleBounds().contains(coordinateInScreen.x,
+                        coordinateInScreen.y)) {
+                    return new Widget(mLauncher, widget);
+                }
+            }
+        }
+        mLauncher.fail("Unable to find widget at cell " + cellX + "," + cellY);
+        // This statement is unreachable because mLauncher.fail throws an exception
+        // but is needed for compiling
+        return null;
+    }
+
     @Nullable
     public Widget tryGetPendingWidget(long timeout) {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
diff --git a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
index 021cc98..141476c 100644
--- a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
+++ b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
@@ -32,24 +32,37 @@
         Launchable launchable = getLaunchable();
         LauncherInstrumentation launcher = launchable.mLauncher;
         try (LauncherInstrumentation.Closable e = launcher.eventsCheck()) {
-            final Point launchableCenter = launchable.getObject().getVisibleCenter();
-            final Point displaySize = launcher.getRealDisplaySize();
-            final int width = displaySize.x / 2;
-            Workspace.dragIconToWorkspace(
-                    launcher,
-                    launchable,
-                    () -> new Point(
-                            launchableCenter.x >= width
-                                    ? launchableCenter.x - width / 2
-                                    : launchableCenter.x + width / 2,
-                            displaySize.y / 2),
-                    startsActivity,
-                    isWidgetShortcut,
-                    launchable::addExpectedEventsForLongClick);
+            internalDragToWorkspace(startsActivity, isWidgetShortcut);
         }
     }
 
     /**
+     * TODO(Redesign WorkspaceDragSource to have actual private methods)
+     * Temporary private method
+     *
+     * @param startsActivity   whether it's expected to start an activity.
+     * @param isWidgetShortcut whether we drag a widget shortcut
+     */
+    default void internalDragToWorkspace(boolean startsActivity, boolean isWidgetShortcut) {
+        Launchable launchable = getLaunchable();
+        LauncherInstrumentation launcher = launchable.mLauncher;
+        final Point launchableCenter = launchable.getObject().getVisibleCenter();
+        final Point displaySize = launcher.getRealDisplaySize();
+        final int width = displaySize.x / 2;
+        Workspace.dragIconToWorkspace(
+                launcher,
+                launchable,
+                () -> new Point(
+                        launchableCenter.x >= width
+                                ? launchableCenter.x - width / 2
+                                : launchableCenter.x + width / 2,
+                        displaySize.y / 2),
+                startsActivity,
+                isWidgetShortcut,
+                launchable::addExpectedEventsForLongClick);
+    }
+
+    /**
      * Drag an object to the given cell in workspace. The target cell must be empty.
      *
      * @param cellX zero based column number, starting from the left of the screen.