diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index c98090638010355476917ae8f7ff7e51e2e26b52..8d8dc10951a67121639cc2f2629503bb1227401e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -48,6 +48,11 @@ public interface BackAnimation {
             int keyAction,
             @BackEvent.SwipeEdge int swipeEdge);
 
+    /**
+     * Called when the input pointers are pilfered.
+     */
+    void onPilferPointers();
+
     /**
      * Sets whether the back gesture is past the trigger threshold or not.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index cf858dcb0637f5dcd8d192f8d6e6455e93c893a6..d8c691b01b61f494a6032c41b003803c273b5a1e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -111,6 +111,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
 
     /** Tracks if we should start the back gesture on the next motion move event */
     private boolean mShouldStartOnNextMoveEvent = false;
+    private boolean mOnBackStartDispatched = false;
 
     private final FlingAnimationUtils mFlingAnimationUtils;
 
@@ -303,6 +304,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
                     /* swipeEdge = */ swipeEdge));
         }
 
+        @Override
+        public void onPilferPointers() {
+            BackAnimationController.this.onPilferPointers();
+        }
+
         @Override
         public void setTriggerBack(boolean triggerBack) {
             mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack));
@@ -384,6 +390,16 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
         return null;
     }
 
+    @VisibleForTesting
+    void onPilferPointers() {
+        mCurrentTracker.updateStartLocation();
+        // Dispatch onBackStarted, only to app callbacks.
+        // System callbacks will receive onBackStarted when the remote animation starts.
+        if (!shouldDispatchToAnimator()) {
+            tryDispatchOnBackStarted(mActiveCallback, mCurrentTracker.createStartEvent(null));
+        }
+    }
+
     /**
      * Called when a new motion event needs to be transferred to this
      * {@link BackAnimationController}
@@ -483,12 +499,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
             mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
             // App is handling back animation. Cancel system animation latency tracking.
             cancelLatencyTracking();
-            dispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
+            tryDispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
         }
     }
 
     private void onMove() {
-        if (!mBackGestureStarted || mBackNavigationInfo == null || mActiveCallback == null) {
+        if (!mBackGestureStarted
+                || mBackNavigationInfo == null
+                || mActiveCallback == null
+                || !mOnBackStartDispatched) {
             return;
         }
         // Skip dispatching if the move corresponds to the queued instead of the current gesture
@@ -524,13 +543,14 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
                 && mBackNavigationInfo.isPrepareRemoteAnimation();
     }
 
-    private void dispatchOnBackStarted(IOnBackInvokedCallback callback,
+    private void tryDispatchOnBackStarted(IOnBackInvokedCallback callback,
             BackMotionEvent backEvent) {
-        if (callback == null) {
+        if (callback == null || mOnBackStartDispatched) {
             return;
         }
         try {
             callback.onBackStarted(backEvent);
+            mOnBackStartDispatched = true;
         } catch (RemoteException e) {
             Log.e(TAG, "dispatchOnBackStarted error: ", e);
         }
@@ -828,6 +848,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
     void finishBackNavigation(boolean triggerBack) {
         ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()");
         mActiveCallback = null;
+        mShouldStartOnNextMoveEvent = false;
+        mOnBackStartDispatched = false;
         mShellBackAnimationRegistry.resetDefaultCrossActivity();
         cancelLatencyTracking();
         if (mBackNavigationInfo != null) {
@@ -909,7 +931,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
                                                                     ::onBackAnimationFinished));
 
                                     if (apps.length >= 1) {
-                                        dispatchOnBackStarted(
+                                        mCurrentTracker.updateStartLocation();
+                                        tryDispatchOnBackStarted(
                                                 mActiveCallback,
                                                 mCurrentTracker.createStartEvent(apps[0]));
                                     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 19eb928d4e30afa0cb07ef08d901dd2d73382b1e..4bd56d460818a198b4941813fa0e3bb8e10cb98c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -104,6 +104,15 @@ class TouchTracker {
         mStartThresholdX = mInitTouchX;
     }
 
+    /** Update the start location used to compute the progress
+     * to the latest touch location.
+     */
+    void updateStartLocation() {
+        mInitTouchX = mLatestTouchX;
+        mInitTouchY = mLatestTouchY;
+        mStartThresholdX = mInitTouchX;
+    }
+
     void reset() {
         mInitTouchX = 0;
         mInitTouchY = 0;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 0395a9b78b2ba02045970ae793b19b850b8f8ba5..771876f7ce5dbd1270ba011991e014b5994120be 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -182,8 +182,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
     }
 
     private void triggerBackGesture() {
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-        doMotionEvent(MotionEvent.ACTION_MOVE, 0);
+        doStartEvents(0, 0);
         mController.setTriggerBack(true);
     }
 
