Merge "Revert "Make numFolderRows/numFolderColumns accept more values"" into main
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 81e4ad5..1be1798 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.util.AttributeSet;
+import android.view.InputDevice;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -268,6 +269,8 @@
         if (mTaskbarDivider != null) {
             mTaskbarDivider.setOnLongClickListener(
                     mControllerCallbacks.getTaskbarDividerLongClickListener());
+            mTaskbarDivider.setOnTouchListener(
+                    mControllerCallbacks.getTaskbarDividerRightClickListener());
         }
     }
 
@@ -408,6 +411,16 @@
     public void setClickAndLongClickListenersForIcon(View icon) {
         icon.setOnClickListener(mIconClickListener);
         icon.setOnLongClickListener(mIconLongClickListener);
+        // Add right-click support to btv icons.
+        icon.setOnTouchListener((v, event) -> {
+            if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+                    && (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0
+                    && v instanceof BubbleTextView) {
+                mActivityContext.showPopupMenuForIcon((BubbleTextView) v);
+                return true;
+            }
+            return false;
+        });
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 0225de4..8a7a98c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -44,6 +44,7 @@
 import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.util.Log;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.Interpolator;
@@ -883,6 +884,17 @@
             };
         }
 
+        public View.OnTouchListener getTaskbarDividerRightClickListener() {
+            return (v, event) -> {
+                if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+                        && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
+                    mControllers.taskbarPinningController.showPinningView(v);
+                    return true;
+                }
+                return false;
+            };
+        }
+
         public View.OnLongClickListener getIconOnLongClickListener() {
             return mControllers.taskbarDragController::startDragOnLongClick;
         }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 3717d9c..b7576c3 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -982,12 +982,11 @@
                     base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
                             mOverviewCommandHelper);
                 }
-            } else if (canStartSystemGesture && FeatureFlags.ENABLE_LONG_PRESS_NAV_HANDLE.get()
-                    && !previousGestureState.isRecentsAnimationRunning()) {
+            } else if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) {
                 reasonString.append(NEWLINE_PREFIX)
                         .append(reasonPrefix)
                         .append(SUBSTRING_PREFIX)
-                        .append("Long press nav handle enabled, ")
+                        .append("Not running recents animation, ")
                         .append("using NavHandleLongPressInputConsumer");
                 base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
                         mDeviceState);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
index 14305cf..57c05e9 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
@@ -48,17 +48,13 @@
     }
 
     /**
-     * Called when nav handle gesture starts. Returns true if long press nav handle is enabled and
-     * supported.
+     * Called when nav handle gesture starts.
      */
-    public boolean canStartTouch() {
-        return false;
-    }
+    public void onTouchStarted() {}
 
     /**
      * Called when nav handle gesture is finished by the user lifting their finger or the system
      * cancelling the touch for some other reason.
      */
-    public void onTouchFinished() {
-    }
+    public void onTouchFinished() {}
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 8051e68..0127cc9 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -16,6 +16,8 @@
 package com.android.quickstep.inputconsumers;
 
 import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DEEP_PRESS_NAVBAR;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_LONG_PRESS_NAVBAR;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.content.Context;
@@ -25,9 +27,11 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.TopTaskTracker;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
@@ -43,8 +47,11 @@
     private final float mTouchSlopSquared;
     private final int mLongPressTimeout;
     private final boolean mDeepPressEnabled;
+    private final StatsLogManager mStatsLogManager;
+    private final TopTaskTracker mTopTaskTracker;
 
     private MotionEvent mCurrentDownEvent;
+    private boolean mDeepPressLogged;  // Whether deep press has been logged for the current touch.
 
     public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
             InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState) {
@@ -60,6 +67,8 @@
         }
         mTouchSlopSquared = deviceState.getSquaredTouchSlop();
         mNavHandleLongPressHandler = NavHandleLongPressHandler.newInstance(context);
+        mStatsLogManager = StatsLogManager.newInstance(context);
+        mTopTaskTracker = TopTaskTracker.INSTANCE.get(context);
     }
 
     @Override
