Merge "Use T50 base instead of T95" into tm-dev
diff --git a/go/quickstep/src/com/android/launcher3/AppSharing.java b/go/quickstep/src/com/android/launcher3/AppSharing.java
index c287446..e717937 100644
--- a/go/quickstep/src/com/android/launcher3/AppSharing.java
+++ b/go/quickstep/src/com/android/launcher3/AppSharing.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.views.ActivityContext;
 
 import java.io.File;
 
@@ -191,9 +192,14 @@
         }
 
         private void showCannotShareToast(Context context) {
+            ActivityContext activityContext = ActivityContext.lookupContext(context);
+            String blockedByMessage = activityContext.getStringCache() != null
+                    ? activityContext.getStringCache().disabledByAdminMessage
+                    : context.getString(R.string.blocked_by_policy);
+
             CharSequence text = (mSharingEnabledForUser)
                     ? context.getText(R.string.toast_p2p_app_not_shareable)
-                    : context.getText(R.string.blocked_by_policy);
+                    : blockedByMessage;
             int duration = Toast.LENGTH_SHORT;
             Toast.makeText(context, text, duration).show();
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 349dd0a..cbdbdb9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
@@ -51,6 +52,7 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.PaintDrawable;
 import android.inputmethodservice.InputMethodService;
+import android.os.Handler;
 import android.util.Property;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -158,6 +160,7 @@
     private BaseDragLayer<TaskbarActivityContext> mSeparateWindowParent; // Initialized in init.
     private final ViewTreeObserverWrapper.OnComputeInsetsListener mSeparateWindowInsetsComputer =
             this::onComputeInsetsForSeparateWindow;
+    private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
 
     public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
         mContext = context;
@@ -297,6 +300,8 @@
                 navButtonsLayoutParams.setMarginEnd(navButtonsLayoutParams.getMarginStart());
                 navButtonsLayoutParams.gravity = Gravity.CENTER;
                 mNavButtonContainer.requestLayout();
+
+                mHomeButton.setOnLongClickListener(null);
             }
 
             // Animate taskbar background when either..
@@ -388,8 +393,7 @@
                         || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
                 VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
 
-
-        // home and recents buttons
+        // home button
         mHomeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
                 navButtonController, R.id.home);
         mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS);
@@ -399,8 +403,21 @@
                         ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
                         (flags & FLAG_DISABLE_HOME) == 0));
+
+        // Recents button
         View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
                 navContainer, navButtonController, R.id.recent_apps);
+        mHitboxExtender.init(recentsButton, mNavButtonsView, mContext.getDeviceProfile(),
+                () -> {
+                    float[] recentsCoords = new float[2];
+                    getDescendantCoordRelativeToAncestor(recentsButton, mNavButtonsView,
+                            recentsCoords, false);
+                    return recentsCoords;
+                }, new Handler());
+        recentsButton.setOnClickListener(v -> {
+            navButtonController.onButtonClick(BUTTON_RECENTS);
+            mHitboxExtender.onRecentsButtonClicked();
+        });
         mPropertyHolders.add(new StatePropertyHolder(recentsButton,
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
                         && !mContext.isNavBarKidsModeActive()));
@@ -504,6 +521,9 @@
             View button = mAllButtons.get(i);
             if (button.getVisibility() == View.VISIBLE) {
                 parent.getDescendantRectRelativeToSelf(button, mTempRect);
+                if (mHitboxExtender.extendedHitboxEnabled()) {
+                    mTempRect.bottom += mContext.mDeviceProfile.getTaskbarOffsetY();
+                }
                 outRegion.op(mTempRect, Op.UNION);
             }
         }
@@ -733,6 +753,17 @@
         return str.toString();
     }
 
