Merge "Import translations. DO NOT MERGE ANYWHERE"
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 9e21e1a..cd4af5e 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -108,7 +108,8 @@
     private boolean mTopBorderActive;
     private boolean mBottomBorderActive;
 
-    private int mResizeMode;
+    private boolean mHorizontalResizeActive;
+    private boolean mVerticalResizeActive;
 
     private int mRunningHInc;
     private int mRunningVInc;
@@ -207,7 +208,6 @@
         mWidgetView.addOnAttachStateChangeListener(mWidgetViewAttachStateChangeListener);
         LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
                 widgetView.getAppWidgetInfo();
-        mResizeMode = info.resizeMode;
         mDragLayer = dragLayer;
 
         mMinHSpan = info.minSpanX;
@@ -218,10 +218,17 @@
         mWidgetPadding = getDefaultPaddingForWidget(getContext(),
                 widgetView.getAppWidgetInfo().provider, null);
 
-        if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
+        // Only show resize handles for the directions in which resizing is possible.
+        InvariantDeviceProfile idp = LauncherAppState.getIDP(cellLayout.getContext());
+        mVerticalResizeActive = (info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0
+                && mMinVSpan < idp.numRows && mMaxVSpan > 1;
+        if (!mVerticalResizeActive) {
             mDragHandles[INDEX_TOP].setVisibility(GONE);
             mDragHandles[INDEX_BOTTOM].setVisibility(GONE);
-        } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
+        }
+        mHorizontalResizeActive = (info.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0
+                && mMinHSpan < idp.numColumns && mMaxHSpan > 1;
+        if (!mHorizontalResizeActive) {
             mDragHandles[INDEX_LEFT].setVisibility(GONE);
             mDragHandles[INDEX_RIGHT].setVisibility(GONE);
         }
@@ -270,14 +277,12 @@
     }
 
     public boolean beginResizeIfPointInRegion(int x, int y) {
-        boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
-        boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
-
-        mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
-        mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
-        mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment) && verticalActive;
+        mLeftBorderActive = (x < mTouchTargetWidth) && mHorizontalResizeActive;
+        mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && mHorizontalResizeActive;
+        mTopBorderActive = (y < mTouchTargetWidth + mTopTouchRegionAdjustment)
+                && mVerticalResizeActive;
         mBottomBorderActive = (y > getHeight() - mTouchTargetWidth + mBottomTouchRegionAdjustment)
-                && verticalActive;
+                && mVerticalResizeActive;
 
         boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
                 || mTopBorderActive || mBottomBorderActive;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2eba4ed..624862d 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -123,6 +123,7 @@
     public int iconDrawablePaddingPx;
     public int iconDrawablePaddingOriginalPx;
 
+    public float cellScaleToFit;
     public int cellWidthPx;
     public int cellHeightPx;
     public int workspaceCellPaddingXPx;
@@ -359,20 +360,20 @@
         // Now that we have all of the variables calculated, we can tune certain sizes.
         if (isScalableGrid && inv.devicePaddings != null) {
             // Paddings were created assuming no scaling, so we first unscale the extra space.
-            int unscaledExtraSpace = (int) (extraSpace / iconScale);
+            int unscaledExtraSpace = (int) (extraSpace / cellScaleToFit);
             DevicePadding padding = inv.devicePaddings.getDevicePadding(unscaledExtraSpace);
 
             int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace);
             int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace);
             int paddingHotseatBottom = padding.getHotseatBottomPadding(unscaledExtraSpace);
 
-            workspaceTopPadding = Math.round(paddingWorkspaceTop * iconScale);
-            workspaceBottomPadding = Math.round(paddingWorkspaceBottom * iconScale);
-            extraHotseatBottomPadding = Math.round(paddingHotseatBottom * iconScale);
+            workspaceTopPadding = Math.round(paddingWorkspaceTop * cellScaleToFit);
+            workspaceBottomPadding = Math.round(paddingWorkspaceBottom * cellScaleToFit);
+            extraHotseatBottomPadding = Math.round(paddingHotseatBottom * cellScaleToFit);
 
             hotseatBarSizePx += extraHotseatBottomPadding;
 
