Merge "Instrument latency and jank for IME"
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index d55367f..ed6a88f 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -223,11 +223,13 @@
                 final SomeArgs args = (SomeArgs) msg.obj;
                 final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg3;
                 if (isValid(inputMethod, target, "DO_SHOW_SOFT_INPUT")) {
-                    ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+                    ImeTracker.forLogging().onProgress(
+                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
                     inputMethod.showSoftInputWithToken(
                             msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1, statsToken);
                 } else {
-                    ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+                    ImeTracker.forLogging().onFailed(
+                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
                 }
                 args.recycle();
                 return;
@@ -236,11 +238,13 @@
                 final SomeArgs args = (SomeArgs) msg.obj;
                 final ImeTracker.Token statsToken = (ImeTracker.Token) args.arg3;
                 if (isValid(inputMethod, target, "DO_HIDE_SOFT_INPUT")) {
-                    ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+                    ImeTracker.forLogging().onProgress(
+                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
                     inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
                             (IBinder) args.arg1, statsToken);
                 } else {
-                    ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
+                    ImeTracker.forLogging().onFailed(
+                            statsToken, ImeTracker.PHASE_IME_WRAPPER_DISPATCH);
                 }
                 args.recycle();
                 return;
@@ -428,7 +432,7 @@
     @Override
     public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
             int flags, ResultReceiver resultReceiver) {
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
         mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT,
                 flags, showInputToken, resultReceiver, statsToken));
     }
@@ -437,7 +441,7 @@
     @Override
     public void hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
             int flags, ResultReceiver resultReceiver) {
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
         mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_HIDE_SOFT_INPUT,
                 flags, hideInputToken, resultReceiver, statsToken));
     }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 872414a..ee9d8a4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -896,7 +896,8 @@
         @MainThread
         @Override
         public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
