1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.development.qstile; 18 19 import static com.android.settings.development.qstile.DevelopmentTiles.WinscopeTrace 20 .SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE; 21 import static com.android.settings.development.qstile.DevelopmentTiles.WinscopeTrace 22 .SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE; 23 import static com.google.common.truth.Truth.assertThat; 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.eq; 26 import static org.mockito.ArgumentMatchers.isNull; 27 import static org.mockito.Mockito.doReturn; 28 import static org.mockito.Mockito.doThrow; 29 import static org.mockito.Mockito.spy; 30 import static org.mockito.Mockito.verify; 31 import static org.mockito.Mockito.verifyNoMoreInteractions; 32 33 import android.os.IBinder; 34 import android.os.RemoteException; 35 import android.view.IWindowManager; 36 import android.widget.Toast; 37 38 import com.android.settings.testutils.SettingsRobolectricTestRunner; 39 import com.android.settings.testutils.shadow.ShadowParcel; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.mockito.Mock; 46 import org.mockito.MockitoAnnotations; 47 import org.robolectric.annotation.Config; 48 import org.robolectric.util.ReflectionHelpers; 49 50 @RunWith(SettingsRobolectricTestRunner.class) 51 public class WinscopeTraceTest { 52 53 @Mock 54 private IWindowManager mWindowManager; 55 @Mock 56 private IBinder mSurfaceFlinger; 57 @Mock 58 private Toast mToast; 59 60 private DevelopmentTiles.WinscopeTrace mWinscopeTrace; 61 62 @Before 63 public void setUp() { 64 MockitoAnnotations.initMocks(this); 65 mWinscopeTrace = spy(new DevelopmentTiles.WinscopeTrace()); 66 ReflectionHelpers.setField(mWinscopeTrace, "mWindowManager", mWindowManager); 67 ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", mSurfaceFlinger); 68 ReflectionHelpers.setField(mWinscopeTrace, "mToast", mToast); 69 } 70 71 @After 72 public void teardown() { 73 verifyNoMoreInteractions(mToast); 74 } 75 76 @Test 77 @Config(shadows = ShadowParcel.class) 78 public void wmReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException { 79 // Assume Surface Trace is disabled. 80 ShadowParcel.sReadBoolResult = false; 81 doReturn(true).when(mWindowManager).isWindowTraceEnabled(); 82 assertThat(mWinscopeTrace.isEnabled()).isTrue(); 83 } 84 85 @Test 86 @Config(shadows = ShadowParcel.class) 87 public void sfReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException { 88 // Assume Window Trace is disabled. 89 doReturn(false).when(mWindowManager).isWindowTraceEnabled(); 90 ShadowParcel.sReadBoolResult = true; 91 assertThat(mWinscopeTrace.isEnabled()).isTrue(); 92 verify(mSurfaceFlinger) 93 .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(), 94 eq(0 /* flags */)); 95 verifyNoMoreInteractions(mSurfaceFlinger); 96 } 97 98 @Test 99 @Config(shadows = ShadowParcel.class) 100 public void sfAndWmReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException { 101 ShadowParcel.sReadBoolResult = true; 102 doReturn(true).when(mWindowManager).isWindowTraceEnabled(); 103 assertThat(mWinscopeTrace.isEnabled()).isTrue(); 104 } 105 106 @Test 107 public void wmAndSfReturnsTraceDisabled_shouldReturnDisabled() throws RemoteException { 108 ShadowParcel.sReadBoolResult = false; 109 doReturn(false).when(mWindowManager).isWindowTraceEnabled(); 110 assertThat(mWinscopeTrace.isEnabled()).isFalse(); 111 verify(mSurfaceFlinger) 112 .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(), 113 eq(0 /* flags */)); 114 verifyNoMoreInteractions(mSurfaceFlinger); 115 } 116 117 @Test 118 @Config(shadows = ShadowParcel.class) 119 public void wmThrowsRemoteExAndSfReturnsTraceDisabled_shouldReturnDisabled() 120 throws RemoteException { 121 ShadowParcel.sReadBoolResult = false; 122 doThrow(new RemoteException("Unknown")) 123 .when(mWindowManager).isWindowTraceEnabled(); 124 assertThat(mWinscopeTrace.isEnabled()).isFalse(); 125 } 126 127 @Test 128 public void sfUnavailableAndWmReturnsTraceDisabled_shouldReturnDisabled() 129 throws RemoteException { 130 doReturn(false).when(mWindowManager).isWindowTraceEnabled(); 131 ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", null); 132 assertThat(mWinscopeTrace.isEnabled()).isFalse(); 133 } 134 135 136 @Test 137 public void setIsEnableTrue_shouldEnableWindowTrace() throws RemoteException { 138 mWinscopeTrace.setIsEnabled(true); 139 verify(mWindowManager).startWindowTrace(); 140 verifyNoMoreInteractions(mWindowManager); 141 } 142 143 @Test 144 @Config(shadows = ShadowParcel.class) 145 public void setIsEnableTrue_shouldEnableLayerTrace() throws RemoteException { 146 mWinscopeTrace.setIsEnabled(true); 147 assertThat(ShadowParcel.sWriteIntResult).isEqualTo(1); 148 verify(mSurfaceFlinger) 149 .transact(eq(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE), any(), isNull(), 150 eq(0 /* flags */)); 151 verifyNoMoreInteractions(mSurfaceFlinger); 152 } 153 154 @Test 155 @Config(shadows = ShadowParcel.class) 156 public void setIsEnableFalse_shouldDisableWindowTrace() throws RemoteException { 157 mWinscopeTrace.setIsEnabled(false); 158 verify(mWindowManager).stopWindowTrace(); 159 verifyNoMoreInteractions(mWindowManager); 160 verify(mToast).show(); 161 } 162 163 @Test 164 @Config(shadows = ShadowParcel.class) 165 public void setIsEnableFalse_shouldDisableLayerTrace() throws RemoteException { 166 mWinscopeTrace.setIsEnabled(false); 167 assertThat(ShadowParcel.sWriteIntResult).isEqualTo(0); 168 verify(mSurfaceFlinger) 169 .transact(eq(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE), any(), isNull(), 170 eq(0 /* flags */)); 171 verifyNoMoreInteractions(mSurfaceFlinger); 172 verify(mToast).show(); 173 } 174 175 @Test 176 public void setIsEnableFalse_shouldShowToast() { 177 mWinscopeTrace.setIsEnabled(false); 178 verify(mToast).show(); 179 } 180 181 /** 182 * Verify when window manager call throws a remote exception, it is handled without 183 * re-throwing the exception. 184 */ 185 @Test 186 public void setIsEnableAndWmThrowsRemoteException_shouldFailGracefully() 187 throws RemoteException { 188 doThrow(new RemoteException("Unknown")).when(mWindowManager).isWindowTraceEnabled(); 189 mWinscopeTrace.setIsEnabled(true); 190 } 191 192 /** 193 * Verify is surface flinger is not available not calls are made to it. 194 */ 195 @Test 196 public void setIsEnableAndSfUnavailable_shouldFailGracefully() { 197 ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", null); 198 mWinscopeTrace.setIsEnabled(true); 199 verifyNoMoreInteractions(mSurfaceFlinger); 200 } 201 } 202