@@ -87,8 +96,9 @@
                     mCurrentDownEvent.recycle();
                 }
                 mCurrentDownEvent = MotionEvent.obtain(ev);
-                if (isInNavBarHorizontalArea(ev.getRawX())
-                        && mNavHandleLongPressHandler.canStartTouch()) {
+                mDeepPressLogged = false;
+                if (isInNavBarHorizontalArea(ev.getRawX())) {
+                    mNavHandleLongPressHandler.onTouchStarted();
                     MAIN_EXECUTOR.getHandler().postDelayed(mTriggerLongPress,
                             mLongPressTimeout);
                 }
@@ -110,25 +120,41 @@
         }
 
         // If the gesture is deep press then trigger long press asap
-        if (mDeepPressEnabled && MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)
-                && ev.getClassification() == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
-            MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
-            MAIN_EXECUTOR.getHandler().post(mTriggerLongPress);
+        if (MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)
+                && ev.getClassification() == MotionEvent.CLASSIFICATION_DEEP_PRESS
+                && !mDeepPressLogged) {
+            // Log deep press even if feature is disabled.
+            String runningPackage = mTopTaskTracker.getCachedTopTask(
+                    /* filterOnlyVisibleRecents */ true).getPackageName();
+            mStatsLogManager.logger().withPackageName(runningPackage)
+                    .log(LAUNCHER_DEEP_PRESS_NAVBAR);
+            mDeepPressLogged = true;
+
+            // But only trigger if the feature is enabled.
+            if (mDeepPressEnabled) {
+                MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
+                MAIN_EXECUTOR.getHandler().post(mTriggerLongPress);
+            }
         }
     }
 
     private void triggerLongPress() {
+        String runningPackage = mTopTaskTracker.getCachedTopTask(
+                /* filterOnlyVisibleRecents */ true).getPackageName();
+        mStatsLogManager.logger().withPackageName(runningPackage).log(LAUNCHER_LONG_PRESS_NAVBAR);
+
         Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable();
-        if (longPressRunnable != null) {
-            OtherActivityInputConsumer oaic = getInputConsumerOfClass(
-                    OtherActivityInputConsumer.class);
-            if (oaic != null && oaic.hasStartedTouchTracking()) {
-                oaic.setForceFinishRecentsTransitionCallback(longPressRunnable);
-                setActive(mCurrentDownEvent);
-            } else {
-                setActive(mCurrentDownEvent);
-                MAIN_EXECUTOR.post(longPressRunnable);
-            }
+        if (longPressRunnable == null) {
+            return;
+        }
+
+        OtherActivityInputConsumer oaic = getInputConsumerOfClass(OtherActivityInputConsumer.class);
+        if (oaic != null && oaic.hasStartedTouchTracking()) {
+            oaic.setForceFinishRecentsTransitionCallback(longPressRunnable);
+            setActive(mCurrentDownEvent);
+        } else {
+            setActive(mCurrentDownEvent);
+            MAIN_EXECUTOR.post(longPressRunnable);
         }
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index 28473cd..f0683f9 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -154,6 +154,11 @@
         getTaskbar().openAllApps().dismissByTappingOutsideForTablet(/* tapRight= */ false);
     }
 
+    @Test
+    public void testOpenMenuViaRightClick() {
+        getTaskbar().getAppIcon(TEST_APP_NAME).openDeepShortcutMenuWithRightClick();
+    }
+
     private boolean isTaskbarTestModeTransient() {
         return TRANSIENT == mTaskbarMode;
     }
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 9980218..f90779c 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -275,6 +275,12 @@
         @UiEvent(doc = "User swipes or fling in DOWN direction on the bottom bazel area.")
         LAUNCHER_SWIPEDOWN_NAVBAR(573),
 
+        @UiEvent(doc = "User deep presses on the bottom bezel area.")
+        LAUNCHER_DEEP_PRESS_NAVBAR(1543),
+
+        @UiEvent(doc = "User long presses on the bottom bezel area.")
+        LAUNCHER_LONG_PRESS_NAVBAR(1544),
+
         @UiEvent(doc = "User swipes or fling in UP direction from bottom bazel area.")
         LAUNCHER_HOME_GESTURE(574),
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 51e1ae0..68e3af0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1820,7 +1820,7 @@
     public void sendPointer(long downTime, long currentTime, int action, Point point,
             GestureScope gestureScope) {
         sendPointer(downTime, currentTime, action, point, gestureScope,
-                InputDevice.SOURCE_TOUCHSCREEN);
+                InputDevice.SOURCE_TOUCHSCREEN, false);
     }
 
     private void injectEvent(InputEvent event) {
@@ -1830,6 +1830,11 @@
 
     public void sendPointer(long downTime, long currentTime, int action, Point point,
             GestureScope gestureScope, int source) {
+        sendPointer(downTime, currentTime, action, point, gestureScope, source, false);
+    }
+
+    public void sendPointer(long downTime, long currentTime, int action, Point point,
+            GestureScope gestureScope, int source, boolean isRightClick) {
         final boolean hasTIS = hasTIS();
         int pointerCount = mPointerCount;
 
@@ -1865,6 +1870,9 @@
                 || action == MotionEvent.ACTION_BUTTON_RELEASE) {
             event.setActionButton(MotionEvent.BUTTON_PRIMARY);
         }
+        if (isRightClick) {
+            event.setButtonState(event.getButtonState() & MotionEvent.BUTTON_SECONDARY);
+        }
         injectEvent(event);
     }
 
