Changes in ImeTracker to be compatible with the InsetsController refactoring

- passing the statsToken (via `InsetsController#reportRequestedVisibleTypes`), and `onControlsChanged`
- setting the mStatsToken in the ImeInsetsSourceProvider after the IME was started/hidden to use when the IME control is dispatched
- adding new phases

Test: atest CtsInputMethodTestCases
Flag: android.view.inputmethod.refactor_insets_controller
Fix: 329229469
Change-Id: Iea89ee3fc15c6a487ccac660ae1edd55ad0488bb
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index da7997d..fe14d457 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -974,6 +974,11 @@
                                 : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+            if (android.view.inputmethod.Flags.refactorInsetsController()) {
+                // The hide request first finishes the animation and then proceeds to the server
+                // side, finally reaching here, marking this the end state.
+                ImeTracker.forLogging().onHidden(statsToken);
+            }
         }
 
         /**
@@ -3104,6 +3109,13 @@
 
         ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW);
 
+        if (android.view.inputmethod.Flags.refactorInsetsController()) {
+            // The ImeInsetsSourceProvider need the statsToken when dispatching the control
+            // (whenever the IME has drawn and its window is visible). Therefore, sending the
+            // statsToken here first.
+            notifyPreImeWindowVisibilityChanged(true /* visible */, statsToken);
+        }
+
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper,
                 null /* icProto */);
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
@@ -3127,7 +3139,9 @@
         if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
         mWindow.show();
         mDecorViewWasVisible = true;
-        applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */, statsToken);
+        if (!android.view.inputmethod.Flags.refactorInsetsController()) {
+            applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */, statsToken);
+        }
         cancelImeSurfaceRemoval();
         mInShowWindow = false;
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -3238,6 +3252,20 @@
                 ? mCurShowInputToken : mCurHideInputToken, setVisible, statsToken);
     }
 
+    /**
+     * Notifies the ImeInsetsSourceProvider before the IME visibility changes.
+     *
+     * @param visible {@code true} if it became visible, {@code false} otherwise.
+     * @param statsToken the token tracking the current IME request.
+     */
+    private void notifyPreImeWindowVisibilityChanged(boolean visible,
+            @NonNull ImeTracker.Token statsToken) {
+        final var viewRootImpl = getWindow().getWindow().getDecorView().getViewRootImpl();
+        if (viewRootImpl != null) {
+            viewRootImpl.notifyImeVisibilityChanged(visible, statsToken);
+        }
+    }
+
     private void finishViews(boolean finishingInput) {
         if (mInputViewStarted) {
             if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
@@ -3279,7 +3307,13 @@
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
                 null /* icProto */);
         setImeWindowStatus(0, mBackDisposition);
-        applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */, statsToken);
+        if (android.view.inputmethod.Flags.refactorInsetsController()) {
+            // The ImeInsetsSourceProvider need the statsToken when dispatching the control. We
+            // send the token here, so that another request in the provider can be cancelled.
+            notifyPreImeWindowVisibilityChanged(false /* visible */, statsToken);
+        } else {
+            applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */, statsToken);
+        }
         mWindowVisible = false;
         finishViews(false /* finishingInput */);
         if (mDecorViewVisible) {
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 14407ca..762a302 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -30,6 +30,7 @@
 import android.view.IWindowId;
 import android.view.MotionEvent;
 import android.view.WindowManager;
+import android.view.inputmethod.ImeTracker;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.Surface;
@@ -276,7 +277,8 @@
     /**
      * Updates the requested visible types of insets.
      */
-    oneway void updateRequestedVisibleTypes(IWindow window, int requestedVisibleTypes);
+    oneway void updateRequestedVisibleTypes(IWindow window, int requestedVisibleTypes,
+            in @nullable ImeTracker.Token imeStatsToken);
 
     /**
      * Called when the system gesture exclusion has changed.
@@ -369,4 +371,14 @@
      * @return {@code true} if the focus changes. Otherwise, {@code false}.
      */
     boolean moveFocusToAdjacentWindow(IWindow fromWindow, int direction);
+
+    /**
+     * Notifies the statsToken and IME visibility to the ImeInsetsSourceProvider.
+     *
+     * @param window The window that is used to get the ImeInsetsSourceProvider.
+     * @param visible {@code true} to make it visible, {@code false} to hide it.
+     * @param statsToken the token tracking the current IME request.
+     */
+    oneway void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
+            in ImeTracker.Token statsToken);
 }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index f166b89..d83f344 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -121,8 +121,10 @@
          * The visibilities should be reported back to WM.
          *
          * @param types Bitwise flags of types requested visible.
+         * @param statsToken the token tracking the current IME request or {@code null} otherwise.
          */
-        void updateRequestedVisibleTypes(@InsetsType int types);
+        void updateRequestedVisibleTypes(@InsetsType int types,
+                @Nullable ImeTracker.Token statsToken);
 
         /**
          * @return Whether the host has any callbacks it wants to synchronize the animations with.
@@ -974,6 +976,7 @@
         int consumedControlCount = 0;
         final @InsetsType int[] showTypes = new int[1];
         final @InsetsType int[] hideTypes = new int[1];
+        ImeTracker.Token statsToken = null;
 
         // Ensure to update all existing source consumers
         for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
@@ -988,6 +991,12 @@
             if (control != null) {
                 controllableTypes |= control.getType();
                 consumedControlCount++;
+
+                if (Flags.refactorInsetsController()) {
+                    if (control.getId() == ID_IME) {
+                        statsToken = control.getImeStatsToken();
+                    }
+                }
             }
 
             // control may be null, but we still need to update the control to null if it got
@@ -1021,34 +1030,31 @@
         if (Flags.refactorInsetsController()) {
             if (mPendingImeControlRequest != null && getImeSourceConsumer().getControl() != null
                     && getImeSourceConsumer().getControl().getLeash() != null) {
-                // TODO we need to pass the statsToken
-                handlePendingControlRequest(null);
+                handlePendingControlRequest(statsToken);
             } else {
                 if (showTypes[0] != 0) {
-                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
-                            null /* statsToken */);
+                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
                 }
                 if (hideTypes[0] != 0) {
-                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
-                            null /* statsToken */);
+                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
                 }
             }
         } else {
             if (showTypes[0] != 0) {
-                final var statsToken =
+                final var newStatsToken =
                         (showTypes[0] & ime()) == 0 ? null : ImeTracker.forLogging().onStart(
                                 ImeTracker.TYPE_SHOW, ImeTracker.ORIGIN_CLIENT,
                                 SoftInputShowHideReason.CONTROLS_CHANGED,
                                 mHost.isHandlingPointerEvent() /* fromUser */);
-                applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
+                applyAnimation(showTypes[0], true /* show */, false /* fromIme */, newStatsToken);
             }
             if (hideTypes[0] != 0) {
-                final var statsToken =
+                final var newStatsToken =
                         (hideTypes[0] & ime()) == 0 ? null : ImeTracker.forLogging().onStart(
                                 ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT,
                                 SoftInputShowHideReason.CONTROLS_CHANGED,
                                 mHost.isHandlingPointerEvent() /* fromUser */);
-                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
+                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, newStatsToken);
             }
         }
 
@@ -1065,7 +1071,9 @@
         }
 
         // InsetsSourceConsumer#setControl might change the requested visibility.
-        reportRequestedVisibleTypes();
+        // TODO(b/353463205) check this: if the requestedVisibleTypes for the IME were already
+        //  sent, the request would fail. Therefore, don't send the statsToken here.
+        reportRequestedVisibleTypes(null /* statsToken */);
     }
 
     @VisibleForTesting(visibility = PACKAGE)
@@ -1176,6 +1184,7 @@
         }
         if (DEBUG) Log.d(TAG, "show typesReady: " + typesReady);
         if ((Flags.refactorInsetsController() || fromIme) && (typesReady & Type.ime()) != 0) {
+            // TODO(b/353463205) check if this is needed here
             ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
         }
         applyAnimation(typesReady, true /* show */, fromIme, statsToken);
@@ -1243,6 +1252,8 @@
                     // an animation again (mRequestedVisibleTypes are reported at the end of the IME
                     // hide animation but set at the beginning)
                     if ((mRequestedVisibleTypes & ime()) == 0) {
+                        ImeTracker.forLogging().onCancelled(statsToken,
+                                ImeTracker.PHASE_CLIENT_ALREADY_HIDDEN);
                         continue;
                     }
                 }
