Merge "Add IME tracing to data gathered in WinscopeTrace"
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