Update Responsive Grid tests with aspect ratio group

Adding aspect ratio group and updating the responsive grid tests to match the refactored classes.

Bug: 299889733
Flag: ACONFIG com.android.launcher3.enable_responsive_workspace TEAMFOOD
Test: AllAppsSpecsTest
Test: CalculatedAllAppsSpecTest
Test: HotseatSpecsTest
Test: CalculatedHotseatSpecTest
Test: WorkspaceSpecsTest
Test: CalculatedWorkspaceSpecTest
Test: ResponsiveFolderTest
Test: CalculatedFolderSpecTest
Change-Id: I918f4e28eb310bc9300fc6cc2b5b2af67d758a96
diff --git a/tests/res/values/attrs.xml b/tests/res/values/attrs.xml
index e5ee064..4ba4fc7 100644
--- a/tests/res/values/attrs.xml
+++ b/tests/res/values/attrs.xml
@@ -26,6 +26,10 @@
         <attr name="maxAvailableSize" format="dimension" />
     </declare-styleable>
 
+    <declare-styleable name="ResponsiveSpecGroup">
+        <attr name="maxAspectRatio" format="float" />
+    </declare-styleable>
+
     <declare-styleable name="WorkspaceSpec">
         <attr name="specType" />
         <attr name="maxAvailableSize" />
diff --git a/tests/res/xml/invalid_all_apps_file_case_1.xml b/tests/res/xml/invalid_all_apps_file_case_1.xml
index 6fd35b1..f09ecd8 100644
--- a/tests/res/xml/invalid_all_apps_file_case_1.xml
+++ b/tests/res/xml/invalid_all_apps_file_case_1.xml
@@ -14,23 +14,24 @@
   ~ limitations under the License.
   -->
 <allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <allAppsSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <!--  missing startPadding  -->
-        <endPadding launcher:fixedSize="0dp" />
-        <gutter launcher:matchWorkspace="true" />
-        <cellSize launcher:matchWorkspace="true" />
-    </allAppsSpec>
+    <specs launcher:maxAspectRatio="10">
+        <allAppsSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <!--  missing startPadding  -->
+            <endPadding launcher:fixedSize="0dp" />
+            <gutter launcher:matchWorkspace="true" />
+            <cellSize launcher:matchWorkspace="true" />
+        </allAppsSpec>
 
-    <allAppsSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:matchWorkspace="true" />
-        <endPadding launcher:matchWorkspace="true" />
-        <gutter launcher:matchWorkspace="true" />
-        <cellSize launcher:matchWorkspace="true" />
-    </allAppsSpec>
-
+        <allAppsSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:matchWorkspace="true" />
+            <endPadding launcher:matchWorkspace="true" />
+            <gutter launcher:matchWorkspace="true" />
+            <cellSize launcher:matchWorkspace="true" />
+        </allAppsSpec>
+    </specs>
 </allAppsSpecs>
 
diff --git a/tests/res/xml/invalid_all_apps_file_case_2.xml b/tests/res/xml/invalid_all_apps_file_case_2.xml
index de9c1ac..7644def 100644
--- a/tests/res/xml/invalid_all_apps_file_case_2.xml
+++ b/tests/res/xml/invalid_all_apps_file_case_2.xml
@@ -14,25 +14,26 @@
   ~ limitations under the License.
   -->
 <allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <allAppsSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="0dp" />
-        <endPadding launcher:fixedSize="0dp" />
-        <!--  more than 1 value in one tag -->
-        <gutter
-            launcher:matchWorkspace="true"
-            launcher:fixedSize="16dp" />
-        <cellSize launcher:matchWorkspace="true" />
-    </allAppsSpec>
+    <specs launcher:maxAspectRatio="10">
+        <allAppsSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="0dp" />
+            <!--  more than 1 value in one tag -->
+            <gutter
+                launcher:matchWorkspace="true"
+                launcher:fixedSize="16dp" />
+            <cellSize launcher:matchWorkspace="true" />
+        </allAppsSpec>
 
-    <allAppsSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:matchWorkspace="true" />
-        <endPadding launcher:matchWorkspace="true" />
-        <gutter launcher:matchWorkspace="true" />
-        <cellSize launcher:matchWorkspace="true" />
-    </allAppsSpec>
-
+        <allAppsSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:matchWorkspace="true" />
+            <endPadding launcher:matchWorkspace="true" />
+            <gutter launcher:matchWorkspace="true" />
+            <cellSize launcher:matchWorkspace="true" />
+        </allAppsSpec>
+    </specs>
 </allAppsSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/invalid_all_apps_file_case_3.xml b/tests/res/xml/invalid_all_apps_file_case_3.xml
index 7af0af4..5a3bc64 100644
--- a/tests/res/xml/invalid_all_apps_file_case_3.xml
+++ b/tests/res/xml/invalid_all_apps_file_case_3.xml
@@ -14,24 +14,25 @@
   ~ limitations under the License.
   -->
 <allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <allAppsSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="0dp" />
-        <endPadding launcher:fixedSize="0dp" />
-        <gutter launcher:matchWorkspace="true" />
-        <!--  value bigger than 1 -->
-        <cellSize launcher:ofRemainderSpace="1.001" />
-    </allAppsSpec>
+    <specs launcher:maxAspectRatio="10">
+        <allAppsSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="0dp" />
+            <gutter launcher:matchWorkspace="true" />
+            <!--  value bigger than 1 -->
+            <cellSize launcher:ofRemainderSpace="1.001" />
+        </allAppsSpec>
 
-    <allAppsSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:matchWorkspace="true" />
-        <endPadding launcher:matchWorkspace="true" />
-        <gutter launcher:matchWorkspace="true" />
-        <cellSize launcher:matchWorkspace="true" />
-    </allAppsSpec>
-
+        <allAppsSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:matchWorkspace="true" />
+            <endPadding launcher:matchWorkspace="true" />
+            <gutter launcher:matchWorkspace="true" />
+            <cellSize launcher:matchWorkspace="true" />
+        </allAppsSpec>
+    </specs>
 </allAppsSpecs>
 
diff --git a/tests/res/xml/invalid_folders_specs_1.xml b/tests/res/xml/invalid_folders_specs_1.xml
index 0864249..1715ffd 100644
--- a/tests/res/xml/invalid_folders_specs_1.xml
+++ b/tests/res/xml/invalid_folders_specs_1.xml
@@ -16,25 +16,27 @@
 
 <!-- Tablet - 6x5 portrait -->
 <folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
-        <!--  missing startPadding  -->
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:matchWorkspace="true" />
-    </folderSpec>
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="102dp" />
-    </folderSpec>
+    <specs launcher:maxAspectRatio="10">
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
+            <!--  missing startPadding  -->
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:matchWorkspace="true" />
+        </folderSpec>
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="102dp" />
+        </folderSpec>
 
-    <!-- Height spec is fixed -->
-    <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="24dp" />
-        <!-- mapped to footer height size -->
-        <endPadding launcher:fixedSize="64dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </folderSpec>
+        <!-- Height spec is fixed -->
+        <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="24dp" />
+            <!-- mapped to footer height size -->
+            <endPadding launcher:fixedSize="64dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </folderSpec>
+    </specs>
 </folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_2.xml b/tests/res/xml/invalid_folders_specs_2.xml
index 0b7dd62..bb26e2e 100644
--- a/tests/res/xml/invalid_folders_specs_2.xml
+++ b/tests/res/xml/invalid_folders_specs_2.xml
@@ -16,28 +16,30 @@
 
 <!-- Tablet - 6x5 portrait -->
 <folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <!--  more than 1 value in one tag -->
-        <gutter
-            launcher:ofAvailableSpace="0.0125"
-            launcher:fixedSize="16dp" />
-        <cellSize launcher:matchWorkspace="true" />
-    </folderSpec>
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="102dp" />
-    </folderSpec>
+    <specs launcher:maxAspectRatio="10">
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <!--  more than 1 value in one tag -->
+            <gutter
+                launcher:ofAvailableSpace="0.0125"
+                launcher:fixedSize="16dp" />
+            <cellSize launcher:matchWorkspace="true" />
+        </folderSpec>
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="102dp" />
+        </folderSpec>
 
-    <!-- Height spec is fixed -->
-    <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="24dp" />
-        <!-- mapped to footer height size -->
-        <endPadding launcher:fixedSize="64dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </folderSpec>
+        <!-- Height spec is fixed -->
+        <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="24dp" />
+            <!-- mapped to footer height size -->
+            <endPadding launcher:fixedSize="64dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </folderSpec>
+    </specs>
 </folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_3.xml b/tests/res/xml/invalid_folders_specs_3.xml
index 83fd3e1..cdd8056 100644
--- a/tests/res/xml/invalid_folders_specs_3.xml
+++ b/tests/res/xml/invalid_folders_specs_3.xml
@@ -16,26 +16,28 @@
 
 <!-- Tablet - 6x5 portrait - More the one value first gutter -->
 <folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <!--  value bigger than 1 -->
-        <cellSize launcher:ofRemainderSpace="1.001" />
-    </folderSpec>
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="102dp" />
-    </folderSpec>
+    <specs launcher:maxAspectRatio="10">
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <!--  value bigger than 1 -->
+            <cellSize launcher:ofRemainderSpace="1.001" />
+        </folderSpec>
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="102dp" />
+        </folderSpec>
 
-    <!-- Height spec is fixed -->
-    <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="24dp" />
-        <!-- mapped to footer height size -->
-        <endPadding launcher:fixedSize="64dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </folderSpec>
+        <!-- Height spec is fixed -->
+        <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="24dp" />
+            <!-- mapped to footer height size -->
+            <endPadding launcher:fixedSize="64dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </folderSpec>
+    </specs>
 </folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_4.xml b/tests/res/xml/invalid_folders_specs_4.xml
index 2d8c730..cd5f334 100644
--- a/tests/res/xml/invalid_folders_specs_4.xml
+++ b/tests/res/xml/invalid_folders_specs_4.xml
@@ -15,10 +15,12 @@
   -->
 <!-- missing height spec -->
 <folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:matchWorkspace="true" />
-    </folderSpec>
+    <specs launcher:maxAspectRatio="10">
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:matchWorkspace="true" />
+        </folderSpec>
+    </specs>
 </folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_5.xml b/tests/res/xml/invalid_folders_specs_5.xml
index b4f1f4d..f554521 100644
--- a/tests/res/xml/invalid_folders_specs_5.xml
+++ b/tests/res/xml/invalid_folders_specs_5.xml
@@ -15,19 +15,21 @@
   -->
 <!-- missing breakpoints > 800dp -->
 <folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:matchWorkspace="true" />
-    </folderSpec>
+    <specs launcher:maxAspectRatio="10">
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:matchWorkspace="true" />
+        </folderSpec>
 
-    <!-- Height spec is fixed -->
-    <folderSpec launcher:specType="height" launcher:maxAvailableSize="800dp">
-        <startPadding launcher:fixedSize="24dp" />
-        <!-- mapped to footer height size -->
-        <endPadding launcher:fixedSize="64dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </folderSpec>
+        <!-- Height spec is fixed -->
+        <folderSpec launcher:specType="height" launcher:maxAvailableSize="800dp">
+            <startPadding launcher:fixedSize="24dp" />
+            <!-- mapped to footer height size -->
+            <endPadding launcher:fixedSize="64dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </folderSpec>
+    </specs>
 </folderSpecs>