+    public TouchController getTouchController() {
+        return mHitboxExtender;
+    }
+
+    /**
+     * @param alignment 0 -> Taskbar, 1 -> Workspace
+     */
+    public void updateTaskbarAlignment(float alignment) {
+        mHitboxExtender.onAnimationProgressToOverview(alignment);
+    }
+
     private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
         @Override
         public void onVisibilityChanged(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/RecentsHitboxExtender.java b/quickstep/src/com/android/launcher3/taskbar/RecentsHitboxExtender.java
new file mode 100644
index 0000000..4651570
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/RecentsHitboxExtender.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar;
+
+import android.graphics.Rect;
+import android.os.Handler;
+import android.view.MotionEvent;
+import android.view.TouchDelegate;
+import android.view.View;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.util.TouchController;
+
+import java.util.function.Supplier;
+
+/**
+ * Extends the Recents touch area during the taskbar to overview animation
+ * to give user some error room when trying to quickly double tap recents button since it moves.
+ *
+ * Listens for icon alignment as our indication for the animation.
+ */
+public class RecentsHitboxExtender implements TouchController {
+
+    private static final int RECENTS_HITBOX_TIMEOUT_MS = 500;
+
+    private View mRecentsButton;
+    private View mRecentsParent;
+    private DeviceProfile mDeviceProfile;
+    private Supplier<float[]> mParentCoordSupplier;
+    private TouchDelegate mRecentsTouchDelegate;
+    /**
+     * Will be true while the animation from taskbar to overview is occurring.
+     * Lifecycle of this variable slightly extends past the animation by
+     * {@link #RECENTS_HITBOX_TIMEOUT_MS}, so can use this variable as a proxy for if
+     * the current hitbox is extended or not.
+     */
+    private boolean mAnimatingFromTaskbarToOverview;
+    private float mLastIconAlignment;
+    private final Rect mRecentsHitBox = new Rect();
+    private boolean mRecentsButtonClicked;
+    private Handler mHandler;
+    private final Runnable mRecentsHitboxResetRunnable = this::reset;
+
+    public void init(View recentsButton, View recentsParent, DeviceProfile deviceProfile,
+            Supplier<float[]> parentCoordSupplier, Handler handler) {
+        mRecentsButton = recentsButton;
+        mRecentsParent = recentsParent;
+        mDeviceProfile = deviceProfile;
+        mParentCoordSupplier = parentCoordSupplier;
+        mHandler = handler;
+    }
+
+    public void onRecentsButtonClicked() {
+        mRecentsButtonClicked = true;
+    }
+
+    /**
+     * @param progress 0 -> Taskbar, 1 -> Overview
+     */
+    public void onAnimationProgressToOverview(float progress) {
+        if (progress == 1 || progress == 0) {
+            // Done w/ animation
+            mLastIconAlignment = progress;
+            if (mAnimatingFromTaskbarToOverview) {
+                if (progress == 1) {
+                    // Finished animation to workspace, remove the touch delegate shortly
+                    mHandler.postDelayed(mRecentsHitboxResetRunnable, RECENTS_HITBOX_TIMEOUT_MS);
+                    return;
+                } else {
+                    // Went back to taskbar, reset immediately
+                    mHandler.removeCallbacks(mRecentsHitboxResetRunnable);
+                    reset();
+                }
+            }
+        }
+
+        if (mAnimatingFromTaskbarToOverview) {
+            return;
+        }
+
+        if (progress > 0 && mLastIconAlignment == 0 && mRecentsButtonClicked) {
+            // Starting animation, previously we were showing taskbar
+            mAnimatingFromTaskbarToOverview = true;
+            float[] recentsCoords = mParentCoordSupplier.get();
+            int x = (int) recentsCoords[0];
+            int y = (int) (recentsCoords[1]);
+            // Extend hitbox vertically by the offset amount from mDeviceProfile.getTaskbarOffsetY()
+            mRecentsHitBox.set(x, y,
+                    x + mRecentsButton.getWidth(),
+                    y + mRecentsButton.getHeight() + mDeviceProfile.getTaskbarOffsetY()
+            );
+            mRecentsTouchDelegate = new TouchDelegate(mRecentsHitBox, mRecentsButton);
+            mRecentsParent.setTouchDelegate(mRecentsTouchDelegate);
+        }
+    }
+
+    private void reset() {
+        mAnimatingFromTaskbarToOverview = false;
+        mRecentsButton.setTouchDelegate(null);
+        mRecentsHitBox.setEmpty();
+        mRecentsButtonClicked = false;
+    }
+
+    /**
+     * @return {@code true} if the bounds for recents touches are currently extended
+     */
+    public boolean extendedHitboxEnabled() {
+        return mAnimatingFromTaskbarToOverview;
+    }
+
+    @Override
+    public boolean onControllerTouchEvent(MotionEvent ev) {
+        return mRecentsTouchDelegate.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        return mRecentsHitBox.contains((int)ev.getX(), (int)ev.getY());
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 3e2695c..99c59a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -182,7 +182,8 @@
          */
         public TouchController[] getTouchControllers() {
             return new TouchController[]{mActivity.getDragController(),
-                    mControllers.taskbarForceVisibleImmersiveController};
+                    mControllers.taskbarForceVisibleImmersiveController,
+                    mControllers.navbarButtonsViewController.getTouchController()};
         }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 2be1179..052c695 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -428,6 +428,7 @@
 
         // Switch taskbar and hotseat in last frame
         setTaskbarViewVisible(alignment < 1);
+        mControllers.navbarButtonsViewController.updateTaskbarAlignment(alignment);
     }
 
     private float getCurrentIconAlignmentRatioBetweenAppAndHome() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 5f62749..699ce97 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -66,9 +66,9 @@
     @Override
     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
         RecentsView recentsView = launcher.getOverviewPanel();
-        float workspacePageHeight = launcher.getDeviceProfile().getCellLayoutHeight();
+        float workspacePageWidth = launcher.getDeviceProfile().getWorkspaceWidth();
         recentsView.getTaskSize(sTempRect);
-        float scale = (float) sTempRect.height() / workspacePageHeight;
+        float scale = (float) sTempRect.width() / workspacePageWidth;
         float parallaxFactor = 0.5f;
         return new ScaleAndTranslation(scale, 0, -getDefaultSwipeHeight(launcher) * parallaxFactor);
     }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 13389c0..f60b225 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1177,6 +1177,11 @@
     }
 
     private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) {
+        if (mDp == null || !mDp.isGestureMode || mDownPos == null) {
+            // We probably never received an animation controller, skip logging.
+            return;
+        }
+
         StatsLogManager.EventEnum event;
         switch (endTarget) {
             case HOME:
@@ -1200,11 +1205,6 @@
             logger.withItemInfo(targetTask.getItemInfo());
         }
 
-        DeviceProfile dp = mDp;
-        if (dp == null || mDownPos == null) {
-            // We probably never received an animation controller, skip logging.
-            return;
-        }
         int pageIndex = endTarget == LAST_TASK || mRecentsView == null
                 ? LOG_NO_OP_PAGE_INDEX
                 : mRecentsView.getNextPage();
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 3803f03..300f085 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -256,7 +256,7 @@
     private BaseIconFactory getIconFactory() {
         if (mIconFactory == null) {
             mIconFactory = new BaseIconFactory(mContext,
-                    DisplayController.INSTANCE.get(mContext).getInfo().getDensityDpi(),
+                    DisplayController.INSTANCE.get(mContext).getInfo().densityDpi,
                     mContext.getResources().getDimensionPixelSize(R.dimen.taskbar_icon_size));
         }
         return mIconFactory;
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index f53491b..3ef1332 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.views.ActivityContext;
 import com.android.quickstep.TaskShortcutFactory.SplitSelectSystemShortcut;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.views.OverviewActionsView;
@@ -314,9 +315,14 @@
         }
 
         protected void showBlockedByPolicyMessage() {
+            ActivityContext activityContext = ActivityContext.lookupContext(
+                    mThumbnailView.getContext());
+            String message = activityContext.getStringCache() != null
+                    ? activityContext.getStringCache().disabledByAdminMessage
+                    : mThumbnailView.getContext().getString(R.string.blocked_by_policy);
             Toast.makeText(
                     mThumbnailView.getContext(),
-                    R.string.blocked_by_policy,
+                    message,
                     Toast.LENGTH_LONG).show();
         }
 
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
new file mode 100644
index 0000000..929bff3
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
@@ -0,0 +1,125 @@
+package com.android.launcher3.taskbar;
+
+import static android.view.MotionEvent.ACTION_DOWN;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Handler;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.DeviceProfile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Supplier;
+
+@RunWith(AndroidJUnit4.class)
+public class RecentsHitboxExtenderTest {
+
+    private static final int TASKBAR_OFFSET_Y = 35;
+    private static final int BUTTON_WIDTH = 10;
+    private static final int BUTTON_HEIGHT = 10;
+
+    private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
+    @Mock
+    View mMockRecentsButton;
+    @Mock
+    View mMockRecentsParent;
+    @Mock
+    DeviceProfile mMockDeviceProfile;
+    @Mock
+    Handler mMockHandler;
+    Context mContext;
+
+    float[] mRecentsCoords = new float[]{0,0};
+    private final Supplier<float[]> mSupplier = () -> mRecentsCoords;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = instrumentation.getContext();
+        mHitboxExtender.init(mMockRecentsButton, mMockRecentsParent, mMockDeviceProfile, mSupplier,
+                mMockHandler);
+        when(mMockDeviceProfile.getTaskbarOffsetY()).thenReturn(TASKBAR_OFFSET_Y);
+        when(mMockRecentsButton.getContext()).thenReturn(mContext);
+        when(mMockRecentsButton.getWidth()).thenReturn(BUTTON_WIDTH);
+        when(mMockRecentsButton.getHeight()).thenReturn(BUTTON_HEIGHT);
+    }
+
+    @Test
+    public void noRecentsButtonClick_notActive() {
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertFalse(mHitboxExtender.extendedHitboxEnabled());
+    }
+
+    @Test
+    public void recentsButtonClick_active() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+    }
+
+    @Test
+    public void homeToTaskbar_notActive() {
+        mHitboxExtender.onAnimationProgressToOverview(1);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertFalse(mHitboxExtender.extendedHitboxEnabled());
+    }
+
+    @Test
+    public void animationEndReset() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+        mHitboxExtender.onAnimationProgressToOverview(1);
+        verify(mMockHandler, times(1)).postDelayed(any(), anyLong());
+    }
+
+    @Test
+    public void motionWithinHitbox() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+        // Center width, past height but w/in offset bounds
+        MotionEvent motionEvent = getMotionEvent(ACTION_DOWN,
+                BUTTON_WIDTH / 2, BUTTON_HEIGHT + TASKBAR_OFFSET_Y / 2);
+        assertTrue(mHitboxExtender.onControllerInterceptTouchEvent(motionEvent));
+    }
+
+    @Test
+    public void motionOutsideHitbox() {
+        mHitboxExtender.onRecentsButtonClicked();
+        mHitboxExtender.onAnimationProgressToOverview(0);
+        mHitboxExtender.onAnimationProgressToOverview(0.5f);
+        assertTrue(mHitboxExtender.extendedHitboxEnabled());
+        // Center width, past height and offset
+        MotionEvent motionEvent = getMotionEvent(ACTION_DOWN,
+                BUTTON_WIDTH / 2, BUTTON_HEIGHT + TASKBAR_OFFSET_Y * 2);
+        assertFalse(mHitboxExtender.onControllerInterceptTouchEvent(motionEvent));
+    }
+
+    private MotionEvent getMotionEvent(int action, int x, int y) {
+        return MotionEvent.obtain(0, 0, action, x, y, 0);
+    }
+}
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index e85969b..dd3e08b 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -306,17 +306,6 @@
         if not specified -->
         <attr name="allAppsBorderSpaceTwoPanelLandscapeVertical" format="float" />
 