@@ -1346,7 +1357,7 @@
 
         // We are finishing setting the requested visible types. Report them to the server
         // and/or the app.
-        reportRequestedVisibleTypes();
+        reportRequestedVisibleTypes(statsToken);
     }
 
     private void controlAnimationUncheckedInner(@InsetsType int types,
@@ -1396,8 +1407,8 @@
             // Ime will not be contained in typesReady nor in controls, if we don't have a leash
             Pair<Integer, Integer> typesReadyPair = collectSourceControlsV2(types, controls);
             typesReady = typesReadyPair.first;
-            @InsetsType int typesWithoutLeash = typesReadyPair.second;
             if (animationType == ANIMATION_TYPE_USER) {
+                @InsetsType int typesWithoutLeash = typesReadyPair.second;
                 // When using an app-driven animation, the IME won't have a leash (because the
                 // window isn't created yet). If we have a control, but no leash, defers the
                 // request until the leash gets created.
@@ -1431,6 +1442,11 @@
                 }
                 // We need to wait until all types are ready
                 if (typesReady != types) {
+                    if (DEBUG) {
+                        Log.d(TAG, TextUtils.formatSimple(
+                                "not all types are ready yet, waiting. typesReady: %s, types: %s",
+                                typesReady, types));
+                    }
                     return;
                 }
             }
@@ -1728,9 +1744,13 @@
         } else {
             ImeTracker.forLogging().onProgress(statsToken,
                     ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_HIDE);
-            ImeTracker.forLogging().onHidden(statsToken);
+            // The requestedVisibleTypes are only send at the end of the hide animation.
+            // Therefore, the requested is not finished at this point.
+            if (!Flags.refactorInsetsController()) {
+                ImeTracker.forLogging().onHidden(statsToken);
+            }
         }
-        reportRequestedVisibleTypes();
+        reportRequestedVisibleTypes(shown ? null : runner.getStatsToken());
     }
 
     @Override
@@ -1787,7 +1807,7 @@
                             if (mHost != null) {
                                 // if the (hide) animation is cancelled, the
                                 // requestedVisibleTypes should be reported at this point.
-                                reportRequestedVisibleTypes();
+                                reportRequestedVisibleTypes(control.getStatsToken());
                                 mHost.getInputMethodManager().removeImeSurface(
                                         mHost.getWindowToken());
                             }
@@ -1923,8 +1943,10 @@
 
     /**
      * Called when finishing setting requested visible types or finishing setting controls.
+     *
+     * @param statsToken the token tracking the current IME request or {@code null} otherwise.
      */
-    private void reportRequestedVisibleTypes() {
+    private void reportRequestedVisibleTypes(@Nullable ImeTracker.Token statsToken) {
         final @InsetsType int typesToReport;
         if (Flags.refactorInsetsController()) {
             // If the IME is currently animating out, it is still visible, therefore we only
@@ -1941,8 +1963,23 @@
             if (WindowInsets.Type.hasCompatSystemBars(diff)) {
                 mCompatSysUiVisibilityStaled = true;
             }
+            if (Flags.refactorInsetsController()) {
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES);
+            }
             mReportedRequestedVisibleTypes = mRequestedVisibleTypes;
-            mHost.updateRequestedVisibleTypes(mReportedRequestedVisibleTypes);
+            mHost.updateRequestedVisibleTypes(mReportedRequestedVisibleTypes, statsToken);
+        } else if (Flags.refactorInsetsController()) {
+            if ((typesToReport & ime()) != 0 && mImeSourceConsumer != null) {
+                InsetsSourceControl control = mImeSourceConsumer.getControl();
+                if (control != null && control.getLeash() == null) {
+                    // If the IME was requested twice, and we didn't receive the controls
+                    // yet, this request will not continue. It should be cancelled here, as
+                    // it would time out otherwise.
+                    ImeTracker.forLogging().onCancelled(statsToken,
+                            ImeTracker.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES);
+                }
+            }
         }
         updateCompatSysUiVisibility();
     }
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 2efa647..7877352 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -31,6 +31,7 @@
 import android.os.Parcelable;
 import android.util.proto.ProtoOutputStream;
 import android.view.WindowInsets.Type.InsetsType;
+import android.view.inputmethod.ImeTracker;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -56,6 +57,9 @@
     private boolean mSkipAnimationOnce;
     private int mParcelableFlags;
 
+    /** The token tracking the current IME request */
+    private @Nullable ImeTracker.Token mImeStatsToken;
+
     public InsetsSourceControl(int id, @InsetsType int type, @Nullable SurfaceControl leash,
             boolean initiallyVisible, Point surfacePosition, Insets insetsHint) {
         mId = id;
@@ -78,6 +82,7 @@
         mSurfacePosition = new Point(other.mSurfacePosition);
         mInsetsHint = other.mInsetsHint;
         mSkipAnimationOnce = other.getAndClearSkipAnimationOnce();
+        mImeStatsToken = other.getImeStatsToken();
     }
 
     public InsetsSourceControl(Parcel in) {
@@ -88,6 +93,7 @@
         mSurfacePosition = in.readTypedObject(Point.CREATOR);
         mInsetsHint = in.readTypedObject(Insets.CREATOR);
         mSkipAnimationOnce = in.readBoolean();
+        mImeStatsToken = in.readTypedObject(ImeTracker.Token.CREATOR);
     }
 
     public int getId() {
@@ -153,6 +159,15 @@
         return result;
     }
 
+    @Nullable
+    public ImeTracker.Token getImeStatsToken() {
+        return mImeStatsToken;
+    }
+
+    public void setImeStatsToken(@Nullable ImeTracker.Token imeStatsToken) {
+        mImeStatsToken = imeStatsToken;
+    }
+
     public void setParcelableFlags(int parcelableFlags) {
         mParcelableFlags = parcelableFlags;
     }
@@ -171,6 +186,7 @@
         dest.writeTypedObject(mSurfacePosition, mParcelableFlags);
         dest.writeTypedObject(mInsetsHint, mParcelableFlags);
         dest.writeBoolean(mSkipAnimationOnce);
+        dest.writeTypedObject(mImeStatsToken, mParcelableFlags);
     }
 
     public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
@@ -196,13 +212,14 @@
                 && mInitiallyVisible == that.mInitiallyVisible
                 && mSurfacePosition.equals(that.mSurfacePosition)
                 && mInsetsHint.equals(that.mInsetsHint)
-                && mSkipAnimationOnce == that.mSkipAnimationOnce;
+                && mSkipAnimationOnce == that.mSkipAnimationOnce
+                && Objects.equals(mImeStatsToken, that.mImeStatsToken);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mId, mType, mLeash, mInitiallyVisible, mSurfacePosition, mInsetsHint,
-                mSkipAnimationOnce);
+                mSkipAnimationOnce, mImeStatsToken);
     }
 
     @Override
@@ -225,6 +242,7 @@
         pw.print(" mSurfacePosition="); pw.print(mSurfacePosition);
         pw.print(" mInsetsHint="); pw.print(mInsetsHint);
         pw.print(" mSkipAnimationOnce="); pw.print(mSkipAnimationOnce);
