Add IME tracing to data gathered in WinscopeTrace

This change starts and stops IME tracing together with the other traces
gathered when the WinscopeTrace tile is used. The data is saved along
the other traces in /data/misc/wmtrace/.

Bug: 154348613
Bug: 167948910
Test: flash a device together with the other change in this topic
      enable the WinscopeTrace tile and do some actions
      disable the WinscopeTrace tile
      do a bugreport and visualise contents in Winscope
      or just check contents of /data/misc/wmtrace/ through adb
Change-Id: If0b16dd5c19aa8bb33174abe2fe242fc8e6bdd90
diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java
index b8af740..e64c8c0 100644
--- a/src/com/android/settings/development/qstile/DevelopmentTiles.java
+++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java
@@ -49,6 +49,7 @@
 
 import com.android.internal.app.LocalePicker;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.view.IInputMethodManager;
 import com.android.settings.R;
 import com.android.settings.development.WirelessDebuggingPreferenceController;
 import com.android.settings.overlay.FeatureFactory;
@@ -197,6 +198,7 @@
         static final int SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE = 1026;
         private IBinder mSurfaceFlinger;
         private IWindowManager mWindowManager;
+        private IInputMethodManager mInputMethodManager;
         private Toast mToast;
 
         @Override
@@ -204,6 +206,8 @@
             super.onCreate();
             mWindowManager = WindowManagerGlobal.getWindowManagerService();
             mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
+            mInputMethodManager = IInputMethodManager.Stub.asInterface(
+                    ServiceManager.getService("input_method"));
             Context context = getApplicationContext();
             CharSequence text = "Trace files written to /data/misc/wmtrace";
             mToast = Toast.makeText(context, text, Toast.LENGTH_LONG);
@@ -256,9 +260,19 @@
             return false;
         }
 
+        private boolean isImeTraceEnabled() {
+            try {
+                return mInputMethodManager.isImeTraceEnabled();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Could not get ime trace status, defaulting to false.", e);
+            }
+            return false;
+        }
+
         @Override
         protected boolean isEnabled() {
-            return isWindowTraceEnabled() || isLayerTraceEnabled() || isSystemUiTracingEnabled();
+            return isWindowTraceEnabled() || isLayerTraceEnabled() || isSystemUiTracingEnabled()
+                    || isImeTraceEnabled();
         }
 
         private void setWindowTraceEnabled(boolean isEnabled) {
@@ -308,11 +322,24 @@
             }
         }
 
+        private void setImeTraceEnabled(boolean isEnabled) {
+            try {
+                if (isEnabled) {
+                    mInputMethodManager.startImeTrace();
+                } else {
+                    mInputMethodManager.stopImeTrace();
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Could not set ime trace status." + e.toString());
+            }
+        }
+
         @Override
         protected void setIsEnabled(boolean isEnabled) {
             setWindowTraceEnabled(isEnabled);
             setLayerTraceEnabled(isEnabled);
             setSystemUiTracing(isEnabled);
+            setImeTraceEnabled(isEnabled);
             if (!isEnabled) {
                 mToast.show();
             }
diff --git a/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java b/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java
index cafebe4..b4dab0d 100644
--- a/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java
+++ b/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java
@@ -37,6 +37,7 @@
 import android.view.IWindowManager;
 import android.widget.Toast;
 
+import com.android.internal.view.IInputMethodManager;
 import com.android.settings.testutils.shadow.ShadowParcel;
 
 import org.junit.After;
@@ -55,6 +56,8 @@
     @Mock
     private IWindowManager mWindowManager;
     @Mock
+    private IInputMethodManager mInputMethodManager;
+    @Mock
     private IBinder mSurfaceFlinger;
     @Mock
     private Toast mToast;
@@ -66,6 +69,7 @@
         MockitoAnnotations.initMocks(this);
         mWinscopeTrace = spy(new DevelopmentTiles.WinscopeTrace());
         ReflectionHelpers.setField(mWinscopeTrace, "mWindowManager", mWindowManager);
+        ReflectionHelpers.setField(mWinscopeTrace, "mInputMethodManager", mInputMethodManager);
         ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", mSurfaceFlinger);
         ReflectionHelpers.setField(mWinscopeTrace, "mToast", mToast);
     }
@@ -78,7 +82,7 @@
     @Test
     @Config(shadows = ShadowParcel.class)
     public void wmReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
-        // Assume Surface Trace is disabled.
+        // Assume Surface Trace and Input Method Manager are disabled.
         ShadowParcel.sReadBoolResult = false;
         doReturn(true).when(mWindowManager).isWindowTraceEnabled();
         assertThat(mWinscopeTrace.isEnabled()).isTrue();
@@ -87,8 +91,9 @@
     @Test
     @Config(shadows = ShadowParcel.class)
     public void sfReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
-        // Assume Window Trace is disabled.
+        // Assume Window Trace and Input Method Manager are disabled.
         doReturn(false).when(mWindowManager).isWindowTraceEnabled();
+        doReturn(false).when(mInputMethodManager).isImeTraceEnabled();
         ShadowParcel.sReadBoolResult = true;
         assertThat(mWinscopeTrace.isEnabled()).isTrue();
         verify(mSurfaceFlinger)
@@ -106,17 +111,49 @@
     }
 
     @Test