-            qsbBottomMarginPx = Math.round(qsbBottomMarginOriginalPx * iconScale);
+            qsbBottomMarginPx = Math.round(qsbBottomMarginOriginalPx * cellScaleToFit);
         } else if (!isVerticalBarLayout() && isPhone && isTallDevice) {
             // We increase the hotseat size when there is extra space.
             // ie. For a display with a large aspect ratio, we can keep the icons on the workspace
@@ -540,15 +541,18 @@
      * hotseat sizes, workspaceSpringLoadedShrinkFactor, folderIconSizePx, and folderIconOffsetYPx.
      */
     public void updateIconSize(float scale, Resources res) {
-        iconScale = scale;
+        // Icon scale should never exceed 1, otherwise pixellation may occur.
+        iconScale = Math.min(1f, scale);
+        cellScaleToFit = scale;
+
 
         // Workspace
         final boolean isVerticalLayout = isVerticalBarLayout();
         float invIconSizeDp = isLandscape ? inv.landscapeIconSize : inv.iconSize;
-        iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale));
+        iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, iconScale));
         float invIconTextSizeSp = isLandscape ? inv.landscapeIconTextSize : inv.iconTextSize;
-        iconTextSizePx = (int) (pxFromSp(invIconTextSizeSp, mMetrics) * scale);
-        iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
+        iconTextSizePx = (int) (pxFromSp(invIconTextSizeSp, mMetrics) * iconScale);
+        iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * iconScale);
 
         setCellLayoutBorderSpacing((int) (cellLayoutBorderSpacingOriginalPx * scale));
 
@@ -942,6 +946,9 @@
         writer.println(prefix + "\tinv.minCellWidth:" + inv.minCellWidth + "dp");
         writer.println(prefix + "\tinv.minCellHeight:" + inv.minCellHeight + "dp");
 
+        writer.println(prefix + "\tinv.numColumns:" + inv.numColumns);
+        writer.println(prefix + "\tinv.numRows:" + inv.numRows);
+
         writer.println(prefix + pxToDpStr("cellWidthPx", cellWidthPx));
         writer.println(prefix + pxToDpStr("cellHeightPx", cellHeightPx));
 
@@ -995,7 +1002,8 @@
         writer.println(prefix + pxToDpStr("workspacePadding.right", workspacePadding.right));
         writer.println(prefix + pxToDpStr("workspacePadding.bottom", workspacePadding.bottom));
 
-        writer.println(prefix + pxToDpStr("scaleToFit", iconScale));
+        writer.println(prefix + pxToDpStr("iconScale", iconScale));
+        writer.println(prefix + pxToDpStr("cellScaleToFit ", cellScaleToFit));
         writer.println(prefix + pxToDpStr("extraSpace", extraSpace));
 
         if (inv.devicePaddings != null) {
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 365cab1..01b3e6e 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -32,13 +32,11 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.util.GridOccupancy;
-import com.android.launcher3.util.IOUtils;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.PackageManagerHelper;
 
@@ -182,13 +180,6 @@
 
                 // log bitmap and label
                 FileLog.d(LOG, "Adding item info to workspace: " + itemInfo);
-                if (itemInfo instanceof ItemInfoWithIcon) {
-                    ItemInfoWithIcon infoWithIcon = (ItemInfoWithIcon) itemInfo;
-
-                    FileLog.d(LOG, "Item info icon base 64 string: "
-                            + infoWithIcon.bitmap.icon == null
-                            ? "null" : IOUtils.toBase64String(infoWithIcon.bitmap.icon));
-                }
             }
         }
 
diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
index b3057d5..7ca283e 100644
--- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java
+++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
@@ -25,6 +25,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.logger.LauncherAtom.ItemInfo;
 import com.android.launcher3.logger.LauncherAtom.SearchActionItem;
 