diff --git a/tests/res/xml/invalid_hotseat_file_case_1.xml b/tests/res/xml/invalid_hotseat_file_case_1.xml
index aaaf8bb..bd40690 100644
--- a/tests/res/xml/invalid_hotseat_file_case_1.xml
+++ b/tests/res/xml/invalid_hotseat_file_case_1.xml
@@ -14,19 +14,19 @@
   ~ limitations under the License.
   -->
 <hotseatSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <specs launcher:maxAspectRatio="10">
+        <hotseatSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="847dp">
+            <hotseatQsbSpace launcher:ofAvailableSpace="1" />
+            <edgePadding launcher:fixedSize="36dp" />
+        </hotseatSpec>
 
-    <hotseatSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="847dp">
-        <hotseatQsbSpace launcher:ofAvailableSpace="1" />
-        <edgePadding launcher:fixedSize="36dp" />
-    </hotseatSpec>
-
-    <hotseatSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <hotseatQsbSpace launcher:fixedSize="36dp" />
-        <edgePadding launcher:fixedSize="36dp" />
-    </hotseatSpec>
-
+        <hotseatSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <hotseatQsbSpace launcher:fixedSize="36dp" />
+            <edgePadding launcher:fixedSize="36dp" />
+        </hotseatSpec>
+    </specs>
 </hotseatSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/invalid_responsive_spec_1.xml b/tests/res/xml/invalid_responsive_spec_1.xml
new file mode 100644
index 0000000..7a474bf
--- /dev/null
+++ b/tests/res/xml/invalid_responsive_spec_1.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 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.
+  -->
+<!-- invalid file - missing groups (specs) with aspect ratio -->
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <workspaceSpec
+        launcher:maxAvailableSize="9999dp"
+        launcher:specType="height">
+        <cellSize launcher:fixedSize="104dp" />
+        <endPadding launcher:ofRemainderSpace="1" />
+        <gutter launcher:fixedSize="16dp" />
+        <startPadding launcher:fixedSize="8dp" />
+    </workspaceSpec>
+
+    <workspaceSpec
+        launcher:maxAvailableSize="9999dp"
+        launcher:specType="width">
+        <cellSize launcher:ofRemainderSpace="0.25" />
+        <endPadding launcher:fixedSize="22dp" />
+        <gutter launcher:fixedSize="16dp" />
+        <startPadding launcher:fixedSize="22dp" />
+    </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_responsive_spec_2.xml b/tests/res/xml/invalid_responsive_spec_2.xml
new file mode 100644
index 0000000..6735300
--- /dev/null
+++ b/tests/res/xml/invalid_responsive_spec_2.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 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.
+  -->
+<!-- invalid file - groups (specs) applied only for half of the specs  -->
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <specs launcher:maxAspectRatio="10">
+        <workspaceSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="height">
+            <cellSize launcher:fixedSize="104dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <startPadding launcher:fixedSize="8dp" />
+        </workspaceSpec>
+
+        <workspaceSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="width">
+            <cellSize launcher:ofRemainderSpace="0.25" />
+            <endPadding launcher:fixedSize="22dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <startPadding launcher:fixedSize="22dp" />
+        </workspaceSpec>
+    </specs>
+
+    <workspaceSpec
+        launcher:maxAvailableSize="9999dp"
+        launcher:specType="width">
+        <cellSize launcher:ofRemainderSpace="0.25" />
+        <endPadding launcher:fixedSize="22dp" />
+        <gutter launcher:fixedSize="16dp" />
+        <startPadding launcher:fixedSize="22dp" />
+    </workspaceSpec>
+    <workspaceSpec
+        launcher:maxAvailableSize="9999dp"
+        launcher:specType="height">
+        <cellSize launcher:fixedSize="104dp" />
+        <endPadding launcher:ofRemainderSpace="1" />
+        <gutter launcher:fixedSize="16dp" />
+        <startPadding launcher:fixedSize="8dp" />
+    </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_responsive_spec_3.xml b/tests/res/xml/invalid_responsive_spec_3.xml
new file mode 100644
index 0000000..72d0c20
--- /dev/null
+++ b/tests/res/xml/invalid_responsive_spec_3.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 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.
+  -->
+<!-- invalid file - aspect ratio = 0 (it must be bigger than zero) -->
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <specs launcher:maxAspectRatio="10">
+        <workspaceSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="height">
+            <cellSize launcher:fixedSize="104dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <startPadding launcher:fixedSize="8dp" />
+        </workspaceSpec>
+
+        <workspaceSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="width">
+            <cellSize launcher:ofRemainderSpace="0.25" />
+            <endPadding launcher:fixedSize="22dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <startPadding launcher:fixedSize="22dp" />
+        </workspaceSpec>
+    </specs>
+
+    <specs launcher:maxAspectRatio="0">
+        <workspaceSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="height">
+            <cellSize launcher:fixedSize="104dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <startPadding launcher:fixedSize="8dp" />
+        </workspaceSpec>
+
+        <workspaceSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="width">
+            <cellSize launcher:ofRemainderSpace="0.25" />
+            <endPadding launcher:fixedSize="22dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <startPadding launcher:fixedSize="22dp" />
+        </workspaceSpec>
+    </specs>
+
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_1.xml b/tests/res/xml/invalid_workspace_file_case_1.xml
index 0be704b..fc6ff59 100644
--- a/tests/res/xml/invalid_workspace_file_case_1.xml
+++ b/tests/res/xml/invalid_workspace_file_case_1.xml
@@ -15,42 +15,44 @@
   -->
 
 <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="648dp">
-        <!--  missing startPadding  -->
-        <endPadding
-            launcher:ofAvailableSpace="0.05" />
-        <gutter
-            launcher:fixedSize="16dp" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
-    </workspaceSpec>
+    <specs launcher:maxAspectRatio="10">
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="648dp">
+            <!--  missing startPadding  -->
+            <endPadding
+                launcher:ofAvailableSpace="0.05" />
+            <gutter
+                launcher:fixedSize="16dp" />
+            <cellSize
+                launcher:ofRemainderSpace="0.2" />
+        </workspaceSpec>
 
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0306" />
-        <endPadding
-            launcher:ofAvailableSpace="0.068" />
-        <gutter
-            launcher:fixedSize="16dp" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
-    </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofAvailableSpace="0.0306" />
+            <endPadding
+                launcher:ofAvailableSpace="0.068" />
+            <gutter
+                launcher:fixedSize="16dp" />
+            <cellSize
+                launcher:ofRemainderSpace="0.2" />
+        </workspaceSpec>
 
-    <!-- Width spec is always the same -->
-    <workspaceSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <endPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <gutter
-            launcher:ofRemainderSpace="0.11425509" />
-        <cellSize
-            launcher:fixedSize="120dp" />
-    </workspaceSpec>
+        <!-- Width spec is always the same -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <endPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <gutter
+                launcher:ofRemainderSpace="0.11425509" />
+            <cellSize
+                launcher:fixedSize="120dp" />
+        </workspaceSpec>
+    </specs>
 </workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_2.xml b/tests/res/xml/invalid_workspace_file_case_2.xml
index 5a37d97..2feeb54 100644
--- a/tests/res/xml/invalid_workspace_file_case_2.xml
+++ b/tests/res/xml/invalid_workspace_file_case_2.xml
@@ -15,45 +15,47 @@
   -->
 
 <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="648dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0125" />
-        <endPadding
-            launcher:ofAvailableSpace="0.05" />
-        <!--  more than 1 value in one tag -->
-        <gutter
-            launcher:ofAvailableSpace="0.0125"
-            launcher:fixedSize="16dp" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
-    </workspaceSpec>
+    <specs launcher:maxAspectRatio="10">
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="648dp">
+            <startPadding
+                launcher:ofAvailableSpace="0.0125" />
+            <endPadding
+                launcher:ofAvailableSpace="0.05" />
+            <!--  more than 1 value in one tag -->
+            <gutter
+                launcher:ofAvailableSpace="0.0125"
+                launcher:fixedSize="16dp" />
+            <cellSize
+                launcher:ofRemainderSpace="0.2" />
+        </workspaceSpec>
 
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0306" />
-        <endPadding
-            launcher:ofAvailableSpace="0.068" />
-        <gutter
-            launcher:fixedSize="16dp" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
-    </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofAvailableSpace="0.0306" />
+            <endPadding
+                launcher:ofAvailableSpace="0.068" />
+            <gutter
+                launcher:fixedSize="16dp" />
+            <cellSize
+                launcher:ofRemainderSpace="0.2" />
+        </workspaceSpec>
 
-    <!-- Width spec is always the same -->
-    <workspaceSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <endPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <gutter
-            launcher:ofRemainderSpace="0.11425509" />
-        <cellSize
-            launcher:fixedSize="120dp" />
-    </workspaceSpec>
+        <!-- Width spec is always the same -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <endPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <gutter
+                launcher:ofRemainderSpace="0.11425509" />
+            <cellSize
+                launcher:fixedSize="120dp" />
+        </workspaceSpec>
+    </specs>
 </workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_3.xml b/tests/res/xml/invalid_workspace_file_case_3.xml
index 3e68edb..79e6fbd 100644
--- a/tests/res/xml/invalid_workspace_file_case_3.xml
+++ b/tests/res/xml/invalid_workspace_file_case_3.xml
@@ -15,44 +15,46 @@
   -->
 
 <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="648dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0125" />
-        <endPadding
-            launcher:ofAvailableSpace="0.05" />
-        <gutter
-            launcher:fixedSize="16dp" />
-        <!--  value bigger than 1 -->
-        <cellSize
-            launcher:ofRemainderSpace="1.001" />
-    </workspaceSpec>
+    <specs launcher:maxAspectRatio="10">
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="648dp">
+            <startPadding
+                launcher:ofAvailableSpace="0.0125" />
+            <endPadding
+                launcher:ofAvailableSpace="0.05" />
+            <gutter
+                launcher:fixedSize="16dp" />
+            <!--  value bigger than 1 -->
+            <cellSize
+                launcher:ofRemainderSpace="1.001" />
+        </workspaceSpec>
 
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0306" />
-        <endPadding
-            launcher:ofAvailableSpace="0.068" />
-        <gutter
-            launcher:fixedSize="16dp" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
-    </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofAvailableSpace="0.0306" />
+            <endPadding
+                launcher:ofAvailableSpace="0.068" />
+            <gutter
+                launcher:fixedSize="16dp" />
+            <cellSize
+                launcher:ofRemainderSpace="0.2" />
+        </workspaceSpec>
 
-    <!-- Width spec is always the same -->
-    <workspaceSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <endPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <gutter
-            launcher:ofRemainderSpace="0.11425509" />
-        <cellSize
-            launcher:fixedSize="120dp" />
-    </workspaceSpec>
+        <!-- Width spec is always the same -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <endPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <gutter
+                launcher:ofRemainderSpace="0.11425509" />
+            <cellSize
+                launcher:fixedSize="120dp" />
+        </workspaceSpec>
+    </specs>
 </workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_4.xml b/tests/res/xml/invalid_workspace_file_case_4.xml
index 9e74c85..66a2618 100644
--- a/tests/res/xml/invalid_workspace_file_case_4.xml
+++ b/tests/res/xml/invalid_workspace_file_case_4.xml
@@ -15,44 +15,46 @@
   -->
 
 <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="648dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0125" />