+        pw.print(" mImeStatsToken="); pw.print(mImeStatsToken);
         pw.println();
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2f204f9..37d5220 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10057,6 +10057,24 @@
     }
 
     /**
+     * Dispatches the statsToken and IME visibility to the ImeInsetsSourceProvider.
+     *
+     * @param visible {@code true} if it became visible, {@code false} otherwise.
+     * @param statsToken the token tracking the current IME request.
+     *
+     * @hide
+     */
+    public void notifyImeVisibilityChanged(boolean visible, @NonNull ImeTracker.Token statsToken) {
+        ImeTracker.forLogging().onProgress(statsToken,
+                ImeTracker.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED);
+        try {
+            mWindowSession.notifyImeWindowVisibilityChangedFromClient(mWindow, visible, statsToken);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Represents a pending input event that is waiting in a queue.
      *
      * Input events are processed in serial order by the timestamp specified by
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index b66c59a..889acca4 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -19,12 +19,14 @@
 import static android.view.InsetsController.DEBUG;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.inputmethod.ImeTracker;
 import android.view.inputmethod.InputMethodManager;
 
 import java.util.List;
@@ -151,10 +153,17 @@
     }
 
     @Override
-    public void updateRequestedVisibleTypes(@WindowInsets.Type.InsetsType int types) {
+    public void updateRequestedVisibleTypes(@WindowInsets.Type.InsetsType int types,
+            @Nullable ImeTracker.Token statsToken) {
         try {
             if (mViewRoot.mAdded) {
-                mViewRoot.mWindowSession.updateRequestedVisibleTypes(mViewRoot.mWindow, types);
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES);
+                mViewRoot.mWindowSession.updateRequestedVisibleTypes(mViewRoot.mWindow, types,
+                        statsToken);
+            } else {
+                ImeTracker.forLogging().onFailed(statsToken,
+                        ImeTracker.PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to call insetsModified", e);
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 7871858..0d027f1 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -30,6 +30,7 @@
 import android.util.MergedConfiguration;
 import android.view.View.FocusDirection;
 import android.view.WindowInsets.Type.InsetsType;
+import android.view.inputmethod.ImeTracker;
 import android.window.ClientWindowFrames;
 import android.window.InputTransferToken;
 import android.window.OnBackInvokedCallbackInfo;
@@ -596,7 +597,7 @@
 
     @Override
     public void updateRequestedVisibleTypes(IWindow window,
-            @InsetsType int requestedVisibleTypes)  {
+            @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token imeStatsToken)  {
     }
 
     @Override
@@ -677,6 +678,11 @@
         return false;
     }
 
+    @Override
+    public void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
+            @NonNull ImeTracker.Token statsToken) {
+    }
+
     void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
         IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder();
         IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder();
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index edc9921..b9751c8 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -202,6 +202,24 @@
             PHASE_IME_HIDE_WINDOW,
             PHASE_IME_PRIVILEGED_OPERATIONS,
             PHASE_SERVER_CURRENT_ACTIVE_IME,
+            PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES,
+            PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY,
+            PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED,
+            PHASE_CLIENT_HANDLE_DISPATCH_IME_VISIBILITY_CHANGED,
+            PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED,
+            PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES,
+            PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SET_REQUESTED_VISIBILITY,
+            PHASE_WM_GET_CONTROL_WITH_LEASH,
+            PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES,
+            PHASE_SERVER_SET_VISIBILITY_ON_FOCUSED_WINDOW,
+            PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY,
+            PHASE_CLIENT_SET_IME_VISIBILITY,
+            PHASE_WM_DISPATCH_IME_REQUESTED_CHANGED,
+            PHASE_CLIENT_NO_ONGOING_USER_ANIMATION,
+            PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT,
+            PHASE_WM_POSTING_CHANGED_IME_VISIBILITY,
+            PHASE_WM_INVOKING_IME_REQUESTED_LISTENER,
+            PHASE_CLIENT_ALREADY_HIDDEN,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface Phase {}
@@ -351,6 +369,62 @@
     /** Checked that the calling IME is the currently active IME. */
     int PHASE_SERVER_CURRENT_ACTIVE_IME = ImeProtoEnums.PHASE_SERVER_CURRENT_ACTIVE_IME;
 
+    /** Reporting the new requested visible types. */
+    int PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES =
+            ImeProtoEnums.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES;
+    /** Setting the IME visibility for the RemoteInsetsControlTarget. */
+    int PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY =
+            ImeProtoEnums.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY;
+    /** IME has no insets pending and is server visible. Notify about changed controls. */
+    int PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED =
+            ImeProtoEnums.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED;
+    /** Handling the dispatch of the IME visibility change. */
+    int PHASE_CLIENT_HANDLE_DISPATCH_IME_VISIBILITY_CHANGED =
+            ImeProtoEnums.PHASE_CLIENT_HANDLE_DISPATCH_IME_VISIBILITY_CHANGED;
+    /** Dispatching the IME visibility change. */
+    int PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED =
+            ImeProtoEnums.PHASE_CLIENT_NOTIFY_IME_VISIBILITY_CHANGED;
+    /** Updating the requested visible types. */
+    int PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES =
+            ImeProtoEnums.PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES;
+    /** Reached the remote insets control target's setImeInputTargetRequestedVisibility method. */
+    int PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SET_REQUESTED_VISIBILITY =
+            ImeProtoEnums.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SET_REQUESTED_VISIBILITY;
+    /** Received a new insets source control with a leash. */
+    int PHASE_WM_GET_CONTROL_WITH_LEASH =
+            ImeProtoEnums.PHASE_WM_GET_CONTROL_WITH_LEASH;
+    /**
+     * Updating the requested visible types in the WindowState and sending them to state
+     * controller.
+     */
+    int PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES =
+            ImeProtoEnums.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES;
+    /** Setting the requested IME visibility of a window. */
+    int PHASE_SERVER_SET_VISIBILITY_ON_FOCUSED_WINDOW =
+            ImeProtoEnums.PHASE_SERVER_SET_VISIBILITY_ON_FOCUSED_WINDOW;
+    /** Reached the redirect of InputMethodManager to InsetsController show/hide. */
+    int PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY =
+            ImeProtoEnums.PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY;
+    /** Reached the InputMethodManager Handler call to send the visibility. */
+    int PHASE_CLIENT_SET_IME_VISIBILITY = ImeProtoEnums.PHASE_CLIENT_SET_IME_VISIBILITY;
+    /** Calling into the listener to show/hide the IME from the ImeInsetsSourceProvider. */
+    int PHASE_WM_DISPATCH_IME_REQUESTED_CHANGED =
+            ImeProtoEnums.PHASE_WM_DISPATCH_IME_REQUESTED_CHANGED;
+    /** An ongoing user animation will not be interrupted by a IMM#showSoftInput. */
+    int PHASE_CLIENT_NO_ONGOING_USER_ANIMATION =
+            ImeProtoEnums.PHASE_CLIENT_NO_ONGOING_USER_ANIMATION;
+    /** Dispatching the token to the ImeInsetsSourceProvider. */
+    int PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT =
+            ImeProtoEnums.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT;
+    /** Now posting the IME visibility to the WMS handler. */
+    int PHASE_WM_POSTING_CHANGED_IME_VISIBILITY =
+            ImeProtoEnums.PHASE_WM_POSTING_CHANGED_IME_VISIBILITY;
+    /** Inside the WMS handler calling into the listener that calls into IMMS show/hide. */
+    int PHASE_WM_INVOKING_IME_REQUESTED_LISTENER =
+            ImeProtoEnums.PHASE_WM_INVOKING_IME_REQUESTED_LISTENER;
+    /** IME is requested to be hidden, but already hidden. Don't hide to avoid another animation. */
+    int PHASE_CLIENT_ALREADY_HIDDEN = ImeProtoEnums.PHASE_CLIENT_ALREADY_HIDDEN;
+
     /**
      * Called when an IME request is started.
      *
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index fed8eea..d40b72c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1350,11 +1350,15 @@
                     return;
                 }
                 case MSG_SET_VISIBILITY:
-                    final boolean visible = msg.arg1 != 0;
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    final boolean visible = (boolean) args.arg1;
+                    final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg2;
                     synchronized (mH) {
                         if (mCurRootView != null) {
                             final var insetsController = mCurRootView.getInsetsController();
                             if (insetsController != null) {
+                                ImeTracker.forLogging().onProgress(statsToken,
+                                        ImeTracker.PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY);
                                 if (visible) {
                                     insetsController.show(WindowInsets.Type.ime(),
                                             false /* fromIme */, null /* statsToken */);
@@ -1363,6 +1367,9 @@
                                             false /* fromIme */, null /* statsToken */);
                                 }
                             }
+                        } else {
+                            ImeTracker.forLogging().onFailed(statsToken,
+                                    ImeTracker.PHASE_CLIENT_HANDLE_SET_IME_VISIBILITY);
                         }
                     }
                     break;
@@ -1463,8 +1470,13 @@
         }
 
         @Override