-        <!-- alignment of hotseat to the grid.
-        Not applicable for 3 button mode when taskbar is enabled -->
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpan" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanLandscape" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanTwoPanelLandscape" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanTwoPanelPortrait" format="integer" />
-
         <!-- defaults to borderSpaceDps, if not specified -->
         <attr name="hotseatBorderSpace" format="float" />
         <!-- defaults to hotseatBorderSpace, if not specified -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 864bb58..2109510 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -76,7 +76,7 @@
     </style>
 
     <style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme">
-        <item name="disabledIconAlpha">.254</item>
+        <item name="disabledIconAlpha">.54</item>
 
     </style>
 
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index 258da80..07ce598 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -176,7 +176,6 @@
             launcher:allAppsBorderSpaceHorizontal="8"
             launcher:allAppsBorderSpaceVertical="16"
             launcher:allAppsBorderSpaceLandscape="16"
-            launcher:hotseatColumnSpanLandscape="4"
             launcher:hotseatBorderSpace="58"
             launcher:hotseatBorderSpaceLandscape="50.4"
             launcher:canBeDefault="true" />
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 561f9b9..31f1da8 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -158,7 +158,6 @@
     public final int numShownHotseatIcons;
     public int hotseatCellHeightPx;
     private final int hotseatExtraVerticalSize;
-    private final boolean areNavButtonsInline;
     // In portrait: size = height, in landscape: size = width
     public int hotseatBarSizePx;
     public int hotseatBarTopPaddingPx;
@@ -359,7 +358,7 @@
 
         // We shrink hotseat sizes regardless of orientation, if nav buttons are inline and QSB
         // might be inline in either orientations, to keep hotseat size consistent across rotation.
-        areNavButtonsInline = isTaskbarPresent && !isGestureMode;
+        boolean areNavButtonsInline = isTaskbarPresent && !isGestureMode;
         if (areNavButtonsInline && canQsbInline) {
             numShownHotseatIcons = inv.numShrunkenHotseatIcons;
         } else {
@@ -374,14 +373,15 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
         if (isQsbInline) {
             hotseatBarBottomPaddingPx = res.getDimensionPixelSize(R.dimen.inline_qsb_bottom_margin);
+            qsbWidth = calculateQsbWidth();
         } else {
             hotseatBarBottomPaddingPx = (isTallDevice ? res.getDimensionPixelSize(
                     R.dimen.dynamic_grid_hotseat_bottom_tall_padding)
                     : res.getDimensionPixelSize(
                             R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding))
                     + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
+            qsbWidth = 0;
         }
-
         springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize(
                 R.dimen.spring_loaded_hotseat_top_margin);
         hotseatBarSidePaddingEndPx =
@@ -390,7 +390,9 @@
         hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
         hotseatExtraVerticalSize =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size);
-        updateHotseatIconSize(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
+        hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics);
+        updateHotseatIconSize(
+                pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
 
         qsbBottomMarginOriginalPx = isScalableGrid
                 ? res.getDimensionPixelSize(R.dimen.scalable_grid_qsb_bottom_margin)
@@ -481,10 +483,6 @@
                 cellLayoutPadding);
         updateWorkspacePadding();
 
-        // Hotseat and QSB width depends on updated cellSize and workspace padding
-        hotseatBorderSpace = calculateHotseatBorderSpace();
-        qsbWidth = calculateQsbWidth();
-
         flingToDeleteThresholdVelocity = res.getDimensionPixelSize(
                 R.dimen.drag_flingToDeleteMinVelocity);
 
@@ -495,26 +493,14 @@
                 new DotRenderer(allAppsIconSizePx, dotPath, DEFAULT_DOT_SIZE);
     }
 
-    /**
-     * QSB width is always calculated because when in 3 button nav the width doesn't follow the
-     * width of the hotseat.
-     */
     private int calculateQsbWidth() {
-        if (isQsbInline) {
-            int columns = getPanelCount() * inv.numColumns;
-            return getIconToIconWidthForColumns(columns)
-                    - iconSizePx * numShownHotseatIcons
-                    - hotseatBorderSpace * numShownHotseatIcons;
-        } else {
-            int columns = inv.hotseatColumnSpan[mTypeIndex];
-            return getIconToIconWidthForColumns(columns);
-        }
-    }
+        int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
 