-        <endPadding
-            launcher:ofAvailableSpace="0.05" />
-        <!--  value in workspace spec using matchWorkspace -->
-        <gutter
-            launcher:matchWorkspace="true" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
-    </workspaceSpec>
+    <specs launcher:maxAspectRatio="10">
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="648dp">
+            <startPadding
+                launcher:ofAvailableSpace="0.0125" />
+            <endPadding
+                launcher:ofAvailableSpace="0.05" />
+            <!--  value in workspace spec using matchWorkspace -->
+            <gutter
+                launcher:matchWorkspace="true" />
+            <cellSize
+                launcher:ofRemainderSpace="0.2" />
+        </workspaceSpec>
 
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0306" />
-        <endPadding
-            launcher:ofAvailableSpace="0.068" />
-        <gutter
-            launcher:fixedSize="16dp" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
-    </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofAvailableSpace="0.0306" />
+            <endPadding
+                launcher:ofAvailableSpace="0.068" />
+            <gutter
+                launcher:fixedSize="16dp" />
+            <cellSize
+                launcher:ofRemainderSpace="0.2" />
+        </workspaceSpec>
 
-    <!-- Width spec is always the same -->
-    <workspaceSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <endPadding
-            launcher:ofRemainderSpace="0.21436227" />
-        <gutter
-            launcher:ofRemainderSpace="0.11425509" />
-        <cellSize
-            launcher:fixedSize="120dp" />
-    </workspaceSpec>
+        <!-- Width spec is always the same -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <endPadding
+                launcher:ofRemainderSpace="0.21436227" />
+            <gutter
+                launcher:ofRemainderSpace="0.11425509" />
+            <cellSize
+                launcher:fixedSize="120dp" />
+        </workspaceSpec>
+    </specs>
 </workspaceSpecs>
diff --git a/tests/res/xml/valid_all_apps_file.xml b/tests/res/xml/valid_all_apps_file.xml
index 0be55d1..f0967c4 100644
--- a/tests/res/xml/valid_all_apps_file.xml
+++ b/tests/res/xml/valid_all_apps_file.xml
@@ -15,22 +15,23 @@
   -->
 
 <allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <allAppsSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="0dp" />
-        <endPadding launcher:fixedSize="0dp" />
-        <gutter launcher:matchWorkspace="true" />
-        <cellSize launcher:matchWorkspace="true" />
-    </allAppsSpec>
+    <specs launcher:maxAspectRatio="10">
+        <allAppsSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="0dp" />
+            <gutter launcher:matchWorkspace="true" />
+            <cellSize launcher:matchWorkspace="true" />
+        </allAppsSpec>
 
-    <allAppsSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:matchWorkspace="true" />
-        <endPadding launcher:matchWorkspace="true" />
-        <gutter launcher:matchWorkspace="true" />
-        <cellSize launcher:matchWorkspace="true" />
-    </allAppsSpec>
-
+        <allAppsSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:matchWorkspace="true" />
+            <endPadding launcher:matchWorkspace="true" />
+            <gutter launcher:matchWorkspace="true" />
+            <cellSize launcher:matchWorkspace="true" />
+        </allAppsSpec>
+    </specs>
 </allAppsSpecs>
diff --git a/tests/res/xml/valid_folders_specs.xml b/tests/res/xml/valid_folders_specs.xml
index 0c45544..2ef59a9 100644
--- a/tests/res/xml/valid_folders_specs.xml
+++ b/tests/res/xml/valid_folders_specs.xml
@@ -14,25 +14,27 @@
   ~ limitations under the License.
   -->
 <folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:matchWorkspace="true" />
-    </folderSpec>
-    <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="16dp" />
-        <endPadding launcher:fixedSize="16dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="102dp" />
-    </folderSpec>
+    <specs launcher:maxAspectRatio="10">
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:matchWorkspace="true" />
+        </folderSpec>
+        <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="16dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="102dp" />
+        </folderSpec>
 
-    <!-- Height spec is fixed -->
-    <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="24dp" />
-        <!-- mapped to footer height size -->
-        <endPadding launcher:fixedSize="64dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:matchWorkspace="true" />
-    </folderSpec>
+        <!-- Height spec is fixed -->
+        <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="24dp" />
+            <!-- mapped to footer height size -->
+            <endPadding launcher:fixedSize="64dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:matchWorkspace="true" />
+        </folderSpec>
+    </specs>
 </folderSpecs>
diff --git a/tests/res/xml/valid_hotseat_file.xml b/tests/res/xml/valid_hotseat_file.xml
index f698bd1..d1c9e49 100644
--- a/tests/res/xml/valid_hotseat_file.xml
+++ b/tests/res/xml/valid_hotseat_file.xml
@@ -14,19 +14,19 @@
   ~ limitations under the License.
   -->
 <hotseatSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <specs launcher:maxAspectRatio="10">
+        <hotseatSpec
+            launcher:maxAvailableSize="847dp"
+            launcher:specType="height">
+            <hotseatQsbSpace launcher:fixedSize="24dp" />
+            <edgePadding launcher:fixedSize="48dp" />
+        </hotseatSpec>
 
-    <hotseatSpec
-        launcher:maxAvailableSize="847dp"
-        launcher:specType="height">
-        <hotseatQsbSpace launcher:fixedSize="24dp" />
-        <edgePadding launcher:fixedSize="48dp" />
-    </hotseatSpec>
-
-    <hotseatSpec
-        launcher:maxAvailableSize="9999dp"
-        launcher:specType="height">
-        <hotseatQsbSpace launcher:fixedSize="36dp" />
-        <edgePadding launcher:fixedSize="48dp" />
-    </hotseatSpec>
-
+        <hotseatSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="height">
+            <hotseatQsbSpace launcher:fixedSize="36dp" />
+            <edgePadding launcher:fixedSize="48dp" />
+        </hotseatSpec>
+    </specs>
 </hotseatSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/valid_hotseat_land_file.xml b/tests/res/xml/valid_hotseat_land_file.xml
index fc4a836..a72fd18 100644
--- a/tests/res/xml/valid_hotseat_land_file.xml
+++ b/tests/res/xml/valid_hotseat_land_file.xml
@@ -14,19 +14,19 @@
   ~ limitations under the License.
   -->
 <hotseatSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <specs launcher:maxAspectRatio="10">
+        <hotseatSpec
+            launcher:maxAvailableSize="743dp"
+            launcher:specType="width">
+            <hotseatQsbSpace launcher:fixedSize="0dp" />
+            <edgePadding launcher:fixedSize="48dp" />
+        </hotseatSpec>
 
-    <hotseatSpec
-        launcher:maxAvailableSize="743dp"
-        launcher:specType="width">
-        <hotseatQsbSpace launcher:fixedSize="0dp" />
-        <edgePadding launcher:fixedSize="48dp" />
-    </hotseatSpec>
-
-    <hotseatSpec
-        launcher:maxAvailableSize="9999dp"
-        launcher:specType="width">
-        <hotseatQsbSpace launcher:fixedSize="0dp" />
-        <edgePadding launcher:fixedSize="64dp" />
-    </hotseatSpec>
-
+        <hotseatSpec
+            launcher:maxAvailableSize="9999dp"
+            launcher:specType="width">
+            <hotseatQsbSpace launcher:fixedSize="0dp" />
+            <edgePadding launcher:fixedSize="64dp" />
+        </hotseatSpec>
+    </specs>
 </hotseatSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/valid_responsive_spec_unsorted.xml b/tests/res/xml/valid_responsive_spec_unsorted.xml
new file mode 100644
index 0000000..7cefc8e
--- /dev/null
+++ b/tests/res/xml/valid_responsive_spec_unsorted.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 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.
+  -->
+
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <specs launcher:maxAspectRatio="10">
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="34dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+
+        <!-- Height spec -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="371dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="24dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+
+        <!-- Width spec -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="716dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="64dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="36dp" />
+            <endPadding launcher:fixedSize="80dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="602dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="36dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+    </specs>
+
+    <!-- specs from land/handheld_workspace_spec_4x4.xml -->
+    <specs launcher:maxAspectRatio="12">
+        <!-- Height spec -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="2dp" />
+            <endPadding launcher:fixedSize="2dp" />
+            <gutter launcher:fixedSize="8dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+
+        <!-- Width spec -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="1dp" />
+            <endPadding launcher:fixedSize="1dp" />
+            <gutter launcher:fixedSize="8dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+    </specs>
+
+    <specs launcher:maxAspectRatio="1.05">
+        <!-- 584 grid height + 28 remainder space -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="612dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </workspaceSpec>
+
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="8dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </workspaceSpec>
+
+        <!-- 584 grid height -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="584dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="32dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:ofAvailableSpace="0.15808" />
+        </workspaceSpec>
+
+        <!-- Width spec is always the same -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="22dp" />
+            <endPadding launcher:fixedSize="22dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+    </specs>
+</workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_file.xml b/tests/res/xml/valid_workspace_file.xml
index 1f97314..da5ca11 100644
--- a/tests/res/xml/valid_workspace_file.xml
+++ b/tests/res/xml/valid_workspace_file.xml
@@ -15,45 +15,93 @@
   -->
 
 <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
-    <!-- 584 grid height -->
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="584dp">
-        <startPadding launcher:fixedSize="0dp" />
-        <endPadding launcher:fixedSize="32dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:ofAvailableSpace="0.15808" />
-    </workspaceSpec>
+    <specs launcher:maxAspectRatio="1.05">
+        <!-- 584 grid height -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="584dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="32dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:ofAvailableSpace="0.15808" />
+        </workspaceSpec>
 
-    <!-- 584 grid height + 28 remainder space -->
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="612dp">
-        <startPadding launcher:fixedSize="0dp" />
-        <endPadding launcher:ofRemainderSpace="1" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </workspaceSpec>
+        <!-- 584 grid height + 28 remainder space -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="612dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </workspaceSpec>
 
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="8dp" />
-        <endPadding launcher:ofRemainderSpace="1" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="8dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </workspaceSpec>
 
-    <!--  TODO(b/241386436): other specs here for height ...  -->
+        <!--  TODO(b/241386436): other specs here for height ...  -->
 
-    <!-- Width spec is always the same -->
-    <workspaceSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="22dp" />
-        <endPadding launcher:fixedSize="22dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:ofRemainderSpace="0.25" />
-    </workspaceSpec>
+        <!-- Width spec is always the same -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="22dp" />
+            <endPadding launcher:fixedSize="22dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+    </specs>
 
+    <!-- specs from land/handheld_workspace_spec_4x4.xml -->
+    <specs launcher:maxAspectRatio="99999">
+        <!-- Height spec -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="371dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="24dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="34dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+
+        <!-- Width spec -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="602dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="36dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="716dp">
+            <startPadding launcher:fixedSize="16dp" />
+            <endPadding launcher:fixedSize="64dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="36dp" />
+            <endPadding launcher:fixedSize="80dp" />
+            <gutter launcher:fixedSize="12dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+    </specs>
 </workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_unsorted_file.xml b/tests/res/xml/valid_workspace_unsorted_file.xml
index 1216c81..9f2bdc3 100644
--- a/tests/res/xml/valid_workspace_unsorted_file.xml
+++ b/tests/res/xml/valid_workspace_unsorted_file.xml
@@ -15,44 +15,44 @@
   -->
 
 <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <specs launcher:maxAspectRatio="1.05">
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="8dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </workspaceSpec>
 
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="8dp" />
-        <endPadding launcher:ofRemainderSpace="1" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </workspaceSpec>
+        <!-- 584 grid height -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="584dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:fixedSize="32dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:ofAvailableSpace="0.15808" />
+        </workspaceSpec>
 