-    public void wmAndSfReturnsTraceDisabled_shouldReturnDisabled() throws RemoteException {
+    public void wmAndSfAndImmReturnTraceDisabled_shouldReturnDisabled() throws RemoteException {
         ShadowParcel.sReadBoolResult = false;
         doReturn(false).when(mWindowManager).isWindowTraceEnabled();
+        doReturn(false).when(mInputMethodManager).isImeTraceEnabled();
         assertThat(mWinscopeTrace.isEnabled()).isFalse();
         verify(mSurfaceFlinger)
                 .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(),
-                        eq(0 /* flags */));
+                eq(0 /* flags */));
         verifyNoMoreInteractions(mSurfaceFlinger);
     }
 
     @Test
+    public void wmAndSfReturnTraceDisabled_immReturnsTraceEnabled_shouldReturnEnabled()
+            throws RemoteException {
+        ShadowParcel.sReadBoolResult = false;
+        doReturn(false).when(mWindowManager).isWindowTraceEnabled();
+        doReturn(true).when(mInputMethodManager).isImeTraceEnabled();
+        assertThat(mWinscopeTrace.isEnabled()).isTrue();
+        verify(mSurfaceFlinger)
+                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(),
+                eq(0 /* flags */));
+        verifyNoMoreInteractions(mSurfaceFlinger);
+    }
+
+    @Test
+    @Config(shadows = ShadowParcel.class)
+    public void immReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
+        // Assume Window Manager and Surface Trace are disabled.
+        ShadowParcel.sReadBoolResult = false;
+        doReturn(true).when(mInputMethodManager).isImeTraceEnabled();
+        assertThat(mWinscopeTrace.isEnabled()).isTrue();
+    }
+
+    @Test
+    @Config(shadows = ShadowParcel.class)
+    public void immReturnsTraceDisabled_shouldReturnDisabled() throws RemoteException {
+        // Assume Window Manager and Surface Trace are disabled.
+        ShadowParcel.sReadBoolResult = false;
+        doReturn(false).when(mInputMethodManager).isImeTraceEnabled();
+        assertThat(mWinscopeTrace.isEnabled()).isFalse();
+    }
+
+    @Test
     @Config(shadows = ShadowParcel.class)
     public void wmThrowsRemoteExAndSfReturnsTraceDisabled_shouldReturnDisabled()
             throws RemoteException {
@@ -127,9 +164,10 @@
     }
 
     @Test
-    public void sfUnavailableAndWmReturnsTraceDisabled_shouldReturnDisabled()
+    public void sfUnavailableAndWmAndImmReturnTraceDisabled_shouldReturnDisabled()
             throws RemoteException {
         doReturn(false).when(mWindowManager).isWindowTraceEnabled();
+        doReturn(false).when(mInputMethodManager).isImeTraceEnabled();
         ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", null);
         assertThat(mWinscopeTrace.isEnabled()).isFalse();
     }
@@ -142,6 +180,13 @@
     }
 
     @Test
+    public void setIsEnableTrue_shouldEnableImeTrace() throws RemoteException {
+        mWinscopeTrace.setIsEnabled(true);
+        verify(mInputMethodManager).startImeTrace();
+        verifyNoMoreInteractions(mInputMethodManager);
+    }
+
+    @Test
     @Config(shadows = ShadowParcel.class)
     public void setIsEnableTrue_shouldEnableLayerTrace() throws RemoteException {
         mWinscopeTrace.setIsEnabled(true);
@@ -163,6 +208,15 @@
 
     @Test
     @Config(shadows = ShadowParcel.class)
+    public void setIsEnableFalse_shouldDisableImeTrace() throws RemoteException {
+        mWinscopeTrace.setIsEnabled(false);
+        verify(mInputMethodManager).stopImeTrace();
+        verifyNoMoreInteractions(mInputMethodManager);
+        verify(mToast).show();
+    }
+
+    @Test
+    @Config(shadows = ShadowParcel.class)
     public void setIsEnableFalse_shouldDisableLayerTrace() throws RemoteException {
         mWinscopeTrace.setIsEnabled(false);
         assertThat(ShadowParcel.sWriteIntResult).isEqualTo(0);
@@ -191,6 +245,17 @@
     }
 
     /**
+     * Verify when input method manager call throws a remote exception, it is handled without
+     * re-throwing the exception.
+     */
+    @Test
+    public void setIsEnableAndImmThrowsRemoteException_shouldFailGracefully()
+            throws RemoteException {
+        doThrow(new RemoteException("Unknown")).when(mInputMethodManager).isImeTraceEnabled();
+        mWinscopeTrace.setIsEnabled(true);
+    }
+
+    /**
      * Verify is surface flinger is not available not calls are made to it.
      */
     @Test