-        public void setImeVisibility(boolean visible) {
-            mH.obtainMessage(MSG_SET_VISIBILITY, visible ? 1 : 0, 0).sendToTarget();
+        public void setImeVisibility(boolean visible, @Nullable ImeTracker.Token statsToken) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = visible;
+            args.arg2 = statsToken;
+            ImeTracker.forLogging().onProgress(statsToken,
+                    ImeTracker.PHASE_CLIENT_SET_IME_VISIBILITY);
+            mH.obtainMessage(MSG_SET_VISIBILITY, args).sendToTarget();
         }
 
         @Override
@@ -2344,11 +2356,15 @@
                 if (viewRootImpl != null
                         && (viewRootImpl.getInsetsController().computeUserAnimatingTypes()
                                 & WindowInsets.Type.ime()) == 0) {
+                    ImeTracker.forLogging().onProgress(statsToken,
+                            ImeTracker.PHASE_CLIENT_NO_ONGOING_USER_ANIMATION);
                     // TODO(b/322992891) handle case of SHOW_IMPLICIT
                     viewRootImpl.getInsetsController().show(WindowInsets.Type.ime(),
                             false /* fromIme */, statsToken);
                     return true;
                 }
+                ImeTracker.forLogging().onCancelled(statsToken,
+                        ImeTracker.PHASE_CLIENT_NO_ONGOING_USER_ANIMATION);
                 return false;
             } else {
                 // Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl b/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl
index 6a7fa99..6eb9d2e 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodClient.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.inputmethod;
 
+import android.view.inputmethod.ImeTracker;
 import com.android.internal.inputmethod.InputBindResult;
 
 /**
@@ -30,7 +31,7 @@
     void onUnbindAccessibilityService(int sequence, int id);
     void setActive(boolean active, boolean fullscreen);
     void setInteractive(boolean active, boolean fullscreen);
-    void setImeVisibility(boolean visible);
+    void setImeVisibility(boolean visible, in @nullable ImeTracker.Token statsToken);
     void scheduleStartInputIfNecessary(boolean fullscreen);
     void reportFullscreenMode(boolean fullscreen);
     void setImeTraceEnabled(boolean enabled);
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index ae7f465..7bc0d2f 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -56,6 +56,7 @@
 import static java.util.concurrent.TimeUnit.SECONDS;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Point;
@@ -1095,9 +1096,10 @@
         }
 
         @Override
-        public void updateRequestedVisibleTypes(@InsetsType int requestedVisibleTypes) {
+        public void updateRequestedVisibleTypes(@InsetsType int requestedVisibleTypes,
+                @Nullable ImeTracker.Token statsToken) {
             mRequestedVisibleTypes = requestedVisibleTypes;
-            super.updateRequestedVisibleTypes(requestedVisibleTypes);
+            super.updateRequestedVisibleTypes(requestedVisibleTypes, statsToken);
         }
 
         public boolean isRequestedVisible(@InsetsType int types) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index f4ac5f2..4fbb574 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -344,8 +344,7 @@
 
             if (android.view.inputmethod.Flags.refactorInsetsController()) {
                 if (pendingImeStartAnimation) {
-                    startAnimation(true, true /* forceRestart */,
-                            null /* statsToken */);
+                    startAnimation(true, true /* forceRestart */);
                 }
             }
         }
@@ -398,8 +397,7 @@
                 // already (e.g., when focussing an editText in activity B, while and editText in
                 // activity A is focussed), we will not get a call of #insetsControlChanged, and
                 // therefore have to start the show animation from here
-                startAnimation(mImeRequestedVisible /* show */, false /* forceRestart */,
-                        null /* TODO statsToken */);
+                startAnimation(mImeRequestedVisible /* show */, false /* forceRestart */);
             }
         }
 
@@ -436,16 +434,31 @@
                     .navBarFrameHeight();
         }
 