-    private int getIconToIconWidthForColumns(int columns) {
-        return columns * getCellSize().x
-                + (columns - 1) * cellLayoutBorderSpacePx.x
-                - (getCellSize().x - iconSizePx);  // left and right cell space
+        return cellWidthPx * columns
+                + cellLayoutBorderSpacePx.x * (columns - 1)
+                - (cellWidthPx - iconSizePx) // left and right cell space
+                - iconSizePx * numShownHotseatIcons
+                - hotseatBorderSpace * numShownHotseatIcons;
     }
 
     private int getHorizontalMarginPx(InvariantDeviceProfile idp, Resources res) {
@@ -665,10 +651,11 @@
         updateIconSize(1f, res);
 
         updateWorkspacePadding();
+        Point workspacePadding = getTotalWorkspacePadding();
 
         // Check to see if the icons fit within the available height.
         float usedHeight = getCellLayoutHeightSpecification();
-        final int maxHeight = getCellLayoutHeight();
+        final int maxHeight = getWorkspaceHeight(workspacePadding);
         float extraHeight = Math.max(0, maxHeight - usedHeight);
         float scaleY = maxHeight / usedHeight;
         boolean shouldScale = scaleY < 1f;
@@ -701,7 +688,7 @@
     }
 
     private int getCellLayoutWidthSpecification() {
-        int numColumns = getPanelCount() * inv.numColumns;
+        int numColumns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
         return (cellWidthPx * numColumns) + (cellLayoutBorderSpacePx.x * (numColumns - 1))
                 + cellLayoutPaddingPx.left + cellLayoutPaddingPx.right;
     }
@@ -754,6 +741,13 @@
         // All apps
         updateAllAppsIconSize(scale, res);
 
+        // Hotseat
+        hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics, scale);
+        if (isQsbInline) {
+            qsbWidth = calculateQsbWidth();
+        } else {
+            qsbWidth = 0;
+        }
         updateHotseatIconSize(iconSizePx);
 
         // Folder icon
@@ -761,23 +755,6 @@
         folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2;
     }
 
-    /**
-     * Hotseat width spans a certain number of columns on scalable grids.
-     * This method calculates the space between the icons to achieve that width.
-     */
-    private int calculateHotseatBorderSpace() {
-        if (!isScalableGrid) return 0;
-        //TODO(http://b/228998082) remove this when 3 button spaces are fixed
-        if (areNavButtonsInline) {
-            return pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics);
-        } else {
-            int columns = inv.hotseatColumnSpan[mTypeIndex];
-            float hotseatWidthPx = getIconToIconWidthForColumns(columns);
-            float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons;
-            return (int) (hotseatWidthPx - hotseatIconsTotalPx) / (numShownHotseatIcons - 1);
-        }
-    }
-
 
     /**
      * Updates the iconSize for allApps* variants.
@@ -901,18 +878,16 @@
             result = new Point();
         }
 
-        result.x = calculateCellWidth(getShortcutAndWidgetContainerWidth(),
-                cellLayoutBorderSpacePx.x, inv.numColumns);
-        result.y = calculateCellHeight(getShortcutAndWidgetContainerHeight(),
-                cellLayoutBorderSpacePx.y, inv.numRows);
-        return result;
-    }
+        // Since we are only concerned with the overall padding, layout direction does
+        // not matter.
+        Point padding = getTotalWorkspacePadding();
 
-    /**
-     * Gets the number of panels within the workspace.
-     */
-    public int getPanelCount() {
-        return isTwoPanels ? 2 : 1;
+        int numColumns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
+        int screenWidthPx = getWorkspaceWidth(padding);
+        result.x = calculateCellWidth(screenWidthPx, cellLayoutBorderSpacePx.x, numColumns);
+        int screenHeightPx = getWorkspaceHeight(padding);
+        result.y = calculateCellHeight(screenHeightPx, cellLayoutBorderSpacePx.y, inv.numRows);
+        return result;
     }
 
     /**
@@ -933,7 +908,7 @@
     /**
      * Gets the scaled top of the workspace in px for the spring-loaded edit state.
      */
