Merge "Fix blinking for the active tile" into main
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 0ef4541..3514447 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -26,6 +26,7 @@
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
 import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode;
+import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
@@ -380,10 +381,12 @@
         int navButtonSize = mContext.getResources().getDimensionPixelSize(
                 R.dimen.taskbar_nav_buttons_size);
         boolean isRtl = Utilities.isRtl(mContext.getResources());
-        mPropertyHolders.add(new StatePropertyHolder(
-                mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
-                        || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
-                VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
+        if (!isPhoneMode(mContext.getDeviceProfile())) {
+            mPropertyHolders.add(new StatePropertyHolder(
+                    mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
+                            || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
+                    VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
+        }
 
         // home button
         mHomeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index a3bfb17..d7ff59e 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1225,12 +1225,12 @@
                         : null;
         ActiveGestureLog.INSTANCE.addLog(
                 new ActiveGestureLog.CompoundString("calculateEndTarget: velocities=(x=")
-                        .append(Float.toString(dpiFromPx(velocityPxPerMs.x)))
+                        .append(dpiFromPx(velocityPxPerMs.x))
                         .append("dp/ms, y=")
-                        .append(Float.toString(dpiFromPx(velocityPxPerMs.y)))
+                        .append(dpiFromPx(velocityPxPerMs.y))
                         .append("dp/ms), angle=")
-                        .append(Double.toString(Math.toDegrees(Math.atan2(
-                                -velocityPxPerMs.y, velocityPxPerMs.x)))), gestureEvent);
+                        .append(Math.toDegrees(Math.atan2(
+                                -velocityPxPerMs.y, velocityPxPerMs.x))), gestureEvent);
 
         if (mGestureState.isHandlingAtomicEvent()) {
             // Button mode, this is only used to go to recents.
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index ac6c274..2aa9240 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -32,6 +32,7 @@
 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__OVERVIEW;
 
 import android.content.Context;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.StatsEvent;
 import android.view.View;
@@ -227,6 +228,7 @@
         private Optional<Integer> mCardinality = Optional.empty();
         private int mInputType = SysUiStatsLog.LAUNCHER_UICHANGED__INPUT_TYPE__UNKNOWN;
         private Optional<Integer> mFeatures = Optional.empty();
+        private Optional<String> mPackageName = Optional.empty();
 
         StatsCompatLogger(Context context, ActivityContext activityContext) {
             mContext = context;
@@ -332,6 +334,12 @@
         }
 
         @Override
+        public StatsLogger withPackageName(@Nullable String packageName) {
+            mPackageName = Optional.ofNullable(packageName);
+            return this;
+        }
+
+        @Override
         public void log(EventEnum event) {
             if (!Utilities.ATLEAST_R) {
                 return;
@@ -431,6 +439,7 @@
             int srcState = mSrcState;
             int dstState = mDstState;
             int inputType = mInputType;
+            String packageName = mPackageName.orElseGet(() -> getPackageName(atomInfo));
             if (IS_VERBOSE) {
                 String name = (event instanceof Enum) ? ((Enum) event).name() :
                         event.getId() + "";
@@ -448,6 +457,9 @@
                 if (atomInfo.hasContainerInfo()) {
                     logStringBuilder.append("\n").append(atomInfo);
                 }
+                if (!TextUtils.isEmpty(packageName)) {
+                    logStringBuilder.append(String.format("\nPackage name: %s", packageName));
+                }
                 Log.d(TAG, logStringBuilder.toString());
             }
 
@@ -472,7 +484,7 @@
                     atomInfo.getItemCase().getNumber() /* target_id */,
                     instanceId.getId() /* instance_id TODO */,
                     0 /* uid TODO */,
-                    getPackageName(atomInfo) /* package_name */,
+                    packageName /* package_name */,
                     getComponentName(atomInfo) /* component_name */,
                     getGridX(atomInfo, false) /* grid_x */,
                     getGridY(atomInfo, false) /* grid_y */,
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 6f4b6cb..278ca56 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -18,6 +18,8 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.util.Preconditions;
+
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -43,14 +45,6 @@
      */
     public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID";
 
-    private static final int TYPE_ONE_OFF = 0;
-    private static final int TYPE_FLOAT = 1;
-    private static final int TYPE_INTEGER = 2;
-    private static final int TYPE_BOOL_TRUE = 3;
-    private static final int TYPE_BOOL_FALSE = 4;
-    private static final int TYPE_COMPOUND_STRING = 5;
-    private static final int TYPE_GESTURE_EVENT = 6;
-
     private final EventLog[] logs;
     private int nextIndex;
     private int mCurrentLogId = 100;
@@ -67,9 +61,12 @@
      *                   execution.
      */
     public void trackEvent(@Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
-        addLog(TYPE_GESTURE_EVENT, "", 0, CompoundString.NO_OP, gestureEvent);
+        addLog(CompoundString.NO_OP, gestureEvent);
     }
 
+    /**
+     * Adds a log to be printed at log-dump-time.
+     */
     public void addLog(String event) {
         addLog(event, null);
     }
@@ -82,54 +79,35 @@
         addLog(event, extras, null);
     }
 
-    public void addLog(CompoundString compoundString) {
-        if (compoundString == CompoundString.NO_OP) return;
-        addLog(TYPE_COMPOUND_STRING, "", 0, compoundString, null);
-    }
-
-    public void addLog(
-            CompoundString compoundString,
-            @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
-        if (compoundString == CompoundString.NO_OP) {
-            trackEvent(gestureEvent);
-            return;
-        }
-        addLog(TYPE_COMPOUND_STRING, "", 0, compoundString, gestureEvent);
-    }
-
     /**
-     * Adds a log and track the associated event for error detection.
+     * Adds a log to be printed at log-dump-time and track the associated event for error detection.
      *
      * @param gestureEvent GestureEvent representing the event being logged.
      */
     public void addLog(
             String event, @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
-        addLog(TYPE_ONE_OFF, event, 0, CompoundString.NO_OP, gestureEvent);
+        addLog(new CompoundString(event), gestureEvent);
     }
 
     public void addLog(
             String event,
             int extras,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
-        addLog(TYPE_INTEGER, event, extras, CompoundString.NO_OP, gestureEvent);
+        addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
     }
 
     public void addLog(
             String event,
             boolean extras,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
-        addLog(
-                extras ? TYPE_BOOL_TRUE : TYPE_BOOL_FALSE,
-                event,
-                0,
-                CompoundString.NO_OP,
-                gestureEvent);
+        addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
     }
 
-    private void addLog(
-            int type,
-            String event,
-            float extras,
+    public void addLog(CompoundString compoundString) {
+        addLog(compoundString, null);
+    }
+
+    public void addLog(
             CompoundString compoundString,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         EventLog lastEventLog = logs[(nextIndex + logs.length - 1) % logs.length];
@@ -137,7 +115,7 @@
             EventLog eventLog = new EventLog(mCurrentLogId, mIsFullyGesturalNavMode);
             EventEntry eventEntry = new EventEntry();
 
-            eventEntry.update(type, event, extras, compoundString, gestureEvent);
+            eventEntry.update(compoundString, gestureEvent);
             eventLog.eventEntries.add(eventEntry);
             logs[nextIndex] = eventLog;
             nextIndex = (nextIndex + 1) % logs.length;
@@ -146,17 +124,17 @@
 
         // Update the last EventLog
         List<EventEntry> lastEventEntries = lastEventLog.eventEntries;
-        EventEntry lastEntry = lastEventEntries.size() > 0
+        EventEntry lastEntry = !lastEventEntries.isEmpty()
                 ? lastEventEntries.get(lastEventEntries.size() - 1) : null;
 
         // Update the last EventEntry if it's a duplicate
-        if (isEntrySame(lastEntry, type, event, extras, compoundString, gestureEvent)) {
+        if (isEntrySame(lastEntry, compoundString, gestureEvent)) {
             lastEntry.duplicateCount++;
             return;
         }
         EventEntry eventEntry = new EventEntry();
 
-        eventEntry.update(type, event, extras, compoundString, gestureEvent);
+        eventEntry.update(compoundString, gestureEvent);
         lastEventEntries.add(eventEntry);
     }
 
@@ -181,30 +159,14 @@
 
             writer.println(prefix + "\tLogs for logId: " + eventLog.logId);
             for (EventEntry eventEntry : eventLog.eventEntries) {
+                if (eventEntry.mCompoundString.mIsNoOp) {
+                    continue;
+                }
                 date.setTime(eventEntry.time);
 
-                StringBuilder msg = new StringBuilder(prefix + "\t\t").append(sdf.format(date))
-                        .append(eventEntry.event);
-                switch (eventEntry.type) {
-                    case TYPE_BOOL_FALSE:
-                        msg.append(": false");
-                        break;
-                    case TYPE_BOOL_TRUE:
-                        msg.append(": true");
-                        break;
-                    case TYPE_FLOAT:
-                        msg.append(": ").append(eventEntry.extras);
-                        break;
-                    case TYPE_INTEGER:
-                        msg.append(": ").append((int) eventEntry.extras);
-                        break;
-                    case TYPE_COMPOUND_STRING:
-                        msg.append(eventEntry.mCompoundString);
-                        break;
-                    case TYPE_GESTURE_EVENT:
-                        continue;
-                    default: // fall out
-                }
+                StringBuilder msg = new StringBuilder(prefix + "\t\t")
+                        .append(sdf.format(date))
+                        .append(eventEntry.mCompoundString);
                 if (eventEntry.duplicateCount > 0) {
                     msg.append(" & ").append(eventEntry.duplicateCount).append(" similar events");
                 }
@@ -232,15 +194,9 @@
 
     private boolean isEntrySame(
             EventEntry entry,
-            int type,
-            String event,
-            float extras,
             CompoundString compoundString,
             ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         return entry != null
-                && entry.type == type
-                && entry.event.equals(event)
-                && Float.compare(entry.extras, extras) == 0
                 && entry.mCompoundString.equals(compoundString)
                 && entry.gestureEvent == gestureEvent;
     }
@@ -248,9 +204,6 @@
     /** A single event entry. */
     protected static class EventEntry {
 
-        private int type;
-        private String event;
-        private float extras;
         @NonNull private CompoundString mCompoundString;
         private ActiveGestureErrorDetector.GestureEvent gestureEvent;
         private long time;
@@ -264,14 +217,8 @@
         }
 
         private void update(
-                int type,
-                String event,
-                float extras,
                 @NonNull CompoundString compoundString,
                 ActiveGestureErrorDetector.GestureEvent gestureEvent) {
-            this.type = type;
-            this.event = event;
-            this.extras = extras;
             this.mCompoundString = compoundString;
             this.gestureEvent = gestureEvent;
             time = System.currentTimeMillis();
@@ -302,6 +249,7 @@
         public static final CompoundString NO_OP = new CompoundString();
 
         private final List<String> mSubstrings;
+        private final List<Object> mArgs;
 
         private final boolean mIsNoOp;
 
@@ -313,10 +261,12 @@
             mIsNoOp = substring == null;
             if (mIsNoOp) {
                 mSubstrings = null;
+                mArgs = null;
                 return;
             }
             mSubstrings = new ArrayList<>();
             mSubstrings.add(substring);
+            mArgs = new ArrayList<>();
         }
 
         public CompoundString append(CompoundString substring) {
@@ -338,19 +288,41 @@
         }
 
         public CompoundString append(int num) {
-            if (mIsNoOp) {
-                return this;
-            }
-            mSubstrings.add(Integer.toString(num));
+            mArgs.add(num);
 
-            return this;
+            return append("%d");
+        }
+
+        public CompoundString append(float num) {
+            mArgs.add(num);
+
+            return append("%.2f");
+        }
+
+        public CompoundString append(double num) {
+            mArgs.add(num);
+
+            return append("%.2f");
+        }
+
+        public CompoundString append(boolean bool) {
+            mArgs.add(bool);
+
+            return append("%b");
+        }
+
+        public Object[] getArgs() {
+            return mArgs.toArray();
         }
 
         @Override
         public String toString() {
-            if (mIsNoOp) {
-                return "ERROR: cannot use No-Op compound string";
-            }
+            return String.format(toUnformattedString(), getArgs());
+        }
+
+        public String toUnformattedString() {
+            Preconditions.assertTrue(!mIsNoOp);
+
             StringBuilder sb = new StringBuilder();
             for (String substring : mSubstrings) {
                 sb.append(substring);
diff --git a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
index 79ca076..21c9e09 100644
--- a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
+++ b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java
@@ -44,7 +44,7 @@
     private final PriorityQueue<Task.TaskKey> mQueue;
 
     public TaskKeyByLastActiveTimeCache(int maxSize) {
-        mMap = new HashMap(maxSize);
+        mMap = new HashMap(0);
         mQueue = new PriorityQueue<>(Comparator.comparingLong(t -> t.lastActiveTime));
         mMaxSize = new AtomicInteger(maxSize);
     }
@@ -106,7 +106,8 @@
     }
 
     /**
-     * Adds an entry to the cache, optionally evicting the last accessed entry
+     * Adds an entry to the cache, optionally evicting the last accessed entry excluding the newly
+     * added entry
      */
     @Override
     public final synchronized void put(Task.TaskKey key, V value) {
@@ -117,9 +118,9 @@
                 mQueue.remove(entry.mKey);
             }
 
+            removeExcessIfNeeded(mMaxSize.get() - 1);
             mMap.put(key.id, new Entry<>(key, value));
             mQueue.add(key);
-            removeExcessIfNeeded();
         } else {
             Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
         }
@@ -143,11 +144,11 @@
     @Override
     public synchronized void updateCacheSizeAndRemoveExcess(int cacheSize) {
         mMaxSize.compareAndSet(mMaxSize.get(), cacheSize);
-        removeExcessIfNeeded();
+        removeExcessIfNeeded(mMaxSize.get());
     }
 
-    private synchronized void removeExcessIfNeeded() {
-        while (mQueue.size() > mMaxSize.get() && !mQueue.isEmpty()) {
+    private synchronized void removeExcessIfNeeded(int maxSize) {
+        while (mQueue.size() > maxSize && !mQueue.isEmpty()) {
             Task.TaskKey key = mQueue.poll();
             mMap.remove(key.id);
         }
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 20e7089..8d84c90 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -164,7 +164,19 @@
 
         <!-- numFolderRows & numFolderColumns defaults to numRows & numColumns, if not specified -->
         <attr name="numFolderRows" format="integer" />
+        <!-- defaults to numFolderRows, if not specified -->
+        <attr name="numFolderRowsLandscape" format="integer" />
+        <!-- defaults to numFolderRows, if not specified -->
+        <attr name="numFolderRowsTwoPanelLandscape" format="integer" />
+        <!-- defaults to numFolderRows, if not specified -->
+        <attr name="numFolderRowsTwoPanelPortrait" format="integer" />
         <attr name="numFolderColumns" format="integer" />
+        <!-- defaults to numFolderColumns, if not specified -->
+        <attr name="numFolderColumnsLandscape" format="integer" />
+        <!-- defaults to numFolderColumns, if not specified -->
+        <attr name="numFolderColumnsTwoPanelLandscape" format="integer" />
+        <!-- defaults to numFolderColumns, if not specified -->
+        <attr name="numFolderColumnsTwoPanelPortrait" format="integer" />
         <!-- Support attributes in FolderStyle -->
         <attr name="folderStyle" format="reference" />
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7ca8b82..badd1c4 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -439,8 +439,8 @@
         }
 
         folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);
-        numFolderRows = inv.numFolderRows;
-        numFolderColumns = inv.numFolderColumns;
+        numFolderRows = inv.numFolderRows[mTypeIndex];
+        numFolderColumns = inv.numFolderColumns[mTypeIndex];
 
         if (mIsScalableGrid && inv.folderStyle != INVALID_RESOURCE_HANDLE) {
             TypedArray folderStyle = context.obtainStyledAttributes(inv.folderStyle,
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 567d0c5..dfbbcaa 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -122,8 +122,8 @@
     /**
      * Number of icons per row and column in the folder.
      */
-    public int numFolderRows;
-    public int numFolderColumns;
+    public int[] numFolderRows;
+    public int[] numFolderColumns;
     public float[] iconSize;
     public float[] iconTextSize;
     public int iconBitmapSize;
@@ -810,8 +810,8 @@
         public final int numSearchContainerColumns;
         public final int deviceCategory;
 
-        private final int numFolderRows;
-        private final int numFolderColumns;
+        private final int[] numFolderRows = new int[COUNT_SIZES];
+        private final int[] numFolderColumns = new int[COUNT_SIZES];
         private final @StyleRes int folderStyle;
         private final @StyleRes int cellStyle;
 
@@ -888,11 +888,39 @@
                     a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
                             R.dimen.taskbar_button_margin_default);
 
-            numFolderRows = a.getInt(
+            numFolderRows[INDEX_DEFAULT] = a.getInt(
                     R.styleable.GridDisplayOption_numFolderRows, numRows);
-            numFolderColumns = a.getInt(
+            numFolderColumns[INDEX_DEFAULT] = a.getInt(
                     R.styleable.GridDisplayOption_numFolderColumns, numColumns);
 
+            if (FeatureFlags.enableResponsiveWorkspace()) {
+                numFolderRows[INDEX_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderRowsLandscape,
+                        numFolderRows[INDEX_DEFAULT]);
+                numFolderColumns[INDEX_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderColumnsLandscape,
+                        numFolderColumns[INDEX_DEFAULT]);
+                numFolderRows[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderRowsTwoPanelPortrait,
+                        numFolderRows[INDEX_DEFAULT]);
+                numFolderColumns[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderColumnsTwoPanelPortrait,
+                        numFolderColumns[INDEX_DEFAULT]);
+                numFolderRows[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderRowsTwoPanelLandscape,
+                        numFolderRows[INDEX_DEFAULT]);
+                numFolderColumns[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderColumnsTwoPanelLandscape,
+                        numFolderColumns[INDEX_DEFAULT]);
+            } else {
+                numFolderRows[INDEX_LANDSCAPE] = numFolderRows[INDEX_DEFAULT];
+                numFolderColumns[INDEX_LANDSCAPE] = numFolderColumns[INDEX_DEFAULT];
+                numFolderRows[INDEX_TWO_PANEL_PORTRAIT] = numFolderRows[INDEX_DEFAULT];
+                numFolderColumns[INDEX_TWO_PANEL_PORTRAIT] = numFolderColumns[INDEX_DEFAULT];
+                numFolderRows[INDEX_TWO_PANEL_LANDSCAPE] = numFolderRows[INDEX_DEFAULT];
+                numFolderColumns[INDEX_TWO_PANEL_LANDSCAPE] = numFolderColumns[INDEX_DEFAULT];
+            }
+
             folderStyle = a.getResourceId(R.styleable.GridDisplayOption_folderStyle,
                     INVALID_RESOURCE_HANDLE);
 
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 5f73ced..9980218 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -860,6 +860,13 @@
         }
 
         /**
+         * Set the package name of the log message.
+         */
+        default StatsLogger withPackageName(@Nullable String packageName) {
+            return this;
+        }
+
+        /**
          * Builds the final message and logs it as {@link EventEnum}.
          */
         default void log(EventEnum event) {
diff --git a/src/com/android/launcher3/util/Preconditions.java b/src/com/android/launcher3/util/Preconditions.java
index 63d56e4..0e5ab9a 100644
--- a/src/com/android/launcher3/util/Preconditions.java
+++ b/src/com/android/launcher3/util/Preconditions.java
@@ -51,6 +51,12 @@
         }
     }
 
+    public static void assertTrue(boolean condition) {
+        if (FeatureFlags.IS_STUDIO_BUILD && !condition) {
+            throw new IllegalStateException();
+        }
+    }
+
     private static boolean isSameLooper(Looper looper) {
         return Looper.myLooper() == looper;
     }
diff --git a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index a421006..30b5663 100644
--- a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -121,8 +121,8 @@
                     listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
                         .toTypedArray()
 
-                numFolderRows = 3
-                numFolderColumns = 3
+                numFolderRows = intArrayOf(3, 3, 3, 3)
+                numFolderColumns = intArrayOf(3, 3, 3, 3)
                 folderStyle = R.style.FolderStyleDefault
 
                 inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
@@ -204,8 +204,8 @@
                     listOf(PointF(16f, 64f), PointF(64f, 16f), PointF(16f, 64f), PointF(16f, 64f))
                         .toTypedArray()
 
-                numFolderRows = 3
-                numFolderColumns = 3
+                numFolderRows = intArrayOf(3, 3, 3, 3)
+                numFolderColumns = intArrayOf(3, 3, 3, 3)
                 folderStyle = R.style.FolderStyleDefault
 
                 inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
@@ -288,8 +288,8 @@
                     listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 20f), PointF(20f, 20f))
                         .toTypedArray()
 
-                numFolderRows = 3
-                numFolderColumns = 3
+                numFolderRows = intArrayOf(3, 3, 3, 3)
+                numFolderColumns = intArrayOf(3, 3, 3, 3)
                 folderStyle = R.style.FolderStyleDefault
 
                 inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split