@@ -244,10 +243,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
                 /* enableAnimation = */ true,
                 /* isAnimationCallback = */ false);
 
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
-        // Check that back start and progress is dispatched when first move.
-        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+        doStartEvents(0, 100);
 
         simulateRemoteAnimationStart();
 
@@ -270,10 +266,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
                 /* enableAnimation = */ true,
                 /* isAnimationCallback = */ true);
 
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
         // Check that back start and progress is dispatched when first move.
-        doMotionEvent(MotionEvent.ACTION_MOVE, 100, 3000);
+        doStartEvents(0, 100);
 
         simulateRemoteAnimationStart();
 
@@ -359,8 +353,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
                 .injectInputEvent(any(KeyEvent.class), any(Integer.class));
 
         // Verify that we start accepting gestures again once transition finishes.
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+        doStartEvents(0, 100);
 
         simulateRemoteAnimationStart();
         verify(mAnimatorCallback).onBackStarted(any());
@@ -399,8 +392,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
                 .injectInputEvent(any(KeyEvent.class), any(Integer.class));
 
         // Verify that we start accepting gestures again once transition finishes.
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+        doStartEvents(0, 100);
 
         simulateRemoteAnimationStart();
         verify(mAnimatorCallback).onBackStarted(any());
@@ -427,8 +419,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
         mShellExecutor.flushAll();
         reset(mAnimatorCallback);
 
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+        doStartEvents(0, 100);
         simulateRemoteAnimationStart();
         verify(mAnimatorCallback).onBackStarted(any());
     }
@@ -441,9 +432,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
                 /* enableAnimation = */ true,
                 /* isAnimationCallback = */ false);
 
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-        // Check that back start and progress is dispatched when first move.
-        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+        doStartEvents(0, 100);
 
         simulateRemoteAnimationStart();
         verify(mAnimatorCallback).onBackStarted(any());
@@ -563,10 +552,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
                 /* enableAnimation = */ true,
                 /* isAnimationCallback = */ false);
 
-        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
         // Check that back start and progress is dispatched when first move.
-        doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+        doStartEvents(0, 100);
 
         simulateRemoteAnimationStart();
 
@@ -593,6 +580,15 @@ public class BackAnimationControllerTest extends ShellTestCase {
                 /* swipeEdge */ BackEvent.EDGE_LEFT);
     }
 
+    /**
+     * Simulate event sequence that starts a back navigation.
+     */
+    private void doStartEvents(int startX, int moveX) {
+        doMotionEvent(MotionEvent.ACTION_DOWN, startX);
+        mController.onPilferPointers();
+        doMotionEvent(MotionEvent.ACTION_MOVE, moveX);
+    }
+
     private void simulateRemoteAnimationStart() throws RemoteException {
         RemoteAnimationTarget animationTarget = createAnimationTarget();
         RemoteAnimationTarget[] targets = new RemoteAnimationTarget[]{animationTarget};
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 9846f4b6c9800d9207ae73474b2e090e98882691..e660b97b5c6b9a441c74ea0deae8d1a3c6c611bd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -69,7 +69,6 @@ import androidx.annotation.DimenRes;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.policy.GestureNavigationSettingsObserver;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
@@ -81,6 +80,7 @@ import com.android.systemui.plugins.NavigationEdgeBackPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputChannelCompat;
@@ -1113,6 +1113,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack
                             // Capture inputs
                             mInputMonitor.pilferPointers();
                             if (mBackAnimation != null) {
+                                mBackAnimation.onPilferPointers();
                                 // Notify FalsingManager that an intentional gesture has occurred.
                                 mFalsingManager.isFalseTouch(BACK_GESTURE);
                             }