-    public float getCellLayoutSpringLoadShrunkTop() {
+    public float getWorkspaceSpringLoadShrunkTop() {
         workspaceSpringLoadShrunkTop = mInsets.top + dropTargetBarTopMarginPx + dropTargetBarSizePx
                 + dropTargetBarBottomMarginPx;
         return workspaceSpringLoadShrunkTop;
@@ -942,7 +917,7 @@
     /**
      * Gets the scaled bottom of the workspace in px for the spring-loaded edit state.
      */
-    private float getCellLayoutSpringLoadShrunkBottom() {
+    private float getWorkspaceSpringLoadShrunkBottom() {
         int topOfHotseat = hotseatBarSizePx + springLoadedHotseatBarTopMarginPx;
         workspaceSpringLoadShrunkBottom =
                 heightPx - (isVerticalBarLayout() ? getVerticalHotseatLastItemBottomOffset()
@@ -961,8 +936,9 @@
      * Gets the scale of the workspace for the spring-loaded edit state.
      */
     public float getWorkspaceSpringLoadScale() {
-        float scale = (getCellLayoutSpringLoadShrunkBottom() - getCellLayoutSpringLoadShrunkTop())
-                / getCellLayoutHeight();
+        float cellLayoutHeight = availableHeightPx - workspacePadding.top - workspacePadding.bottom;
+        float scale = (getWorkspaceSpringLoadShrunkBottom() - getWorkspaceSpringLoadShrunkTop())
+                / cellLayoutHeight;
         scale = Math.min(scale, 1f);
 
         // Reduce scale if next pages would not be visible after scaling the workspace
@@ -976,55 +952,19 @@
         return scale;
     }
 
-    /**
-     * Gets the width of the Workspace, aka a scrollable page of the homescreen.
-     */
     public int getWorkspaceWidth() {
-        return availableWidthPx;
+        return getWorkspaceWidth(getTotalWorkspacePadding());
     }
 
-    /**
-     * Gets the height of the Workspace, aka a scrollable page of the homescreen.
-     */
-    public int getWorkspaceHeight() {
-        return availableHeightPx;
+    public int getWorkspaceWidth(Point workspacePadding) {
+        int cellLayoutTotalPadding =
+                (isTwoPanels ? 2 : 1) * (cellLayoutPaddingPx.left + cellLayoutPaddingPx.right);
+        return availableWidthPx - workspacePadding.x - cellLayoutTotalPadding;
     }
 
-    /**
-     * Gets the width of a single Cell Layout, aka a single panel within a Workspace.
-     *
-     * <p>This is the width of a Workspace, less its horizontal padding. Note that two-panel
-     * layouts have two Cell Layouts per workspace.
-     */
-    public int getCellLayoutWidth() {
-        return (getWorkspaceWidth() - getTotalWorkspacePadding().x) / getPanelCount();
-    }
-
-    /**
-     * Gets the height of a single Cell Layout, aka a single panel within a Workspace.
-     *
-     * <p>This is the height of a Workspace, less its vertical padding.
-     */
-    public int getCellLayoutHeight() {
-        return getWorkspaceHeight() - getTotalWorkspacePadding().y;
-    }
-
-    /**
-     * Gets the width of the container holding the shortcuts and widgets.
-     *
-     * <p>This is the width of one Cell Layout less its horizontal padding.
-     */
-    public int getShortcutAndWidgetContainerWidth() {
-        return getCellLayoutWidth() - (cellLayoutPaddingPx.left + cellLayoutPaddingPx.right);
-    }
-
-    /**
-     * Gets the height of the container holding the shortcuts and widgets.
-     *
-     * <p>This is the height of one Cell Layout less its vertical padding.
-     */
-    public int getShortcutAndWidgetContainerHeight() {
-        return getCellLayoutHeight() - (cellLayoutPaddingPx.top + cellLayoutPaddingPx.bottom);
+    private int getWorkspaceHeight(Point workspacePadding) {
+        return availableHeightPx - workspacePadding.y - (cellLayoutPaddingPx.top
+                + cellLayoutPaddingPx.bottom);
     }
 
     public Point getTotalWorkspacePadding() {
@@ -1130,13 +1070,6 @@
                 mHotseatPadding.left -= diff;
                 mHotseatPadding.right += diff;
             }
-        } else if (isScalableGrid) {
-            int sideSpacing = (availableWidthPx - qsbWidth) / 2;
-            mHotseatPadding.set(sideSpacing,
-                    hotseatBarTopPaddingPx,
-                    sideSpacing,
-                    hotseatBarSizePx - hotseatCellHeightPx - hotseatBarTopPaddingPx
-                            + mInsets.bottom);
         } else {
             // We want the edges of the hotseat to line up with the edges of the workspace, but the
             // icons in the hotseat are a different size, and so don't line up perfectly. To account
@@ -1373,7 +1306,6 @@
         writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
 
         writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
-        writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]);
         writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
         writer.println(prefix + pxToDpStr("hotseatBarTopPaddingPx", hotseatBarTopPaddingPx));
         writer.println(prefix + pxToDpStr("hotseatBarBottomPaddingPx", hotseatBarBottomPaddingPx));
@@ -1452,7 +1384,7 @@
     private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) {
         Configuration config = new Configuration(c.getResources().getConfiguration());
         config.orientation = orientation;
-        config.densityDpi = info.getDensityDpi();
+        config.densityDpi = info.densityDpi;
         config.smallestScreenWidthDp = (int) info.smallestSizeDp(bounds);
         return c.createConfigurationContext(config);
     }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 76106fc..a9db5ce 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -173,9 +173,17 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        int qsbWidth = mActivity.getDeviceProfile().qsbWidth;
+        int width;
+        if (mActivity.getDeviceProfile().isQsbInline) {
+            width = mActivity.getDeviceProfile().qsbWidth;
+        } else {
+            MarginLayoutParams qsbParams = (MarginLayoutParams) mQsb.getLayoutParams();
+            width = getShortcutsAndWidgets().getMeasuredWidth()
+                    - qsbParams.getMarginStart()
+                    - qsbParams.getMarginEnd();
+        }
 
-        mQsb.measure(MeasureSpec.makeMeasureSpec(qsbWidth, MeasureSpec.EXACTLY),
+        mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY));
     }
 
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 0373eef..1f92079 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -127,7 +127,6 @@
     public PointF[] borderSpaces;
     public float folderBorderSpace;
     public float[] hotseatBorderSpaces;
-    public int[] hotseatColumnSpan;
 
     public float[] horizontalMargin;
 
@@ -359,7 +358,6 @@
         numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
                 ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
         hotseatBorderSpaces = displayOption.hotseatBorderSpaces;
-        hotseatColumnSpan = displayOption.hotseatColumnSpan;
 
         numAllAppsColumns = closestProfile.numAllAppsColumns;
         numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
@@ -400,8 +398,7 @@
             // We need to ensure that there is enough extra space in the wallpaper
             // for the intended parallax effects
             float parallaxFactor =
-                    dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.getDensityDpi())
-                            < 720
+                    dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.densityDpi) < 720
                             ? 2
                             : wallpaperTravelToScreenWidthRatio(displayWidth, displayHeight);
             defaultWallpaperSize.x =
@@ -590,8 +587,8 @@
             }
         }
 
-        float width = dpiFromPx(minWidthPx, displayInfo.getDensityDpi());
-        float height = dpiFromPx(minHeightPx, displayInfo.getDensityDpi());
+        float width = dpiFromPx(minWidthPx, displayInfo.densityDpi);
+        float height = dpiFromPx(minHeightPx, displayInfo.densityDpi);
 
         // Sort the profiles based on the closeness to the device size
         Collections.sort(points, (a, b) ->
@@ -824,9 +821,7 @@
         private float folderBorderSpace;
         private final PointF[] borderSpaces = new PointF[COUNT_SIZES];
         private final float[] horizontalMargin = new float[COUNT_SIZES];
-        //TODO(http://b/228998082) remove this when 3 button spaces are fixed
         private final float[] hotseatBorderSpaces = new float[COUNT_SIZES];
-        private final int[] hotseatColumnSpan = new int[COUNT_SIZES];
 
         private final float[] iconSizes = new float[COUNT_SIZES];
         private final float[] textSizes = new float[COUNT_SIZES];
@@ -1052,17 +1047,6 @@
                     R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelPortrait,
                     hotseatBorderSpaces[INDEX_DEFAULT]);
 
-            hotseatColumnSpan[INDEX_DEFAULT] = a.getInt(
-                    R.styleable.ProfileDisplayOption_hotseatColumnSpan, grid.numColumns);
-            hotseatColumnSpan[INDEX_LANDSCAPE] = a.getInt(
-                    R.styleable.ProfileDisplayOption_hotseatColumnSpanLandscape, grid.numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
-                    R.styleable.ProfileDisplayOption_hotseatColumnSpanTwoPanelLandscape,
-                    grid.numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
-                    R.styleable.ProfileDisplayOption_hotseatColumnSpanTwoPanelPortrait,
-                    grid.numColumns);
-
             a.recycle();
         }
 
@@ -1121,7 +1105,6 @@
                 minCellSize[i].y += p.minCellSize[i].y;
                 horizontalMargin[i] += p.horizontalMargin[i];
                 hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i];
-                hotseatColumnSpan[i] = p.hotseatColumnSpan[i];
                 allAppsCellSize[i].x += p.allAppsCellSize[i].x;
                 allAppsCellSize[i].y += p.allAppsCellSize[i].y;
                 allAppsIconSizes[i] += p.allAppsIconSizes[i];
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 4501159..597bc8d 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3;
 