-    <!-- 584 grid height -->
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="584dp">
-        <startPadding launcher:fixedSize="0dp" />
-        <endPadding launcher:fixedSize="32dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:ofAvailableSpace="0.15808" />
-    </workspaceSpec>
+        <!-- 584 grid height + 28 remainder space -->
+        <workspaceSpec
+            launcher:specType="height"
+            launcher:maxAvailableSize="612dp">
+            <startPadding launcher:fixedSize="0dp" />
+            <endPadding launcher:ofRemainderSpace="1" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:fixedSize="104dp" />
+        </workspaceSpec>
 
-    <!-- 584 grid height + 28 remainder space -->
-    <workspaceSpec
-        launcher:specType="height"
-        launcher:maxAvailableSize="612dp">
-        <startPadding launcher:fixedSize="0dp" />
-        <endPadding launcher:ofRemainderSpace="1" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:fixedSize="104dp" />
-    </workspaceSpec>
-
-    <!-- Width spec is always the same -->
-    <workspaceSpec
-        launcher:specType="width"
-        launcher:maxAvailableSize="9999dp">
-        <startPadding launcher:fixedSize="22dp" />
-        <endPadding launcher:fixedSize="22dp" />
-        <gutter launcher:fixedSize="16dp" />
-        <cellSize launcher:ofRemainderSpace="0.25" />
-    </workspaceSpec>
-
+        <!-- Width spec is always the same -->
+        <workspaceSpec
+            launcher:specType="width"
+            launcher:maxAvailableSize="9999dp">
+            <startPadding launcher:fixedSize="22dp" />
+            <endPadding launcher:fixedSize="22dp" />
+            <gutter launcher:fixedSize="16dp" />
+            <cellSize launcher:ofRemainderSpace="0.25" />
+        </workspaceSpec>
+    </specs>
 </workspaceSpecs>
diff --git a/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt b/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
index cd95e99..c99da96 100644
--- a/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
+++ b/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
@@ -21,6 +21,7 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
 import com.android.launcher3.tests.R as TestR
 import com.android.launcher3.util.TestResourceHelper
 import com.google.common.truth.Truth.assertThat
@@ -32,22 +33,30 @@
 @RunWith(AndroidJUnit4::class)
 class AllAppsSpecsTest : AbstractDeviceProfileTest() {
     override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+    val deviceSpec = deviceSpecs["phone"]!!
+    val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
 
     @Before
     fun setup() {
-        initializeVarsForPhone(deviceSpecs["phone"]!!)
+        initializeVarsForPhone(deviceSpec)
     }
 
     @Test
     fun parseValidFile() {
         val allAppsSpecs =
-            AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_all_apps_file))
-        assertThat(allAppsSpecs.heightSpecs.size).isEqualTo(1)
-        assertThat(allAppsSpecs.heightSpecs[0].toString())
+            ResponsiveSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_all_apps_file),
+                ResponsiveSpecType.AllApps
+            )
+
+        val specs = allAppsSpecs.getSpecsByAspectRatio(aspectRatio)
+        assertThat(specs.heightSpecs.size).isEqualTo(1)
+        assertThat(specs.heightSpecs[0].toString())
             .isEqualTo(
-                "AllAppsSpec(" +
+                "ResponsiveSpec(" +
                     "maxAvailableSize=26247, " +
-                    "specType=HEIGHT, " +
+                    "dimensionType=HEIGHT, " +
+                    "specType=AllApps, " +
                     "startPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
@@ -71,12 +80,13 @@
                     ")"
             )
 
-        assertThat(allAppsSpecs.widthSpecs.size).isEqualTo(1)
-        assertThat(allAppsSpecs.widthSpecs[0].toString())
+        assertThat(specs.widthSpecs.size).isEqualTo(1)
+        assertThat(specs.widthSpecs[0].toString())
             .isEqualTo(
-                "AllAppsSpec(" +
+                "ResponsiveSpec(" +
                     "maxAvailableSize=26247, " +
-                    "specType=WIDTH, " +
+                    "dimensionType=WIDTH, " +
+                    "specType=AllApps, " +
                     "startPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
@@ -103,16 +113,25 @@
 
     @Test(expected = IllegalStateException::class)
     fun parseInvalidFile_missingTag_throwsError() {
-        AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_1))
+        ResponsiveSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_1),
+            ResponsiveSpecType.AllApps
+        )
     }
 
     @Test(expected = IllegalStateException::class)
     fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
-        AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_2))
+        ResponsiveSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_2),
+            ResponsiveSpecType.AllApps
+        )
     }
 
     @Test(expected = IllegalStateException::class)
     fun parseInvalidFile_valueBiggerThan1_throwsError() {
-        AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_3))
+        ResponsiveSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_3),
+            ResponsiveSpecType.AllApps
+        )
     }
 }
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
index 0f12e58..1cc5ed2 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
+++ b/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
@@ -21,6 +21,8 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
 import com.android.launcher3.tests.R as TestR
 import com.android.launcher3.util.TestResourceHelper
 import com.google.common.truth.Truth.assertThat
@@ -40,6 +42,7 @@
     @Test
     fun normalPhone_copiesFromWorkspace() {
         val deviceSpec = deviceSpecs["phone"]!!
+        val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
         initializeVarsForPhone(deviceSpec)
 
         val availableWidth = deviceSpec.naturalSize.first
@@ -48,14 +51,30 @@
         val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495
 
         val workspaceSpecs =
-            WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
-        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
-        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+            ResponsiveSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_workspace_file),
+                ResponsiveSpecType.Workspace
+            )
+        val widthSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+        val heightSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
 
         val allAppsSpecs =
-            AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_all_apps_file))
+            ResponsiveSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_all_apps_file),
+                ResponsiveSpecType.AllApps
+            )
 
-        with(allAppsSpecs.getCalculatedWidthSpec(4, availableWidth, widthSpec)) {
+        with(
+            allAppsSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.WIDTH,
+                4,
+                availableWidth,
+                widthSpec
+            )
+        ) {
             assertThat(availableSpace).isEqualTo(availableWidth)
             assertThat(cells).isEqualTo(4)
             assertThat(startPaddingPx).isEqualTo(widthSpec.startPaddingPx)
@@ -64,7 +83,15 @@
             assertThat(cellSizePx).isEqualTo(widthSpec.cellSizePx)
         }
 