+        private void startAnimation(final boolean show, final boolean forceRestart) {
+            final var imeSource = mInsetsState.peekSource(InsetsSource.ID_IME);
+            if (imeSource == null || mImeSourceControl == null) {
+                return;
+            }
+            final var statsToken = mImeSourceControl.getImeStatsToken();
+
+            startAnimation(show, forceRestart, statsToken);
+        }
+
         private void startAnimation(final boolean show, final boolean forceRestart,
                 @SoftInputShowHideReason int reason) {
             final var imeSource = mInsetsState.peekSource(InsetsSource.ID_IME);
             if (imeSource == null || mImeSourceControl == null) {
                 return;
             }
-            final var statsToken = ImeTracker.forLogging().onStart(
-                    show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_WM_SHELL,
-                    reason, false /* fromUser */);
-
+            final ImeTracker.Token statsToken;
+            if (android.view.inputmethod.Flags.refactorInsetsController()
+                    && mImeSourceControl.getImeStatsToken() != null) {
+                statsToken = mImeSourceControl.getImeStatsToken();
+            } else {
+                statsToken = ImeTracker.forLogging().onStart(
+                        show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE,
+                        ImeTracker.ORIGIN_WM_SHELL, reason, false /* fromUser */);
+            }
             startAnimation(show, forceRestart, statsToken);
         }
 
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index 7c93c8b..5c939bc 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -202,7 +202,7 @@
                 break;
             case STATE_HIDE_IME_EXPLICIT:
                 if (Flags.refactorInsetsController()) {
-                    setImeVisibilityOnFocusedWindowClient(false, userId);
+                    setImeVisibilityOnFocusedWindowClient(false, userId, statsToken);
                 } else {
                     mService.hideCurrentInputLocked(windowToken, statsToken,
                             0 /* flags */, null /* resultReceiver */, reason, userId);
@@ -210,7 +210,7 @@
                 break;
             case STATE_HIDE_IME_NOT_ALWAYS:
                 if (Flags.refactorInsetsController()) {
-                    setImeVisibilityOnFocusedWindowClient(false, userId);
+                    setImeVisibilityOnFocusedWindowClient(false, userId, statsToken);
                 } else {
                     mService.hideCurrentInputLocked(windowToken, statsToken,
                             InputMethodManager.HIDE_NOT_ALWAYS, null /* resultReceiver */, reason,
@@ -221,7 +221,7 @@
                 if (Flags.refactorInsetsController()) {
                     // This can be triggered by IMMS#startInputOrWindowGainedFocus. We need to
                     // set the requestedVisibleTypes in InsetsController first, before applying it.
-                    setImeVisibilityOnFocusedWindowClient(true, userId);
+                    setImeVisibilityOnFocusedWindowClient(true, userId, statsToken);
                 } else {
                     mService.showCurrentInputLocked(windowToken, statsToken,
                             InputMethodManager.SHOW_IMPLICIT, MotionEvent.TOOL_TYPE_UNKNOWN,
@@ -278,14 +278,17 @@
     }
 
     @GuardedBy("ImfLock.class")
-    private void setImeVisibilityOnFocusedWindowClient(boolean visibility, @UserIdInt int userId) {
+    private void setImeVisibilityOnFocusedWindowClient(boolean visibility, @UserIdInt int userId,
+            @NonNull ImeTracker.Token statsToken) {
         final var userData = mService.getUserData(userId);
         if (userData.mImeBindingState != null
                 && userData.mImeBindingState.mFocusedWindowClient != null
                 && userData.mImeBindingState.mFocusedWindowClient.mClient != null) {
-            userData.mImeBindingState.mFocusedWindowClient.mClient.setImeVisibility(visibility);
+            userData.mImeBindingState.mFocusedWindowClient.mClient.setImeVisibility(visibility,
+                    statsToken);
         } else {
-            // TODO(b/329229469): ImeTracker?
+            ImeTracker.forLogging().onFailed(statsToken,
+                    ImeTracker.PHASE_SERVER_SET_VISIBILITY_ON_FOCUSED_WINDOW);
         }
     }
 }
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java
index eada288..650ea60 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodClientInvoker.java
@@ -25,6 +25,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.view.inputmethod.ImeTracker;
 
 import com.android.internal.inputmethod.IInputMethodClient;
 import com.android.internal.inputmethod.InputBindResult;
@@ -250,18 +251,18 @@
     }
 
     @AnyThread
-    void setImeVisibility(boolean visible) {
+    void setImeVisibility(boolean visible, @Nullable ImeTracker.Token statsToken) {
         if (mIsProxy) {
-            setImeVisibilityInternal(visible);
+            setImeVisibilityInternal(visible, statsToken);
         } else {
-            mHandler.post(() -> setImeVisibilityInternal(visible));
+            mHandler.post(() -> setImeVisibilityInternal(visible, statsToken));
         }
     }
 
     @AnyThread
-    private void setImeVisibilityInternal(boolean visible) {
+    private void setImeVisibilityInternal(boolean visible, @Nullable ImeTracker.Token statsToken) {
         try {
-            mTarget.setImeVisibility(visible);
+            mTarget.setImeVisibility(visible, statsToken);
         } catch (RemoteException e) {
             logRemoteException(e);
         }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a9723cc..f93e458 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1429,12 +1429,12 @@
 
     void registerImeRequestedChangedListener() {
         mWindowManagerInternal.setOnImeRequestedChangedListener(
-                (windowToken, imeVisible) -> {
+                (windowToken, imeVisible, statsToken) -> {
                     if (Flags.refactorInsetsController()) {
                         if (imeVisible) {
-                            showCurrentInputInternal(windowToken);
+                            showCurrentInputInternal(windowToken, statsToken);
                         } else {
-                            hideCurrentInputInternal(windowToken);
+                            hideCurrentInputInternal(windowToken, statsToken);
                         }
                     }
                 });
@@ -1887,7 +1887,12 @@
         if (Flags.refactorInsetsController()) {
             if (isShowRequestedForCurrentWindow(userId) && userData.mImeBindingState != null
                     && userData.mImeBindingState.mFocusedWindow != null) {
-                showCurrentInputInternal(userData.mImeBindingState.mFocusedWindow);
+                // Re-use current statsToken, if it exists.
+                final var statsToken = userData.mCurStatsToken != null ? userData.mCurStatsToken
+                        : createStatsTokenForFocusedClient(true /* show */,
+                                SoftInputShowHideReason.ATTACH_NEW_INPUT, userId);
+                userData.mCurStatsToken = null;
+                showCurrentInputInternal(userData.mImeBindingState.mFocusedWindow, statsToken);
             }
         } else {
             if (isShowRequestedForCurrentWindow(userId)) {
@@ -3099,7 +3104,7 @@
                             && userData.mImeBindingState.mFocusedWindowClient != null
                             && userData.mImeBindingState.mFocusedWindowClient.mClient != null) {
                         userData.mImeBindingState.mFocusedWindowClient.mClient
-                                .setImeVisibility(true);
+                                .setImeVisibility(true, statsToken);
                         if (resultReceiver != null) {
                             resultReceiver.send(
                                     wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
@@ -3119,7 +3124,8 @@
         }
     }
 
-    boolean showCurrentInputInternal(IBinder windowToken) {
+    // TODO(b/353463205) check callers to see if we can make statsToken @NonNull
+    boolean showCurrentInputInternal(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showCurrentInputInternal");
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#showSoftInput", mDumper);
@@ -3129,7 +3135,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
-                return showCurrentInputLocked(windowToken, null /* statsToken */, 0 /* flags */,
+                return showCurrentInputLocked(windowToken, statsToken, 0 /* flags */,
                         0 /* lastClickTooType */, null /* resultReceiver */,
                         SoftInputShowHideReason.SHOW_SOFT_INPUT, userId);
             } finally {
@@ -3139,7 +3145,8 @@
         }
     }
 
-    boolean hideCurrentInputInternal(IBinder windowToken) {
+    // TODO(b/353463205) check callers to see if we can make statsToken @NonNull
+    boolean hideCurrentInputInternal(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideCurrentInputInternal");
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#hideSoftInput", mDumper);
@@ -3149,7 +3156,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
-                return hideCurrentInputLocked(windowToken, null /* statsToken */, 0 /* flags */,
+                return hideCurrentInputLocked(windowToken, statsToken, 0 /* flags */,
                         null /* resultReceiver */, SoftInputShowHideReason.HIDE_SOFT_INPUT,
                         userId);
             } finally {
@@ -3536,7 +3543,7 @@
                         boolean wasVisible = isInputShownLocked();
                         // TODO add windowToken to interface
                         userData.mImeBindingState.mFocusedWindowClient.mClient
-                                .setImeVisibility(false);
+                                .setImeVisibility(false, statsToken);
                         if (resultReceiver != null) {
                             resultReceiver.send(wasVisible ? InputMethodManager.RESULT_HIDDEN
                                     : InputMethodManager.RESULT_UNCHANGED_HIDDEN, null);
@@ -4855,13 +4862,13 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     if (Flags.refactorInsetsController()) {
-                        userData.mCurClient.mClient.setImeVisibility(false);
+                        userData.mCurClient.mClient.setImeVisibility(false, statsToken);
                         // TODO we will loose the flags here
                         if (userData.mImeBindingState != null
                                 && userData.mImeBindingState.mFocusedWindowClient != null
                                 && userData.mImeBindingState.mFocusedWindowClient.mClient != null) {
                             userData.mImeBindingState.mFocusedWindowClient.mClient
-                                    .setImeVisibility(false);
+                                    .setImeVisibility(false, statsToken);
                         }
                     } else {
                         hideCurrentInputLocked(mLastImeTargetWindow, statsToken, flags,
@@ -4894,13 +4901,13 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     if (Flags.refactorInsetsController()) {
-                        userData.mCurClient.mClient.setImeVisibility(false);
+                        userData.mCurClient.mClient.setImeVisibility(false, statsToken);
                         // TODO we will loose the flags here
                         if (userData.mImeBindingState != null
                                 && userData.mImeBindingState.mFocusedWindowClient != null
                                 && userData.mImeBindingState.mFocusedWindowClient.mClient != null) {
                             userData.mImeBindingState.mFocusedWindowClient.mClient
-                                    .setImeVisibility(true);
+                                    .setImeVisibility(true, statsToken);
                         }
                     } else {
                         showCurrentInputLocked(mLastImeTargetWindow, statsToken, flags,
@@ -5074,7 +5081,8 @@
                                 && userData.mImeBindingState.mFocusedWindowClient != null
                                 && userData.mImeBindingState.mFocusedWindowClient.mClient != null) {
                             userData.mImeBindingState.mFocusedWindowClient.mClient
-                                    .setImeVisibility(false);
+                                    .setImeVisibility(false,
+                                    null /* TODO(b329229469) check statsToken */);
                         }
                     } else {
                         @SoftInputShowHideReason final int reason = (int) msg.obj;
@@ -6822,7 +6830,8 @@
                                     && userData.mImeBindingState.mFocusedWindowClient.mClient
                                     != null) {
                                 userData.mImeBindingState.mFocusedWindowClient.mClient
-                                        .setImeVisibility(false);
+                                        .setImeVisibility(false,
+                                        null /* TODO(b329229469) initialize statsToken here? */);
                             } else {
                                 // TODO(b329229469): ImeTracker?
                             }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f22e654..1efb3ef 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -7180,8 +7180,8 @@
         @Override
         public void setImeInputTargetRequestedVisibility(boolean visible) {
             if (android.view.inputmethod.Flags.refactorInsetsController()) {
+                // TODO(b/329229469) we won't have the statsToken in all cases, but should still log
                 try {
-                    // TODO stats token
                     mRemoteInsetsController.setImeInputTargetRequestedVisibility(visible);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Failed to deliver setImeInputTargetRequestedVisibility", e);
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 91c61b1..4f4daa1 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -89,6 +89,7 @@
 
     @Override
     void onPostLayout() {
+        boolean wasServerVisible = mServerVisible;
         super.onPostLayout();
 
         if (android.view.inputmethod.Flags.refactorInsetsController()) {
@@ -101,11 +102,32 @@
             // again, so that the control with leash can be eventually dispatched
             if (!mGivenInsetsReady && mServerVisible && !givenInsetsPending) {
                 mGivenInsetsReady = true;
+                ImeTracker.forLogging().onProgress(mStatsToken,
+                        ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
                 mStateController.notifyControlChanged(mControlTarget);
+            } else if (wasServerVisible && mServerVisible && mGivenInsetsReady
+                    && givenInsetsPending) {
+                // If the server visibility didn't change (still visible), and mGivenInsetsReady
+                // is set, we won't call into notifyControlChanged. Therefore, we can reset the
+                // statsToken, if available.
+                ImeTracker.forLogging().onCancelled(mStatsToken,
+                        ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
+                mStatsToken = null;
             }
         }
     }
 
+    @Nullable
+    ImeTracker.Token getAndClearStatsToken() {
+        if (android.view.inputmethod.Flags.refactorInsetsController()) {
+            ImeTracker.Token statsToken = mStatsToken;
+            mStatsToken = null;
+            return statsToken;
+        } else {
+            return null;
+        }
+    }
+
     @Override
     protected boolean isLeashReadyForDispatching() {
         if (android.view.inputmethod.Flags.refactorInsetsController()) {
@@ -142,6 +164,14 @@
             }
             control.setSkipAnimationOnce(startingData != null && startingData.hasImeSurface());
         }
+        if (android.view.inputmethod.Flags.refactorInsetsController()) {
+            if (control != null && control.getLeash() != null) {
+                ImeTracker.Token statsToken = getAndClearStatsToken();
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_WM_GET_CONTROL_WITH_LEASH);
+                control.setImeStatsToken(statsToken);
+            }
+        }
         return control;
     }
 
@@ -168,7 +198,7 @@
             if (android.view.inputmethod.Flags.refactorInsetsController()) {
                 if (!serverVisible && !mFrozen) {
                     mGivenInsetsReady = false;
-                    updateControlForTarget(mControlTarget, true /* force */);
+                    updateControlForTarget(mControlTarget, true /* force */, null /* statsToken */);
                 }
             }
         }
@@ -214,22 +244,29 @@
     }
 
     @Override
-    void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
+    void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force,
+            @NonNull ImeTracker.Token statsToken) {
         if (target != null && target.getWindow() != null) {
             // ime control target could be a different window.
             // Refer WindowState#getImeControlTarget().
             target = target.getWindow().getImeControlTarget();
         }
-        super.updateControlForTarget(target, force);
+        // TODO(b/329229469) make sure that the statsToken of all callers is non-null (currently
+        //  not the case)
+        super.updateControlForTarget(target, force, statsToken);
         if (Flags.refactorInsetsController()) {
+            // TODO(b/353463205) investigate if we should fail the statsToken, or if it's only
+            //  temporary null.
             if (target != null) {
-                invokeOnImeRequestedChangedListener(target.getWindow());
+                invokeOnImeRequestedChangedListener(target.getWindow(), statsToken);
             }
         }
     }
 
+    // TODO(b/353463205) change statsToken to be NonNull, after the flag is permanently enabled
     @Override
-    protected boolean updateClientVisibility(InsetsControlTarget caller) {
+    protected boolean updateClientVisibility(InsetsControlTarget caller,
+            @Nullable ImeTracker.Token statsToken) {
         InsetsControlTarget controlTarget = getControlTarget();
         if (caller != controlTarget) {
             if (Flags.refactorInsetsController()) {
@@ -240,6 +277,8 @@
                     // its new requested visibility for the IME
                     boolean imeVisible = caller.isRequestedVisible(WindowInsets.Type.ime());
                     if (controlTarget != null) {
+                        ImeTracker.forLogging().onProgress(statsToken,
+                                ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
                         controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
                     } else {
                         // In case of a virtual display that cannot show the IME, the
@@ -249,17 +288,24 @@
                         controlTarget = mDisplayContent.getImeHostOrFallback(caller.getWindow());
 
                         if (controlTarget != caller) {
+                            ImeTracker.forLogging().onProgress(statsToken,
+                                    ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
                             controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
+                        } else {
+                            ImeTracker.forLogging().onFailed(statsToken,
+                                    ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
                         }
                     }
 
                     WindowState windowState = caller.getWindow();
-                    invokeOnImeRequestedChangedListener(windowState);
+                    invokeOnImeRequestedChangedListener(windowState, statsToken);
+                } else {
+                    // TODO(b/353463205) add ImeTracker?
                 }
             }
             return false;
         }
-        boolean changed = super.updateClientVisibility(caller);
+        boolean changed = super.updateClientVisibility(caller, statsToken);
         if (!Flags.refactorInsetsController()) {
             if (changed && caller.isRequestedVisible(mSource.getType())) {
                 reportImeDrawnForOrganizerIfNeeded(caller);
@@ -273,7 +319,11 @@
                 WindowState windowState = caller.getWindow() != null ? caller.getWindow()
                         : ((mDisplayContent.getImeInputTarget() != null)
                                 ? mDisplayContent.getImeInputTarget().getWindowState() : null);
-                invokeOnImeRequestedChangedListener(windowState);
+                invokeOnImeRequestedChangedListener(windowState, statsToken);
+            } else {
+                // TODO(b/329229469) change phase and check cancelled / failed
+                ImeTracker.forLogging().onCancelled(statsToken,
+                        ImeTracker.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES);
             }
         }
         return changed;
@@ -288,22 +338,34 @@
                 // know about the new requestedVisibleTypes for the IME.
                 if (imeControlTarget != null) {
                     imeControlTarget.setImeInputTargetRequestedVisibility(
-                            (targetWin.getRequestedVisibleTypes()
-                                    & WindowInsets.Type.ime()) != 0);
+                            (targetWin.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
                 }
             }
         }
     }
 
-    private void invokeOnImeRequestedChangedListener(WindowState windowState) {
+    // TODO(b/353463205) check callers to see if we can make statsToken @NonNull
+    private void invokeOnImeRequestedChangedListener(WindowState windowState,
+            @Nullable ImeTracker.Token statsToken) {
         final var imeListener = mDisplayContent.mWmService.mOnImeRequestedChangedListener;
         if (imeListener != null) {
             if (windowState != null) {
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_WM_POSTING_CHANGED_IME_VISIBILITY);
                 mDisplayContent.mWmService.mH.post(() -> {
+                    ImeTracker.forLogging().onProgress(statsToken,
+                            ImeTracker.PHASE_WM_INVOKING_IME_REQUESTED_LISTENER);
                     imeListener.onImeRequestedChanged(windowState.mClient.asBinder(),
-                            windowState.isRequestedVisible(WindowInsets.Type.ime()));
+                            windowState.isRequestedVisible(WindowInsets.Type.ime()), statsToken);
                 });
+            } else {
+                ImeTracker.forLogging().onFailed(statsToken,
+                        ImeTracker.PHASE_WM_POSTING_CHANGED_IME_VISIBILITY);
             }
+        } else {
+            // TODO(b/353463205) We could combine the upper if's and remove the additional phase.
+            ImeTracker.forLogging().onFailed(statsToken,
+                    ImeTracker.PHASE_WM_DISPATCH_IME_REQUESTED_CHANGED);
         }
     }
 
@@ -399,9 +461,9 @@
             // This can later become ready, so we don't want to cancel the pending request here.
             return;
         }
+        // TODO(b/329229469) check if this is still triggered, as we don't go into STATE_SHOW_IME
+        //  (DefaultImeVisibilityApplier)
         if (android.view.inputmethod.Flags.refactorInsetsController()) {
-            // Clear token here so we don't report an error in abortShowImePostLayout().
-            abortShowImePostLayout();
             // The IME is drawn, so call into {@link WindowState#notifyInsetsControlChanged}
             // if we have a leash
             if (mControl != null && mControl.getLeash() != null
@@ -517,6 +579,33 @@
     }
 
     /**
+     * Sets the statsToken before the IMS was shown/hidden.
+     * @param visible {@code true} to make it visible, false to hide it.
+     * @param statsToken the token tracking the current IME request.
+     */
+    void receiveImeStatsToken(boolean visible,
+            @NonNull ImeTracker.Token statsToken) {
+        if (!android.view.inputmethod.Flags.refactorInsetsController()) {
+            return;
+        }
+
+        if (mStatsToken != null) {
+            // We have an ongoing show request will be cancelled by the newly received show
+            // request (cancelling the initial show) or hide request (aborting the initial show).
+            logIsScheduledAndReadyToShowIme(!visible /* aborted */);
+        }
+        if (visible) {
+            ImeTracker.forLogging().onCancelled(
+                    mStatsToken, ImeTracker.PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT);
+            mStatsToken = statsToken;
+        } else {
+            ImeTracker.forLogging().onFailed(
+                    mStatsToken, ImeTracker.PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT);
+            mStatsToken = null;
+        }
+    }
+
+    /**
      * Logs the current state that can be checked by {@link #isScheduledAndReadyToShowIme}.
      *
      * @param aborted whether the scheduled show IME request was aborted or cancelled.
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 6288a42..62bef74 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -47,6 +47,7 @@
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimation.Bounds;
 import android.view.WindowManager;
+import android.view.inputmethod.ImeTracker;
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.R;
@@ -433,8 +434,9 @@
         return originalState;
     }
 
-    void onRequestedVisibleTypesChanged(InsetsControlTarget caller) {
-        mStateController.onRequestedVisibleTypesChanged(caller);
+    void onRequestedVisibleTypesChanged(InsetsControlTarget caller,
+            @Nullable ImeTracker.Token statsToken) {
+        mStateController.onRequestedVisibleTypesChanged(caller, statsToken);
         checkAbortTransient(caller);
         updateBarControlTarget(mFocusedWin);
     }
@@ -803,7 +805,8 @@
         }
 
         @Override
-        public void updateRequestedVisibleTypes(int types) { }
+        public void updateRequestedVisibleTypes(int types, @Nullable ImeTracker.Token statsToken) {
+        }
 
         @Override
         public boolean hasAnimationCallbacks() {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 33dea54..f5c92f6 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -46,6 +46,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowInsets;
+import android.view.inputmethod.ImeTracker;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
@@ -498,7 +499,8 @@
         );
     }
 
-    void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
+    void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force,
+            @Nullable ImeTracker.Token statsToken) {
         if (mSeamlessRotating) {
             // We are un-rotating the window against the display rotation. We don't want the target
             // to control the window for now.
@@ -570,7 +572,8 @@
         mSeamlessRotating = false;
     }
 
-    boolean updateClientVisibility(InsetsControlTarget caller) {
+    boolean updateClientVisibility(InsetsControlTarget caller,
+            @Nullable ImeTracker.Token statsToken) {
         final boolean requestedVisible = caller.isRequestedVisible(mSource.getType());
         if (caller != mControlTarget || requestedVisible == mClientVisible) {
             return false;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index dcadb0f..9c2a8de 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -40,6 +40,7 @@
 import android.view.InsetsState;
 import android.view.WindowInsets;
 import android.view.WindowInsets.Type.InsetsType;
+import android.view.inputmethod.ImeTracker;
 
 import com.android.internal.protolog.ProtoLog;
 import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -216,10 +217,14 @@
         }
     }
 
-    void onRequestedVisibleTypesChanged(InsetsControlTarget caller) {
+    void onRequestedVisibleTypesChanged(InsetsControlTarget caller,
+            @Nullable ImeTracker.Token statsToken) {
         boolean changed = false;
         for (int i = mProviders.size() - 1; i >= 0; i--) {
-            changed |= mProviders.valueAt(i).updateClientVisibility(caller);
+            final InsetsSourceProvider provider = mProviders.valueAt(i);
+            final boolean isImeProvider = provider.getSource().getType() == WindowInsets.Type.ime();
+            changed |= provider.updateClientVisibility(caller,
+                    isImeProvider ? statsToken : null);
         }
         if (!android.view.inputmethod.Flags.refactorInsetsController()) {
             if (changed) {
@@ -310,7 +315,9 @@
             // aborted.
             provider.updateFakeControlTarget(target);
         } else {
-            provider.updateControlForTarget(target, false /* force */);
+            // TODO(b/329229469) if the IME controlTarget changes, any pending requests should fail
+            provider.updateControlForTarget(target, false /* force */,
+                    null /* TODO(b/329229469) check if needed here */);
 
             // Get control target again in case the provider didn't accept the one we passed to it.
             target = provider.getControlTarget();
@@ -394,7 +401,9 @@
             // to the clients, so that the clients can change the current visibilities to the
             // requested visibilities with animations.
             for (int i = newControlTargets.size() - 1; i >= 0; i--) {
-                onRequestedVisibleTypesChanged(newControlTargets.valueAt(i));
+                // TODO(b/353463205) the statsToken shouldn't be null as it is used later in the
+                //  IME provider. Check if we have to create a new request here
+                onRequestedVisibleTypesChanged(newControlTargets.valueAt(i), null /* statsToken */);
             }
             newControlTargets.clear();
             if (!android.view.inputmethod.Flags.refactorInsetsController()) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index cc95518..32ec020 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -37,6 +37,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -78,6 +79,7 @@
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowManager;
 import android.view.WindowRelayoutResult;
+import android.view.inputmethod.ImeTracker;
 import android.window.InputTransferToken;
 import android.window.OnBackInvokedCallbackInfo;
 
@@ -710,13 +712,20 @@
     }
 
     @Override
-    public void updateRequestedVisibleTypes(IWindow window, @InsetsType int requestedVisibleTypes) {
+    public void updateRequestedVisibleTypes(IWindow window, @InsetsType int requestedVisibleTypes,
+            @Nullable ImeTracker.Token imeStatsToken) {
         synchronized (mService.mGlobalLock) {
             final WindowState win = mService.windowForClientLocked(this, window,
                     false /* throwOnError */);
             if (win != null) {
+                ImeTracker.forLogging().onProgress(imeStatsToken,
+                        ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
                 win.setRequestedVisibleTypes(requestedVisibleTypes);
-                win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win);
+                win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win,
+                        imeStatsToken);
+            } else {
+                ImeTracker.forLogging().onFailed(imeStatsToken,
+                        ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
             }
         }
     }
@@ -985,4 +994,28 @@
             }
         }
     }
+
+    @Override
+    public void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
+            @NonNull ImeTracker.Token statsToken) {
+        synchronized (mService.mGlobalLock) {
+            // TODO(b/353463205) check if we can use mService.getDefaultDisplayContentLocked()
+            //  instead of window
+            final WindowState win = mService.windowForClientLocked(this, window,
+                    false /* throwOnError */);
+            if (win != null) {
+                final InsetsStateController insetsStateController =
+                        win.getDisplayContent().getInsetsStateController();
+                ProtoLog.d(WM_DEBUG_IME, "notifyImeWindowVisibilityChangedFromClient: %s",
+                        insetsStateController.getImeSourceProvider());
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT);
+                insetsStateController.getImeSourceProvider().receiveImeStatsToken(visible,
+                        statsToken);
+            } else {
+                ImeTracker.forLogging().onFailed(statsToken,
+                        ImeTracker.PHASE_WM_NOTIFY_IME_VISIBILITY_CHANGED_FROM_CLIENT);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 5061133..8ae1cf0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -365,8 +365,10 @@
          *
          * @param windowToken The window token
          * @param imeVisible {@code true} if the IME should be shown, {@code false} to hide
+         * @param statsToken the token tracking the current IME request.
          */
-        void onImeRequestedChanged(IBinder windowToken, boolean imeVisible);
+        void onImeRequestedChanged(IBinder windowToken, boolean imeVisible,
+                @Nullable ImeTracker.Token statsToken);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f65eea0..a218068 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4717,8 +4717,10 @@
                     return;
                 }
                 dc.mRemoteInsetsControlTarget.setRequestedVisibleTypes(requestedVisibleTypes);
+                // TODO(b/353463205) the statsToken shouldn't be null as it is used later in the
+                //  IME provider. Check if we have to create a new request here
                 dc.getInsetsStateController().onRequestedVisibleTypesChanged(
-                        dc.mRemoteInsetsControlTarget);
+                        dc.mRemoteInsetsControlTarget, null /* statsToken */);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 24fc7ee..421bbae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3354,7 +3354,8 @@
 
         // app1 requests IME visible.
         app1.setRequestedVisibleTypes(ime(), ime());
-        mDisplayContent.getInsetsStateController().onRequestedVisibleTypesChanged(app1);
+        mDisplayContent.getInsetsStateController().onRequestedVisibleTypesChanged(app1,
+                null /* statsToken */);
 
         // Verify app1's IME insets is visible and app2's IME insets frozen flag set.
         assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
@@ -3425,7 +3426,7 @@
         assertFalse(activity2.mImeInsetsFrozenUntilStartInput);
 
         app1.setRequestedVisibleTypes(ime());
-        controller.onRequestedVisibleTypesChanged(app1);
+        controller.onRequestedVisibleTypesChanged(app1, null /* statsToken */);
 
         // Expect all activities in split-screen will get IME insets visible state
         assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index c77a4d6..caeb41c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -554,7 +554,7 @@
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
         displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
         final InsetsSourceProvider navBarProvider = mNavBarWindow.getControllableInsetProvider();
-        navBarProvider.updateControlForTarget(mAppWindow, false);
+        navBarProvider.updateControlForTarget(mAppWindow, false, null /* statsToken */);
         navBarProvider.getSource().setVisible(false);
 
         displayPolicy.setCanSystemBarsBeShownByUser(false);
@@ -579,7 +579,7 @@
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
         displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs);
         final InsetsSourceProvider navBarProvider = mNavBarWindow.getControllableInsetProvider();
-        navBarProvider.updateControlForTarget(win, false);
+        navBarProvider.updateControlForTarget(win, false, null /* statsToken */);
         navBarProvider.getSource().setVisible(false);
 
         displayPolicy.setCanSystemBarsBeShownByUser(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index eeec54f..b26c267 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -361,7 +361,7 @@
 
         mAppWindow.setRequestedVisibleTypes(
                 navigationBars() | statusBars(), navigationBars() | statusBars());
-        policy.onRequestedVisibleTypesChanged(mAppWindow);
+        policy.onRequestedVisibleTypesChanged(mAppWindow, null /* statsToken */);
         waitUntilWindowAnimatorIdle();
 
         controls = mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 2a025cd..6190807 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -112,13 +112,13 @@
         statusBar.getFrame().set(0, 0, 500, 100);
 
         // We must not have control or control target before we have the insets source window.
-        mProvider.updateControlForTarget(target, true /* force */);
+        mProvider.updateControlForTarget(target, true /* force */, null /* statsToken */);
         assertNull(mProvider.getControl(target));
         assertNull(mProvider.getControlTarget());
 
         // We can have the control or the control target after we have the insets source window.
         mProvider.setWindowContainer(statusBar, null, null);
-        mProvider.updateControlForTarget(target, false /* force */);
+        mProvider.updateControlForTarget(target, false /* force */, null /* statsToken */);
         assertNotNull(mProvider.getControl(target));
         assertNotNull(mProvider.getControlTarget());
 
@@ -127,25 +127,25 @@
         mProvider.startSeamlessRotation();
         assertNull(mProvider.getControl(target));
         assertNull(mProvider.getControlTarget());
-        mProvider.updateControlForTarget(target, true /* force */);
+        mProvider.updateControlForTarget(target, true /* force */, null /* statsToken */);
         assertNull(mProvider.getControl(target));
         assertNull(mProvider.getControlTarget());
 
         // We can have the control and the control target after seamless rotation.
         mProvider.finishSeamlessRotation();
-        mProvider.updateControlForTarget(target, false /* force */);
+        mProvider.updateControlForTarget(target, false /* force */, null /* statsToken */);
         assertNotNull(mProvider.getControl(target));
         assertNotNull(mProvider.getControlTarget());
 
         // We can clear the control and the control target.
-        mProvider.updateControlForTarget(null, false /* force */);
+        mProvider.updateControlForTarget(null, false /* force */, null /* statsToken */);
         assertNull(mProvider.getControl(target));
         assertNull(mProvider.getControlTarget());
 
         // We must not have control or control target if the insets source window doesn't have a
         // surface.
         statusBar.setSurfaceControl(null);
-        mProvider.updateControlForTarget(target, true /* force */);
+        mProvider.updateControlForTarget(target, true /* force */, null /* statsToken */);
         assertNull(mProvider.getControl(target));
         assertNull(mProvider.getControlTarget());
     }
@@ -173,7 +173,7 @@
 
         // We must not have control or control target before we have the insets source window,
         // so also no leash.
-        mProvider.updateControlForTarget(target, true /* force */);
+        mProvider.updateControlForTarget(target, true /* force */, null /* statsToken */);
         assertNull(mProvider.getControl(target));
         assertNull(mProvider.getControlTarget());
         assertNull(mProvider.getLeash(target));
@@ -181,7 +181,7 @@
         // We can have the control or the control target after we have the insets source window,
         // but no leash as this is not yet ready for dispatching.
         mProvider.setWindowContainer(statusBar, null, null);
-        mProvider.updateControlForTarget(target, false /* force */);
+        mProvider.updateControlForTarget(target, false /* force */, null /* statsToken */);
         assertNotNull(mProvider.getControl(target));
         assertNotNull(mProvider.getControlTarget());
         assertEquals(mProvider.getControlTarget(), target);
@@ -265,9 +265,9 @@
         final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
         statusBar.getFrame().set(0, 0, 500, 100);
         mProvider.setWindowContainer(statusBar, null, null);
-        mProvider.updateControlForTarget(target, false /* force */);
+        mProvider.updateControlForTarget(target, false /* force */, null /* statsToken */);
         target.setRequestedVisibleTypes(0, statusBars());
-        mProvider.updateClientVisibility(target);
+        mProvider.updateClientVisibility(target, null /* statsToken */);
         assertFalse(mSource.isVisible());
     }
 
@@ -278,7 +278,7 @@
         statusBar.getFrame().set(0, 0, 500, 100);
         mProvider.setWindowContainer(statusBar, null, null);
         target.setRequestedVisibleTypes(0, statusBars());
-        mProvider.updateClientVisibility(target);
+        mProvider.updateClientVisibility(target, null /* statsToken */);
         assertTrue(mSource.isVisible());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index c69faed..0dc56f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -201,7 +201,7 @@
                 .setWindowContainer(mImeWindow, null, null);
         getController().onImeControlTargetChanged(base);
         base.setRequestedVisibleTypes(ime(), ime());
-        getController().onRequestedVisibleTypesChanged(base);
+        getController().onRequestedVisibleTypesChanged(base, null /* statsToken */);
 
         // Send our spy window (app) into the system so that we can detect the invocation.
         final WindowState win = createWindow(null, TYPE_APPLICATION, "app");
@@ -445,7 +445,7 @@
 
         waitUntilHandlersIdle();
         clearInvocations(mDisplayContent);
-        imeSourceProvider.updateControlForTarget(app, false /* force */);
+        imeSourceProvider.updateControlForTarget(app, false /* force */, null /* statsToken */);
         imeSourceProvider.setClientVisible(true);
         verify(mDisplayContent).assignWindowLayers(anyBoolean());
         waitUntilHandlersIdle();
@@ -497,7 +497,7 @@
         mDisplayContent.updateImeInputAndControlTarget(app);
 
         app.setRequestedVisibleTypes(ime(), ime());
-        getController().onRequestedVisibleTypesChanged(app);
+        getController().onRequestedVisibleTypesChanged(app, null /* statsToken */);
         assertTrue(ime.getControllableInsetProvider().getSource().isVisible());
 
         getController().updateAboveInsetsState(true /* notifyInsetsChange */);
@@ -544,7 +544,7 @@
         imeInsetsProvider.setWindowContainer(mImeWindow, null, null);
         imeInsetsProvider.updateSourceFrame(mImeWindow.getFrame());
 
-        imeInsetsProvider.updateControlForTarget(app1, false);
+        imeInsetsProvider.updateControlForTarget(app1, false, null /* statsToken */);
         imeInsetsProvider.onPostLayout();
         final InsetsSourceControl control1 = imeInsetsProvider.getControl(app1);
         assertNotNull(control1);
@@ -553,7 +553,7 @@
 
         // Simulate the IME control target updated from app1 to app2 when IME insets was invisible.
         imeInsetsProvider.setServerVisible(false);
-        imeInsetsProvider.updateControlForTarget(app2, false);
+        imeInsetsProvider.updateControlForTarget(app2, false, null /* statsToken */);
 
         // Verify insetsHint of the new control is same as last IME source frame after the layout.
         imeInsetsProvider.onPostLayout();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e13376b..b46189c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -472,7 +472,7 @@
         app.setRequestedVisibleTypes(0, statusBars());
         mDisplayContent.getInsetsStateController()
                 .getOrCreateSourceProvider(statusBarId, statusBars())
-                .updateClientVisibility(app);
+                .updateClientVisibility(app, null /* statsToken */);
         waitUntilHandlersIdle();
         assertFalse(statusBar.isVisible());
     }