@@ -34,6 +35,7 @@
 public class SearchActionItemInfo extends ItemInfoWithIcon {
 
     public static final int FLAG_SHOULD_START = 1 << 1;
+    @Deprecated
     public static final int FLAG_SHOULD_START_FOR_RESULT = FLAG_SHOULD_START | 1 << 2;
     public static final int FLAG_BADGE_WITH_PACKAGE = 1 << 3;
     public static final int FLAG_PRIMARY_ICON_FROM_TITLE = 1 << 4;
@@ -89,10 +91,13 @@
      * Setter for mIntent with assertion for null value mPendingIntent
      */
     public void setIntent(Intent intent) {
-        if (mPendingIntent != null && intent != null) {
+        if (mPendingIntent != null && intent != null && Utilities.IS_DEBUG_DEVICE) {
             throw new RuntimeException(
                     "SearchActionItemInfo can only have either an Intent or a PendingIntent");
         }
+        if (intent != null) {
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
         mIntent = intent;
     }
 
@@ -104,7 +109,7 @@
      * Setter of mPendingIntent with assertion for null value mIntent
      */
     public void setPendingIntent(PendingIntent pendingIntent) {
-        if (mIntent != null && pendingIntent != null) {
+        if (mIntent != null && pendingIntent != null && Utilities.IS_DEBUG_DEVICE) {
             throw new RuntimeException(
                     "SearchActionItemInfo can only have either an Intent or a PendingIntent");
         }
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 2bd9ba0..ab35bd6 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -25,7 +25,6 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
 import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
@@ -41,7 +40,6 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.util.IOUtils;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.MainThreadInitializedObject;
@@ -231,37 +229,12 @@
     }
 
     public boolean verifySessionInfo(PackageInstaller.SessionInfo sessionInfo) {
-        boolean validSessionInfo = verify(sessionInfo) != null
+        return verify(sessionInfo) != null
                 && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
                 && sessionInfo.getAppIcon() != null
                 && !TextUtils.isEmpty(sessionInfo.getAppLabel())
                 && !new PackageManagerHelper(mAppContext).isAppInstalled(
                         sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
-
-        if (sessionInfo != null) {
-            Bitmap appIcon = sessionInfo.getAppIcon();
-
-            if (Utilities.IS_DEBUG_DEVICE) {
-                FileLog.d(LOG, String.format(
-                        "Verifying session info. Valid: %b,"
-                                + " Session verified: %b,"
-                                + " Install reason valid: %b,"
-                                + " App icon: %s,"
-                                + " App label: %s,"
-                                + " App installed: %b.",
-                        validSessionInfo,
-                        verify(sessionInfo) != null,
-                        sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER,
-                        appIcon == null ? "null" : IOUtils.toBase64String(appIcon),
-                        sessionInfo.getAppLabel(),
-                        new PackageManagerHelper(mAppContext).isAppInstalled(
-                                sessionInfo.getAppPackageName(), getUserHandle(sessionInfo))));
-            }
-        } else {
-            FileLog.d(LOG, "Verifying session info failed: session info null.");
-        }
-
-        return validSessionInfo;
     }
 
     public InstallSessionTracker registerInstallTracker(InstallSessionTracker.Callback callback) {
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index b53f96e..408ba28 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -262,19 +262,12 @@
      */
     public static void onClickSearchAction(Launcher launcher, SearchActionItemInfo itemInfo) {
         if (itemInfo.getIntent() != null) {
-            if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) {
-                launcher.startActivityForResult(itemInfo.getIntent(), 0);
-            } else {
-                launcher.startActivity(itemInfo.getIntent());
-            }
+            launcher.startActivity(itemInfo.getIntent());
         } else if (itemInfo.getPendingIntent() != null) {
             try {
                 PendingIntent pendingIntent = itemInfo.getPendingIntent();
                 if (!itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START)) {
                     pendingIntent.send();
-                } else if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) {
-                    launcher.startIntentSenderForResult(pendingIntent.getIntentSender(), 0, null, 0,
-                            0, 0);
                 } else {
                     launcher.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
                 }
diff --git a/src/com/android/launcher3/util/IOUtils.java b/src/com/android/launcher3/util/IOUtils.java
index d7fa905..1cec0ec 100644
--- a/src/com/android/launcher3/util/IOUtils.java
+++ b/src/com/android/launcher3/util/IOUtils.java
@@ -16,9 +16,7 @@
 
 package com.android.launcher3.util;
 
-import android.graphics.Bitmap;
 import android.os.FileUtils;
-import android.util.Base64;
 import android.util.Log;
 
 import com.android.launcher3.Utilities;
@@ -52,12 +50,6 @@
         return out.toByteArray();
     }
 
-    public static String toBase64String(Bitmap bitmap) {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
-        return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
-    }
-
     public static long copy(InputStream from, OutputStream to) throws IOException {
         if (Utilities.ATLEAST_Q) {
             return FileUtils.copy(from, to);
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 78916ac..a88b8b7 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -18,6 +18,8 @@
 
 import static android.view.HapticFeedbackConstants.CLOCK_TICK;
 
+import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
+
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
@@ -30,6 +32,7 @@
 import android.graphics.RectF;
 import android.os.Build;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.Property;
 import android.view.MotionEvent;
 import android.view.View;
@@ -54,9 +57,14 @@
  * The track and scrollbar that shows when you scroll the list.
  */
 public class RecyclerViewFastScroller extends View {
-
-    private static final int FASTSCROLL_THRESHOLD_MILLIS = 200;
+    private static final String TAG = "RecyclerViewFastScroller";
+    private static final boolean DEBUG = false;
+    private static final int FASTSCROLL_THRESHOLD_MILLIS = 40;
     private static final int SCROLL_DELTA_THRESHOLD_DP = 4;
+
+    // Track is very narrow to target and correctly. This is especially the case if a user is
+    // using a hardware case. Even if x is offset by following amount, we consider it to be valid.
+    private static final int SCROLLBAR_LEFT_OFFSET_TOUCH_DELEGATE_DP = 5;
     private static final Rect sTempRect = new Rect();
 
     private static final Property<RecyclerViewFastScroller, Integer> TRACK_WIDTH =
@@ -86,6 +94,7 @@
     /** Keeps the last known scrolling delta/velocity along y-axis. */
     private int mDy = 0;
     private final float mDeltaThreshold;
+    private final float mScrollbarLeftOffsetTouchDelegate;
 
     private final ViewConfiguration mConfig;
 
@@ -157,6 +166,8 @@
 
         mConfig = ViewConfiguration.get(context);
         mDeltaThreshold = res.getDisplayMetrics().density * SCROLL_DELTA_THRESHOLD_DP;
+        mScrollbarLeftOffsetTouchDelegate = res.getDisplayMetrics().density
+                * SCROLLBAR_LEFT_OFFSET_TOUCH_DELEGATE_DP;
 
         TypedArray ta =
                 context.obtainStyledAttributes(attrs, R.styleable.RecyclerViewFastScroller, defStyleAttr, 0);
@@ -239,6 +250,7 @@
     public boolean handleTouchEvent(MotionEvent ev, Point offset) {
         int x = (int) ev.getX() - offset.x;
         int y = (int) ev.getY() - offset.y;
+
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 // Keep track of the down positions
@@ -247,7 +259,7 @@
                 mDownTimeStampMillis = ev.getDownTime();
 
                 if ((Math.abs(mDy) < mDeltaThreshold &&
-                        mRv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE)) {
+                        mRv.getScrollState() != SCROLL_STATE_IDLE)) {
                     // now the touch events are being passed to the {@link WidgetCell} until the
                     // touch sequence goes over the touch slop.
                     mRv.stopScroll();
@@ -293,6 +305,13 @@
                 }
                 break;
         }
+        if (DEBUG) {
+            Log.d(TAG, (ev.getAction() == MotionEvent.ACTION_DOWN ? "\n" : "")
+                    + "handleTouchEvent " + MotionEvent.actionToString(ev.getAction())
+                    + " (" + x + "," + y + ")" + " isDragging=" + mIsDragging
+                    + " mIgnoreDragGesture=" + mIgnoreDragGesture);
+
+        }
         return mIsDragging;
     }
 
@@ -401,7 +420,8 @@
      * Returns whether the specified x position is near the scroll bar.
      */
     public boolean isNearScrollBar(int x) {
-        return x >= (getWidth() - mMaxWidth) / 2 && x <= (getWidth() + mMaxWidth) / 2;
+        return x >= (getWidth() - mMaxWidth) / 2 - mScrollbarLeftOffsetTouchDelegate
+                && x <= (getWidth() + mMaxWidth) / 2;
     }
 
     private void animatePopupVisibility(boolean visible) {
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 3bf993e..9f0b9d9 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -24,11 +24,14 @@
 import android.view.View.OnLongClickListener;
 import android.widget.Toast;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.Nullable;
 import androidx.core.view.ViewCompat;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -47,10 +50,11 @@
  */
 public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
         implements OnClickListener, OnLongClickListener, DragSource,
-        PopupDataProvider.PopupDataChangeListener {
+        PopupDataProvider.PopupDataChangeListener, Insettable {
 
     protected static final String KEY_WIDGETS_EDUCATION_TIP_SEEN =
             "launcher.widgets_education_tip_seen";
+    protected final Rect mInsets = new Rect();
 
     /* Touch handling related member variables. */
     private Toast mWidgetInstructionToast;
@@ -105,6 +109,35 @@
         return true;
     }
 
+    @Override
+    public void setInsets(Rect insets) {
+        mInsets.set(insets);
+    }
+
+
+    /**
+     * Measures the dimension of this view and its children by taking system insets, navigation bar,
+     * status bar, into account.
+     */
+    @GuardedBy("MainThread")
+    protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+        int widthUsed;
+        if (mInsets.bottom > 0) {
+            widthUsed = mInsets.left + mInsets.right;
+        } else {
+            Rect padding = deviceProfile.workspacePadding;
+            widthUsed = Math.max(padding.left + padding.right,
+                    2 * (mInsets.left + mInsets.right));
+        }
+
+        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
+        measureChildWithMargins(mContent, widthMeasureSpec,
+                widthUsed, heightMeasureSpec, heightUsed);
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
+    }
+
     private boolean beginDraggingWidget(WidgetCell v) {
         // Get the widget preview as the drag representation
         WidgetImageView image = v.getWidgetView();
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 37b950d..d7928c7 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -23,7 +23,6 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.IntProperty;
-import android.util.Log;
 import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -36,10 +35,7 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
-import androidx.annotation.GuardedBy;
-
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.PendingAnimation;
@@ -53,7 +49,7 @@
 /**
  * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
  */
-public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
+public class WidgetsBottomSheet extends BaseWidgetSheet {
     private static final String TAG = "WidgetsBottomSheet";
 
     private static final IntProperty<View> PADDING_BOTTOM =
@@ -74,7 +70,6 @@
     private static final long EDUCATION_TIP_DELAY_MS = 300;
 
     private ItemInfo mOriginalItemInfo;
-    private final Rect mInsets;
     private final int mMaxTableHeight;
     private int mMaxHorizontalSpan = 4;
 
@@ -114,7 +109,6 @@
     public WidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         setWillNotDraw(false);
-        mInsets = new Rect();
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         // Set the max table height to 2 / 3 of the grid height so that the bottom picker won't
         // take over the entire view vertically.
@@ -132,53 +126,20 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (doMeasure(widthMeasureSpec, heightMeasureSpec)) {
-            boolean hasUpdated = doMeasure(widthMeasureSpec, heightMeasureSpec);
-            if (hasUpdated) {
-                Log.w(TAG, "WidgetsBottomSheet dimension has been updated after a 2nd"
-                        + " measurement.");
-            }
+        doMeasure(widthMeasureSpec, heightMeasureSpec);
+        if (updateMaxSpansPerRow()) {
+            doMeasure(widthMeasureSpec, heightMeasureSpec);
         }
     }
 
-    /**
-     * Measures the dimension of this view and its children.
-     *
-     * <p>This function takes account of the following during measurement:
-     * <ol>
-     *     <li>status bar and system navigation bar insets</li>
-     *     <li>
-     *         number of spans that can fit in a row. This affects the number of widgets that can
-     *         fit in a row.
-     *     </li>
-     * </ol>
-     *
-     * @return {@code true} if the width or height of this view or its children have changed after
-     *          the measurement. Otherwise, returns {@code false}.
-     */
-    @GuardedBy("MainThread")
-    private boolean doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
-        int widthUsed;
-        if (mInsets.bottom > 0) {
-            widthUsed = mInsets.left + mInsets.right;
-        } else {
-            Rect padding = deviceProfile.workspacePadding;
-            widthUsed = Math.max(padding.left + padding.right,
-                    2 * (mInsets.left + mInsets.right));
-        }
-
-        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
-        measureChildWithMargins(mContent, widthMeasureSpec,
-                widthUsed, heightMeasureSpec, heightUsed);
-        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
-                MeasureSpec.getSize(heightMeasureSpec));
+    /** Returns {@code true} if the max spans have been updated. */
+    private boolean updateMaxSpansPerRow() {
+        if (getMeasuredWidth() == 0) return false;
 
         int paddingPx = 2 * getResources().getDimensionPixelOffset(
                 R.dimen.widget_cell_horizontal_padding);
         int maxHorizontalSpan = findViewById(R.id.widgets_table).getMeasuredWidth()
                 / (mActivityContext.getDeviceProfile().cellWidthPx + paddingPx);
-
         if (mMaxHorizontalSpan != maxHorizontalSpan) {
             // Ensure the table layout is showing widgets in the right column after measure.
             mMaxHorizontalSpan = maxHorizontalSpan;
@@ -297,7 +258,8 @@
 
     @Override
     public void setInsets(Rect insets) {
-        mInsets.set(insets);
+        super.setInsets(insets);
+
         mContent.setPadding(mContent.getPaddingStart(),
                 mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
         if (insets.bottom > 0) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 0106ef5..33f4e50 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -45,8 +45,6 @@
 import androidx.recyclerview.widget.DefaultItemAnimator;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
@@ -76,7 +74,7 @@
  * Popup for showing the full list of available widgets
  */
 public class WidgetsFullSheet extends BaseWidgetSheet
-        implements Insettable, ProviderChangedListener, OnActivePageChangedListener,
+        implements ProviderChangedListener, OnActivePageChangedListener,
         WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
     private static final String TAG = WidgetsFullSheet.class.getSimpleName();
 
@@ -309,7 +307,7 @@
 
     @Override
     public void setInsets(Rect insets) {
-        mInsets.set(insets);
+        super.setInsets(insets);
 
         setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, insets.bottom);
         setBottomPadding(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView, insets.bottom);
@@ -351,24 +349,6 @@
         }
     }
 
-    private void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
-        int widthUsed;
-        if (mInsets.bottom > 0) {
-            widthUsed = mInsets.left + mInsets.right;
-        } else {
-            Rect padding = deviceProfile.workspacePadding;
-            widthUsed = Math.max(padding.left + padding.right,
-                    2 * (mInsets.left + mInsets.right));
-        }
-
-        int heightUsed = mInsets.top + deviceProfile.edgeMarginPx;
-        measureChildWithMargins(mContent, widthMeasureSpec,
-                widthUsed, heightMeasureSpec, heightUsed);
-        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
-                MeasureSpec.getSize(heightMeasureSpec));
-    }
-
     /** Returns {@code true} if the max spans have been updated. */
     private boolean updateMaxSpansPerRow() {
         if (getMeasuredWidth() == 0) return false;