-        with(allAppsSpecs.getCalculatedHeightSpec(5, availableHeight, heightSpec)) {
+        with(
+            allAppsSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.HEIGHT,
+                5,
+                availableHeight,
+                heightSpec
+            )
+        ) {
             assertThat(availableSpace).isEqualTo(availableHeight)
             assertThat(cells).isEqualTo(5)
             assertThat(startPaddingPx).isEqualTo(0)
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
new file mode 100644
index 0000000..c4e2d2a
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 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.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CalculatedFolderSpecTest : AbstractDeviceProfileTest() {
+    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+    private val deviceSpec = deviceSpecs["phone"]!!
+    private val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+    @Before
+    fun setup() {
+        initializeVarsForPhone(deviceSpec)
+    }
+
+    @Test
+    fun validate_matchWidthWorkspace() {
+        val columns = 6
+
+        // Loading workspace specs
+        val resourceHelperWorkspace = TestResourceHelper(context, R.xml.valid_workspace_file)
+        val workspaceSpecs =
+            ResponsiveSpecsProvider.create(resourceHelperWorkspace, ResponsiveSpecType.Workspace)
+
+        // Loading folders specs
+        val resourceHelperFolder = TestResourceHelper(context, R.xml.valid_folders_specs)
+        val folderSpecs =
+            ResponsiveSpecsProvider.create(resourceHelperFolder, ResponsiveSpecType.Folder)
+        val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
+
+        assertThat(specs.widthSpecs.size).isEqualTo(2)
+        assertThat(specs.widthSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
+        assertThat(specs.widthSpecs[1].cellSize.matchWorkspace).isEqualTo(false)
+
+        // Validate width spec <= 800
+        var availableWidth = deviceSpec.naturalSize.first
+        var calculatedWorkspace =
+            workspaceSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.WIDTH,
+                columns,
+                availableWidth
+            )
+        var calculatedWidthFolderSpec =
+            folderSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.WIDTH,
+                columns,
+                availableWidth,
+                calculatedWorkspace
+            )
+        with(calculatedWidthFolderSpec) {
+            assertThat(availableSpace).isEqualTo(availableWidth)
+            assertThat(cells).isEqualTo(columns)
+            assertThat(startPaddingPx).isEqualTo(16.dpToPx())
+            assertThat(endPaddingPx).isEqualTo(16.dpToPx())
+            assertThat(gutterPx).isEqualTo(16.dpToPx())
+            assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
+        }
+
+        // Validate width spec > 800
+        availableWidth = 2000.dpToPx()
+        calculatedWorkspace =
+            workspaceSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.WIDTH,
+                columns,
+                availableWidth
+            )
+        calculatedWidthFolderSpec =
+            folderSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.WIDTH,
+                columns,
+                availableWidth,
+                calculatedWorkspace
+            )
+        with(calculatedWidthFolderSpec) {
+            assertThat(availableSpace).isEqualTo(availableWidth)
+            assertThat(cells).isEqualTo(columns)
+            assertThat(startPaddingPx).isEqualTo(16.dpToPx())
+            assertThat(endPaddingPx).isEqualTo(16.dpToPx())
+            assertThat(gutterPx).isEqualTo(16.dpToPx())
+            assertThat(cellSizePx).isEqualTo(102.dpToPx())
+        }
+    }
+
+    @Test
+    fun validate_matchHeightWorkspace() {
+        // Hotseat is roughly 495px on a real device, it doesn't need to be precise on unit tests
+        val hotseatSize = 495
+        val statusBarHeight = deviceSpec.statusBarNaturalPx
+        val availableHeight = deviceSpec.naturalSize.second - statusBarHeight - hotseatSize
+        val rows = 5
+
+        // Loading workspace specs
+        val resourceHelperWorkspace = TestResourceHelper(context, R.xml.valid_workspace_file)
+        val workspaceSpecs =
+            ResponsiveSpecsProvider.create(resourceHelperWorkspace, ResponsiveSpecType.Workspace)
+
+        // Loading folders specs
+        val resourceHelperFolder = TestResourceHelper(context, R.xml.valid_folders_specs)
+        val folderSpecs =
+            ResponsiveSpecsProvider.create(resourceHelperFolder, ResponsiveSpecType.Folder)
+        val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
+
+        assertThat(specs.heightSpecs.size).isEqualTo(1)
+        assertThat(specs.heightSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
+
+        // Validate height spec
+        val calculatedWorkspace =
+            workspaceSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.HEIGHT,
+                rows,
+                availableHeight
+            )
+        val calculatedFolderSpec =
+            folderSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.HEIGHT,
+                rows,
+                availableHeight,
+                calculatedWorkspace
+            )
+        with(calculatedFolderSpec) {
+            assertThat(availableSpace).isEqualTo(availableHeight)
+            assertThat(cells).isEqualTo(rows)
+            assertThat(startPaddingPx).isEqualTo(24.dpToPx())
+            assertThat(endPaddingPx).isEqualTo(64.dpToPx())
+            assertThat(gutterPx).isEqualTo(16.dpToPx())
+            assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecsTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecsTest.kt
deleted file mode 100644
index f2a269a..0000000
--- a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecsTest.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2023 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.responsive
-
-import android.content.Context
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.launcher3.AbstractDeviceProfileTest
-import com.android.launcher3.tests.R
-import com.android.launcher3.util.TestResourceHelper
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class CalculatedFolderSpecsTest : AbstractDeviceProfileTest() {
-    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
-
-    private val deviceSpec = deviceSpecs["phone"]!!
-
-    @Before
-    fun setup() {
-        initializeVarsForPhone(deviceSpec)
-    }
-
-    @Test
-    fun validate_matchWidthWorkspace() {
-        val columns = 6
-
-        // Loading workspace specs
-        val resourceHelperWorkspace = TestResourceHelper(context!!, R.xml.valid_workspace_file)
-        val workspaceSpecs = WorkspaceSpecs.create(resourceHelperWorkspace)
-
-        // Loading folders specs
-        val resourceHelperFolder = TestResourceHelper(context!!, R.xml.valid_folders_specs)
-        val folderSpecs = FolderSpecs.create(resourceHelperFolder)
-
-        assertThat(folderSpecs.widthSpecs.size).isEqualTo(2)
-        assertThat(folderSpecs.widthSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
-        assertThat(folderSpecs.widthSpecs[1].cellSize.matchWorkspace).isEqualTo(false)
-
-        // Validate width spec <= 800
-        var availableWidth = deviceSpec.naturalSize.first
-        var calculatedWorkspace = workspaceSpecs.getCalculatedWidthSpec(columns, availableWidth)
-        var calculatedWidthFolderSpec =
-            folderSpecs.getCalculatedWidthSpec(columns, availableWidth, calculatedWorkspace)
-        with(calculatedWidthFolderSpec) {
-            assertThat(availableSpace).isEqualTo(availableWidth)
-            assertThat(cells).isEqualTo(columns)
-            assertThat(startPaddingPx).isEqualTo(16.dpToPx())
-            assertThat(endPaddingPx).isEqualTo(16.dpToPx())
-            assertThat(gutterPx).isEqualTo(16.dpToPx())
-            assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
-        }
-
-        // Validate width spec > 800
-        availableWidth = 2000.dpToPx()
-        calculatedWorkspace = workspaceSpecs.getCalculatedWidthSpec(columns, availableWidth)
-        calculatedWidthFolderSpec =
-            folderSpecs.getCalculatedWidthSpec(columns, availableWidth, calculatedWorkspace)
-        with(calculatedWidthFolderSpec) {
-            assertThat(availableSpace).isEqualTo(availableWidth)
-            assertThat(cells).isEqualTo(columns)
-            assertThat(startPaddingPx).isEqualTo(16.dpToPx())
-            assertThat(endPaddingPx).isEqualTo(16.dpToPx())
-            assertThat(gutterPx).isEqualTo(16.dpToPx())
-            assertThat(cellSizePx).isEqualTo(102.dpToPx())
-        }
-    }
-
-    @Test
-    fun validate_matchHeightWorkspace() {
-        // Hotseat is roughly 495px on a real device, it doesn't need to be precise on unit tests
-        val hotseatSize = 495
-        val statusBarHeight = deviceSpec.statusBarNaturalPx
-        val availableHeight = deviceSpec.naturalSize.second - statusBarHeight - hotseatSize
-        val rows = 5
-
-        // Loading workspace specs
-        val resourceHelperWorkspace = TestResourceHelper(context!!, R.xml.valid_workspace_file)
-        val workspaceSpecs = WorkspaceSpecs.create(resourceHelperWorkspace)
-
-        // Loading folders specs
-        val resourceHelperFolder = TestResourceHelper(context!!, R.xml.valid_folders_specs)
-        val folderSpecs = FolderSpecs.create(resourceHelperFolder)
-
-        assertThat(folderSpecs.heightSpecs.size).isEqualTo(1)
-        assertThat(folderSpecs.heightSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
-
-        // Validate height spec
-        val calculatedWorkspace = workspaceSpecs.getCalculatedHeightSpec(rows, availableHeight)
-        val calculatedFolderSpec =
-            folderSpecs.getCalculatedHeightSpec(rows, availableHeight, calculatedWorkspace)
-        with(calculatedFolderSpec) {
-            assertThat(availableSpace).isEqualTo(availableHeight)
-            assertThat(cells).isEqualTo(rows)
-            assertThat(startPaddingPx).isEqualTo(24.dpToPx())
-            assertThat(endPaddingPx).isEqualTo(64.dpToPx())
-            assertThat(gutterPx).isEqualTo(16.dpToPx())
-            assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
-        }
-    }
-}
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
index 5865036..1a564ac 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
+++ b/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
@@ -21,6 +21,7 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
 import com.android.launcher3.tests.R as TestR
 import com.android.launcher3.util.TestResourceHelper
 import com.google.common.truth.Truth.assertThat
@@ -31,6 +32,8 @@
 @RunWith(AndroidJUnit4::class)
 class CalculatedHotseatSpecTest : AbstractDeviceProfileTest() {
     override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+    val deviceSpec = deviceSpecs["phone"]!!
+    val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
 
     /**
      * This test tests:
@@ -38,15 +41,19 @@
      */
     @Test
     fun normalPhone_returnsSecondBreakpointSpec() {
-        val deviceSpec = deviceSpecs["phone"]!!
         initializeVarsForPhone(deviceSpec)
 
         // Hotseat uses the whole device height
         val availableHeight = deviceSpec.naturalSize.second
 
-        val hotseatSpecs =
-            HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_file))
-        val heightSpec = hotseatSpecs.getCalculatedHeightSpec(availableHeight)
+        val hotseatSpecsProvider =
+            HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+        val heightSpec =
+            hotseatSpecsProvider.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.HEIGHT,
+                availableHeight
+            )
 
         assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
         assertThat(heightSpec.hotseatQsbSpace).isEqualTo(95)
@@ -59,16 +66,20 @@
      */
     @Test
     fun smallPhone_returnsFirstBreakpointSpec() {
-        val deviceSpec = deviceSpecs["phone"]!!
         deviceSpec.densityDpi = 540 // larger display size
         initializeVarsForPhone(deviceSpec)
 
         // Hotseat uses the whole device height
         val availableHeight = deviceSpec.naturalSize.second
 
-        val hotseatSpecs =
-            HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_file))
-        val heightSpec = hotseatSpecs.getCalculatedHeightSpec(availableHeight)
+        val hotseatSpecsProvider =
+            HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+        val heightSpec =
+            hotseatSpecsProvider.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.HEIGHT,
+                availableHeight
+            )
 
         assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
         assertThat(heightSpec.hotseatQsbSpace).isEqualTo(81)
@@ -81,15 +92,17 @@
      */
     @Test
     fun normalPhoneLandscape_returnsSecondBreakpointSpec() {
-        val deviceSpec = deviceSpecs["phone"]!!
         initializeVarsForPhone(deviceSpec, isVerticalBar = true)
 
         // Hotseat uses the whole device width
         val availableWidth = deviceSpec.naturalSize.second
 
-        val hotseatSpecs =
-            HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_land_file))
-        val widthSpec = hotseatSpecs.getCalculatedWidthSpec(availableWidth)
+        val hotseatSpecsProvider =
+            HotseatSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_hotseat_land_file)
+            )
+        val widthSpec =
+            hotseatSpecsProvider.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, availableWidth)
 
         assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
         assertThat(widthSpec.hotseatQsbSpace).isEqualTo(0)
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
index 8f56c5f..0c5d347 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
+++ b/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
@@ -21,6 +21,8 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
 import com.android.launcher3.tests.R as TestR
 import com.android.launcher3.util.TestResourceHelper
 import com.google.common.truth.Truth.assertThat
@@ -41,6 +43,7 @@
     @Test
     fun normalPhone_returnsThirdBreakpointSpec() {
         val deviceSpec = deviceSpecs["phone"]!!
+        val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
         initializeVarsForPhone(deviceSpec)
 
         val availableWidth = deviceSpec.naturalSize.first
@@ -49,9 +52,14 @@
         val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495
 
         val workspaceSpecs =
-            WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
-        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
-        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+            ResponsiveSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_workspace_file),
+                ResponsiveSpecType.Workspace
+            )
+        val widthSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+        val heightSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
 
         assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
         assertThat(widthSpec.cells).isEqualTo(4)
@@ -77,6 +85,7 @@
     @Test
     fun smallPhone_returnsFirstBreakpointSpec() {
         val deviceSpec = deviceSpecs["phone"]!!
+        val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
         deviceSpec.densityDpi = 540 // larger display size
         initializeVarsForPhone(deviceSpec)
 
@@ -86,9 +95,14 @@
         val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 640
 
         val workspaceSpecs =
-            WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
-        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
-        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+            ResponsiveSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_workspace_file),
+                ResponsiveSpecType.Workspace
+            )
+        val widthSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+        val heightSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
 
         assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
         assertThat(widthSpec.cells).isEqualTo(4)
@@ -114,6 +128,7 @@
     @Test
     fun smallPhone_returnsFirstBreakpointSpec_unsortedFile() {
         val deviceSpec = deviceSpecs["phone"]!!
+        val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
         deviceSpec.densityDpi = 540 // larger display size
         initializeVarsForPhone(deviceSpec)
 
@@ -121,13 +136,15 @@
         // Hotseat size is roughly 640px on a real device,
         // it doesn't need to be precise on unit tests
         val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 640
-
         val workspaceSpecs =
-            WorkspaceSpecs.create(
-                TestResourceHelper(context!!, TestR.xml.valid_workspace_unsorted_file)
+            ResponsiveSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_workspace_unsorted_file),
+                ResponsiveSpecType.Workspace
             )
-        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
-        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+        val widthSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+        val heightSpec =
+            workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
 
         assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
         assertThat(widthSpec.cells).isEqualTo(4)