+import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+
 import static com.android.launcher3.Utilities.getDevicePrefs;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_THEMED_ICONS;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -97,7 +99,8 @@
         modelChangeReceiver.register(mContext, Intent.ACTION_LOCALE_CHANGED,
                 Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
                 Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
-                Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
+                Intent.ACTION_MANAGED_PROFILE_UNLOCKED,
+                ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
         if (FeatureFlags.IS_STUDIO_BUILD) {
             modelChangeReceiver.register(mContext, Context.RECEIVER_EXPORTED, ACTION_FORCE_ROLOAD);
         }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ee6f51e..5c5c101 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3;
 
+import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+
 import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
 import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -51,6 +53,7 @@
 import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask;
 import com.android.launcher3.model.PackageInstallStateChangedTask;
 import com.android.launcher3.model.PackageUpdatedTask;
+import com.android.launcher3.model.ReloadStringCacheTask;
 import com.android.launcher3.model.ShortcutsChangedTask;
 import com.android.launcher3.model.UserLockStateChangedTask;
 import com.android.launcher3.model.data.AppInfo;
@@ -278,6 +281,8 @@
                             user, Intent.ACTION_MANAGED_PROFILE_UNLOCKED.equals(action)));
                 }
             }
+        } else if (ACTION_DEVICE_POLICY_RESOURCE_UPDATED.equals(action)) {
+            enqueueModelUpdateTask(new ReloadStringCacheTask(mModelDelegate));
         } else if (IS_STUDIO_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
             for (Callbacks cb : getCallbacks()) {
                 if (cb instanceof Launcher) {
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 58df50c..33d2f2b 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -118,7 +118,7 @@
             List<AdapterItem> items = mApps.getAdapterItems();
             adapterPosition = Math.max(adapterPosition, items.size() - 1);
             int extraRows = 0;
-            for (int i = 0; i <= adapterPosition; i++) {
+            for (int i = 0; i <= adapterPosition && i < items.size(); i++) {
                 if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_ICON)) {
                     extraRows++;
                 }
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 5bbc67e..72ca5a7 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -437,8 +437,12 @@
         if (showTabs == mUsingTabs && !force) {
             return;
         }
+
+        // replaceRVcontainer() needs to use both mUsingTabs value to remove the old view AND
+        // showTabs value to create new view. Hence the mUsingTabs new value assignment MUST happen
+        // after this call.
+        replaceRVContainer(showTabs);
         mUsingTabs = showTabs;
-        replaceRVContainer(mUsingTabs);
 
         mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.MAIN).mRecyclerView);
         mAllAppsStore.unregisterIconContainer(mAH.get(AdapterHolder.WORK).mRecyclerView);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 626e15c..54edb33 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -261,6 +261,10 @@
     public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag(
             "ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch.");
 
+    public static final BooleanFlag ENABLE_SHOW_KEYBOARD_IN_ALL_APPS = getDebugFlag(
+            "ENABLE_SHOW_KEYBOARD_IN_ALL_APPS", false,
+            "Enable option to show keyboard when going to all-apps");
+
     public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(
             "USE_LOCAL_ICON_OVERRIDES", true,
             "Use inbuilt monochrome icons if app doesn't provide one");
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 2b621bd..5021644 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.folder;
 
+import android.annotation.SuppressLint;
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Process;
@@ -22,11 +24,15 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.WorkerThread;
+
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -94,6 +100,7 @@
     /**
      * Generate and rank the suggested Folder names.
      */
+    @WorkerThread
     public void getSuggestedFolderName(Context context,
             ArrayList<WorkspaceItemInfo> workspaceItemInfos,
             FolderNameInfos nameInfos) {
@@ -107,8 +114,7 @@
         Set<UserHandle> users = workspaceItemInfos.stream().map(w -> w.user)
                 .collect(Collectors.toSet());
         if (users.size() == 1 && !users.contains(Process.myUserHandle())) {
-            String workFolderName = context.getString(R.string.work_folder_name);
-            setAsLastSuggestion(nameInfos, workFolderName);
+            setAsLastSuggestion(nameInfos, getWorkFolderName(context));
         }
 
         // If all the icons are from same package (e.g., main icon, shortcut, shortcut)
@@ -130,6 +136,17 @@
         }
     }
 
+    @WorkerThread
+    @SuppressLint("NewApi")
+    private String getWorkFolderName(Context context) {
+        if (!Utilities.ATLEAST_T) {
+            return context.getString(R.string.work_folder_name);
+        }
+        return context.getSystemService(DevicePolicyManager.class).getResources()
+                .getString(StringCache.WORK_FOLDER_NAME, () ->
+                        context.getString(R.string.work_folder_name));
+    }
+
     private Optional<AppInfo> getAppInfoByPackageName(String packageName) {
         if (mAppInfos == null || mAppInfos.isEmpty()) {
             return Optional.empty();
diff --git a/src/com/android/launcher3/model/ReloadStringCacheTask.java b/src/com/android/launcher3/model/ReloadStringCacheTask.java
new file mode 100644
index 0000000..f4d4298
--- /dev/null
+++ b/src/com/android/launcher3/model/ReloadStringCacheTask.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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.model;
+
+import com.android.launcher3.LauncherAppState;
+
+/**
+ * Handles updates due to changes in Device Policy Management resources triggered by
+ * {@link android.app.admin.DevicePolicyManager#ACTION_DEVICE_POLICY_RESOURCE_UPDATED}.
+ */
+public class ReloadStringCacheTask extends BaseModelUpdateTask {
+    private ModelDelegate mModelDelegate;
+
+    public ReloadStringCacheTask(ModelDelegate modelDelegate) {
+        mModelDelegate = modelDelegate;
+    }
+
+    @Override
+    public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
+        synchronized (dataModel) {
+            mModelDelegate.loadStringCache(dataModel.stringCache);
+            StringCache cloneSC = dataModel.stringCache.clone();
+            scheduleCallbackTask(c -> c.bindStringCache(cloneSC));
+        }
+    }
+}
diff --git a/src/com/android/launcher3/model/StringCache.java b/src/com/android/launcher3/model/StringCache.java
index 663a463..9859ddc 100644
--- a/src/com/android/launcher3/model/StringCache.java
+++ b/src/com/android/launcher3/model/StringCache.java
@@ -35,6 +35,11 @@
     private static final String PREFIX = "Launcher.";
 
     /**
+     * Work folder name.
+     */
+    public static final String WORK_FOLDER_NAME = PREFIX + "WORK_FOLDER_NAME";
+
+    /**
      * User on-boarding title for work profile apps.
      */
     private static final String WORK_PROFILE_EDU = PREFIX + "WORK_PROFILE_EDU";
@@ -91,11 +96,6 @@
             PREFIX + "ALL_APPS_PERSONAL_TAB_ACCESSIBILITY";
 
     /**
-     * Work folder name.
-     */
-    private static final String WORK_FOLDER_NAME = PREFIX + "WORK_FOLDER_NAME";
-
-    /**
      * Label on widget tab to indicate work app widgets.
      */
     private static final String WIDGETS_WORK_TAB = PREFIX + "WIDGETS_WORK_TAB";
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index a205ab5..15cdc20 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -51,7 +51,7 @@
             return super.getWorkspaceScaleAndTranslation(launcher);
         }
 
