Merge "Revert "Grant Launcher permission to access AppSearch"" into udc-dev
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index 49dfe46..08857b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -130,6 +130,8 @@
         applyThumbnail(mThumbnailView2, task2, thumbnailUpdateFunction);
 
         if (iconUpdateFunction == null) {
+            applyIcon(mIcon1, task1);
+            applyIcon(mIcon2, task2);
             setContentDescription(task2 == null
                     ? task1.titleDescription
                     : getContext().getString(
@@ -183,8 +185,8 @@
         thumbnailView.setImageBitmap(bm);
     }
 
-    private void applyIcon(@Nullable ImageView iconView, @NonNull Task task) {
-        if (iconView == null) {
+    private void applyIcon(@Nullable ImageView iconView, @Nullable Task task) {
+        if (iconView == null || task == null) {
             return;
         }
         iconView.setVisibility(VISIBLE);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 88fea31..0a83279 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -36,6 +36,7 @@
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.Pair;
 import android.view.DragEvent;
 import android.view.MotionEvent;
@@ -87,6 +88,7 @@
  */
 public class TaskbarDragController extends DragController<BaseTaskbarContext> implements
         TaskbarControllers.LoggableTaskbarController {
+    private static final String TAG = "TaskbarDragController";
 
     private static final boolean DEBUG_DRAG_SHADOW_SURFACE = false;
     private static final int ANIM_DURATION_RETURN_ICON_TO_TASKBAR = 300;
@@ -318,12 +320,26 @@
             @Override
             public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
                 int iconSize = Math.max(mDragIconSize, btv.getWidth());
-                shadowSize.set(iconSize, iconSize);
+                if (iconSize > 0) {
+                    shadowSize.set(iconSize, iconSize);
+                } else {
+                    Log.d(TAG, "Invalid icon size, dragSize=" + mDragIconSize
+                            + " viewWidth=" + btv.getWidth());
+                }
+
                 // The registration point was taken before the icon scaled to mDragIconSize, so
                 // offset the registration to where the touch is on the new size.
                 int offsetX = (mDragIconSize - mDragObject.dragView.getDragRegionWidth()) / 2;
                 int offsetY = (mDragIconSize - mDragObject.dragView.getDragRegionHeight()) / 2;
-                shadowTouchPoint.set(mRegistrationX + offsetX, mRegistrationY + offsetY);
+                int touchX = mRegistrationX + offsetX;
+                int touchY = mRegistrationY + offsetY;
+                if (touchX >= 0 && touchY >= 0) {
+                    shadowTouchPoint.set(touchX, touchY);
+                } else {
+                    Log.d(TAG, "Invalid touch point, "
+                            + "registrationXY=(" + mRegistrationX + ", " + mRegistrationY + ") "
+                            + "offsetXY=(" + offsetX + ", " + offsetY + ")");
+                }
             }
 
             @Override
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0231090..fb41044 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -55,7 +55,10 @@
 import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.ResourceHelper;
 import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.workspace.CalculatedWorkspaceSpec;
+import com.android.launcher3.workspace.WorkspaceSpecs;
 
 import java.io.PrintWriter;
 import java.util.Locale;
@@ -101,9 +104,14 @@
     public final float aspectRatio;
 
     public final boolean isScalableGrid;
-    public final boolean isResponsiveGrid;
     private final int mTypeIndex;
 
+    // Responsive grid
+    private final boolean mIsResponsiveGrid;
+    private WorkspaceSpecs mWorkspaceSpecs;
+    private CalculatedWorkspaceSpec mResponsiveWidthSpec;
+    private CalculatedWorkspaceSpec mResponsiveHeightSpec;
+
     /**
      * The maximum amount of left/right workspace padding as a percentage of the screen width.
      * To be clear, this means that up to 7% of the screen width can be used as left padding, and
@@ -294,9 +302,8 @@
         this.rotationHint = windowBounds.rotationHint;
         mInsets.set(windowBounds.insets);
 
-        // TODO(b/241386436):
-        //  for testing that the flag works only, shouldn't change any launcher behaviour
-        isResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;
+        // TODO(b/241386436): shouldn't change any launcher behaviour
+        mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;
 
         isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
         // Determine device posture.
@@ -335,6 +342,14 @@
             }
         }
 
+        if (mIsResponsiveGrid) {
+            mWorkspaceSpecs = new WorkspaceSpecs(new ResourceHelper(context, inv.workspaceSpecsId));
+            mResponsiveWidthSpec = mWorkspaceSpecs.getCalculatedWidthSpec(inv.numColumns,
+                    availableWidthPx);
+            mResponsiveHeightSpec = mWorkspaceSpecs.getCalculatedHeightSpec(inv.numRows,
+                    availableHeightPx);
+        }
+
         if (DisplayController.isTransientTaskbar(context)) {
             float invTransientIconSizeDp = inv.transientTaskbarIconSize[mTypeIndex];
             taskbarIconSize = pxFromDp(invTransientIconSizeDp, mMetrics);
@@ -1582,7 +1597,7 @@
 
         writer.println(prefix + "\taspectRatio:" + aspectRatio);
 
-        writer.println(prefix + "\tisResponsiveGrid:" + isResponsiveGrid);
+        writer.println(prefix + "\tisResponsiveGrid:" + mIsResponsiveGrid);
         writer.println(prefix + "\tisScalableGrid:" + isScalableGrid);
 
         writer.println(prefix + "\tinv.numRows: " + inv.numRows);
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index a671c6e..30af502 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -45,7 +45,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.testing.shared.TestProtocol;
@@ -53,7 +52,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.function.Predicate;
 
@@ -97,15 +95,7 @@
             StatsLogManager statsLogManager) {
         mUserManager = userManager;
         mAllApps = allApps;
-        boolean cloningChanges = FeatureFlags.ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER.get();
-        if (TestProtocol.sDebugTracing) {
-            Log.d(WORK_TAB_MISSING, "matcher flag: " + cloningChanges);
-        }
-        if (cloningChanges) {
-            mMatcher = ofWorkProfileUser(userManager);
-        } else {
-            mMatcher = mAllApps.mPersonalMatcher.negate();
-        }
+        mMatcher = mAllApps.mPersonalMatcher.negate();
         mStatsLogManager = statsLogManager;
     }
 
@@ -280,27 +270,4 @@
             }
         };
     }
-
-    /**
-     * Filter to only display apps in managed profile in work tab.
-     */
-    private Predicate<ItemInfo> ofWorkProfileUser(UserManager um) {
-        return info -> info != null && isManagedProfile(um, info.user.hashCode());
-    }
-
-
-    private static boolean isManagedProfile(UserManager um, int userId) {
-        try {
-            // isManagedProfile is a @SystemApi.
-            String methodName = "isManagedProfile";
-            Method method = um.getClass().getDeclaredMethod(methodName, int.class);
-            Object result = method.invoke(um, userId);
-            if (result instanceof Boolean) {
-                return (boolean) result;
-            }
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to call #isManagedProfile via reflection from Launcher");
-        }
-        return false;
-    }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6699825..621c2ab 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -213,11 +213,6 @@
     public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
             "ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar.");
 
-    // TODO(Block 15): Clean up flags
-    public static final BooleanFlag ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER = getDebugFlag(266177840,
-            "ENABLE_APP_CLONING_CHANGES_IN_LAUNCHER", DISABLED,
-            "Removes clone apps from the work profile tab.");
-
     // TODO(Block 16): Clean up flags
     // When enabled the promise icon is visible in all apps while installation an app.
     public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012,
diff --git a/src/com/android/launcher3/workspace/WorkspaceSpecs.kt b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
index 971fd9b..ac0a166 100644
--- a/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
+++ b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt
@@ -25,6 +25,7 @@
 import com.android.launcher3.R
 import com.android.launcher3.util.ResourceHelper
 import java.io.IOException
+import kotlin.math.roundToInt
 import org.xmlpull.v1.XmlPullParser
 import org.xmlpull.v1.XmlPullParserException
 
@@ -159,6 +160,77 @@
             }
         }
     }
+
+    /**
+     * Returns the CalculatedWorkspaceSpec for width, based on the available width and the
+     * WorkspaceSpecs.
+     */
+    fun getCalculatedWidthSpec(columns: Int, availableWidth: Int): CalculatedWorkspaceSpec {
+        val widthSpec = workspaceWidthSpecList.first { availableWidth <= it.maxAvailableSize }
+
+        return CalculatedWorkspaceSpec(availableWidth, columns, widthSpec)
+    }
+
+    /**
+     * Returns the CalculatedWorkspaceSpec for height, based on the available height and the
+     * WorkspaceSpecs.
+     */
+    fun getCalculatedHeightSpec(rows: Int, availableHeight: Int): CalculatedWorkspaceSpec {
+        val heightSpec = workspaceHeightSpecList.first { availableHeight <= it.maxAvailableSize }
+
+        return CalculatedWorkspaceSpec(availableHeight, rows, heightSpec)
+    }
+}
+
+class CalculatedWorkspaceSpec(
+    val availableSpace: Int,
+    val cells: Int,
+    val workspaceSpec: WorkspaceSpec
+) {
+    var startPaddingPx: Int = 0
+        private set
+    var endPaddingPx: Int = 0
+        private set
+    var gutterPx: Int = 0
+        private set
+    var cellSizePx: Int = 0
+        private set
+    init {
+        // Calculate all fixed size first
+        if (workspaceSpec.startPadding.fixedSize > 0)
+            startPaddingPx = workspaceSpec.startPadding.fixedSize.roundToInt()
+        if (workspaceSpec.endPadding.fixedSize > 0)
+            endPaddingPx = workspaceSpec.endPadding.fixedSize.roundToInt()
+        if (workspaceSpec.gutter.fixedSize > 0)
+            gutterPx = workspaceSpec.gutter.fixedSize.roundToInt()
+        if (workspaceSpec.cellSize.fixedSize > 0)
+            cellSizePx = workspaceSpec.cellSize.fixedSize.roundToInt()
+
+        // Calculate all available space next
+        if (workspaceSpec.startPadding.ofAvailableSpace > 0)
+            startPaddingPx =
+                (workspaceSpec.startPadding.ofAvailableSpace * availableSpace).roundToInt()
+        if (workspaceSpec.endPadding.ofAvailableSpace > 0)
+            endPaddingPx = (workspaceSpec.endPadding.ofAvailableSpace * availableSpace).roundToInt()
+        if (workspaceSpec.gutter.ofAvailableSpace > 0)
+            gutterPx = (workspaceSpec.gutter.ofAvailableSpace * availableSpace).roundToInt()
+        if (workspaceSpec.cellSize.ofAvailableSpace > 0)
+            cellSizePx = (workspaceSpec.cellSize.ofAvailableSpace * availableSpace).roundToInt()
+
+        // Calculate remainder space last
+        val gutters = cells - 1
+        val usedSpace = startPaddingPx + endPaddingPx + (gutterPx * gutters) + (cellSizePx * cells)
+        val remainderSpace = availableSpace - usedSpace
+        if (workspaceSpec.startPadding.ofRemainderSpace > 0)
+            startPaddingPx =
+                (workspaceSpec.startPadding.ofRemainderSpace * remainderSpace).roundToInt()
+        if (workspaceSpec.endPadding.ofRemainderSpace > 0)
+            endPaddingPx = (workspaceSpec.endPadding.ofRemainderSpace * remainderSpace).roundToInt()
+        if (workspaceSpec.gutter.ofRemainderSpace > 0)
+            gutterPx = (workspaceSpec.gutter.ofRemainderSpace * remainderSpace).roundToInt()
+        if (workspaceSpec.cellSize.ofRemainderSpace > 0)
+            cellSizePx = (workspaceSpec.cellSize.ofRemainderSpace * remainderSpace).roundToInt()
+    }
 }
 
 data class WorkspaceSpec(
@@ -220,7 +292,7 @@
 
     fun isValid(): Boolean {
         // All attributes are empty
-        if (fixedSize <= 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
+        if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
             Log.e(TAG, "SizeSpec#isValid - all attributes are empty")
             return false
         }
diff --git a/tests/res/xml/valid_workspace_file.xml b/tests/res/xml/valid_workspace_file.xml
index 91a3e48..1f97314 100644
--- a/tests/res/xml/valid_workspace_file.xml
+++ b/tests/res/xml/valid_workspace_file.xml
@@ -15,43 +15,45 @@
   -->
 
 <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+    <!-- 584 grid height -->
     <workspaceSpec
         launcher:specType="height"
-        launcher:maxAvailableSize="648dp">
-        <startPadding
-            launcher:ofAvailableSpace="0.0125" />
-        <endPadding
-            launcher:ofAvailableSpace="0.05" />
-        <gutter
-            launcher:fixedSize="16dp" />
-        <cellSize
-            launcher:ofRemainderSpace="0.2" />
+        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>
 
     <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" />
+        <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 ...  -->
+
     <!-- 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" />
+        <startPadding launcher:fixedSize="22dp" />
+        <endPadding launcher:fixedSize="22dp" />
+        <gutter launcher:fixedSize="16dp" />
+        <cellSize launcher:ofRemainderSpace="0.25" />
     </workspaceSpec>
+
 </workspaceSpecs>
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 01f494b..3de4d55 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -66,7 +66,7 @@
 
     class DeviceSpec(
         val naturalSize: Pair<Int, Int>,
-        val densityDpi: Int,
+        var densityDpi: Int,
         val statusBarNaturalPx: Int,
         val statusBarRotatedPx: Int,
         val gesturePx: Int,
diff --git a/tests/src/com/android/launcher3/workspace/CalculatedWorkspaceSpecTest.kt b/tests/src/com/android/launcher3/workspace/CalculatedWorkspaceSpecTest.kt
new file mode 100644
index 0000000..7f03ba2
--- /dev/null
+++ b/tests/src/com/android/launcher3/workspace/CalculatedWorkspaceSpecTest.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.workspace
+
+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.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CalculatedWorkspaceSpecTest : AbstractDeviceProfileTest() {
+    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+
+    /**
+     * This test tests:
+     * - (height spec) gets the correct breakpoint from the XML - skips the first 2 breakpoints
+     * - (height spec) do the correct calculations for available space and fixed size
+     * - (width spec) do the correct calculations for remainder space and fixed size
+     */
+    @Test
+    fun normalPhone_returnsThirdBreakpointSpec() {
+        val deviceSpec = deviceSpecs["phone"]!!
+        initializeVarsForPhone(deviceSpec)
+
+        val availableWidth = deviceSpec.naturalSize.first
+        // Hotseat size is roughly 495px on a real device,
+        // it doesn't need to be precise on unit tests
+        val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495
+
+        val workspaceSpecs =
+            WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
+        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
+        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+
+        assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
+        assertThat(widthSpec.cells).isEqualTo(4)
+        assertThat(widthSpec.startPaddingPx).isEqualTo(58)
+        assertThat(widthSpec.endPaddingPx).isEqualTo(58)
+        assertThat(widthSpec.gutterPx).isEqualTo(42)
+        assertThat(widthSpec.cellSizePx).isEqualTo(210)
+
+        assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
+        assertThat(heightSpec.cells).isEqualTo(5)
+        assertThat(heightSpec.startPaddingPx).isEqualTo(21)
+        assertThat(heightSpec.endPaddingPx).isEqualTo(233)
+        assertThat(heightSpec.gutterPx).isEqualTo(42)
+        assertThat(heightSpec.cellSizePx).isEqualTo(273)
+    }
+
+    /**
+     * This test tests:
+     * - (height spec) gets the correct breakpoint from the XML - use the first breakpoint
+     * - (height spec) do the correct calculations for remainder space and fixed size
+     * - (width spec) do the correct calculations for remainder space and fixed size
+     */
+    @Test
+    fun smallPhone_returnsFirstBreakpointSpec() {
+        val deviceSpec = deviceSpecs["phone"]!!
+        deviceSpec.densityDpi = 540 // larger display size
+        initializeVarsForPhone(deviceSpec)
+
+        val availableWidth = deviceSpec.naturalSize.first
+        // 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(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
+        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
+        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+
+        assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
+        assertThat(widthSpec.cells).isEqualTo(4)
+        assertThat(widthSpec.startPaddingPx).isEqualTo(74)
+        assertThat(widthSpec.endPaddingPx).isEqualTo(74)
+        assertThat(widthSpec.gutterPx).isEqualTo(54)
+        assertThat(widthSpec.cellSizePx).isEqualTo(193)
+
+        assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
+        assertThat(heightSpec.cells).isEqualTo(5)
+        assertThat(heightSpec.startPaddingPx).isEqualTo(0)
+        assertThat(heightSpec.endPaddingPx).isEqualTo(108)
+        assertThat(heightSpec.gutterPx).isEqualTo(54)
+        assertThat(heightSpec.cellSizePx).isEqualTo(260)
+    }
+}
diff --git a/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
index 0fd8a54..9cd0a2e 100644
--- a/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
+++ b/tests/src/com/android/launcher3/workspace/WorkspaceSpecsTest.kt
@@ -42,43 +42,62 @@
     fun parseValidFile() {
         val workspaceSpecs =
             WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
-        assertThat(workspaceSpecs.workspaceHeightSpecList.size).isEqualTo(2)
+        assertThat(workspaceSpecs.workspaceHeightSpecList.size).isEqualTo(3)
         assertThat(workspaceSpecs.workspaceHeightSpecList[0].toString())
             .isEqualTo(
                 "WorkspaceSpec(" +
-                    "maxAvailableSize=1701, " +
+                    "maxAvailableSize=1533, " +
                     "specType=HEIGHT, " +
                     "startPadding=SizeSpec(fixedSize=0.0, " +
-                    "ofAvailableSpace=0.0125, " +
+                    "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0), " +
-                    "endPadding=SizeSpec(fixedSize=0.0, " +
-                    "ofAvailableSpace=0.05, " +
+                    "endPadding=SizeSpec(fixedSize=84.0, " +
+                    "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0), " +
                     "gutter=SizeSpec(fixedSize=42.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0), " +
                     "cellSize=SizeSpec(fixedSize=0.0, " +
-                    "ofAvailableSpace=0.0, " +
-                    "ofRemainderSpace=0.2)" +
+                    "ofAvailableSpace=0.15808, " +
+                    "ofRemainderSpace=0.0)" +
                     ")"
             )
         assertThat(workspaceSpecs.workspaceHeightSpecList[1].toString())
             .isEqualTo(
                 "WorkspaceSpec(" +
-                    "maxAvailableSize=26247, " +
+                    "maxAvailableSize=1607, " +
                     "specType=HEIGHT, " +
                     "startPadding=SizeSpec(fixedSize=0.0, " +
-                    "ofAvailableSpace=0.0306, " +
+                    "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0), " +
                     "endPadding=SizeSpec(fixedSize=0.0, " +
-                    "ofAvailableSpace=0.068, " +
-                    "ofRemainderSpace=0.0), " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=1.0), " +
                     "gutter=SizeSpec(fixedSize=42.0, " +
                     "ofAvailableSpace=0.0, " +
                     "ofRemainderSpace=0.0), " +
-                    "cellSize=SizeSpec(fixedSize=0.0, " +
+                    "cellSize=SizeSpec(fixedSize=273.0, " +
                     "ofAvailableSpace=0.0, " +
-                    "ofRemainderSpace=0.2)" +
+                    "ofRemainderSpace=0.0)" +
+                    ")"
+            )
+        assertThat(workspaceSpecs.workspaceHeightSpecList[2].toString())
+            .isEqualTo(
+                "WorkspaceSpec(" +
+                    "maxAvailableSize=26247, " +
+                    "specType=HEIGHT, " +
+                    "startPadding=SizeSpec(fixedSize=21.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0), " +
+                    "endPadding=SizeSpec(fixedSize=0.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=1.0), " +
+                    "gutter=SizeSpec(fixedSize=42.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0), " +
+                    "cellSize=SizeSpec(fixedSize=273.0, " +
+                    "ofAvailableSpace=0.0, " +
+                    "ofRemainderSpace=0.0)" +
                     ")"
             )
         assertThat(workspaceSpecs.workspaceWidthSpecList.size).isEqualTo(1)
@@ -87,18 +106,18 @@
                 "WorkspaceSpec(" +
                     "maxAvailableSize=26247, " +
                     "specType=WIDTH, " +
-                    "startPadding=SizeSpec(fixedSize=0.0, " +
+                    "startPadding=SizeSpec(fixedSize=58.0, " +
                     "ofAvailableSpace=0.0, " +
-                    "ofRemainderSpace=0.21436226), " +
-                    "endPadding=SizeSpec(fixedSize=0.0, " +
+                    "ofRemainderSpace=0.0), " +
+                    "endPadding=SizeSpec(fixedSize=58.0, " +
                     "ofAvailableSpace=0.0, " +
-                    "ofRemainderSpace=0.21436226), " +
-                    "gutter=SizeSpec(fixedSize=0.0, " +
+                    "ofRemainderSpace=0.0), " +
+                    "gutter=SizeSpec(fixedSize=42.0, " +
                     "ofAvailableSpace=0.0, " +
-                    "ofRemainderSpace=0.11425509), " +
-                    "cellSize=SizeSpec(fixedSize=315.0, " +
+                    "ofRemainderSpace=0.0), " +
+                    "cellSize=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
-                    "ofRemainderSpace=0.0)" +
+                    "ofRemainderSpace=0.25)" +
                     ")"
             )
     }