-            ImeTracker.get().onProgress(mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
+            ImeTracker.forLogging().onProgress(
+                    mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
             if (DEBUG) Log.v(TAG, "hideSoftInput()");
             if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
                     && !mSystemCallingHideSoftInput) {
@@ -950,7 +951,8 @@
         @MainThread
         @Override
         public void showSoftInput(int flags, ResultReceiver resultReceiver) {
-            ImeTracker.get().onProgress(mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
+            ImeTracker.forLogging().onProgress(
+                    mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
             if (DEBUG) Log.v(TAG, "showSoftInput()");
             // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods.
             if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
@@ -966,11 +968,11 @@
                     null /* icProto */);
             final boolean wasVisible = isInputViewShown();
             if (dispatchOnShowInputRequested(flags, false)) {
-                ImeTracker.get().onProgress(mCurStatsToken,
+                ImeTracker.forLogging().onProgress(mCurStatsToken,
                         ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
                 showWindow(true);
             } else {
-                ImeTracker.get().onFailed(mCurStatsToken,
+                ImeTracker.forLogging().onFailed(mCurStatsToken,
                         ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
             }
             setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
@@ -2979,7 +2981,7 @@
         ImeTracing.getInstance().triggerServiceDump(
                 "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
                 null /* icProto */);
-        ImeTracker.get().onProgress(mCurStatsToken,
+        ImeTracker.forLogging().onProgress(mCurStatsToken,
                 ImeTracker.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER);
         mPrivOps.applyImeVisibilityAsync(setVisible
                 ? mCurShowInputToken : mCurHideInputToken, setVisible, mCurStatsToken);
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 289a5b6..4a3b8ac 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -123,7 +123,7 @@
 
         // TODO: ResultReceiver for IME.
         // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
-        ImeTracker.get().onProgress(statsToken,
+        ImeTracker.forLogging().onProgress(statsToken,
                 ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW);
 
         if (getControl() == null) {
@@ -165,12 +165,13 @@
         //  - we do already have one, but we have control and use the passed in token
         //      for the insets animation already.
         if (statsToken == null || getControl() != null) {
-            statsToken = ImeTracker.get().onRequestHide(null /* component */, Process.myUid(),
+            statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
+                    Process.myUid(),
                     ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
                     SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
         }
 
-        ImeTracker.get().onProgress(statsToken,
+        ImeTracker.forLogging().onProgress(statsToken,
                 ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN);
 
         getImm().notifyImeHidden(mController.getHost().getWindowToken(), statsToken);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1c00e5f..d8bff1c 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -26,6 +26,7 @@
 import static android.view.WindowInsets.Type.all;
 import static android.view.WindowInsets.Type.captionBar;
 import static android.view.WindowInsets.Type.ime;
+import static android.view.inputmethod.ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL;
 
 import android.animation.AnimationHandler;
 import android.animation.Animator;
@@ -35,6 +36,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityThread;
+import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -59,6 +62,7 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
 import android.view.inputmethod.ImeTracker;
+import android.view.inputmethod.ImeTracker.InputMethodJankContext;
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -185,6 +189,14 @@
         @Nullable
         String getRootViewTitle();
 
+        /**
+         * @return the context related to the rootView.
+         */
+        @Nullable
+        default Context getRootViewContext() {
+            return null;
+        }
+
         /** @see ViewRootImpl#dipToPx */
         int dipToPx(int dips);
 
@@ -308,7 +320,7 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE,
             ANIMATION_TYPE_USER, ANIMATION_TYPE_RESIZE})
-    @interface AnimationType {
+    public @interface AnimationType {
     }
 
     /**
@@ -323,6 +335,25 @@
     /** Logging listener. */
     private WindowInsetsAnimationControlListener mLoggingListener;
 
+    /** Context for {@link android.view.inputmethod.ImeTracker.ImeJankTracker} to monitor jank. */
+    private final InputMethodJankContext mJankContext = new InputMethodJankContext() {
+        @Override
+        public Context getDisplayContext() {
+            return mHost != null ? mHost.getRootViewContext() : null;
+        }
+
+        @Override
+        public SurfaceControl getTargetSurfaceControl() {
+            final InsetsSourceControl imeSourceControl = getImeSourceConsumer().getControl();
+            return imeSourceControl != null ? imeSourceControl.getLeash() : null;
+        }
+
+        @Override
+        public String getHostPackageName() {
+            return mHost != null ? mHost.getRootViewContext().getPackageName() : null;
+        }
+    };
+
     /**
      * The default implementation of listener, to be used by InsetsController and InsetsPolicy to
      * animate insets.
@@ -340,6 +371,7 @@
         private final boolean mDisable;
         private final int mFloatingImeBottomInset;
         private final WindowInsetsAnimationControlListener mLoggingListener;
+        private final InputMethodJankContext mInputMethodJankContext;
 
         private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
                 new ThreadLocal<AnimationHandler>() {
@@ -353,7 +385,8 @@
 
         public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
                 @InsetsType int requestedTypes, @Behavior int behavior, boolean disable,
-                int floatingImeBottomInset, WindowInsetsAnimationControlListener loggingListener) {
+                int floatingImeBottomInset, WindowInsetsAnimationControlListener loggingListener,
+                @Nullable InputMethodJankContext jankContext) {
             mShow = show;
             mHasAnimationCallbacks = hasAnimationCallbacks;
             mRequestedTypes = requestedTypes;
@@ -362,6 +395,7 @@
             mDisable = disable;
             mFloatingImeBottomInset = floatingImeBottomInset;
             mLoggingListener = loggingListener;
+            mInputMethodJankContext = jankContext;
         }
 
         @Override
@@ -408,10 +442,26 @@
                         + insetsFraction);
             });
             mAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    if (mInputMethodJankContext == null) return;
+                    ImeTracker.forJank().onRequestAnimation(
+                            mInputMethodJankContext,
+                            mShow ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
+                            !mHasAnimationCallbacks);
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    if (mInputMethodJankContext == null) return;
+                    ImeTracker.forJank().onCancelAnimation();
+                }
 
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     onAnimationFinish();
+                    if (mInputMethodJankContext == null) return;
+                    ImeTracker.forJank().onFinishAnimation();
                 }
             });
             if (!mHasAnimationCallbacks) {
@@ -897,7 +947,7 @@
 
     /**
      * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, boolean, int, int, int, int,
-     *      int, SparseIntArray)
+     *      int, android.util.SparseIntArray)
      */
     @VisibleForTesting
     public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeSystemBars,
@@ -1005,7 +1055,7 @@
     public void show(@InsetsType int types) {
         ImeTracker.Token statsToken = null;
         if ((types & ime()) != 0) {
-            statsToken = ImeTracker.get().onRequestShow(null /* component */,
+            statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
                     SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API);
         }
@@ -1030,6 +1080,9 @@
         }
         // Handle pending request ready in case there was one set.
         if (fromIme && mPendingImeControlRequest != null) {
+            if ((types & Type.ime()) != 0) {
+                ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
+            }
             handlePendingControlRequest(statsToken);
             return;
         }
@@ -1052,7 +1105,7 @@
                         "show ignored for type: %d animType: %d requestedVisible: %s",
                         type, animationType, requestedVisible));
                 if (isImeAnimation) {
-                    ImeTracker.get().onCancelled(statsToken,
+                    ImeTracker.forLogging().onCancelled(statsToken,
                             ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
                 }
                 continue;
@@ -1060,16 +1113,21 @@
             if (fromIme && animationType == ANIMATION_TYPE_USER) {
                 // App is already controlling the IME, don't cancel it.
                 if (isImeAnimation) {
-                    ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
+                    ImeTracker.forLogging().onFailed(
+                            statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
                 }
                 continue;
             }
             if (isImeAnimation) {
-                ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
+                ImeTracker.forLogging().onProgress(
+                        statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
             }
             typesReady |= type;
         }
         if (DEBUG) Log.d(TAG, "show typesReady: " + typesReady);
+        if (fromIme && (typesReady & Type.ime()) != 0) {
+            ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
+        }
         applyAnimation(typesReady, true /* show */, fromIme, statsToken);
     }
 
@@ -1098,7 +1156,7 @@
     public void hide(@InsetsType int types) {
         ImeTracker.Token statsToken = null;
         if ((types & ime()) != 0) {
-            statsToken = ImeTracker.get().onRequestHide(null /* component */,
+            statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
                     SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
         }
@@ -1147,13 +1205,14 @@
                 // no-op: already hidden or animating out (because window visibility is
                 // applied before starting animation).
                 if (isImeAnimation) {
-                    ImeTracker.get().onCancelled(statsToken,
+                    ImeTracker.forLogging().onCancelled(statsToken,
                             ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
                 }
                 continue;
             }
             if (isImeAnimation) {
-                ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
+                ImeTracker.forLogging().onProgress(
+                        statsToken, ImeTracker.PHASE_CLIENT_APPLY_ANIMATION);
             }
             typesReady |= type;
         }
@@ -1225,8 +1284,19 @@
             @AnimationType int animationType,
             @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
             boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken) {
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
         if ((types & mTypesBeingCancelled) != 0) {
+            final boolean monitoredAnimation =
+                    animationType == ANIMATION_TYPE_SHOW || animationType == ANIMATION_TYPE_HIDE;
+            if (monitoredAnimation && (types & Type.ime()) != 0) {
+                if (animationType == ANIMATION_TYPE_SHOW) {
+                    ImeTracker.forLatency().onShowCancelled(statsToken,
+                            PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+                } else {
+                    ImeTracker.forLatency().onHideCancelled(statsToken,
+                            PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+                }
+            }
             throw new IllegalStateException("Cannot start a new insets animation of "
                     + Type.toString(types)
                     + " while an existing " + Type.toString(mTypesBeingCancelled)
@@ -1238,7 +1308,7 @@
             types &= ~mDisabledUserAnimationInsetsTypes;
 
             if ((disabledTypes & ime()) != 0) {
-                ImeTracker.get().onFailed(statsToken,
+                ImeTracker.forLogging().onFailed(statsToken,
                         ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
 
                 if (fromIme
@@ -1260,7 +1330,8 @@
             Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
             return;
         }
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
+        ImeTracker.forLogging().onProgress(statsToken,
+                ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION);
         if (DEBUG) Log.d(TAG, "controlAnimation types: " + types);
         mLastStartedAnimTypes |= types;
 
@@ -1327,8 +1398,11 @@
         if ((typesReady & WindowInsets.Type.ime()) != 0) {
             ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl",
                     mHost.getInputMethodManager(), null /* icProto */);
+            if (animationType == ANIMATION_TYPE_HIDE) {
+                ImeTracker.forLatency().onHidden(statsToken, ActivityThread::currentApplication);
+            }
         }
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_ANIMATION_RUNNING);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_ANIMATION_RUNNING);
         mRunningAnimations.add(new RunningAnimation(runner, animationType));
         if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: "
                 + useInsetsAnimationThread);
@@ -1368,7 +1442,8 @@
     private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, @InsetsType int types,
             SparseArray<InsetsSourceControl> controls, @AnimationType int animationType,
             @Nullable ImeTracker.Token statsToken) {
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS);
+        ImeTracker.forLogging().onProgress(statsToken,
+                ImeTracker.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS);
 
         int typesReady = 0;
         boolean imeReady = true;
@@ -1471,13 +1546,13 @@
         }
         final ImeTracker.Token statsToken = runner.getStatsToken();
         if (shown) {
-            ImeTracker.get().onProgress(statsToken,
+            ImeTracker.forLogging().onProgress(statsToken,
                     ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_SHOW);
-            ImeTracker.get().onShown(statsToken);
+            ImeTracker.forLogging().onShown(statsToken);
         } else {
-            ImeTracker.get().onProgress(statsToken,
+            ImeTracker.forLogging().onProgress(statsToken,
                     ImeTracker.PHASE_CLIENT_ANIMATION_FINISHED_HIDE);
-            ImeTracker.get().onHidden(statsToken);
+            ImeTracker.forLogging().onHidden(statsToken);
         }
         reportRequestedVisibleTypes();
     }
@@ -1503,13 +1578,13 @@
 
     private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
         if (invokeCallback) {
-            ImeTracker.get().onCancelled(control.getStatsToken(),
-                    ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
+            ImeTracker.forLogging().onCancelled(control.getStatsToken(),
+                    PHASE_CLIENT_ANIMATION_CANCEL);
             control.cancel();
         } else {
             // Succeeds if invokeCallback is false (i.e. when called from notifyFinished).
-            ImeTracker.get().onProgress(control.getStatsToken(),
-                    ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
+            ImeTracker.forLogging().onProgress(control.getStatsToken(),
+                    PHASE_CLIENT_ANIMATION_CANCEL);
         }
         if (DEBUG) {
             Log.d(TAG, TextUtils.formatSimple(
@@ -1674,7 +1749,7 @@
         final InternalAnimationControlListener listener = new InternalAnimationControlListener(
                 show, hasAnimationCallbacks, types, mHost.getSystemBarsBehavior(),
                 skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
-                mLoggingListener);
+                mLoggingListener, mJankContext);
 
         // We are about to playing the default animation (show/hide). Passing a null frame indicates
         // the controlled types should be animated regardless of the frame.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d603de2..e49e5c2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5815,7 +5815,7 @@
                 }
                 case MSG_SHOW_INSETS: {
                     final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
-                    ImeTracker.get().onProgress(statsToken,
+                    ImeTracker.forLogging().onProgress(statsToken,
                             ImeTracker.PHASE_CLIENT_HANDLE_SHOW_INSETS);
                     if (mView == null) {
                         Log.e(TAG,
@@ -5828,7 +5828,7 @@
                 }
                 case MSG_HIDE_INSETS: {
                     final ImeTracker.Token statsToken = (ImeTracker.Token) msg.obj;
-                    ImeTracker.get().onProgress(statsToken,
+                    ImeTracker.forLogging().onProgress(statsToken,
                             ImeTracker.PHASE_CLIENT_HANDLE_HIDE_INSETS);
                     mInsetsController.hide(msg.arg1, msg.arg2 == 1, statsToken);
                     break;
@@ -10407,10 +10407,10 @@
                         null /* icProto */);
             }
             if (viewAncestor != null) {
-                ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
+                ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
                 viewAncestor.showInsets(types, fromIme, statsToken);
             } else {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_SHOW_INSETS);
             }
         }
 
@@ -10424,10 +10424,10 @@
                         null /* icProto */);
             }
             if (viewAncestor != null) {
-                ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
+                ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
                 viewAncestor.hideInsets(types, fromIme, statsToken);
             } else {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_HIDE_INSETS);
             }
         }
 
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index c59d83e..a2708ee 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -21,6 +21,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
 
 import android.annotation.NonNull;
+import android.content.Context;
 import android.content.res.CompatibilityInfo;
 import android.os.Handler;
 import android.os.IBinder;
@@ -246,6 +247,11 @@
     }
 
     @Override
+    public Context getRootViewContext() {
+        return mViewRoot != null ? mViewRoot.mContext : null;
+    }
+
+    @Override
     public int dipToPx(int dips) {
         if (mViewRoot != null) {
             return mViewRoot.dipToPx(dips);
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 3b6ec80..e5a99ff 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -16,24 +16,36 @@
 
 package android.view.inputmethod;
 
+import static com.android.internal.inputmethod.InputMethodDebug.softInputDisplayReasonToString;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_IME_INSETS_ANIMATION;
+import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_HIDDEN;
+import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_SHOWN;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityThread;
+import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemProperties;
 import android.util.Log;
+import android.view.InsetsController.AnimationType;
+import android.view.SurfaceControl;
 
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
+import com.android.internal.util.LatencyTracker;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Field;
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Random;
 import java.util.stream.Collectors;
@@ -385,15 +397,35 @@
     void onHidden(@Nullable Token token);
 
     /**
-     * Get the singleton instance of this class.
+     * Get the singleton request tracker instance.
      *
-     * @return the singleton instance of this class
+     * @return the singleton request tracker instance
      */
     @NonNull
-    static ImeTracker get() {
+    static ImeTracker forLogging() {
         return LOGGER;
     }
 
+    /**
+     * Get the singleton jank tracker instance.
+     *
+     * @return the singleton jank tracker instance
+     */
+    @NonNull
+    static ImeJankTracker forJank() {
+        return JANK_TRACKER;
+    }
+
+    /**
+     * Get the singleton latency tracker instance.
+     *
+     * @return the singleton latency tracker instance
+     */
+    @NonNull
+    static ImeLatencyTracker forLatency() {
+        return LATENCY_TRACKER;
+    }
+
     /** The singleton IME tracker instance. */
     @NonNull
     ImeTracker LOGGER = new ImeTracker() {
@@ -489,6 +521,12 @@
         }
     };
 
+    /** The singleton IME tracker instance for instrumenting jank metrics. */
+    ImeJankTracker JANK_TRACKER = new ImeJankTracker();
+
+    /** The singleton IME tracker instance for instrumenting latency metrics. */
+    ImeLatencyTracker LATENCY_TRACKER = new ImeLatencyTracker();
+
     /** A token that tracks the progress of an IME request. */
     class Token implements Parcelable {
 
@@ -592,4 +630,162 @@
             }
         }
     }
+
+    /**
+     * Context related to {@link InteractionJankMonitor}.
+     */
+    interface InputMethodJankContext {
+        /**
+         * @return a context associated with a display
+         */
+        Context getDisplayContext();
+
+        /**
+         * @return a SurfaceControl that is going to be monitored
+         */
+        SurfaceControl getTargetSurfaceControl();
+
+        /**
+         * @return the package name of the host
+         */
+        String getHostPackageName();
+    }
+
+    /**
+     * Context related to {@link LatencyTracker}.
+     */
+    interface InputMethodLatencyContext {
+        /**
+         * @return a context associated with current application
+         */
+        Context getAppContext();
+    }
+
+    /**
+     * A tracker instance which is in charge of communicating with {@link InteractionJankMonitor}.
+     * This class disallows instantiating from outside, use {@link #forJank()} to get the singleton.
+     */
+    final class ImeJankTracker {
+
+        /**
+         * This class disallows instantiating from outside.
+         */
+        private ImeJankTracker() {
+        }
+
+        /**
+         * Called when the animation, which is going to be monitored, starts.
+         *
+         * @param jankContext context which is needed by {@link InteractionJankMonitor}
+         * @param animType {@link AnimationType}
+         * @param useSeparatedThread {@code true} if the animation is handled by the app,
+         *                           {@code false} if the animation will be scheduled on the
+         *                           {@link android.view.InsetsAnimationThread}
+         */
+        public void onRequestAnimation(@NonNull InputMethodJankContext jankContext,
+                @AnimationType int animType, boolean useSeparatedThread) {
+            if (jankContext.getDisplayContext() == null
+                    || jankContext.getTargetSurfaceControl() == null) {
+                return;
+            }
+            final Configuration.Builder builder = Configuration.Builder.withSurface(
+                            CUJ_IME_INSETS_ANIMATION,
+                            jankContext.getDisplayContext(),
+                            jankContext.getTargetSurfaceControl())
+                    .setTag(String.format(Locale.US, "%d@%d@%s", animType,
+                            useSeparatedThread ? 0 : 1, jankContext.getHostPackageName()));
+            InteractionJankMonitor.getInstance().begin(builder);
+        }
+
+        /**
+         * Called when the animation, which is going to be monitored, cancels.
+         */
+        public void onCancelAnimation() {
+            InteractionJankMonitor.getInstance().cancel(CUJ_IME_INSETS_ANIMATION);
+        }
+
+        /**
+         * Called when the animation, which is going to be monitored, ends.
+         */
+        public void onFinishAnimation() {
+            InteractionJankMonitor.getInstance().end(CUJ_IME_INSETS_ANIMATION);
+        }
+    }
+
+    /**
+     * A tracker instance which is in charge of communicating with {@link LatencyTracker}.
+     * This class disallows instantiating from outside, use {@link #forLatency()}
+     * to get the singleton.
+     */
+    final class ImeLatencyTracker {
+
+        /**
+         * This class disallows instantiating from outside.
+         */
+        private ImeLatencyTracker() {
+        }
+
+        private boolean shouldMonitorLatency(@SoftInputShowHideReason int reason) {
+            return reason == SoftInputShowHideReason.SHOW_SOFT_INPUT
+                    || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT
+                    || reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API
+                    || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API
+                    || reason == SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME
+                    || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_IME;
+        }
+
+        public void onRequestShow(@Nullable Token token, @Origin int origin,
+                @SoftInputShowHideReason int reason,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            if (!shouldMonitorLatency(reason)) return;
+            LatencyTracker.getInstance(latencyContext.getAppContext())
+                    .onActionStart(
+                            ACTION_REQUEST_IME_SHOWN,
+                            softInputDisplayReasonToString(reason));
+        }
+
+        public void onRequestHide(@Nullable Token token, @Origin int origin,
+                @SoftInputShowHideReason int reason,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            if (!shouldMonitorLatency(reason)) return;
+            LatencyTracker.getInstance(latencyContext.getAppContext())
+                    .onActionStart(
+                            ACTION_REQUEST_IME_HIDDEN,
+                            softInputDisplayReasonToString(reason));
+        }
+
+        public void onShowFailed(@Nullable Token token, @Phase int phase,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            onShowCancelled(token, phase, latencyContext);
+        }
+
+        public void onHideFailed(@Nullable Token token, @Phase int phase,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            onHideCancelled(token, phase, latencyContext);
+        }
+
+        public void onShowCancelled(@Nullable Token token, @Phase int phase,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            LatencyTracker.getInstance(latencyContext.getAppContext())
+                    .onActionCancel(ACTION_REQUEST_IME_SHOWN);
+        }
+
+        public void onHideCancelled(@Nullable Token token, @Phase int phase,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            LatencyTracker.getInstance(latencyContext.getAppContext())
+                    .onActionCancel(ACTION_REQUEST_IME_HIDDEN);
+        }
+
+        public void onShown(@Nullable Token token,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            LatencyTracker.getInstance(latencyContext.getAppContext())
+                    .onActionEnd(ACTION_REQUEST_IME_SHOWN);
+        }
+
+        public void onHidden(@Nullable Token token,
+                @NonNull InputMethodLatencyContext latencyContext) {
+            LatencyTracker.getInstance(latencyContext.getAppContext())
+                    .onActionEnd(ACTION_REQUEST_IME_HIDDEN);
+        }
+    }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 99bd02d..642182b 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2045,10 +2045,11 @@
     private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken, int flags,
             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
         if (statsToken == null) {
-            statsToken = ImeTracker.get().onRequestShow(null /* component */,
+            statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason);
         }
-
+        ImeTracker.forLatency().onRequestShow(statsToken, ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
+                reason, ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
                 null /* icProto */);
         // Re-dispatch if there is a context mismatch.
@@ -2060,12 +2061,15 @@
         checkFocus();
         synchronized (mH) {
             if (!hasServedByInputMethodLocked(view)) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLatency().onShowFailed(
+                        statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
+                        ActivityThread::currentApplication);
                 Log.w(TAG, "Ignoring showSoftInput() as view=" + view + " is not served.");
                 return false;
             }
 
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
 
             // Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
             // TODO(b/229426865): call WindowInsetsController#show instead.
@@ -2095,20 +2099,20 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
     public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
         synchronized (mH) {
-            final ImeTracker.Token statsToken = ImeTracker.get().onRequestShow(null /* component */,
-                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
+            final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow(
+                    null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
                     SoftInputShowHideReason.SHOW_SOFT_INPUT);
 
             Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
                     + " removed soon. If you are using androidx.appcompat.widget.SearchView,"
                     + " please update to version 26.0 or newer version.");
             if (mCurRootView == null || mCurRootView.getView() == null) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
                 Log.w(TAG, "No current root view, ignoring showSoftInputUnchecked()");
                 return;
             }
 
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
 
             // Makes sure to call ImeInsetsSourceConsumer#onShowRequested on the UI thread.
             // TODO(b/229426865): call WindowInsetsController#show instead.
@@ -2186,20 +2190,24 @@
 
     private boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
-        final ImeTracker.Token statsToken = ImeTracker.get().onRequestHide(null /* component */,
-                Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
-
+        final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
+                null /* component */, Process.myUid(),
+                ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
+        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+                reason, ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
                 this, null /* icProto */);
         checkFocus();
         synchronized (mH) {
             final View servedView = getServedViewLocked();
             if (servedView == null || servedView.getWindowToken() != windowToken) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLatency().onHideFailed(statsToken,
+                        ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
                 return false;
             }
 
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
 
             return IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken,
                     flags, resultReceiver, reason);
@@ -2835,18 +2843,22 @@
 
     @UnsupportedAppUsage
     void closeCurrentInput() {
-        final ImeTracker.Token statsToken = ImeTracker.get().onRequestHide(null /* component */,
-                Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+        final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
+                null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
                 SoftInputShowHideReason.HIDE_SOFT_INPUT);
+        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+                SoftInputShowHideReason.HIDE_SOFT_INPUT, ActivityThread::currentApplication);
 
         synchronized (mH) {
             if (mCurRootView == null || mCurRootView.getView() == null) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLatency().onHideFailed(statsToken,
+                        ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
                 Log.w(TAG, "No current root view, ignoring closeCurrentInput()");
                 return;
             }
 
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
 
             IInputMethodManagerGlobalInvoker.hideSoftInput(
                     mClient,
@@ -2905,11 +2917,13 @@
         synchronized (mH) {
             final View servedView = getServedViewLocked();
             if (servedView == null || servedView.getWindowToken() != windowToken) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
+                ImeTracker.forLogging().onFailed(statsToken,
+                        ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
                 return false;
             }
 
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
+            ImeTracker.forLogging().onProgress(statsToken,
+                    ImeTracker.PHASE_CLIENT_REQUEST_IME_SHOW);
 
             showSoftInput(servedView, statsToken, 0 /* flags */, null /* resultReceiver */,
                     SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API);
@@ -2927,21 +2941,25 @@
      */
     public void notifyImeHidden(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
         if (statsToken == null) {
-            statsToken = ImeTracker.get().onRequestHide(null /* component */,
+            statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
                     SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
         }
-
+        ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+                SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+                ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
                 null /* icProto */);
         synchronized (mH) {
             if (!isImeSessionAvailableLocked() || mCurRootView == null
                     || mCurRootView.getWindowToken() != windowToken) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+                ImeTracker.forLatency().onHideFailed(statsToken,
+                        ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
                 return;
             }
 
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
 
             IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken,
                     0 /* flags */, null /* resultReceiver */,
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index d6cc611..62f1599 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -16,11 +16,15 @@
 
 package com.android.internal.jank;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
 import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
 import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
@@ -89,10 +93,13 @@
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.UiThread;
 import android.annotation.WorkerThread;
+import android.app.ActivityThread;
 import android.content.Context;
 import android.os.Build;
 import android.os.Handler;
@@ -100,7 +107,6 @@
 import android.os.HandlerThread;
 import android.os.SystemClock;
 import android.provider.DeviceConfig;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -233,6 +239,7 @@
     public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66;
     public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67;
     public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68;
+    public static final int CUJ_IME_INSETS_ANIMATION = 69;
 
     private static final int NO_STATSD_LOGGING = -1;
 
@@ -310,6 +317,7 @@
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION,
     };
 
     private static class InstanceHolder {
@@ -402,7 +410,8 @@
             CUJ_RECENTS_SCROLLING,
             CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
             CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE,
-            CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME
+            CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
+            CUJ_IME_INSETS_ANIMATION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -423,29 +432,37 @@
      * @param worker the worker thread for the callbacks
      */
     @VisibleForTesting
+    @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
     public InteractionJankMonitor(@NonNull HandlerThread worker) {
-        // Check permission early.
-        Settings.Config.enforceReadPermission(
-            DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR);
-
         mRunningTrackers = new SparseArray<>();
         mTimeoutActions = new SparseArray<>();
         mWorker = worker;
         mWorker.start();
-        mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
         mDisplayResolutionTracker = new DisplayResolutionTracker(worker.getThreadHandler());
-
-        // Post initialization to the background in case we're running on the main
-        // thread.
-        mWorker.getThreadHandler().post(
-                () -> mPropertiesChangedListener.onPropertiesChanged(
-                        DeviceConfig.getProperties(
-                                DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR)));
-        DeviceConfig.addOnPropertiesChangedListener(
-                DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR,
-                new HandlerExecutor(mWorker.getThreadHandler()),
-                mPropertiesChangedListener);
+        mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
         mEnabled = DEFAULT_ENABLED;
+
+        final Context context = ActivityThread.currentApplication();
+        if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) == PERMISSION_GRANTED) {
+            // Post initialization to the background in case we're running on the main thread.
+            mWorker.getThreadHandler().post(
+                    () -> mPropertiesChangedListener.onPropertiesChanged(
+                            DeviceConfig.getProperties(
+                                    DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR)));
+            DeviceConfig.addOnPropertiesChangedListener(
+                    DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR,
+                    new HandlerExecutor(mWorker.getThreadHandler()),
+                    mPropertiesChangedListener);
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "Initialized the InteractionJankMonitor."
+                        + " (No READ_DEVICE_CONFIG permission to change configs)"
+                        + " enabled=" + mEnabled + ", interval=" + mSamplingInterval
+                        + ", missedFrameThreshold=" + mTraceThresholdMissedFrames
+                        + ", frameTimeThreshold=" + mTraceThresholdFrameTimeMillis
+                        + ", package=" + context.getPackageName());
+            }
+        }
     }
 
     /**
@@ -927,6 +944,8 @@
                 return "LAUNCHER_CLOSE_ALL_APPS_SWIPE";
             case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME:
                 return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME";
+            case CUJ_IME_INSETS_ANIMATION:
+                return "IME_INSETS_ANIMATION";
         }
         return "UNKNOWN";
     }
@@ -1182,7 +1201,7 @@
          */
         @VisibleForTesting
         public int getDisplayId() {
-            return (mSurfaceOnly ? mContext.getDisplay() : mView.getDisplay()).getDisplayId();
+            return (mSurfaceOnly ? mContext : mView.getContext()).getDisplayId();
         }
     }
 
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index afb526a..2d5bb6c 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -14,7 +14,10 @@
 
 package com.android.internal.util;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Trace.TRACE_TAG_APP;
+import static android.provider.DeviceConfig.NAMESPACE_LATENCY_TRACKER;
 
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED;
@@ -24,6 +27,8 @@
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK;
 import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR;
@@ -42,9 +47,12 @@
 import static com.android.internal.util.LatencyTracker.ActionProperties.SAMPLE_INTERVAL_SUFFIX;
 import static com.android.internal.util.LatencyTracker.ActionProperties.TRACE_THRESHOLD_SUFFIX;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.app.ActivityThread;
 import android.content.Context;
 import android.os.Build;
 import android.os.ConditionVariable;
@@ -187,6 +195,16 @@
      */
     public static final int ACTION_SHOW_VOICE_INTERACTION = 19;
 
+    /**
+     * Time it takes to request IME shown animation.
+     */
+    public static final int ACTION_REQUEST_IME_SHOWN = 20;
+
+    /**
+     * Time it takes to request IME hidden animation.
+     */
+    public static final int ACTION_REQUEST_IME_HIDDEN = 21;
+
     private static final int[] ACTIONS_ALL = {
         ACTION_EXPAND_PANEL,
         ACTION_TOGGLE_RECENTS,
@@ -208,6 +226,8 @@
         ACTION_SHOW_SELECTION_TOOLBAR,
         ACTION_FOLD_TO_AOD,
         ACTION_SHOW_VOICE_INTERACTION,
+        ACTION_REQUEST_IME_SHOWN,
+        ACTION_REQUEST_IME_HIDDEN,
     };
 
     /** @hide */
@@ -232,6 +252,8 @@
         ACTION_SHOW_SELECTION_TOOLBAR,
         ACTION_FOLD_TO_AOD,
         ACTION_SHOW_VOICE_INTERACTION,
+        ACTION_REQUEST_IME_SHOWN,
+        ACTION_REQUEST_IME_HIDDEN,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Action {
@@ -259,6 +281,8 @@
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR,
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD,
             UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN,
+            UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN,
     };
 
     private static LatencyTracker sLatencyTracker;
@@ -284,15 +308,30 @@
         return sLatencyTracker;
     }
 
+    @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
     @VisibleForTesting
     public LatencyTracker() {
         mEnabled = DEFAULT_ENABLED;
 
-        // Post initialization to the background in case we're running on the main thread.
-        BackgroundThread.getHandler().post(() -> this.updateProperties(
-                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_LATENCY_TRACKER)));
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_LATENCY_TRACKER,
-                BackgroundThread.getExecutor(), this::updateProperties);
+        final Context context = ActivityThread.currentApplication();
+        if (context != null
+                && context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) == PERMISSION_GRANTED) {
+            // Post initialization to the background in case we're running on the main thread.
+            BackgroundThread.getHandler().post(() -> this.updateProperties(
+                    DeviceConfig.getProperties(NAMESPACE_LATENCY_TRACKER)));
+            DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_LATENCY_TRACKER,
+                    BackgroundThread.getExecutor(), this::updateProperties);
+        } else {
+            if (DEBUG) {
+                if (context == null) {
+                    Log.d(TAG, "No application for " + ActivityThread.currentActivityThread());
+                } else {
+                    Log.d(TAG, "Initialized the LatencyTracker."
+                            + " (No READ_DEVICE_CONFIG permission to change configs)"
+                            + " enabled=" + mEnabled + ", package=" + context.getPackageName());
+                }
+            }
+        }
     }
 
     private void updateProperties(DeviceConfig.Properties properties) {
@@ -368,6 +407,10 @@
                 return "ACTION_FOLD_TO_AOD";
             case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION:
                 return "ACTION_SHOW_VOICE_INTERACTION";
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN:
+                return "ACTION_REQUEST_IME_SHOWN";
+            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN:
+                return "ACTION_REQUEST_IME_HIDDEN";
             default:
                 throw new IllegalArgumentException("Invalid action");
         }
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 a775db9..2ea4316 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
@@ -387,7 +387,7 @@
                 @Nullable ImeTracker.Token statsToken) {
             final InsetsSource imeSource = mInsetsState.peekSource(InsetsSource.ID_IME);
             if (imeSource == null || mImeSourceControl == null) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
                 return;
             }
             final Rect newFrame = imeSource.getFrame();
@@ -410,7 +410,8 @@
             }
             if ((!forceRestart && (mAnimationDirection == DIRECTION_SHOW && show))
                     || (mAnimationDirection == DIRECTION_HIDE && !show)) {
-                ImeTracker.get().onCancelled(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
+                ImeTracker.forLogging().onCancelled(
+                        statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
                 return;
             }
             boolean seek = false;
@@ -454,7 +455,7 @@
                 mTransactionPool.release(t);
             });
             mAnimation.setInterpolator(INTERPOLATOR);
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
             mAnimation.addListener(new AnimatorListenerAdapter() {
                 private boolean mCancelled = false;
                 @Nullable
@@ -477,7 +478,7 @@
                             : 1.f;
                     t.setAlpha(mImeSourceControl.getLeash(), alpha);
                     if (mAnimationDirection == DIRECTION_SHOW) {
-                        ImeTracker.get().onProgress(mStatsToken,
+                        ImeTracker.forLogging().onProgress(mStatsToken,
                                 ImeTracker.PHASE_WM_ANIMATION_RUNNING);
                         t.show(mImeSourceControl.getLeash());
                     }
@@ -514,15 +515,15 @@
                     }
                     dispatchEndPositioning(mDisplayId, mCancelled, t);
                     if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
-                        ImeTracker.get().onProgress(mStatsToken,
+                        ImeTracker.forLogging().onProgress(mStatsToken,
                                 ImeTracker.PHASE_WM_ANIMATION_RUNNING);
                         t.hide(mImeSourceControl.getLeash());
                         removeImeSurface();
-                        ImeTracker.get().onHidden(mStatsToken);
+                        ImeTracker.forLogging().onHidden(mStatsToken);
                     } else if (mAnimationDirection == DIRECTION_SHOW && !mCancelled) {
-                        ImeTracker.get().onShown(mStatsToken);
+                        ImeTracker.forLogging().onShown(mStatsToken);
                     } else if (mCancelled) {
-                        ImeTracker.get().onCancelled(mStatsToken,
+                        ImeTracker.forLogging().onCancelled(mStatsToken,
                                 ImeTracker.PHASE_WM_ANIMATION_RUNNING);
                     }
                     if (DEBUG_IME_VISIBILITY) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
index 8759301..9bdda14 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -162,10 +162,12 @@
                 @Nullable ImeTracker.Token statsToken) {
             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
             if (listeners == null) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+                ImeTracker.forLogging().onFailed(
+                        statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
                 return;
             }
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+            ImeTracker.forLogging().onProgress(
+                    statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
             for (OnInsetsChangedListener listener : listeners) {
                 listener.showInsets(types, fromIme, statsToken);
             }
@@ -175,10 +177,12 @@
                 @Nullable ImeTracker.Token statsToken) {
             CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
             if (listeners == null) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+                ImeTracker.forLogging().onFailed(
+                        statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
                 return;
             }
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
+            ImeTracker.forLogging().onProgress(
+                    statsToken, ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROLLER);
             for (OnInsetsChangedListener listener : listeners) {
                 listener.hideInsets(types, fromIme, statsToken);
             }
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index 298f6ad..9f7ff31 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -130,14 +130,14 @@
             @ImeVisibilityStateComputer.VisibilityState int state, int reason) {
         switch (state) {
             case STATE_SHOW_IME:
-                ImeTracker.get().onProgress(statsToken,
+                ImeTracker.forLogging().onProgress(statsToken,
                         ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                 // Send to window manager to show IME after IME layout finishes.
                 mWindowManagerInternal.showImePostLayout(windowToken, statsToken);
                 break;
             case STATE_HIDE_IME:
                 if (mService.mCurFocusedWindowClient != null) {
-                    ImeTracker.get().onProgress(statsToken,
+                    ImeTracker.forLogging().onProgress(statsToken,
                             ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                     // IMMS only knows of focused window, not the actual IME target.
                     // e.g. it isn't aware of any window that has both
@@ -148,7 +148,7 @@
                     mWindowManagerInternal.hideIme(windowToken,
                             mService.mCurFocusedWindowClient.mSelfReportedDisplayId, statsToken);
                 } else {
-                    ImeTracker.get().onFailed(statsToken,
+                    ImeTracker.forLogging().onFailed(statsToken,
                             ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                 }
                 break;
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index eaca842..ceb9706 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -183,10 +183,10 @@
      */
     boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken, int showFlags) {
         if (mPolicy.mA11yRequestingNoSoftKeyboard || mPolicy.mImeHiddenByDisplayPolicy) {
-            ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
+            ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
             return false;
         }
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_ACCESSIBILITY);
         if ((showFlags & InputMethodManager.SHOW_FORCED) != 0) {
             mRequestedShowExplicitly = true;
             mShowForced = true;
@@ -207,15 +207,15 @@
         if ((hideFlags & InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                 && (mRequestedShowExplicitly || mShowForced)) {
             if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
-            ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
+            ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_IMPLICIT);
             return false;
         }
         if (mShowForced && (hideFlags & InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
             if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
-            ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
+            ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
             return false;
         }
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_HIDE_NOT_ALWAYS);
         return true;
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 27daceb..233e285 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2293,7 +2293,7 @@
             mCurClient.mSessionRequestedForAccessibility = false;
             mCurClient = null;
             mCurVirtualDisplayToScreenMatrix = null;
-            ImeTracker.get().onFailed(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+            ImeTracker.forLogging().onFailed(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
             mCurStatsToken = null;
 
             mMenuController.hideInputMethodMenuLocked();
@@ -3279,7 +3279,8 @@
                 "InputMethodManagerService#showSoftInput");
         synchronized (ImfLock.class) {
             if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken)) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
+                ImeTracker.forLogging().onFailed(
+                        statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
                 return false;
             }
             final long ident = Binder.clearCallingIdentity();
@@ -3375,7 +3376,7 @@
             // TODO(b/261565259): to avoid using null, add package name in ClientState
             final String packageName = (mCurEditorInfo != null) ? mCurEditorInfo.packageName : null;
             final int uid = mCurClient != null ? mCurClient.mUid : -1;
-            statsToken = ImeTracker.get().onRequestShow(packageName, uid,
+            statsToken = ImeTracker.forLogging().onRequestShow(packageName, uid,
                     ImeTracker.ORIGIN_SERVER_START_INPUT, reason);
         }
 
@@ -3384,19 +3385,19 @@
         }
 
         if (!mSystemReady) {
-            ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
+            ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
             return false;
         }
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_SYSTEM_READY);
 
         mVisibilityStateComputer.requestImeVisibility(windowToken, true);
 
         // Ensure binding the connection when IME is going to show.
         mBindingController.setCurrentMethodVisible();
         final IInputMethodInvoker curMethod = getCurMethodLocked();
-        ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+        ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
         if (curMethod != null) {
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_HAS_IME);
             mCurStatsToken = null;
 
             if (lastClickToolType != MotionEvent.TOOL_TYPE_UNKNOWN) {
@@ -3407,7 +3408,7 @@
             mVisibilityStateComputer.setInputShown(true);
             return true;
         } else {
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
             mCurStatsToken = statsToken;
         }
         return false;
@@ -3423,9 +3424,10 @@
         synchronized (ImfLock.class) {
             if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) {
                 if (isInputShown()) {
-                    ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
+                    ImeTracker.forLogging().onFailed(
+                            statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
                 } else {
-                    ImeTracker.get().onCancelled(statsToken,
+                    ImeTracker.forLogging().onCancelled(statsToken,
                             ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
                 }
                 return false;
@@ -3458,7 +3460,7 @@
             } else {
                 uid = -1;
             }
-            statsToken = ImeTracker.get().onRequestHide(packageName, uid,
+            statsToken = ImeTracker.forLogging().onRequestHide(packageName, uid,
                     ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason);
         }
 
@@ -3484,15 +3486,15 @@
             // delivered to the IME process as an IPC.  Hence the inconsistency between
             // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
             // the final state.
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
             mVisibilityApplier.performHideIme(windowToken, statsToken, resultReceiver, reason);
         } else {
-            ImeTracker.get().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
+            ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
         }
         mBindingController.setCurrentMethodNotVisible();
         mVisibilityStateComputer.clearImeShowFlags();
         // Cancel existing statsToken for show IME as we got a hide request.
-        ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
+        ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
         mCurStatsToken = null;
         return shouldHideSoftInput;
     }
@@ -3764,16 +3766,16 @@
             // be made before input is started in it.
             final ClientState cs = mClients.get(client.asBinder());
             if (cs == null) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
+                ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
                 throw new IllegalArgumentException("unknown client " + client.asBinder());
             }
-            ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
+            ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
             if (!isImeClientFocused(mCurFocusedWindow, cs)) {
                 Slog.w(TAG, String.format("Ignoring %s of uid %d : %s", methodName, uid, client));
                 return false;
             }
         }
-        ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
+        ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
         return true;
     }
 
@@ -4550,7 +4552,8 @@
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
         synchronized (ImfLock.class) {
             if (!calledWithValidTokenLocked(token)) {
-                ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
+                ImeTracker.forLogging().onFailed(statsToken,
+                        ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                 return;
             }
             final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(windowToken);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7d89c32..9060456 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6850,12 +6850,12 @@
         public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme,
                 @Nullable ImeTracker.Token statsToken) {
             try {
-                ImeTracker.get().onProgress(statsToken,
+                ImeTracker.forLogging().onProgress(statsToken,
                         ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SHOW_INSETS);
                 mRemoteInsetsController.showInsets(types, fromIme, statsToken);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Failed to deliver showInsets", e);
-                ImeTracker.get().onFailed(statsToken,
+                ImeTracker.forLogging().onFailed(statsToken,
                         ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_SHOW_INSETS);
             }
         }
@@ -6864,12 +6864,12 @@
         public void hideInsets(@InsetsType int types, boolean fromIme,
                 @Nullable ImeTracker.Token statsToken) {
             try {
-                ImeTracker.get().onProgress(statsToken,
+                ImeTracker.forLogging().onProgress(statsToken,
                         ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_HIDE_INSETS);
                 mRemoteInsetsController.hideInsets(types, fromIme, statsToken);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Failed to deliver hideInsets", e);
-                ImeTracker.get().onFailed(statsToken,
+                ImeTracker.forLogging().onFailed(statsToken,
                         ImeTracker.PHASE_WM_REMOTE_INSETS_CONTROL_TARGET_HIDE_INSETS);
             }
         }
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index f38ae3f..4be98a3 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -182,7 +182,8 @@
         boolean targetChanged = isTargetChangedWithinActivity(imeTarget);
         mImeRequester = imeTarget;
         // There was still a stats token, so that request presumably failed.
-        ImeTracker.get().onFailed(mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
+        ImeTracker.forLogging().onFailed(
+                mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
         mImeRequesterStatsToken = statsToken;
         if (targetChanged) {
             // target changed, check if new target can show IME.
@@ -197,12 +198,12 @@
         ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeRequester.getWindow() == null
                 ? mImeRequester : mImeRequester.getWindow().getName());
         mShowImeRunner = () -> {
-            ImeTracker.get().onProgress(mImeRequesterStatsToken,
+            ImeTracker.forLogging().onProgress(mImeRequesterStatsToken,
                     ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
             ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner");
             // Target should still be the same.
             if (isReadyToShowIme()) {
-                ImeTracker.get().onProgress(mImeRequesterStatsToken,
+                ImeTracker.forLogging().onProgress(mImeRequesterStatsToken,
                         ImeTracker.PHASE_WM_SHOW_IME_READY);
                 final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_CONTROL);
 
@@ -219,7 +220,7 @@
                                     ? mImeRequester.getWindow().getName() : ""));
                 }
             } else {
-                ImeTracker.get().onFailed(mImeRequesterStatsToken,
+                ImeTracker.forLogging().onFailed(mImeRequesterStatsToken,
                         ImeTracker.PHASE_WM_SHOW_IME_READY);
             }
             // Clear token here so we don't report an error in abortShowImePostLayout().
@@ -258,7 +259,8 @@
         mImeRequester = null;
         mIsImeLayoutDrawn = false;
         mShowImeRunner = null;
-        ImeTracker.get().onCancelled(mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
+        ImeTracker.forLogging().onCancelled(
+                mImeRequesterStatsToken, ImeTracker.PHASE_WM_SHOW_IME_RUNNER);
         mImeRequesterStatsToken = null;
     }
 
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 5c5eadc..0b8af4a 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -718,7 +718,8 @@
 
         InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
             super(show, false /* hasCallbacks */, types, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
-                    false /* disable */, 0 /* floatingImeBottomInsets */, null);
+                    false /* disable */, 0 /* floatingImeBottomInsets */,
+                    null /* loggingListener */, null /* jankContext */);
             mFinishCallback = finishCallback;
             mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 23d3637..5f49aeb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8127,14 +8127,14 @@
                     dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
                 }
                 if (dc != null && dc.getImeTarget(IME_TARGET_CONTROL) != null) {
-                    ImeTracker.get().onProgress(statsToken,
+                    ImeTracker.forLogging().onProgress(statsToken,
                             ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
                     ProtoLog.d(WM_DEBUG_IME, "hideIme Control target: %s ",
                             dc.getImeTarget(IME_TARGET_CONTROL));
                     dc.getImeTarget(IME_TARGET_CONTROL).hideInsets(WindowInsets.Type.ime(),
                             true /* fromIme */, statsToken);
                 } else {
-                    ImeTracker.get().onFailed(statsToken,
+                    ImeTracker.forLogging().onFailed(statsToken,
                             ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
                 }
                 if (dc != null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d8ac0ff..bf6bab3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4016,12 +4016,12 @@
     public void showInsets(@InsetsType int types, boolean fromIme,
             @Nullable ImeTracker.Token statsToken) {
         try {
-            ImeTracker.get().onProgress(statsToken,
+            ImeTracker.forLogging().onProgress(statsToken,
                     ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_SHOW_INSETS);
             mClient.showInsets(types, fromIme, statsToken);
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to deliver showInsets", e);
-            ImeTracker.get().onFailed(statsToken,
+            ImeTracker.forLogging().onFailed(statsToken,
                     ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_SHOW_INSETS);
         }
     }
@@ -4030,12 +4030,12 @@
     public void hideInsets(@InsetsType int types, boolean fromIme,
             @Nullable ImeTracker.Token statsToken) {
         try {
-            ImeTracker.get().onProgress(statsToken,
+            ImeTracker.forLogging().onProgress(statsToken,
                     ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_HIDE_INSETS);
             mClient.hideInsets(types, fromIme, statsToken);
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to deliver hideInsets", e);
-            ImeTracker.get().onFailed(statsToken,
+            ImeTracker.forLogging().onFailed(statsToken,
                     ImeTracker.PHASE_WM_WINDOW_INSETS_CONTROL_TARGET_HIDE_INSETS);
         }
     }