-        float shrunkTop = grid.getCellLayoutSpringLoadShrunkTop();
+        float shrunkTop = grid.getWorkspaceSpringLoadShrunkTop();
         float scale = grid.getWorkspaceSpringLoadScale();
 
         float halfHeight = ws.getHeight() / 2;
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 7c73be5..777da23 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -290,7 +290,7 @@
 
         // Configuration property
         public final float fontScale;
-        private final int densityDpi;
+        public final int densityDpi;
         public final NavigationMode navigationMode;
 
         private final PortraitSize mScreenSizeDp;
@@ -357,10 +357,6 @@
         public float smallestSizeDp(WindowBounds bounds) {
             return dpiFromPx(Math.min(bounds.bounds.width(), bounds.bounds.height()), densityDpi);
         }
-
-        public int getDensityDpi() {
-            return densityDpi;
-        }
     }
 
     /**
diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
index 6d0fcb6..f91f1c4 100644
--- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
@@ -64,7 +64,6 @@
         windowBounds = WindowBounds(x, y, x, y - 100, 0)
 
         whenever(info.isTablet(any())).thenReturn(false)
-        whenever(info.getDensityDpi()).thenReturn(560)
 
         inv = newScalableInvariantDeviceProfile()
     }
@@ -78,7 +77,6 @@
         windowBounds = WindowBounds(x, y, x, y - 100, 0)
 
         whenever(info.isTablet(any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
 
         inv = newScalableInvariantDeviceProfile()
     }
@@ -109,7 +107,6 @@
                 PointF(16f, 16f)
             ).toTypedArray()
             hotseatBorderSpaces = FloatArray(4) { 16f }
-            hotseatColumnSpan = IntArray(4) { 4 }
             iconSize = FloatArray(4) { 56f }
             allAppsIconSize = FloatArray(4) { 56f }
             iconTextSize = FloatArray(4) { 14f }
diff --git a/tests/src/com/android/launcher3/DeviceProfileGridDimensionsTest.kt b/tests/src/com/android/launcher3/DeviceProfileGridDimensionsTest.kt
deleted file mode 100644
index 63abc7d..0000000
--- a/tests/src/com/android/launcher3/DeviceProfileGridDimensionsTest.kt
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3
-
-import android.graphics.PointF
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.launcher3.util.WindowBounds
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
-import org.mockito.Mockito.`when` as whenever
-
-/**
- * Test for [DeviceProfile] grid dimensions.
- *
- * This includes workspace, cell layout, shortcut and widget container, cell sizes, etc.
- */
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class DeviceProfileGridDimensionsTest : DeviceProfileBaseTest() {
-
-    @Test
-    fun getWorkspaceWidth_twoPanelLandscapeScalable4By4GridTablet_workspaceWidthIsFullPage() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        val expectedWorkspaceWidth = availableWidth
-        assertThat(dp.workspaceWidth).isEqualTo(expectedWorkspaceWidth)
-    }
-
-    @Test
-    fun getWorkspaceHeight_twoPanelLandscapeScalable4By4GridTablet_workspaceHeightIsFullPage() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        val expectedWorkspaceHeight = availableHeight
-        assertThat(dp.workspaceHeight).isEqualTo(expectedWorkspaceHeight)
-    }
-
-    @Test
-    fun getCellLayoutWidth_twoPanelLandscapeScalable4By4GridTablet_equalsSinglePanelWidth() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        val expectedWorkspaceWidth = availableWidth
-        val expectedCellLayoutWidth =
-                (expectedWorkspaceWidth - (dp.workspacePadding.right + dp.workspacePadding.left)) /
-                        dp.panelCount
-        assertThat(dp.cellLayoutWidth).isEqualTo(expectedCellLayoutWidth)
-    }
-
-    @Test
-    fun getCellLayoutHeight_twoPanelLandscapeScalable4By4GridTablet_equalsSinglePanelHeight() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        val expectedWorkspaceHeight = availableHeight
-        val expectedCellLayoutHeight =
-                expectedWorkspaceHeight - (dp.workspacePadding.top + dp.workspacePadding.bottom)
-        assertThat(dp.cellLayoutHeight).isEqualTo(expectedCellLayoutHeight)
-    }
-
-    @Test
-    fun getShortcutAndWidgetContainerWidth_twoPanelLandscapeScalable4By4GridTablet_equalsIconsPlusBorderSpacesWidth() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        val expectedWorkspaceWidth = availableWidth
-        val expectedCellLayoutWidth =
-                (expectedWorkspaceWidth - (dp.workspacePadding.right + dp.workspacePadding.left)) /
-                        dp.panelCount
-        val expectedShortcutAndWidgetContainerWidth = expectedCellLayoutWidth -
-                (dp.cellLayoutPaddingPx.left + dp.cellLayoutPaddingPx.right)
-        assertThat(dp.shortcutAndWidgetContainerWidth).isEqualTo(expectedShortcutAndWidgetContainerWidth)
-    }
-
-    @Test
-    fun getShortcutAndWidgetContainerHeight_twoPanelLandscapeScalable4By4GridTablet_equalsIconsPlusBorderSpacesHeight() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        val expectedWorkspaceHeight = availableHeight
-        val expectedCellLayoutHeight =
-                expectedWorkspaceHeight - (dp.workspacePadding.top + dp.workspacePadding.bottom)
-        val expectedShortcutAndWidgetContainerHeight = expectedCellLayoutHeight -
-                (dp.cellLayoutPaddingPx.top + dp.cellLayoutPaddingPx.bottom)
-        assertThat(dp.shortcutAndWidgetContainerHeight).isEqualTo(
-                expectedShortcutAndWidgetContainerHeight)
-    }
-
-    @Test
-    fun getCellSize_twoPanelLandscapeScalable4By4GridTablet_equalsSinglePanelWidth() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        val expectedWorkspaceWidth = availableWidth
-        val expectedCellLayoutWidth =
-                (expectedWorkspaceWidth - (dp.workspacePadding.right + dp.workspacePadding.left)) /
-                        dp.panelCount
-        val expectedShortcutAndWidgetContainerWidth =
-                expectedCellLayoutWidth -
-                        (dp.cellLayoutPaddingPx.left + dp.cellLayoutPaddingPx.right)
-        assertThat(dp.getCellSize().x).isEqualTo(
-                (expectedShortcutAndWidgetContainerWidth -
-                        ((inv!!.numColumns - 1) * dp.cellLayoutBorderSpacePx.x)) / inv!!.numColumns)
-        val expectedWorkspaceHeight = availableHeight
-        val expectedCellLayoutHeight =
-                expectedWorkspaceHeight - (dp.workspacePadding.top + dp.workspacePadding.bottom)
-        val expectedShortcutAndWidgetContainerHeight = expectedCellLayoutHeight -
-                (dp.cellLayoutPaddingPx.top + dp.cellLayoutPaddingPx.bottom)
-        assertThat(dp.getCellSize().y).isEqualTo(
-                (expectedShortcutAndWidgetContainerHeight -
-                        ((inv!!.numRows - 1) * dp.cellLayoutBorderSpacePx.y)) / inv!!.numRows)
-    }
-
-    @Test
-    fun getPanelCount_twoPanelLandscapeScalable4By4GridTablet_equalsTwoPanels() {
-        val tabletWidth = 2560
-        val tabletHeight = 1600
-        val availableWidth = 2560
-        val availableHeight = 1500
-        windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0)
-        useTwoPanels = true
-        whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true)
-        whenever(info.getDensityDpi()).thenReturn(320)
-        inv = getScalable4By4InvariantDeviceProfile()
-
-        val dp = newDP()
-
-        assertThat(dp.panelCount).isEqualTo(2)
-    }
-
-    fun getScalable4By4InvariantDeviceProfile(): InvariantDeviceProfile {
-        return InvariantDeviceProfile().apply {
-            isScalable = true
-            numColumns = 4
-            numRows = 4
-            numShownHotseatIcons = 4
-            numDatabaseHotseatIcons = 6
-            numShrunkenHotseatIcons = 5
-            horizontalMargin = FloatArray(4) { 22f }
-            borderSpaces = listOf(
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f)
-            ).toTypedArray()
-            allAppsBorderSpaces = listOf(
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f)
-            ).toTypedArray()
-            hotseatBorderSpaces = FloatArray(4) { 16f }
-            hotseatColumnSpan = IntArray(4) { 4 }
-            iconSize = FloatArray(4) { 56f }
-            allAppsIconSize = FloatArray(4) { 56f }
-            iconTextSize = FloatArray(4) { 14f }
-            allAppsIconTextSize = FloatArray(4) { 14f }
-            minCellSize = listOf(
-                    PointF(64f, 83f),
-                    PointF(64f, 83f),
-                    PointF(64f, 83f),
-                    PointF(64f, 83f)
-            ).toTypedArray()
-            allAppsCellSize = listOf(
-                    PointF(64f, 83f),
-                    PointF(64f, 83f),
-                    PointF(64f, 83f),
-                    PointF(64f, 83f)
-            ).toTypedArray()
-            inlineQsb = booleanArrayOf(
-                    false,
-                    false,
-                    false,
-                    false
-            )
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/HotseatShownIconsTest.kt b/tests/src/com/android/launcher3/HotseatSizeTest.kt
similarity index 97%
rename from tests/src/com/android/launcher3/HotseatShownIconsTest.kt
rename to tests/src/com/android/launcher3/HotseatSizeTest.kt
index 593239d..a44939f 100644
--- a/tests/src/com/android/launcher3/HotseatShownIconsTest.kt
+++ b/tests/src/com/android/launcher3/HotseatSizeTest.kt
@@ -23,13 +23,15 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.`when` as whenever
 
 /**
  * Test for [DeviceProfile]
  */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class HotseatShownIconsTest : DeviceProfileBaseTest() {
+class HotseatSizeTest : DeviceProfileBaseTest() {
 
     @Test
     fun hotseat_size_is_normal_for_handhelds() {
diff --git a/tests/src/com/android/launcher3/InlineQsbTest.kt b/tests/src/com/android/launcher3/InlineQsbTest.kt
index 905c1e1..e00dca8 100644
--- a/tests/src/com/android/launcher3/InlineQsbTest.kt
+++ b/tests/src/com/android/launcher3/InlineQsbTest.kt
@@ -29,16 +29,17 @@
 class InlineQsbTest : DeviceProfileBaseTest() {
 
     @Test
-    fun qsb_is_not_inline_for_phones() {
+    fun qsbWidth_is_match_parent_for_phones() {
         initializeVarsForPhone()
 
         val dp = newDP()
 
         assertThat(dp.isQsbInline).isFalse()
+        assertThat(dp.qsbWidth).isEqualTo(0)
     }
 
     @Test
-    fun qsb_is_inline_for_tablet_portrait() {
+    fun qsbWidth_is_match_parent_for_tablet_portrait() {
         initializeVarsForTablet()
         inv = newScalableInvariantDeviceProfile().apply {
             inlineQsb = booleanArrayOf(
@@ -61,10 +62,11 @@
         )
 
         assertThat(dp.isQsbInline).isFalse()
+        assertThat(dp.qsbWidth).isEqualTo(0)
     }
 
     @Test
-    fun qsb_is_inline_for_tablet_landscape() {
+    fun qsbWidth_has_size_for_tablet_landscape() {
         initializeVarsForTablet(isLandscape = true)
         inv = newScalableInvariantDeviceProfile().apply {
             inlineQsb = booleanArrayOf(
@@ -73,17 +75,16 @@
                 false,
                 false
             )
-            numColumns = 6
-            numRows = 5
-            numShownHotseatIcons = 6
         }
 
         val dp = newDP()
 
         if (dp.hotseatQsbHeight > 0) {
             assertThat(dp.isQsbInline).isTrue()
+            assertThat(dp.qsbWidth).isGreaterThan(0)
         } else { // Launcher3 doesn't have QSB height
             assertThat(dp.isQsbInline).isFalse()
+            assertThat(dp.qsbWidth).isEqualTo(0)
         }
     }
 
@@ -91,13 +92,14 @@
      * This test is to make sure that a tablet doesn't inline the QSB if the layout doesn't support
      */
     @Test
-    fun qsb_is_not_inline_for_tablet_landscape_without_inline() {
+    fun qsbWidth_is_match_parent_for_tablet_landscape_without_inline() {
         initializeVarsForTablet(isLandscape = true)
         useTwoPanels = true
 
         val dp = newDP()
 
         assertThat(dp.isQsbInline).isFalse()
+        assertThat(dp.qsbWidth).isEqualTo(0)
     }
 
 }
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java
index 8d275cc..3623513 100644
--- a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java
+++ b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java
@@ -135,7 +135,7 @@
             resourceOverrides.put(s, getDimenByName(s, context.getResources(), 0));
         }
         return new DeviceEmulationData(info.currentSize.x, info.currentSize.y,
-                info.getDensityDpi(), info.cutout, code, grids, resourceOverrides);
+                info.densityDpi, info.cutout, code, grids, resourceOverrides);
     }
 
     public static DeviceEmulationData getDevice(String deviceCode) throws Exception {