diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 910c7b9b1bfea363210d7a1279c2522447ba44aa..e6324abe2123616413cb0718bff0325b91dcf455 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5584,6 +5584,13 @@ public final class Settings {
          */
         public static final String VOLUME_ANSWER_CALL = "volume_answer_call";
 
+        /**
+         * Action to perform when the screen edge is long-swiped. (Default is 0)
+         * (See KEY_HOME_LONG_PRESS_ACTION for valid values)
+         * @hide
+         */
+        public static final String KEY_EDGE_LONG_SWIPE_ACTION = "key_edge_long_swipe_action";
+
         /**
          * IMPORTANT: If you add a new public settings you also have to add it to
          * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
index 12372593b62f19504dd477a9862818dd67838ab4..008cfa557581857a262e11ab72f240260586b99b 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
@@ -45,6 +45,9 @@ public interface NavigationEdgeBackPlugin extends Plugin {
     /** Sets the callback that should be invoked when a Back gesture is detected. */
     void setBackCallback(BackCallback callback);
 
+    /** Specifies if the long swipe should be enabled or not. */
+    void setLongSwipeEnabled(boolean enabled);
+
     /** Sets the base LayoutParams for the UI. */
     void setLayoutParams(WindowManager.LayoutParams layoutParams);
 
@@ -57,7 +60,7 @@ public interface NavigationEdgeBackPlugin extends Plugin {
     /** Callback to let the system react to the detected back gestures. */
     interface BackCallback {
         /** Indicates that a Back gesture was recognized and the system should go back. */
-        void triggerBack();
+        void triggerBack(boolean isLongPress);
 
         /** Indicates that the gesture was cancelled and the system should not go back. */
         void cancelBack();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 621075cba785fa70f3f8553a3df59f1dd14e8832..5dfa88583d8f8e0ac03250a00acf0944a70b9fee 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -19,6 +19,8 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_
 
 import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
 
+import static com.android.internal.util.libremobileos.DeviceKeysConstants.Action;
+
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -37,8 +39,10 @@ import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.provider.DeviceConfig;
+import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.TypedValue;
 import android.view.Choreographer;
 import android.view.Display;
@@ -57,6 +61,7 @@ import android.view.WindowMetrics;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.policy.GestureNavigationSettingsObserver;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -80,6 +85,7 @@ import com.android.systemui.shared.tracing.ProtoTraceable;
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto;
 import com.android.systemui.tracing.nano.SystemUiTraceProto;
+import com.android.systemui.tuner.TunerService;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
@@ -94,12 +100,16 @@ import javax.inject.Inject;
  * Utility class to handle edge swipes for back gesture
  */
 public class EdgeBackGestureHandler extends CurrentUserTracker
-        implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> {
+        implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto>,
+        TunerService.Tunable {
 
     private static final String TAG = "EdgeBackGestureHandler";
     private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
             "gestures.back_timeout", 250);
 
+    private static final String KEY_EDGE_LONG_SWIPE_ACTION =
+            "customsystem:" + Settings.System.KEY_EDGE_LONG_SWIPE_ACTION;
+
     private static final int MAX_NUM_LOGGED_PREDICTIONS = 10;
     private static final int MAX_NUM_LOGGED_GESTURES = 10;
 
@@ -228,6 +238,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
     private boolean mIsEnabled;
     private boolean mIsNavBarShownTransiently;
     private boolean mIsBackGestureAllowed;
+    private boolean mIsLongSwipeEnabled;
     private boolean mGestureBlockingActivityRunning;
     private boolean mIsInPipMode;
 
@@ -238,6 +249,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
     private int mLeftInset;
     private int mRightInset;
     private int mSysUiFlags;
+    private float mLongSwipeWidth;
 
     // For Tf-Lite model.
     private BackGestureTfClassifierProvider mBackGestureTfClassifierProvider;
@@ -259,12 +271,14 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
     private final NavigationEdgeBackPlugin.BackCallback mBackCallback =
             new NavigationEdgeBackPlugin.BackCallback() {
                 @Override
-                public void triggerBack() {
+                public void triggerBack(boolean isLongPress) {
                     // Notify FalsingManager that an intentional gesture has occurred.
                     // TODO(b/186519446): use a different method than isFalseTouch
                     mFalsingManager.isFalseTouch(BACK_GESTURE);
-                    boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
-                    boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
+                    boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK,
+                            isLongPress ? KeyEvent.FLAG_LONG_PRESS : 0);
+                    boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK,
+                            isLongPress ? KeyEvent.FLAG_LONG_PRESS : 0);
                     if (DEBUG_MISSING_GESTURE) {
                         Log.d(DEBUG_MISSING_GESTURE_TAG, "Triggered back: down=" + sendDown
                                 + ", up=" + sendUp);
@@ -370,6 +384,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
         if (mMLEnableWidth > mEdgeWidthRight) mMLEnableWidth = mEdgeWidthRight;
         if (mMLEnableWidth > mEdgeWidthLeft) mMLEnableWidth = mEdgeWidthLeft;
 
+        final TunerService tunerService = Dependency.get(TunerService.class);
+        tunerService.addTunable(this, KEY_EDGE_LONG_SWIPE_ACTION);
+
         // Reduce the default touch slop to ensure that we can intercept the gesture
         // before the app starts to react to it.
         // TODO(b/130352502) Tune this value and extract into a constant
@@ -501,6 +518,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
             setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
             mPluginManager.addPluginListener(
                     this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
+            updateLongSwipeWidth();
         }
         // Update the ML model resources.
         updateMLModelState();
@@ -511,6 +529,12 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
         setEdgeBackPlugin(plugin);
     }
 
+    private void updateLongSwipeWidth() {
+        if (mIsEnabled && mEdgeBackPlugin != null) {
+            mEdgeBackPlugin.setLongSwipeEnabled(mIsLongSwipeEnabled);
+        }
+    }
+
     @Override
     public void onPluginDisconnected(NavigationEdgeBackPlugin plugin) {
         setEdgeBackPlugin(new NavigationBarEdgePanel(mContext));
@@ -867,13 +891,23 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
         if (mEdgeBackPlugin != null) {
             mEdgeBackPlugin.setDisplaySize(mDisplaySize);
         }
+        updateLongSwipeWidth();
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (KEY_EDGE_LONG_SWIPE_ACTION.equals(key)) {
+            mIsLongSwipeEnabled = Action.fromIntSafe(TunerService.parseInteger(
+                    newValue, 0)) != Action.NOTHING;
+            updateLongSwipeWidth();
+        }
     }
 
-    private boolean sendEvent(int action, int code) {
+    private boolean sendEvent(int action, int code, int flags) {
         long when = SystemClock.uptimeMillis();
         final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
                 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
-                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+                flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                 InputDevice.SOURCE_KEYBOARD);
 
         ev.setDisplayId(mContext.getDisplay().getDisplayId());
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 8d1dfc842fba517023c2c6fe62cec7591e6ab6fb..32f8253ec2ccb4d25d1883ca7327ffaee9b17ff8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -210,7 +210,9 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
     private boolean mDragSlopPassed;
     private boolean mArrowsPointLeft;
     private float mMaxTranslation;
+    private float mLongSwipeThreshold;
     private boolean mTriggerBack;
+    private boolean mTriggerLongSwipe;
     private float mPreviousTouchTranslation;
     private float mTotalTouchDelta;
     private float mVerticalTranslation;
@@ -226,6 +228,8 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
     private final Handler mHandler = new Handler();
     private final Runnable mFailsafeRunnable = this::onFailsafe;
 
+    private boolean mIsLongSwipeEnabled;
+
     private DynamicAnimation.OnAnimationEndListener mSetGoneEndListener
             = new DynamicAnimation.OnAnimationEndListener() {
         @Override
@@ -423,6 +427,14 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
         mWindowManager.addView(this, mLayoutParams);
     }
 
+    @Override
+    public void setLongSwipeEnabled(boolean enabled) {
+        mLongSwipeThreshold = enabled ? MathUtils.min(
+                mDisplaySize.x * 0.5f, mLayoutParams.width * 2.5f) : 0.0f;
+        mIsLongSwipeEnabled = mLongSwipeThreshold > 0;
+        setTriggerLongSwipe(mIsLongSwipeEnabled && mTriggerLongSwipe, false /* animated */);
+    }
+
     /**
      * Adjusts the sampling rect to conform to the actual visible bounding box of the arrow.
      */
@@ -482,8 +494,10 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
                     Log.d(DEBUG_MISSING_GESTURE_TAG,
                             "NavigationBarEdgePanel ACTION_UP, mTriggerBack=" + mTriggerBack);
                 }
-                if (mTriggerBack) {
-                    triggerBack();
+                if (mTriggerLongSwipe) {
+                    triggerBack(true);
+                } else if (mTriggerBack) {
+                    triggerBack(false);
                 } else {
                     cancelBack();
                 }
@@ -522,6 +536,11 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
         float x = (polarToCartX(mCurrentAngle) * mArrowLength);
         float y = (polarToCartY(mCurrentAngle) * mArrowLength);
         Path arrowPath = calculatePath(x,y);
+        if (mTriggerLongSwipe) {
+            arrowPath.addPath(calculatePath(x,y),
+                    mArrowThickness * 2.0f * (mIsLeftPanel ? 1 : -1), 0.0f);
+        }
+
         if (mShowProtection) {
             canvas.drawPath(arrowPath, mProtectionPaint);
         }
@@ -616,8 +635,8 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
         return mCurrentTranslation;
     }
 
-    private void triggerBack() {
-        mBackCallback.triggerBack();
+    private void triggerBack(boolean triggerLongSwipe) {
+        mBackCallback.triggerBack(triggerLongSwipe);
 
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
@@ -695,6 +714,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
             Log.d(DEBUG_MISSING_GESTURE_TAG, "reset mTriggerBack=false");
         }
         setTriggerBack(false /* triggerBack */, false /* animated */);
+        setTriggerLongSwipe(false /* triggerLongSwipe */, false /* animated */);
         setDesiredTranslation(0, false /* animated */);
         setCurrentTranslation(0);
         updateAngle(false /* animate */);
@@ -719,6 +739,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
             }
         }
         mPreviousTouchTranslation = touchTranslation;
+        boolean isLongSwipe = touchTranslation > mLongSwipeThreshold;
 
         // Apply a haptic on drag slop passed
         if (!mDragSlopPassed && touchTranslation > mSwipeThreshold) {
@@ -781,6 +802,12 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
                     + ", x=" + x
                     + ", mStartX=" + mStartX);
         }
+
+        if (mIsLongSwipeEnabled) {
+            boolean triggerLongSwipe = triggerBack && isLongSwipe;
+            setTriggerLongSwipe(triggerLongSwipe, true /* animated */);
+        }
+
         setTriggerBack(triggerBack, true /* animated */);
 
         if (!mTriggerBack) {
@@ -869,6 +896,18 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
         }
     }
 
+    private void setTriggerLongSwipe(boolean triggerLongSwipe, boolean animated) {
+        if (mTriggerLongSwipe != triggerLongSwipe) {
+            mTriggerLongSwipe = triggerLongSwipe;
+            mVibratorHelper.vibrate(VibrationEffect.EFFECT_CLICK);
+            mAngleAnimation.cancel();
+            updateAngle(animated);
+            // Whenever the trigger back state changes the existing translation animation should be
+            // cancelled
+            mTranslationAnimation.cancel();
+        }
+    }
+
     private void updateAngle(boolean animated) {
         float newAngle = mTriggerBack ? ARROW_ANGLE_WHEN_EXTENDED_DEGREES + mAngleOffset : 90;
         if (newAngle != mDesiredAngle) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index cf5cbc72e3b8ad2d6b3f33c0628debb73ef6fe50..0a2666e62bc3c71f4c5e30fe1af21490f550cf16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -35,6 +35,7 @@ import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
 import com.android.internal.policy.SystemBarUtils;
+import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d4073b0555724934ad689429aebe30393c825b08..113f8b2f6e04d3109e9bc4b52bc35eacee6b2c38 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -564,6 +564,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     private Action mAssistLongPressAction;
     private Action mAppSwitchPressAction;
     private Action mAppSwitchLongPressAction;
+    private Action mEdgeLongSwipeAction;
 
     // support for activating the lock screen while the screen is on
     private HashSet<Integer> mAllowLockscreenWhenOnDisplays = new HashSet<>();
@@ -688,6 +689,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
 
     private LineageHardwareManager mLineageHardware;
 
+    private boolean mLongSwipeDown;
+    private static final int LONG_SWIPE_FLAGS = KeyEvent.FLAG_LONG_PRESS
+            | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY;
+
     private class PolicyHandler extends Handler {
         @Override
         public void handleMessage(Message msg) {
@@ -848,6 +853,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.KEY_APP_SWITCH_LONG_PRESS_ACTION), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.KEY_EDGE_LONG_SWIPE_ACTION), false, this,
+                    UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.HOME_WAKE_SCREEN), false, this,
                     UserHandle.USER_ALL);
@@ -2344,6 +2352,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         mAppSwitchLongPressAction = Action.fromIntSafe(res.getInteger(
                 com.android.internal.R.integer.config_longPressOnAppSwitchBehavior));
 
+        mEdgeLongSwipeAction = Action.NOTHING;
+
         mHomeLongPressAction = Action.fromIntSafe(res.getInteger(
                 com.android.internal.R.integer.config_longPressOnHomeBehavior));
         if (mHomeLongPressAction.ordinal() > Action.SLEEP.ordinal()) {
@@ -2388,6 +2398,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                 Settings.System.KEY_APP_SWITCH_LONG_PRESS_ACTION,
                 mAppSwitchLongPressAction);
 
+        mEdgeLongSwipeAction = Action.fromSettings(resolver,
+                Settings.System.KEY_EDGE_LONG_SWIPE_ACTION,
+                mEdgeLongSwipeAction);
+
         mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_NOTHING;
         if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
             mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
@@ -4005,6 +4019,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         // Handle special keys.
         switch (keyCode) {
             case KeyEvent.KEYCODE_BACK: {
+                boolean isLongSwipe = (event.getFlags() & LONG_SWIPE_FLAGS) == LONG_SWIPE_FLAGS;
+                if (mLongSwipeDown && isLongSwipe && !down) {
+                    // Trigger long swipe action
+                    performKeyAction(mEdgeLongSwipeAction, event);
+                    // Reset long swipe state
+                    mLongSwipeDown = false;
+                    // Don't pass back press to app
+                    result &= ~ACTION_PASS_TO_USER;
+                    break;
+                }
+                mLongSwipeDown = isLongSwipe && down;
+                if (mLongSwipeDown) {
+                    // Don't pass back press to app
+                    result &= ~ACTION_PASS_TO_USER;
+                    break;
+                }
+
                 if (down) {
                     mBackKeyHandled = false;
                 } else {