Simplify Window/Surface trace by using one QS Tile

- Trigger both traces using a new Winscope Trace Tile

Bug: 73496681
Test: make RunSettingsRoboTests ROBOTEST_FILTER=WinscopeTraceTest
Test: flash and manually click on new tile
Change-Id: I3e05f625a983c382e58cc797d293a695223c630a
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dec12ba..7b24600 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3213,19 +3213,9 @@
             </intent-filter>
         </service>
         <service
-            android:name=".development.qstile.DevelopmentTiles$WindowTrace"
-            android:label="@string/window_trace_quick_settings_title"
-            android:icon="@drawable/tile_icon_window_trace"
-            android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
-            android:enabled="false">
-            <intent-filter>
-                <action android:name="android.service.quicksettings.action.QS_TILE" />
-            </intent-filter>
-        </service>
-        <service
-            android:name=".development.qstile.DevelopmentTiles$LayerTrace"
-            android:label="@string/layer_trace_quick_settings_title"
-            android:icon="@drawable/tile_icon_layer_trace"
+            android:name=".development.qstile.DevelopmentTiles$WinscopeTrace"
+            android:label="@string/winscope_trace_quick_settings_title"
+            android:icon="@drawable/tile_icon_winscope_trace"
             android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
             android:enabled="false">
             <intent-filter>
diff --git a/res/drawable/tile_icon_layer_trace.xml b/res/drawable/tile_icon_layer_trace.xml
deleted file mode 100644
index 21dafd3..0000000
--- a/res/drawable/tile_icon_layer_trace.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-    Copyright (C) 2018 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:pathData="M11.709,11.712 L7.061,8.098 6.039,8.893l5.676,4.415 5.676,-4.415 -1.028,-0.801zM11.716,10.11 L16.357,6.496 17.392,5.695 11.716,1.281 6.039,5.695 7.067,6.496Z"
-        android:fillColor="#FFFFFFFF"/>
-    <path
-        android:pathData="m20.27,15.235c0,0.82 -0.671,1.491 -1.491,1.491 -0.134,0 -0.261,-0.015 -0.38,-0.052l-2.654,2.646C15.782,19.439 15.797,19.573 15.797,19.708c0,0.82 -0.671,1.491 -1.491,1.491 -0.82,0 -1.491,-0.671 -1.491,-1.491 0,-0.134 0.015,-0.268 0.052,-0.388L10.966,17.419C10.847,17.456 10.713,17.471 10.579,17.471 10.444,17.471 10.31,17.456 10.191,17.419L6.799,20.818C6.836,20.938 6.851,21.064 6.851,21.199 6.851,22.019 6.18,22.689 5.36,22.689 4.54,22.689 3.869,22.019 3.869,21.199c0,-0.82 0.671,-1.491 1.491,-1.491 0.134,0 0.261,0.015 0.38,0.052L9.14,16.368C9.103,16.249 9.088,16.114 9.088,15.98 9.088,15.16 9.759,14.489 10.579,14.489c0.82,0 1.491,0.671 1.491,1.491 0,0.134 -0.015,0.268 -0.052,0.388l1.901,1.901C14.038,18.232 14.172,18.217 14.306,18.217c0.134,0 0.268,0.015 0.388,0.052L17.34,15.615C17.303,15.496 17.288,15.369 17.288,15.235c0,-0.82 0.671,-1.491 1.491,-1.491 0.82,0 1.491,0.671 1.491,1.491z"
-        android:fillColor="#FFFFFFFF"/>
-</vector>
-
diff --git a/res/drawable/tile_icon_window_trace.xml b/res/drawable/tile_icon_winscope_trace.xml
similarity index 100%
rename from res/drawable/tile_icon_window_trace.xml
rename to res/drawable/tile_icon_winscope_trace.xml
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d7a4586..cbfcbf4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8886,11 +8886,8 @@
     <!-- [CHAR LIMIT=60] Name of dev option to enable extra quick settings tiles -->
     <string name="quick_settings_developer_tiles">Quick settings developer tiles</string>
 
-    <!-- [CHAR LIMIT=25] Title of developer tile to toggle window trace -->
-    <string name="window_trace_quick_settings_title">Window Trace</string>
-
-    <!-- [CHAR LIMIT=25] Title of developer tile to toggle layer trace -->
-    <string name="layer_trace_quick_settings_title">Surface Trace</string>
+    <!-- [CHAR LIMIT=25] Title of developer tile to toggle winscope trace -->
+    <string name="winscope_trace_quick_settings_title">Winscope Trace</string>
 
     <!-- Template for formatting country and language. eg Canada - French [CHAR LIMIT=NONE]-->
     <string name="support_country_format"><xliff:g id="country" example="Canada">%1$s</xliff:g> - <xliff:g id="language" example="French">%2$s</xliff:g></string>
diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java
index 38f9565..736c40c 100644
--- a/src/com/android/settings/development/qstile/DevelopmentTiles.java
+++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java
@@ -142,26 +142,29 @@
     }
 
     /**
-     * Tile to toggle Window Trace.
+     * Tile to toggle Winscope trace which consists of Window and Layer traces.
      */
-    public static class WindowTrace extends DevelopmentTiles {
+    public static class WinscopeTrace extends DevelopmentTiles {
         @VisibleForTesting
-        IWindowManagerWrapper mWindowManager;
+        static final int SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE = 1025;
         @VisibleForTesting
-        Toast mToast;
+        static final int SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE = 1026;
+        private IBinder mSurfaceFlinger;
+        private IWindowManagerWrapper mWindowManager;
+        private Toast mToast;
 
         @Override
         public void onCreate() {
             super.onCreate();
             mWindowManager = new IWindowManagerWrapper(WindowManagerGlobal
                     .getWindowManagerService());
+            mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
             Context context = getApplicationContext();
-            CharSequence text = "Trace written to /data/misc/wmtrace/wm_trace.pb";
+            CharSequence text = "Trace files written to /data/misc/wmtrace";
             mToast = Toast.makeText(context, text, Toast.LENGTH_LONG);
         }
 
-        @Override
-        protected boolean isEnabled() {
+        private boolean isWindowTraceEnabled() {
             try {
                 return mWindowManager.isWindowTraceEnabled();
             } catch (RemoteException e) {
@@ -171,46 +174,8 @@
             return false;
         }
 
-        @Override
-        protected void setIsEnabled(boolean isEnabled) {
-            try {
-                if (isEnabled) {
-                    mWindowManager.startWindowTrace();
-                } else {
-                    mWindowManager.stopWindowTrace();
-                    mToast.show();
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Could not set window trace status." + e.toString());
-            }
-        }
-    }
-
-    /**
-     * Tile to toggle Layer Trace.
-     */
-    public static class LayerTrace extends DevelopmentTiles {
-        @VisibleForTesting
-        static final int SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE = 1025;
-        @VisibleForTesting
-        static final int SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE = 1026;
-        @VisibleForTesting
-        IBinder mSurfaceFlinger;
-        @VisibleForTesting
-        Toast mToast;
-
-        @Override
-        public void onCreate() {
-            super.onCreate();
-            mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
-            Context context = getApplicationContext();
-            CharSequence text = "Trace written to /data/misc/wmtrace/layers_trace.pb";
-            mToast = Toast.makeText(context, text, Toast.LENGTH_LONG);
-        }
-
-        @Override
-        protected boolean isEnabled() {
-            boolean surfaceTraceEnabled = false;
+        private boolean isLayerTraceEnabled() {
+            boolean layerTraceEnabled = false;
             Parcel reply = null;
             Parcel data = null;
             try {
@@ -219,8 +184,8 @@
                     data = Parcel.obtain();
                     data.writeInterfaceToken("android.ui.ISurfaceComposer");
                     mSurfaceFlinger.transact(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE,
-                            data, reply, 0 /* flags */ );
-                    surfaceTraceEnabled = reply.readBoolean();
+                            data, reply, 0 /* flags */);
+                    layerTraceEnabled = reply.readBoolean();
                 }
             } catch (RemoteException e) {
                 Log.e(TAG, "Could not get layer trace status, defaulting to false." + e.toString());
@@ -230,11 +195,27 @@
                     reply.recycle();
                 }
             }
-            return surfaceTraceEnabled;
+            return layerTraceEnabled;
         }
 
         @Override
-        protected void setIsEnabled(boolean isEnabled) {
+        protected boolean isEnabled() {
+            return isWindowTraceEnabled() || isLayerTraceEnabled();
+        }
+
+        private void setWindowTraceEnabled(boolean isEnabled) {
+            try {
+                if (isEnabled) {
+                    mWindowManager.startWindowTrace();
+                } else {
+                    mWindowManager.stopWindowTrace();
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Could not set window trace status." + e.toString());
+            }
+        }
+
+        private void setLayerTraceEnabled(boolean isEnabled) {
             Parcel data = null;
             try {
                 if (mSurfaceFlinger != null) {
@@ -243,9 +224,6 @@
                     data.writeInt(isEnabled ? 1 : 0);
                     mSurfaceFlinger.transact(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE,
                             data, null, 0 /* flags */);
-                    if (!isEnabled){
-                        mToast.show();
-                    }
                 }
             } catch (RemoteException e) {
                 Log.e(TAG, "Could not set layer tracing." + e.toString());
@@ -255,5 +233,14 @@
                 }
             }
         }
+
+        @Override
+        protected void setIsEnabled(boolean isEnabled) {
+            setWindowTraceEnabled(isEnabled);
+            setLayerTraceEnabled(isEnabled);
+            if (!isEnabled) {
+                mToast.show();
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/development/qstile/LayerTraceTest.java b/tests/robotests/src/com/android/settings/development/qstile/LayerTraceTest.java
deleted file mode 100644
index 0e42759..0000000
--- a/tests/robotests/src/com/android/settings/development/qstile/LayerTraceTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.development.qstile;
-
-import static com.android.settings.development.qstile.DevelopmentTiles.LayerTrace
-        .SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE;
-import static com.android.settings.development.qstile.DevelopmentTiles.LayerTrace
-        .SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.widget.Toast;
-
-import com.android.settings.TestConfig;
-import com.android.settings.testutils.shadow.ShadowParcel;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.ReflectionHelpers;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class LayerTraceTest {
-    @Mock
-    private IBinder mSurfaceFlinger;
-    @Mock
-    private Toast mToast;
-
-    private DevelopmentTiles.LayerTrace mLayerTraceTile;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mLayerTraceTile = spy(new DevelopmentTiles.LayerTrace());
-        ReflectionHelpers.setField(mLayerTraceTile, "mSurfaceFlinger", mSurfaceFlinger);
-        ReflectionHelpers.setField(mLayerTraceTile, "mToast", mToast);
-    }
-
-    @After
-    public void after() {
-        verifyNoMoreInteractions(mSurfaceFlinger);
-        verifyNoMoreInteractions(mToast);
-    }
-
-    @Test
-    @Config(shadows = {ShadowParcel.class})
-    public void sfReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
-        ShadowParcel.sReadBoolResult = true;
-        assertThat(mLayerTraceTile.isEnabled()).isTrue();
-        verify(mSurfaceFlinger)
-                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(),
-                        eq(0 /* flags */));
-    }
-
-    @Test
-    @Config(shadows = {ShadowParcel.class})
-    public void sfReturnsTraceDisabled_shouldReturnDisabled() throws RemoteException {
-        ShadowParcel.sReadBoolResult = false;
-        assertThat(mLayerTraceTile.isEnabled()).isFalse();
-        verify(mSurfaceFlinger)
-                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(),
-                        eq(0 /* flags */));
-    }
-
-    @Test
-    public void sfUnavailable_shouldReturnDisabled() throws RemoteException {
-        ReflectionHelpers.setField(mLayerTraceTile, "mSurfaceFlinger", null);
-        assertThat(mLayerTraceTile.isEnabled()).isFalse();
-    }
-
-    @Test
-    @Config(shadows = {ShadowParcel.class})
-    public void setIsEnableTrue_shouldEnableLayerTrace() throws RemoteException {
-        mLayerTraceTile.setIsEnabled(true);
-        assertThat(ShadowParcel.sWriteIntResult).isEqualTo(1);
-        verify(mSurfaceFlinger)
-                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE), any(), isNull(),
-                        eq(0 /* flags */));
-    }
-
-    @Test
-    @Config(shadows = {ShadowParcel.class})
-    public void setIsEnableFalse_shouldDisableLayerTraceAndShowToast() throws RemoteException {
-        mLayerTraceTile.setIsEnabled(false);
-        assertThat(ShadowParcel.sWriteIntResult).isEqualTo(0);
-        verify(mSurfaceFlinger)
-                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE), any(), isNull(),
-                        eq(0 /* flags */));
-        verify(mToast).show();
-    }
-
-    @Test
-    public void setIsEnableAndSfUnavailable_shouldDoNothing() throws RemoteException {
-        ReflectionHelpers.setField(mLayerTraceTile, "mSurfaceFlinger", null);
-        mLayerTraceTile.setIsEnabled(true);
-        mLayerTraceTile.setIsEnabled(false);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/development/qstile/WindowTraceTest.java b/tests/robotests/src/com/android/settings/development/qstile/WindowTraceTest.java
deleted file mode 100644
index d8a8084..0000000
--- a/tests/robotests/src/com/android/settings/development/qstile/WindowTraceTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.development.qstile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.os.RemoteException;
-import android.widget.Toast;
-
-import com.android.settings.TestConfig;
-import com.android.settings.testutils.shadow.ShadowParcel;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.wrapper.IWindowManagerWrapper;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.ReflectionHelpers;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class WindowTraceTest {
-    @Mock
-    private IWindowManagerWrapper mWindowManager;
-    @Mock
-    private Toast mToast;
-
-    private DevelopmentTiles.WindowTrace mWindowTrace;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mWindowTrace = spy(new DevelopmentTiles.WindowTrace());
-        ReflectionHelpers.setField(mWindowTrace, "mWindowManager", mWindowManager);
-        ReflectionHelpers.setField(mWindowTrace, "mToast", mToast);
-    }
-
-    @After
-    public void teardown() {
-        verifyNoMoreInteractions(mToast);
-    }
-
-    @Test
-    public void wmReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
-        doReturn(true).when(mWindowManager).isWindowTraceEnabled();
-        assertThat(mWindowTrace.isEnabled()).isTrue();
-    }
-
-    @Test
-    public void wmReturnsTraceDisabled_shouldReturnDisabled() throws RemoteException {
-        doReturn(false).when(mWindowManager).isWindowTraceEnabled();
-        assertThat(mWindowTrace.isEnabled()).isFalse();
-    }
-
-    @Test
-    public void wmThrowsRemoteException_shouldReturnDisabled() throws RemoteException {
-        doThrow(new RemoteException("Unknown"))
-                .when(mWindowManager).isWindowTraceEnabled();
-        assertThat(mWindowTrace.isEnabled()).isFalse();
-    }
-
-    @Test
-    public void setIsEnableTrue_shouldEnableWindowTrace() throws RemoteException {
-        mWindowTrace.setIsEnabled(true);
-        verify(mWindowManager).startWindowTrace();
-        verifyNoMoreInteractions(mWindowManager);
-    }
-
-    @Test
-    @Config(shadows = {ShadowParcel.class})
-    public void setIsEnableFalse_shouldDisableWindowTraceAndShowToast() throws RemoteException {
-        mWindowTrace.setIsEnabled(false);
-        verify(mWindowManager).stopWindowTrace();
-        verify(mToast).show();
-        verifyNoMoreInteractions(mWindowManager);
-    }
-
-    @Test
-    public void setIsEnableAndWmThrowsRemoteException_shouldDoNothing() throws RemoteException {
-        doThrow(new RemoteException("Unknown")).when(mWindowManager).isWindowTraceEnabled();
-        mWindowTrace.setIsEnabled(true);
-    }
-}
diff --git a/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java b/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java
new file mode 100644
index 0000000..92f5c22
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.qstile;
+
+import static com.android.settings.development.qstile.DevelopmentTiles.WinscopeTrace
+        .SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE;
+import static com.android.settings.development.qstile.DevelopmentTiles.WinscopeTrace
+        .SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.widget.Toast;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.shadow.ShadowParcel;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.wrapper.IWindowManagerWrapper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class WinscopeTraceTest {
+    @Mock
+    private IWindowManagerWrapper mWindowManager;
+    @Mock
+    private IBinder mSurfaceFlinger;
+    @Mock
+    private Toast mToast;
+
+    private DevelopmentTiles.WinscopeTrace mWinscopeTrace;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mWinscopeTrace = spy(new DevelopmentTiles.WinscopeTrace());
+        ReflectionHelpers.setField(mWinscopeTrace, "mWindowManager", mWindowManager);
+        ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", mSurfaceFlinger);
+        ReflectionHelpers.setField(mWinscopeTrace, "mToast", mToast);
+    }
+
+    @After
+    public void teardown() {
+        verifyNoMoreInteractions(mToast);
+    }
+
+    @Test
+    @Config(shadows = {ShadowParcel.class})
+    public void wmReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
+        // Assume Surface Trace is disabled.
+        ShadowParcel.sReadBoolResult = false;
+        doReturn(true).when(mWindowManager).isWindowTraceEnabled();
+        assertThat(mWinscopeTrace.isEnabled()).isTrue();
+    }
+
+    @Test
+    @Config(shadows = {ShadowParcel.class})
+    public void sfReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
+        // Assume Window Trace is disabled.
+        doReturn(false).when(mWindowManager).isWindowTraceEnabled();
+        ShadowParcel.sReadBoolResult = true;
+        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 sfAndWmReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException {
+        ShadowParcel.sReadBoolResult = true;
+        doReturn(true).when(mWindowManager).isWindowTraceEnabled();
+        assertThat(mWinscopeTrace.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void wmAndSfReturnsTraceDisabled_shouldReturnDisabled() throws RemoteException {
+        ShadowParcel.sReadBoolResult = false;
+        doReturn(false).when(mWindowManager).isWindowTraceEnabled();
+        assertThat(mWinscopeTrace.isEnabled()).isFalse();
+        verify(mSurfaceFlinger)
+                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(),
+                        eq(0 /* flags */));
+        verifyNoMoreInteractions(mSurfaceFlinger);
+    }
+
+    @Test
+    @Config(shadows = {ShadowParcel.class})
+    public void wmThrowsRemoteExAndSfReturnsTraceDisabled_shouldReturnDisabled()
+            throws RemoteException {
+        ShadowParcel.sReadBoolResult = false;
+        doThrow(new RemoteException("Unknown"))
+                .when(mWindowManager).isWindowTraceEnabled();
+        assertThat(mWinscopeTrace.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void sfUnavailableAndWmReturnsTraceDisabled_shouldReturnDisabled()
+            throws RemoteException {
+        doReturn(false).when(mWindowManager).isWindowTraceEnabled();
+        ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", null);
+        assertThat(mWinscopeTrace.isEnabled()).isFalse();
+    }
+
+
+    @Test
+    public void setIsEnableTrue_shouldEnableWindowTrace() throws RemoteException {
+        mWinscopeTrace.setIsEnabled(true);
+        verify(mWindowManager).startWindowTrace();
+        verifyNoMoreInteractions(mWindowManager);
+    }
+
+    @Test
+    @Config(shadows = {ShadowParcel.class})
+    public void setIsEnableTrue_shouldEnableLayerTrace() throws RemoteException {
+        mWinscopeTrace.setIsEnabled(true);
+        assertThat(ShadowParcel.sWriteIntResult).isEqualTo(1);
+        verify(mSurfaceFlinger)
+                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE), any(), isNull(),
+                        eq(0 /* flags */));
+        verifyNoMoreInteractions(mSurfaceFlinger);
+    }
+
+    @Test
+    @Config(shadows = {ShadowParcel.class})
+    public void setIsEnableFalse_shouldDisableWindowTrace() throws RemoteException {
+        mWinscopeTrace.setIsEnabled(false);
+        verify(mWindowManager).stopWindowTrace();
+        verifyNoMoreInteractions(mWindowManager);
+        verify(mToast).show();
+    }
+
+    @Test
+    @Config(shadows = {ShadowParcel.class})
+    public void setIsEnableFalse_shouldDisableLayerTrace() throws RemoteException {
+        mWinscopeTrace.setIsEnabled(false);
+        assertThat(ShadowParcel.sWriteIntResult).isEqualTo(0);
+        verify(mSurfaceFlinger)
+                .transact(eq(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE), any(), isNull(),
+                        eq(0 /* flags */));
+        verifyNoMoreInteractions(mSurfaceFlinger);
+        verify(mToast).show();
+    }
+
+    @Test
+    public void setIsEnableFalse_shouldShowToast() throws RemoteException {
+        mWinscopeTrace.setIsEnabled(false);
+        verify(mToast).show();
+    }
+
+    /**
+     * Verify when window manager call throws a remote exception, it is handled without
+     * re-throwing the exception.
+     */
+    @Test
+    public void setIsEnableAndWmThrowsRemoteException_shouldFailGracefully()
+            throws RemoteException {
+        doThrow(new RemoteException("Unknown")).when(mWindowManager).isWindowTraceEnabled();
+        mWinscopeTrace.setIsEnabled(true);
+    }
+
+    /**
+     * Verify is surface flinger is not available not calls are made to it.
+     */
+    @Test
+    public void setIsEnableAndSfUnavailable_shouldFailGracefully() throws RemoteException {
+        ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", null);
+        mWinscopeTrace.setIsEnabled(true);
+        verifyNoMoreInteractions(mSurfaceFlinger);
+    }
+}