diff --git a/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt b/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt
new file mode 100644
index 0000000..1756c9a
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2023 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.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FolderSpecTest : AbstractDeviceProfileTest() {
+    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+    val deviceSpec = deviceSpecs["tablet"]!!
+    val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+    @Before
+    fun setup() {
+        initializeVarsForPhone(deviceSpec)
+    }
+
+    @Test
+    fun parseValidFile() {
+        val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+        val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+        val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
+
+        val sizeSpec16 = SizeSpec(16f.dpToPx())
+        val widthSpecsExpected =
+            listOf(
+                ResponsiveSpec(
+                    maxAvailableSize = 800.dpToPx(),
+                    dimensionType = DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Folder,
+                    startPadding = sizeSpec16,
+                    endPadding = sizeSpec16,
+                    gutter = sizeSpec16,
+                    cellSize = SizeSpec(matchWorkspace = true)
+                ),
+                ResponsiveSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Folder,
+                    startPadding = sizeSpec16,
+                    endPadding = sizeSpec16,
+                    gutter = sizeSpec16,
+                    cellSize = SizeSpec(102f.dpToPx())
+                )
+            )
+
+        val heightSpecsExpected =
+            ResponsiveSpec(
+                maxAvailableSize = 9999.dpToPx(),
+                dimensionType = DimensionType.HEIGHT,
+                specType = ResponsiveSpecType.Folder,
+                startPadding = SizeSpec(24f.dpToPx()),
+                endPadding = SizeSpec(64f.dpToPx()),
+                gutter = sizeSpec16,
+                cellSize = SizeSpec(matchWorkspace = true)
+            )
+
+        assertThat(specs.widthSpecs.size).isEqualTo(widthSpecsExpected.size)
+        assertThat(specs.widthSpecs[0]).isEqualTo(widthSpecsExpected[0])
+        assertThat(specs.widthSpecs[1]).isEqualTo(widthSpecsExpected[1])
+
+        assertThat(specs.heightSpecs.size).isEqualTo(1)
+        assertThat(specs.heightSpecs[0]).isEqualTo(heightSpecsExpected)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_missingTag_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_1)
+        ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_2)
+        ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_valueBiggerThan1_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_3)
+        ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_missingSpecs_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_4)
+        ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_missingWidthBreakpoint_throwsError() {
+        val availableSpace = 900.dpToPx()
+        val cells = 3
+
+        val workspaceSpec =
+            ResponsiveSpec(
+                maxAvailableSize = availableSpace,
+                dimensionType = DimensionType.WIDTH,
+                specType = ResponsiveSpecType.Folder,
+                startPadding = SizeSpec(fixedSize = 10f),
+                endPadding = SizeSpec(fixedSize = 10f),
+                gutter = SizeSpec(fixedSize = 10f),
+                cellSize = SizeSpec(fixedSize = 10f)
+            )
+        val calculatedWorkspaceSpec = CalculatedResponsiveSpec(availableSpace, cells, workspaceSpec)
+
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_5)
+        val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+        folderSpecs.getCalculatedSpec(
+            aspectRatio,
+            DimensionType.WIDTH,
+            cells,
+            availableSpace,
+            calculatedWorkspaceSpec
+        )
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_missingHeightBreakpoint_throwsError() {
+        val availableSpace = 900.dpToPx()
+        val cells = 3
+
+        val workspaceSpec =
+            ResponsiveSpec(
+                maxAvailableSize = availableSpace,
+                dimensionType = DimensionType.HEIGHT,
+                specType = ResponsiveSpecType.Folder,
+                startPadding = SizeSpec(fixedSize = 10f),
+                endPadding = SizeSpec(fixedSize = 10f),
+                gutter = SizeSpec(fixedSize = 10f),
+                cellSize = SizeSpec(fixedSize = 10f)
+            )
+        val calculatedWorkspaceSpec = CalculatedResponsiveSpec(availableSpace, cells, workspaceSpec)
+
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_5)
+        val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+        folderSpecs.getCalculatedSpec(
+            aspectRatio,
+            DimensionType.HEIGHT,
+            cells,
+            availableSpace,
+            calculatedWorkspaceSpec
+        )
+    }
+
+    @Test
+    fun retrievesCalculatedWidthSpec() {
+        val availableSpace = 800.dpToPx()
+        val cells = 3
+
+        val workspaceSpec =
+            ResponsiveSpec(
+                maxAvailableSize = availableSpace,
+                dimensionType = DimensionType.WIDTH,
+                specType = ResponsiveSpecType.Workspace,
+                startPadding = SizeSpec(fixedSize = 10f),
+                endPadding = SizeSpec(fixedSize = 10f),
+                gutter = SizeSpec(fixedSize = 10f),
+                cellSize = SizeSpec(fixedSize = 10f)
+            )
+        val calculatedWorkspaceSpec = CalculatedResponsiveSpec(availableSpace, cells, workspaceSpec)
+
+        val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+        val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+        val calculatedWidthSpec =
+            folderSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.WIDTH,
+                cells,
+                availableSpace,
+                calculatedWorkspaceSpec
+            )
+
+        assertThat(calculatedWidthSpec.cells).isEqualTo(cells)
+        assertThat(calculatedWidthSpec.availableSpace).isEqualTo(availableSpace)
+        assertThat(calculatedWidthSpec.startPaddingPx).isEqualTo(16.dpToPx())
+        assertThat(calculatedWidthSpec.endPaddingPx).isEqualTo(16.dpToPx())
+        assertThat(calculatedWidthSpec.gutterPx).isEqualTo(16.dpToPx())
+        assertThat(calculatedWidthSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun retrievesCalculatedWidthSpec_invalidCalculatedResponsiveSpecType_throwsError() {
+        val availableSpace = 10.dpToPx()
+        val cells = 3
+
+        val workspaceSpec =
+            ResponsiveSpec(
+                maxAvailableSize = availableSpace,
+                dimensionType = DimensionType.HEIGHT,
+                specType = ResponsiveSpecType.Folder,
+                startPadding = SizeSpec(fixedSize = 10f),
+                endPadding = SizeSpec(fixedSize = 10f),
+                gutter = SizeSpec(fixedSize = 10f),
+                cellSize = SizeSpec(fixedSize = 10f)
+            )
+        val calculatedWorkspaceSpec = CalculatedResponsiveSpec(availableSpace, cells, workspaceSpec)
+
+        val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+        val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+        folderSpecs.getCalculatedSpec(
+            aspectRatio,
+            DimensionType.WIDTH,
+            cells,
+            availableSpace,
+            calculatedWorkspaceSpec
+        )
+    }
+
+    @Test
+    fun retrievesCalculatedHeightSpec() {
+        val availableSpace = 700.dpToPx()
+        val cells = 3
+
+        val workspaceSpec =
+            ResponsiveSpec(
+                maxAvailableSize = availableSpace,
+                dimensionType = DimensionType.HEIGHT,
+                specType = ResponsiveSpecType.Workspace,
+                startPadding = SizeSpec(fixedSize = 10f),
+                endPadding = SizeSpec(fixedSize = 10f),
+                gutter = SizeSpec(fixedSize = 10f),
+                cellSize = SizeSpec(fixedSize = 10f)
+            )
+        val calculatedWorkspaceSpec = CalculatedResponsiveSpec(availableSpace, cells, workspaceSpec)
+
+        val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+        val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+        val calculatedHeightSpec =
+            folderSpecs.getCalculatedSpec(
+                aspectRatio,
+                DimensionType.HEIGHT,
+                cells,
+                availableSpace,
+                calculatedWorkspaceSpec
+            )
+
+        assertThat(calculatedHeightSpec.cells).isEqualTo(cells)
+        assertThat(calculatedHeightSpec.availableSpace).isEqualTo(availableSpace)
+        assertThat(calculatedHeightSpec.startPaddingPx).isEqualTo(24.dpToPx())
+        assertThat(calculatedHeightSpec.endPaddingPx).isEqualTo(64.dpToPx())
+        assertThat(calculatedHeightSpec.gutterPx).isEqualTo(16.dpToPx())
+        assertThat(calculatedHeightSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun retrievesCalculatedHeightSpec_invalidCalculatedResponsiveSpecType_throwsError() {
+        val availableSpace = 10.dpToPx()
+        val cells = 3
+
+        val workspaceSpec =
+            ResponsiveSpec(
+                maxAvailableSize = availableSpace,
+                dimensionType = DimensionType.WIDTH,
+                specType = ResponsiveSpecType.Folder,
+                startPadding = SizeSpec(fixedSize = 10f),
+                endPadding = SizeSpec(fixedSize = 10f),
+                gutter = SizeSpec(fixedSize = 10f),
+                cellSize = SizeSpec(fixedSize = 10f)
+            )
+        val calculatedWorkspaceSpec = CalculatedResponsiveSpec(availableSpace, cells, workspaceSpec)
+
+        val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+        val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+        folderSpecs.getCalculatedSpec(
+            aspectRatio,
+            DimensionType.HEIGHT,
+            cells,
+            availableSpace,
+            calculatedWorkspaceSpec
+        )
+    }
+}
diff --git a/tests/src/com/android/launcher3/responsive/FolderSpecsTest.kt b/tests/src/com/android/launcher3/responsive/FolderSpecsTest.kt
deleted file mode 100644
index 4b05949..0000000
--- a/tests/src/com/android/launcher3/responsive/FolderSpecsTest.kt
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2023 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.responsive
-
-import android.content.Context
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.launcher3.AbstractDeviceProfileTest
-import com.android.launcher3.responsive.ResponsiveSpec.SpecType
-import com.android.launcher3.tests.R
-import com.android.launcher3.util.TestResourceHelper
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class FolderSpecsTest : AbstractDeviceProfileTest() {
-    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
-
-    @Before
-    fun setup() {
-        initializeVarsForPhone(deviceSpecs["tablet"]!!)
-    }
-
-    @Test
-    fun parseValidFile() {
-        val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
-        val folderSpecs = FolderSpecs.create(resourceHelper)
-
-        val sizeSpec16 = SizeSpec(16f.dpToPx())
-        val widthSpecsExpected =
-            listOf(
-                FolderSpec(
-                    maxAvailableSize = 800.dpToPx(),
-                    specType = SpecType.WIDTH,
-                    startPadding = sizeSpec16,
-                    endPadding = sizeSpec16,
-                    gutter = sizeSpec16,
-                    cellSize = SizeSpec(matchWorkspace = true)
-                ),
-                FolderSpec(
-                    maxAvailableSize = 9999.dpToPx(),
-                    specType = SpecType.WIDTH,
-                    startPadding = sizeSpec16,
-                    endPadding = sizeSpec16,
-                    gutter = sizeSpec16,
-                    cellSize = SizeSpec(102f.dpToPx())
-                )
-            )
-
-        val heightSpecsExpected =
-            FolderSpec(
-                maxAvailableSize = 9999.dpToPx(),
-                specType = SpecType.HEIGHT,
-                startPadding = SizeSpec(24f.dpToPx()),
-                endPadding = SizeSpec(64f.dpToPx()),
-                gutter = sizeSpec16,
-                cellSize = SizeSpec(matchWorkspace = true)
-            )
-
-        assertThat(folderSpecs.widthSpecs.size).isEqualTo(widthSpecsExpected.size)
-        assertThat(folderSpecs.widthSpecs[0]).isEqualTo(widthSpecsExpected[0])
-        assertThat(folderSpecs.widthSpecs[1]).isEqualTo(widthSpecsExpected[1])
-
-        assertThat(folderSpecs.heightSpecs.size).isEqualTo(1)
-        assertThat(folderSpecs.heightSpecs[0]).isEqualTo(heightSpecsExpected)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun parseInvalidFile_missingTag_throwsError() {
-        val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_1)
-        FolderSpecs.create(resourceHelper)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
-        val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_2)
-        FolderSpecs.create(resourceHelper)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun parseInvalidFile_valueBiggerThan1_throwsError() {
-        val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_3)
-        FolderSpecs.create(resourceHelper)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun parseInvalidFile_missingSpecs_throwsError() {
-        val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_4)
-        FolderSpecs.create(resourceHelper)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun parseInvalidFile_missingWidthBreakpoint_throwsError() {
-        val availableSpace = 900.dpToPx()
-        val cells = 3
-
-        val workspaceSpec =
-            WorkspaceSpec(
-                maxAvailableSize = availableSpace,
-                specType = SpecType.WIDTH,
-                startPadding = SizeSpec(fixedSize = 10f),
-                endPadding = SizeSpec(fixedSize = 10f),
-                gutter = SizeSpec(fixedSize = 10f),
-                cellSize = SizeSpec(fixedSize = 10f)
-            )
-        val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
-        val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_5)
-        val folderSpecs = FolderSpecs.create(resourceHelper)
-        folderSpecs.getCalculatedWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun parseInvalidFile_missingHeightBreakpoint_throwsError() {
-        val availableSpace = 900.dpToPx()
-        val cells = 3
-
-        val workspaceSpec =
-            WorkspaceSpec(
-                maxAvailableSize = availableSpace,
-                specType = SpecType.HEIGHT,
-                startPadding = SizeSpec(fixedSize = 10f),
-                endPadding = SizeSpec(fixedSize = 10f),
-                gutter = SizeSpec(fixedSize = 10f),
-                cellSize = SizeSpec(fixedSize = 10f)
-            )
-        val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
-        val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_5)
-        val folderSpecs = FolderSpecs.create(resourceHelper)
-        folderSpecs.getCalculatedHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
-    }
-
-    @Test
-    fun retrievesCalculatedWidthSpec() {
-        val availableSpace = 800.dpToPx()
-        val cells = 3
-
-        val workspaceSpec =
-            WorkspaceSpec(
-                maxAvailableSize = availableSpace,
-                specType = SpecType.WIDTH,
-                startPadding = SizeSpec(fixedSize = 10f),
-                endPadding = SizeSpec(fixedSize = 10f),
-                gutter = SizeSpec(fixedSize = 10f),
-                cellSize = SizeSpec(fixedSize = 10f)
-            )
-        val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
-        val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
-        val folderSpecs = FolderSpecs.create(resourceHelper)
-        val calculatedWidthSpec =
-            folderSpecs.getCalculatedWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
-
-        assertThat(calculatedWidthSpec.cells).isEqualTo(cells)
-        assertThat(calculatedWidthSpec.availableSpace).isEqualTo(availableSpace)
-        assertThat(calculatedWidthSpec.startPaddingPx).isEqualTo(16.dpToPx())
-        assertThat(calculatedWidthSpec.endPaddingPx).isEqualTo(16.dpToPx())
-        assertThat(calculatedWidthSpec.gutterPx).isEqualTo(16.dpToPx())
-        assertThat(calculatedWidthSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun retrievesCalculatedWidthSpec_invalidCalculatedWorkspaceSpecType_throwsError() {
-        val availableSpace = 10.dpToPx()
-        val cells = 3
-
-        val workspaceSpec =
-            WorkspaceSpec(
-                maxAvailableSize = availableSpace,
-                specType = SpecType.HEIGHT,
-                startPadding = SizeSpec(fixedSize = 10f),
-                endPadding = SizeSpec(fixedSize = 10f),
-                gutter = SizeSpec(fixedSize = 10f),
-                cellSize = SizeSpec(fixedSize = 10f)
-            )
-        val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
-        val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
-        val folderSpecs = FolderSpecs.create(resourceHelper)
-        folderSpecs.getCalculatedWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
-    }
-
-    @Test
-    fun retrievesCalculatedHeightSpec() {
-        val availableSpace = 700.dpToPx()
-        val cells = 3
-
-        val workspaceSpec =
-            WorkspaceSpec(
-                maxAvailableSize = availableSpace,
-                specType = SpecType.HEIGHT,
-                startPadding = SizeSpec(fixedSize = 10f),
-                endPadding = SizeSpec(fixedSize = 10f),
-                gutter = SizeSpec(fixedSize = 10f),
-                cellSize = SizeSpec(fixedSize = 10f)
-            )
-        val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
-        val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
-        val folderSpecs = FolderSpecs.create(resourceHelper)
-        val calculatedHeightSpec =
-            folderSpecs.getCalculatedHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
-
-        assertThat(calculatedHeightSpec.cells).isEqualTo(cells)
-        assertThat(calculatedHeightSpec.availableSpace).isEqualTo(availableSpace)
-        assertThat(calculatedHeightSpec.startPaddingPx).isEqualTo(24.dpToPx())
-        assertThat(calculatedHeightSpec.endPaddingPx).isEqualTo(64.dpToPx())
-        assertThat(calculatedHeightSpec.gutterPx).isEqualTo(16.dpToPx())
-        assertThat(calculatedHeightSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun retrievesCalculatedHeightSpec_invalidCalculatedWorkspaceSpecType_throwsError() {
-        val availableSpace = 10.dpToPx()
-        val cells = 3
-
-        val workspaceSpec =
-            WorkspaceSpec(
-                maxAvailableSize = availableSpace,
-                specType = SpecType.WIDTH,
-                startPadding = SizeSpec(fixedSize = 10f),
-                endPadding = SizeSpec(fixedSize = 10f),
-                gutter = SizeSpec(fixedSize = 10f),
-                cellSize = SizeSpec(fixedSize = 10f)
-            )
-        val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
-        val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
-        val folderSpecs = FolderSpecs.create(resourceHelper)
-        folderSpecs.getCalculatedHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
-    }
-}
diff --git a/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt b/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
new file mode 100644
index 0000000..32249e0
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 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.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.tests.R as TestR
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class HotseatSpecsProviderTest : AbstractDeviceProfileTest() {
+    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+    val deviceSpec = deviceSpecs["phone"]!!
+    val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+    @Before
+    fun setup() {
+        initializeVarsForPhone(deviceSpec)
+    }
+
+    @Test
+    fun parseValidFile() {
+        val hotseatSpecsProvider =
+            HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+        val specs = hotseatSpecsProvider.getSpecsByAspectRatio(aspectRatio)
+
+        val expectedHeightSpecs =
+            listOf(
+                HotseatSpec(
+                    maxAvailableSize = 847.dpToPx(),
+                    dimensionType = ResponsiveSpec.DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Hotseat,
+                    hotseatQsbSpace = SizeSpec(24f.dpToPx()),
+                    edgePadding = SizeSpec(48f.dpToPx())
+                ),
+                HotseatSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = ResponsiveSpec.DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Hotseat,
+                    hotseatQsbSpace = SizeSpec(36f.dpToPx()),
+                    edgePadding = SizeSpec(48f.dpToPx())
+                ),
+            )
+
+        assertThat(specs.heightSpecs.size).isEqualTo(expectedHeightSpecs.size)
+        assertThat(specs.heightSpecs[0]).isEqualTo(expectedHeightSpecs[0])
+        assertThat(specs.heightSpecs[1]).isEqualTo(expectedHeightSpecs[1])
+
+        assertThat(specs.widthSpecs.size).isEqualTo(0)
+    }
+
+    @Test
+    fun parseValidLandscapeFile() {
+        val hotseatSpecsProvider =
+            HotseatSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_hotseat_land_file)
+            )
+        val specs = hotseatSpecsProvider.getSpecsByAspectRatio(aspectRatio)
+        assertThat(specs.heightSpecs.size).isEqualTo(0)
+
+        val expectedWidthSpecs =
+            listOf(
+                HotseatSpec(
+                    maxAvailableSize = 743.dpToPx(),
+                    dimensionType = ResponsiveSpec.DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Hotseat,
+                    hotseatQsbSpace = SizeSpec(0f),
+                    edgePadding = SizeSpec(48f.dpToPx())
+                ),
+                HotseatSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = ResponsiveSpec.DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Hotseat,
+                    hotseatQsbSpace = SizeSpec(0f),
+                    edgePadding = SizeSpec(64f.dpToPx())
+                ),
+            )
+
+        assertThat(specs.widthSpecs.size).isEqualTo(expectedWidthSpecs.size)
+        assertThat(specs.widthSpecs[0]).isEqualTo(expectedWidthSpecs[0])
+        assertThat(specs.widthSpecs[1]).isEqualTo(expectedWidthSpecs[1])
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_spaceIsNotFixedSize_throwsError() {
+        HotseatSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_hotseat_file_case_1)
+        )
+    }
+}
diff --git a/tests/src/com/android/launcher3/responsive/HotseatSpecsTest.kt b/tests/src/com/android/launcher3/responsive/HotseatSpecsTest.kt
deleted file mode 100644
index f650e91..0000000
--- a/tests/src/com/android/launcher3/responsive/HotseatSpecsTest.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2023 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.responsive
-
-import android.content.Context
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.launcher3.AbstractDeviceProfileTest
-import com.android.launcher3.tests.R as TestR
-import com.android.launcher3.util.TestResourceHelper
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class HotseatSpecsTest : AbstractDeviceProfileTest() {
-    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
-
-    @Before
-    fun setup() {
-        initializeVarsForPhone(deviceSpecs["phone"]!!)
-    }
-
-    @Test
-    fun parseValidFile() {
-        val hotseatSpecs =
-            HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_file))
-
-        val expectedHeightSpecs =
-            listOf(
-                HotseatSpec(
-                    maxAvailableSize = 847.dpToPx(),
-                    specType = ResponsiveSpec.SpecType.HEIGHT,
-                    hotseatQsbSpace = SizeSpec(24f.dpToPx()),
-                    edgePadding = SizeSpec(48f.dpToPx())
-                ),
-                HotseatSpec(
-                    maxAvailableSize = 9999.dpToPx(),
-                    specType = ResponsiveSpec.SpecType.HEIGHT,
-                    hotseatQsbSpace = SizeSpec(36f.dpToPx()),
-                    edgePadding = SizeSpec(48f.dpToPx())
-                ),
-            )
-
-        assertThat(hotseatSpecs.heightSpecs.size).isEqualTo(expectedHeightSpecs.size)
-        assertThat(hotseatSpecs.heightSpecs[0]).isEqualTo(expectedHeightSpecs[0])
-        assertThat(hotseatSpecs.heightSpecs[1]).isEqualTo(expectedHeightSpecs[1])
-
-        assertThat(hotseatSpecs.widthSpecs.size).isEqualTo(0)
-    }
-
-    @Test
-    fun parseValidLandscapeFile() {
-        val hotseatSpecs =
-            HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_land_file))
-        assertThat(hotseatSpecs.heightSpecs.size).isEqualTo(0)
-
-        val expectedWidthSpecs =
-            listOf(
-                HotseatSpec(
-                    maxAvailableSize = 743.dpToPx(),
-                    specType = ResponsiveSpec.SpecType.WIDTH,
-                    hotseatQsbSpace = SizeSpec(0f),
-                    edgePadding = SizeSpec(48f.dpToPx())
-                ),
-                HotseatSpec(
-                    maxAvailableSize = 9999.dpToPx(),
-                    specType = ResponsiveSpec.SpecType.WIDTH,
-                    hotseatQsbSpace = SizeSpec(0f),
-                    edgePadding = SizeSpec(64f.dpToPx())
-                ),
-            )
-
-        assertThat(hotseatSpecs.widthSpecs.size).isEqualTo(expectedWidthSpecs.size)
-        assertThat(hotseatSpecs.widthSpecs[0]).isEqualTo(expectedWidthSpecs[0])
-        assertThat(hotseatSpecs.widthSpecs[1]).isEqualTo(expectedWidthSpecs[1])
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun parseInvalidFile_spaceIsNotFixedSize_throwsError() {
-        HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_hotseat_file_case_1))
-    }
-}
diff --git a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
new file mode 100644
index 0000000..7af0823
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2023 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.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ResponsiveSpecsProviderTest : AbstractDeviceProfileTest() {
+    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+    val deviceSpec = deviceSpecs["tablet"]!!
+    var aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+    @Before
+    fun setup() {
+        initializeVarsForPhone(deviceSpec)
+    }
+
+    @Test
+    fun parseValidFile() {
+        val resourceHelper = TestResourceHelper(context, R.xml.valid_responsive_spec_unsorted)
+        val provider = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+
+        // Validate Portrait
+        val aspectRatioPortrait = 1.0f
+        val portraitSpecs = provider.getSpecsByAspectRatio(aspectRatioPortrait)
+
+        val (expectedPortWidthSpecs, expectedPortHeightSpecs) = expectedPortraitSpecs()
+        validateSpecs(
+            portraitSpecs,
+            aspectRatioPortrait,
+            expectedPortWidthSpecs,
+            expectedPortHeightSpecs
+        )
+
+        // Validate Landscape
+        val aspectRatioLandscape = 1.051f
+        val landscapeSpecs = provider.getSpecsByAspectRatio(aspectRatioLandscape)
+
+        val (expectedLandWidthSpecs, expectedLandHeightSpecs) = expectedLandscapeSpecs()
+        validateSpecs(
+            landscapeSpecs,
+            aspectRatioLandscape,
+            expectedLandWidthSpecs,
+            expectedLandHeightSpecs
+        )
+
+        // Validate Extra Spec
+        val aspectRatioExtra = 10.1f
+        val extraSpecs = provider.getSpecsByAspectRatio(aspectRatioExtra)
+
+        val expectedOtherWidthSpecs =
+            listOf(
+                ResponsiveSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(1f.dpToPx()),
+                    endPadding = SizeSpec(1f.dpToPx()),
+                    gutter = SizeSpec(8f.dpToPx()),
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                )
+            )
+
+        val expectedOtherHeightSpecs =
+            listOf(
+                ResponsiveSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(2f.dpToPx()),
+                    endPadding = SizeSpec(2f.dpToPx()),
+                    gutter = SizeSpec(8f.dpToPx()),
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                ),
+            )
+
+        validateSpecs(
+            extraSpecs,
+            aspectRatioExtra,
+            expectedOtherWidthSpecs,
+            expectedOtherHeightSpecs
+        )
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseValidFile_invalidAspectRatio_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.valid_responsive_spec_unsorted)
+        val provider = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+        provider.getSpecsByAspectRatio(0f)
+    }
+
+    @Test(expected = InvalidResponsiveGridSpec::class)
+    fun parseInvalidFile_missingGroups_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_1)
+        ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+    }
+
+    @Test(expected = InvalidResponsiveGridSpec::class)
+    fun parseInvalidFile_partialGroups_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_2)
+        ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun parseInvalidFile_invalidAspectRatio_throwsError() {
+        val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_3)
+        ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+    }
+
+    private fun validateSpecs(
+        specs: ResponsiveSpecGroup<ResponsiveSpec>,
+        expectedAspectRatio: Float,
+        expectedWidthSpecs: List<ResponsiveSpec>,
+        expectedHeightSpecs: List<ResponsiveSpec>
+    ) {
+        assertThat(specs.aspectRatio).isAtLeast(expectedAspectRatio)
+
+        assertThat(specs.widthSpecs.size).isEqualTo(expectedWidthSpecs.size)
+        specs.widthSpecs.forEachIndexed { index, responsiveSpec ->
+            assertThat(responsiveSpec).isEqualTo(expectedWidthSpecs[index])
+        }
+
+        assertThat(specs.heightSpecs.size).isEqualTo(expectedHeightSpecs.size)
+        specs.heightSpecs.forEachIndexed { index, responsiveSpec ->
+            assertThat(responsiveSpec).isEqualTo(expectedHeightSpecs[index])
+        }
+    }
+
+    private fun expectedPortraitSpecs(): Pair<List<ResponsiveSpec>, List<ResponsiveSpec>> {
+        val sizeSpec16 = SizeSpec(16f.dpToPx())
+        val expectedWidthSpecs =
+            listOf(
+                ResponsiveSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(22f.dpToPx()),
+                    endPadding = SizeSpec(22f.dpToPx()),
+                    gutter = sizeSpec16,
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                )
+            )
+
+        val expectedHeightSpecs =
+            listOf(
+                ResponsiveSpec(
+                    maxAvailableSize = 584.dpToPx(),
+                    dimensionType = DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(0f),
+                    endPadding = SizeSpec(32f.dpToPx()),
+                    gutter = sizeSpec16,
+                    cellSize = SizeSpec(ofAvailableSpace = .15808f)
+                ),
+                ResponsiveSpec(
+                    maxAvailableSize = 612.dpToPx(),
+                    dimensionType = DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(0f),
+                    endPadding = SizeSpec(ofRemainderSpace = 1f),
+                    gutter = sizeSpec16,
+                    cellSize = SizeSpec(104f.dpToPx())
+                ),
+                ResponsiveSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(8f.dpToPx()),
+                    endPadding = SizeSpec(ofRemainderSpace = 1f),
+                    gutter = sizeSpec16,
+                    cellSize = SizeSpec(104f.dpToPx())
+                ),
+            )
+
+        return Pair(expectedWidthSpecs, expectedHeightSpecs)
+    }
+
+    private fun expectedLandscapeSpecs(): Pair<List<ResponsiveSpec>, List<ResponsiveSpec>> {
+        val sizeSpec12 = SizeSpec(12f.dpToPx())
+        val expectedWidthSpecs =
+            listOf(
+                ResponsiveSpec(
+                    maxAvailableSize = 602.dpToPx(),
+                    dimensionType = DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(0f.dpToPx()),
+                    endPadding = SizeSpec(36f.dpToPx()),
+                    gutter = sizeSpec12,
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                ),
+                ResponsiveSpec(
+                    maxAvailableSize = 716.dpToPx(),
+                    dimensionType = DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(16f.dpToPx()),
+                    endPadding = SizeSpec(64f.dpToPx()),
+                    gutter = sizeSpec12,
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                ),
+                ResponsiveSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = DimensionType.WIDTH,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(36f.dpToPx()),
+                    endPadding = SizeSpec(80f.dpToPx()),
+                    gutter = sizeSpec12,
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                )
+            )
+
+        val expectedHeightSpecs =
+            listOf(
+                ResponsiveSpec(
+                    maxAvailableSize = 371.dpToPx(),
+                    dimensionType = DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(0f),
+                    endPadding = SizeSpec(24f.dpToPx()),
+                    gutter = sizeSpec12,
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                ),
+                ResponsiveSpec(
+                    maxAvailableSize = 9999.dpToPx(),
+                    dimensionType = DimensionType.HEIGHT,
+                    specType = ResponsiveSpecType.Workspace,
+                    startPadding = SizeSpec(0f),
+                    endPadding = SizeSpec(34f.dpToPx()),
+                    gutter = sizeSpec12,
+                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                ),
+            )
+
+        return Pair(expectedWidthSpecs, expectedHeightSpecs)
+    }
+}
diff --git a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
index 0364069..9781645 100644
--- a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
+++ b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
@@ -21,6 +21,7 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
 import com.android.launcher3.tests.R as TestR
 import com.android.launcher3.util.TestResourceHelper
 import com.google.common.truth.Truth.assertThat
