1 /* 2 * Copyright (C) 2022 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 android.car.evs; 18 19 import static android.car.evs.CarEvsManager.ERROR_NONE; 20 import static android.car.evs.CarEvsManager.ERROR_UNAVAILABLE; 21 import static android.car.feature.Flags.FLAG_CAR_EVS_STREAM_MANAGEMENT; 22 23 import static com.google.common.truth.Truth.assertThat; 24 import static com.google.common.truth.Truth.assertWithMessage; 25 26 import static org.junit.Assert.assertThrows; 27 import static org.mockito.Mockito.any; 28 import static org.mockito.Mockito.anyInt; 29 import static org.mockito.Mockito.anyString; 30 import static org.mockito.Mockito.atLeastOnce; 31 import static org.mockito.Mockito.doNothing; 32 import static org.mockito.Mockito.doThrow; 33 import static org.mockito.Mockito.never; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.when; 36 37 import android.car.evs.CarEvsManager.CarEvsStatusListener; 38 import android.car.evs.CarEvsManager.CarEvsStreamCallback; 39 import android.car.feature.FakeFeatureFlagsImpl; 40 import android.hardware.HardwareBuffer; 41 import android.os.IBinder; 42 import android.os.RemoteException; 43 import android.platform.test.annotations.IgnoreUnderRavenwood; 44 import android.platform.test.ravenwood.RavenwoodRule; 45 46 import com.android.car.internal.ICarBase; 47 48 import org.junit.After; 49 import org.junit.Before; 50 import org.junit.Rule; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.ArgumentCaptor; 54 import org.mockito.Captor; 55 import org.mockito.Mock; 56 import org.mockito.junit.MockitoJUnitRunner; 57 58 /** 59 * <p>This class contains unit tests for the {@link CarEvsManager}. 60 */ 61 @RunWith(MockitoJUnitRunner.class) 62 public final class CarEvsManagerUnitTest { 63 64 @Rule 65 public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); 66 67 private static final int[] SERVICE_TYPES = { 68 CarEvsManager.SERVICE_TYPE_REARVIEW, CarEvsManager.SERVICE_TYPE_SURROUNDVIEW, 69 CarEvsManager.SERVICE_TYPE_FRONTVIEW, CarEvsManager.SERVICE_TYPE_LEFTVIEW, 70 CarEvsManager.SERVICE_TYPE_RIGHTVIEW, CarEvsManager.SERVICE_TYPE_DRIVERVIEW, 71 CarEvsManager.SERVICE_TYPE_FRONT_PASSENGERSVIEW, 72 CarEvsManager.SERVICE_TYPE_REAR_PASSENGERSVIEW, 73 }; 74 75 @Mock private ICarBase mMockCar; 76 @Mock private CarEvsStatusListener mMockCarEvsStatusListener; 77 @Mock private CarEvsStreamCallback mMockCarEvsStreamCallback; 78 @Mock private IBinder mMockBinder; 79 @Mock private ICarEvsService.Stub mMockICarEvsService; 80 81 @Captor private ArgumentCaptor<ICarEvsStatusListener> mCarEvsStatusListenerCaptor; 82 @Captor private ArgumentCaptor<ICarEvsStreamCallback> mCarEvsStreamCallbackCaptor; 83 @Captor private ArgumentCaptor<CarEvsStatus> mCarEvsStatusCaptor; 84 85 private final FakeFeatureFlagsImpl mFakeFeatureFlags = new FakeFeatureFlagsImpl(); 86 private CarEvsManager mManager; 87 88 @Before setUp()89 public void setUp() throws Exception { 90 mFakeFeatureFlags.setFlag(FLAG_CAR_EVS_STREAM_MANAGEMENT, true); 91 when(mMockBinder.queryLocalInterface(anyString())).thenReturn(mMockICarEvsService); 92 93 mManager = new CarEvsManager(mMockCar, mMockBinder, mFakeFeatureFlags); 94 assertThat(mManager).isNotNull(); 95 } 96 97 @After tearDown()98 public void tearDown() throws Exception { 99 mManager = null; 100 } 101 102 @Test testSetStatusListenerWithInvalidArguments()103 public void testSetStatusListenerWithInvalidArguments() { 104 assertThrows(NullPointerException.class, 105 () -> mManager.setStatusListener(/* executor= */ null, /* listener= */ null)); 106 assertThrows(NullPointerException.class, 107 () -> mManager.setStatusListener(/* executor= */ null, mMockCarEvsStatusListener)); 108 } 109 110 @Test testSetStatusListenerWithValidArguments()111 public void testSetStatusListenerWithValidArguments() throws Exception { 112 mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener); 113 verify(mMockICarEvsService, atLeastOnce()).registerStatusListener(any()); 114 } 115 116 @Test testSetStatusListenerWithValidArgumentsTwice()117 public void testSetStatusListenerWithValidArgumentsTwice() throws Exception { 118 mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener); 119 120 verify(mMockICarEvsService, atLeastOnce()).registerStatusListener(any()); 121 IllegalStateException thrown = assertThrows(IllegalStateException.class, 122 () -> mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener)); 123 assertWithMessage("Register CarEvsStatusListener") 124 .that(thrown).hasMessageThat() 125 .contains("A status listener is already registered."); 126 } 127 128 @Test testSetStatusListenerWithValidArgumentsRemoteExceptionThrown()129 public void testSetStatusListenerWithValidArgumentsRemoteExceptionThrown() throws Exception { 130 doThrow(new RemoteException()).when(mMockICarEvsService).registerStatusListener(any()); 131 132 mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener); 133 134 verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any()); 135 } 136 137 @Test testStatusChangedEvent()138 public void testStatusChangedEvent() throws Exception { 139 doNothing().when(mMockICarEvsService) 140 .registerStatusListener(mCarEvsStatusListenerCaptor.capture()); 141 142 mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener); 143 ICarEvsStatusListener listener = mCarEvsStatusListenerCaptor.getValue(); 144 listener.onStatusChanged(new CarEvsStatus(CarEvsManager.SERVICE_TYPE_REARVIEW, 145 CarEvsManager.SERVICE_STATE_INACTIVE)); 146 147 verify(mMockCarEvsStatusListener, atLeastOnce()) 148 .onStatusChanged(mCarEvsStatusCaptor.capture()); 149 CarEvsStatus received = mCarEvsStatusCaptor.getValue(); 150 assertThat(received.describeContents()).isEqualTo(0); 151 assertThat(received.toString()).contains("CarEvsStatus:"); 152 } 153 154 @Test testClearStatusListener()155 public void testClearStatusListener() throws Exception { 156 doNothing().when(mMockICarEvsService) 157 .registerStatusListener(mCarEvsStatusListenerCaptor.capture()); 158 159 mManager.setStatusListener(Runnable::run, mMockCarEvsStatusListener); 160 ICarEvsStatusListener listener = mCarEvsStatusListenerCaptor.getValue(); 161 mManager.clearStatusListener(); 162 163 verify(mMockICarEvsService, atLeastOnce()).unregisterStatusListener(listener); 164 } 165 166 @Test testClearStatusListenerRemoteExceptionThrown()167 public void testClearStatusListenerRemoteExceptionThrown() throws Exception { 168 doThrow(new RemoteException()).when(mMockICarEvsService).unregisterStatusListener(any()); 169 170 mManager.clearStatusListener(); 171 172 verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any()); 173 } 174 175 @Test 176 @IgnoreUnderRavenwood(blockedBy = HardwareBuffer.class) testStartVideoStreamWithoutToken()177 public void testStartVideoStreamWithoutToken() throws Exception { 178 when(mMockICarEvsService 179 .startVideoStream(anyInt(), any(), mCarEvsStreamCallbackCaptor.capture())) 180 .thenReturn(ERROR_NONE); 181 182 assertThat(mManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, 183 /* token= */ null, Runnable::run, 184 mMockCarEvsStreamCallback)) 185 .isEqualTo(ERROR_NONE); 186 187 ICarEvsStreamCallback cb = mCarEvsStreamCallbackCaptor.getValue(); 188 cb.onStreamEvent(CarEvsManager.SERVICE_TYPE_REARVIEW, 189 CarEvsManager.STREAM_EVENT_STREAM_STOPPED); 190 verify(mMockCarEvsStreamCallback, atLeastOnce()).onStreamEvent( 191 CarEvsManager.SERVICE_TYPE_REARVIEW, CarEvsManager.STREAM_EVENT_STREAM_STOPPED); 192 193 int bufferId = 1; 194 HardwareBuffer hwbuffer = 195 HardwareBuffer.create(/* width= */ 64, /* height= */ 32, 196 /* format= */ HardwareBuffer.RGBA_8888, 197 /* layers= */ 1, 198 /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN); 199 CarEvsBufferDescriptor buffer = new CarEvsBufferDescriptor(bufferId, 200 CarEvsManager.SERVICE_TYPE_REARVIEW, hwbuffer); 201 cb.onNewFrame(buffer); 202 verify(mMockCarEvsStreamCallback, atLeastOnce()).onNewFrame(buffer); 203 } 204 205 @Test testStartVideoStreamWithoutTokenRemoteExceptionThrown()206 public void testStartVideoStreamWithoutTokenRemoteExceptionThrown() throws Exception { 207 when(mMockICarEvsService.startVideoStream(anyInt(), any(), any())) 208 .thenThrow(new RemoteException()); 209 210 assertThat(mManager.startVideoStream(/* type= */ CarEvsManager.SERVICE_TYPE_REARVIEW, 211 /* token= */ null, 212 /* executor= */ Runnable::run, 213 /* callback= */ mMockCarEvsStreamCallback)) 214 .isEqualTo(ERROR_UNAVAILABLE); 215 216 verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any()); 217 } 218 219 @Test testStopVideoStream()220 public void testStopVideoStream() throws Exception { 221 mManager.stopVideoStream(); 222 verify(mMockICarEvsService, never()).stopVideoStream(any()); 223 224 assertThat(mManager.startVideoStream(/* type= */ CarEvsManager.SERVICE_TYPE_REARVIEW, 225 /* token= */ null, 226 /* executor= */ Runnable::run, 227 /* callback= */ mMockCarEvsStreamCallback)) 228 .isEqualTo(ERROR_NONE); 229 230 mManager.stopVideoStream(); 231 232 verify(mMockICarEvsService, atLeastOnce()).stopVideoStream(any()); 233 } 234 235 @Test testStopVideoStreamRemoteExceptionThrown()236 public void testStopVideoStreamRemoteExceptionThrown() throws Exception { 237 doThrow(new RemoteException()).when(mMockICarEvsService).stopVideoStream(any()); 238 239 assertThat(mManager.startVideoStream(/* type= */ CarEvsManager.SERVICE_TYPE_REARVIEW, 240 /* token= */ null, 241 /* executor= */ Runnable::run, 242 /* callback= */ mMockCarEvsStreamCallback)) 243 .isEqualTo(ERROR_NONE); 244 mManager.stopVideoStream(); 245 246 verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any()); 247 } 248 249 @Test testGetCurrentStatus()250 public void testGetCurrentStatus() throws Exception { 251 when(mMockICarEvsService.getCurrentStatus(anyInt())) 252 .thenReturn(new CarEvsStatus(CarEvsManager.SERVICE_TYPE_REARVIEW, 253 CarEvsManager.SERVICE_STATE_INACTIVE)); 254 255 CarEvsStatus currentStatus = mManager.getCurrentStatus(); 256 257 assertThat(currentStatus).isNotNull(); 258 assertThat(currentStatus.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW); 259 assertThat(currentStatus.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE); 260 } 261 262 @Test testGetCurrentStatusWithType()263 public void testGetCurrentStatusWithType() throws Exception { 264 for (int type : SERVICE_TYPES) { 265 when(mMockICarEvsService.getCurrentStatus(anyInt())) 266 .thenReturn(new CarEvsStatus(type, CarEvsManager.SERVICE_STATE_INACTIVE)); 267 268 CarEvsStatus currentStatus = mManager.getCurrentStatus(type); 269 270 assertThat(currentStatus).isNotNull(); 271 assertThat(currentStatus.getServiceType()).isEqualTo(type); 272 assertThat(currentStatus.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE); 273 } 274 } 275 276 @Test testGetCurrentStatusRemoteExceptionThrown()277 public void testGetCurrentStatusRemoteExceptionThrown() throws Exception { 278 when(mMockICarEvsService.getCurrentStatus(anyInt())).thenThrow(new RemoteException()); 279 280 CarEvsStatus currentStatus = mManager.getCurrentStatus(); 281 282 assertThat(currentStatus.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW); 283 assertThat(currentStatus.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_UNAVAILABLE); 284 } 285 286 @Test testGetCurrentStatusWithTypeRemoteExceptionThrown()287 public void testGetCurrentStatusWithTypeRemoteExceptionThrown() throws Exception { 288 when(mMockICarEvsService.getCurrentStatus(anyInt())).thenThrow(new RemoteException()); 289 290 for (int type : SERVICE_TYPES) { 291 assertThat(mManager.getCurrentStatus(type)).isNull(); 292 } 293 } 294 295 @Test testGenerateSessionToken()296 public void testGenerateSessionToken() throws Exception { 297 assertThat(mManager.generateSessionToken()).isNotNull(); 298 299 when(mMockICarEvsService.generateSessionToken()).thenReturn(null); 300 assertThat(mManager.generateSessionToken()).isNotNull(); 301 } 302 303 @Test testGenerateSessionTokenRemoteExceptionThrown()304 public void testGenerateSessionTokenRemoteExceptionThrown() throws Exception { 305 when(mMockICarEvsService.generateSessionToken()).thenThrow(new RemoteException()); 306 307 assertThat(mManager.generateSessionToken()).isNotNull(); 308 } 309 310 @Test testIsSupported()311 public void testIsSupported() throws Exception { 312 when(mMockICarEvsService.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).thenReturn(true); 313 when(mMockICarEvsService.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)) 314 .thenReturn(false); 315 316 assertThat(mManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue(); 317 assertThat(mManager.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse(); 318 } 319 320 @Test testIsSupportedRemoteExceptionThrown()321 public void testIsSupportedRemoteExceptionThrown() throws Exception { 322 when(mMockICarEvsService.isSupported(anyInt())).thenThrow(new RemoteException()); 323 324 assertThat(mManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isFalse(); 325 } 326 327 @Test 328 @IgnoreUnderRavenwood(blockedBy = HardwareBuffer.class) testReturnFrameBuffer()329 public void testReturnFrameBuffer() throws Exception { 330 int bufferId = 1; 331 HardwareBuffer hwbuffer = 332 HardwareBuffer.create(/* width= */ 64, /* height= */ 32, 333 /* format= */ HardwareBuffer.RGBA_8888, 334 /* layers= */ 1, 335 /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN); 336 CarEvsBufferDescriptor buffer = new CarEvsBufferDescriptor(bufferId, hwbuffer); 337 338 mManager.returnFrameBuffer(buffer); 339 340 verify(mMockICarEvsService, atLeastOnce()).returnFrameBuffer(buffer); 341 } 342 343 @Test 344 @IgnoreUnderRavenwood(blockedBy = HardwareBuffer.class) testReturnFrameBufferRemoteExceptionThrown()345 public void testReturnFrameBufferRemoteExceptionThrown() throws Exception { 346 doThrow(new RemoteException()).when(mMockICarEvsService).returnFrameBuffer(any()); 347 int bufferId = 1; 348 HardwareBuffer hwbuffer = 349 HardwareBuffer.create(/* width= */ 64, /* height= */ 32, 350 /* format= */ HardwareBuffer.RGBA_8888, 351 /* layers= */ 1, 352 /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN); 353 CarEvsBufferDescriptor buffer = new CarEvsBufferDescriptor(bufferId, hwbuffer); 354 355 mManager.returnFrameBuffer(buffer); 356 357 verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any()); 358 } 359 360 @Test testStartActivity()361 public void testStartActivity() throws Exception { 362 when(mMockICarEvsService.startActivity(anyInt())).thenReturn(ERROR_NONE); 363 364 assertThat(mManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW)) 365 .isEqualTo(ERROR_NONE); 366 367 verify(mMockICarEvsService, atLeastOnce()).startActivity(anyInt()); 368 } 369 370 @Test testStartActivityRemoteExceptionThrown()371 public void testStartActivityRemoteExceptionThrown() throws Exception { 372 when(mMockICarEvsService.startActivity(anyInt())).thenThrow(new RemoteException()); 373 374 assertThat(mManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW)) 375 .isEqualTo(ERROR_UNAVAILABLE); 376 377 verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any()); 378 } 379 380 @Test testStopActivity()381 public void testStopActivity() throws Exception { 382 mManager.stopActivity(); 383 384 verify(mMockICarEvsService, atLeastOnce()).stopActivity(); 385 } 386 387 @Test testStopActivityRemoteExceptionThrown()388 public void testStopActivityRemoteExceptionThrown() throws Exception { 389 doThrow(new RemoteException()).when(mMockICarEvsService).stopActivity(); 390 391 mManager.stopActivity(); 392 393 verify(mMockCar, atLeastOnce()).handleRemoteExceptionFromCarService(any()); 394 } 395 396 @Test testOnCarDisconnected()397 public void testOnCarDisconnected() { 398 mManager.onCarDisconnected(); 399 } 400 401 @Test testCarEvsStatus()402 public void testCarEvsStatus() { 403 CarEvsStatus[] arr = CarEvsStatus.CREATOR.newArray(3); 404 assertThat(arr.length).isEqualTo(3); 405 406 CarEvsStatus original = new CarEvsStatus(CarEvsManager.SERVICE_TYPE_REARVIEW, 407 CarEvsManager.SERVICE_STATE_INACTIVE); 408 assertThat(original.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW); 409 assertThat(original.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE); 410 411 android.os.Parcel packet = android.os.Parcel.obtain(); 412 original.writeToParcel(packet, /* flags= */ 0); 413 assertThat(CarEvsStatus.CREATOR.createFromParcel(packet)).isNotNull(); 414 } 415 416 @Test 417 @IgnoreUnderRavenwood(blockedBy = HardwareBuffer.class) testCarEvsBufferDescriptor()418 public void testCarEvsBufferDescriptor() { 419 CarEvsBufferDescriptor[] arr = CarEvsBufferDescriptor.CREATOR.newArray(3); 420 assertThat(arr.length).isEqualTo(3); 421 422 int bufferId = 1; 423 HardwareBuffer hwbuffer = 424 HardwareBuffer.create(/* width= */ 64, /* height= */ 32, 425 /* format= */ HardwareBuffer.RGBA_8888, 426 /* layers= */ 1, 427 /* usage= */ HardwareBuffer.USAGE_CPU_READ_OFTEN); 428 CarEvsBufferDescriptor original = new CarEvsBufferDescriptor(bufferId, hwbuffer); 429 430 assertThat(original.getId()).isEqualTo(bufferId); 431 assertThat(original.getHardwareBuffer().getWidth()).isEqualTo(64); 432 assertThat(original.getHardwareBuffer().getHeight()).isEqualTo(32); 433 assertThat(original.getHardwareBuffer().getFormat()).isEqualTo(HardwareBuffer.RGBA_8888); 434 435 android.os.Parcel packet = android.os.Parcel.obtain(); 436 original.writeToParcel(packet, /* flags= */ 0); 437 packet.setDataPosition(0); 438 assertThat(CarEvsBufferDescriptor.CREATOR.createFromParcel(packet)).isNotNull(); 439 } 440 } 441