@@ -1975,6 +1983,22 @@
         return result;
     }
 
+    @NonNull
+    UiObject2 rightClickAndGet(
+            @NonNull final UiObject2 target, @NonNull String resName, Pattern rightClickEvent) {
+        final Point targetCenter = target.getVisibleCenter();
+        final long downTime = SystemClock.uptimeMillis();
+        sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter,
+                GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
+                /* isRightClick= */ true);
+        expectEvent(TestProtocol.SEQUENCE_MAIN, rightClickEvent);
+        final UiObject2 result = waitForLauncherObject(resName);
+        sendPointer(downTime, SystemClock.uptimeMillis(), ACTION_UP, targetCenter,
+                GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
+                /* isRightClick= */ true);
+        return result;
+    }
+
     private static int getSystemIntegerRes(Context context, String resName) {
         Resources res = context.getResources();
         int resId = res.getIdentifier(resName, "integer", "android");
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
index d747150..064f80c 100644
--- a/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
@@ -25,6 +25,7 @@
 public final class TaskbarAppIcon extends AppIcon implements SplitscreenDragSource {
 
     private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onTaskbarItemLongClick");
+    private static final Pattern RIGHT_CLICK_EVENT = Pattern.compile("onTaskbarItemRightClick");
 
     TaskbarAppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
         super(launcher, icon);
@@ -35,11 +36,26 @@
         return LONG_CLICK_EVENT;
     }
 
+    protected Pattern getRightClickEvent() {
+        return RIGHT_CLICK_EVENT;
+    }
+
     @Override
     public TaskbarAppIconMenu openDeepShortcutMenu() {
         return (TaskbarAppIconMenu) super.openDeepShortcutMenu();
     }
 
+    /**
+     * Right-clicks the icon to open its menu.
+     */
+    public TaskbarAppIconMenu openDeepShortcutMenuWithRightClick() {
+        try (LauncherInstrumentation.Closable e = mLauncher.addContextLayer(
+                "want to return the shortcut menu when icon is right-clicked.")) {
+            return createMenu(mLauncher.rightClickAndGet(
+                    mObject, /* resName= */ "deep_shortcuts_container", getRightClickEvent()));
+        }
+    }
+
     @Override
     protected TaskbarAppIconMenu createMenu(UiObject2 menu) {
         return new TaskbarAppIconMenu(mLauncher, menu);