@@ -32,22 +33,30 @@
 @RunWith(AndroidJUnit4::class)
 class WorkspaceSpecsTest : AbstractDeviceProfileTest() {
     override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+    val deviceSpec = deviceSpecs["phone"]!!
+    val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
 
     @Before
     fun setup() {
-        initializeVarsForPhone(deviceSpecs["phone"]!!)
+        initializeVarsForPhone(deviceSpec)
     }
 
     @Test
     fun parseValidFile() {
         val workspaceSpecs =
-            WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
-        assertThat(workspaceSpecs.heightSpecs.size).isEqualTo(3)
-        assertThat(workspaceSpecs.heightSpecs[0].toString())
+            ResponsiveSpecsProvider.create(
+                TestResourceHelper(context, TestR.xml.valid_workspace_file),
+                ResponsiveSpecType.Workspace
+            )
+
+        val specs = workspaceSpecs.getSpecsByAspectRatio(aspectRatio)
+        assertThat(specs.heightSpecs.size).isEqualTo(3)
+        assertThat(specs.heightSpecs[0].toString())
             .isEqualTo(
-                "WorkspaceSpec(" +
+                "ResponsiveSpec(" +
                     "maxAvailableSize=1533, " +
-                    "specType=HEIGHT, " +
+                    "dimensionType=HEIGHT, " +
+                    "specType=Workspace, " +
                     "startPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
@@ -70,11 +79,12 @@
                     "maxSize=2147483647)" +
                     ")"
             )
-        assertThat(workspaceSpecs.heightSpecs[1].toString())
+        assertThat(specs.heightSpecs[1].toString())
             .isEqualTo(
-                "WorkspaceSpec(" +
+                "ResponsiveSpec(" +
                     "maxAvailableSize=1607, " +
-                    "specType=HEIGHT, " +
+                    "dimensionType=HEIGHT, " +
+                    "specType=Workspace, " +
                     "startPadding=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
@@ -97,11 +107,12 @@
                     "maxSize=2147483647)" +
                     ")"
             )
-        assertThat(workspaceSpecs.heightSpecs[2].toString())
+        assertThat(specs.heightSpecs[2].toString())
             .isEqualTo(
-                "WorkspaceSpec(" +
+                "ResponsiveSpec(" +
                     "maxAvailableSize=26247, " +
-                    "specType=HEIGHT, " +
+                    "dimensionType=HEIGHT, " +
+                    "specType=Workspace, " +
                     "startPadding=SizeSpec(fixedSize=21.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
@@ -124,12 +135,13 @@
                     "maxSize=2147483647)" +
                     ")"
             )
-        assertThat(workspaceSpecs.widthSpecs.size).isEqualTo(1)
-        assertThat(workspaceSpecs.widthSpecs[0].toString())
+        assertThat(specs.widthSpecs.size).isEqualTo(1)
+        assertThat(specs.widthSpecs[0].toString())
             .isEqualTo(
-                "WorkspaceSpec(" +
+                "ResponsiveSpec(" +
                     "maxAvailableSize=26247, " +
-                    "specType=WIDTH, " +
+                    "dimensionType=WIDTH, " +
+                    "specType=Workspace, " +
                     "startPadding=SizeSpec(fixedSize=58.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0, " +
@@ -156,29 +168,33 @@
 
     @Test(expected = IllegalStateException::class)
     fun parseInvalidFile_missingTag_throwsError() {
-        WorkspaceSpecs.create(
-            TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_1)
+        ResponsiveSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_1),
+            ResponsiveSpecType.Workspace
         )
     }
 
     @Test(expected = IllegalStateException::class)
     fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
-        WorkspaceSpecs.create(
-            TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_2)
+        ResponsiveSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_2),
+            ResponsiveSpecType.Workspace
         )
     }
 
     @Test(expected = IllegalStateException::class)
     fun parseInvalidFile_valueBiggerThan1_throwsError() {
-        WorkspaceSpecs.create(
-            TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_3)
+        ResponsiveSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_3),
+            ResponsiveSpecType.Workspace
         )
     }
 
     @Test(expected = IllegalStateException::class)
     fun parseInvalidFile_matchWorkspace_true_throwsError() {
-        WorkspaceSpecs.create(
-            TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_4)
+        ResponsiveSpecsProvider.create(
+            TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_4),
+            ResponsiveSpecType.Workspace
         )
     }
 }
diff --git a/tests/src/com/android/launcher3/util/TestResourceHelper.kt b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
index cf80ece..b4d3ba8 100644
--- a/tests/src/com/android/launcher3/util/TestResourceHelper.kt
+++ b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
@@ -32,6 +32,8 @@
                 styleId.contentEquals(R.styleable.WorkspaceSpec) -> TestR.styleable.WorkspaceSpec
                 styleId.contentEquals(R.styleable.FolderSpec) -> TestR.styleable.FolderSpec
                 styleId.contentEquals(R.styleable.AllAppsSpec) -> TestR.styleable.AllAppsSpec
+                styleId.contentEquals(R.styleable.ResponsiveSpecGroup) ->
+                    TestR.styleable.ResponsiveSpecGroup
                 else -> styleId.clone()
             }