1 /* 2 * Copyright (C) 2021 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.car; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assume.assumeTrue; 22 23 import android.car.Car; 24 import android.car.evs.CarEvsBufferDescriptor; 25 import android.car.evs.CarEvsManager; 26 import android.car.evs.CarEvsManager.CarEvsServiceState; 27 import android.car.evs.CarEvsManager.CarEvsServiceType; 28 import android.car.evs.CarEvsManager.CarEvsStreamEvent; 29 import android.car.evs.CarEvsStatus; 30 import android.content.Context; 31 import android.os.SystemClock; 32 import android.test.suitebuilder.annotation.MediumTest; 33 34 import androidx.test.core.app.ApplicationProvider; 35 import androidx.test.runner.AndroidJUnit4; 36 37 import org.junit.After; 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 import java.util.ArrayList; 43 import java.util.concurrent.CountDownLatch; 44 import java.util.concurrent.ExecutorService; 45 import java.util.concurrent.Executors; 46 import java.util.concurrent.Semaphore; 47 import java.util.concurrent.TimeUnit; 48 49 /* 50 * IMPORTANT NOTE: 51 * This test assumes that EVS HAL is running at the time of test. Depending on the test target, the 52 * reference EVS HAL ($ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver) may be needed. 53 * Please add below line to the target's build script to add the reference EVS HAL to the build: 54 * ENABLE_EVS_SAMPLE := true 55 * 56 * The test will likely fail if no EVS HAL is running on the target device. 57 */ 58 @RunWith(AndroidJUnit4.class) 59 @MediumTest 60 public final class CarEvsManagerTest extends MockedCarTestBase { 61 private static final String TAG = CarEvsManagerTest.class.getSimpleName(); 62 63 // We'd expect that underlying stream runs @10fps at least. 64 private static final int NUMBER_OF_FRAMES_TO_WAIT = 10; 65 private static final int FRAME_TIMEOUT_MS = 1000; 66 private static final int SMALL_NAP_MS = 500; 67 private static final int ACTIVITY_REQUEST_TIMEOUT_SEC = 3; 68 private static final int STREAM_REQUEST_TIMEOUT_SEC = 1; 69 70 // Will return frame buffers in the order they arrived. 71 private static final int INDEX_TO_FIRST_ELEM = 0; 72 73 private final ArrayList<CarEvsBufferDescriptor> mReceivedBuffers = new ArrayList<>(); 74 private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1); 75 private final Semaphore mFrameReceivedSignal = new Semaphore(0); 76 private final Semaphore mServiceInRequestedState = new Semaphore(0); 77 private final Semaphore mServiceInActiveState = new Semaphore(0); 78 79 private final Car mCar = Car.createCar(ApplicationProvider.getApplicationContext()); 80 private final CarEvsManager mEvsManager = 81 (CarEvsManager) mCar.getCarManager(Car.CAR_EVS_SERVICE); 82 private final EvsStreamCallbackImpl mStreamCallback = new EvsStreamCallbackImpl(); 83 private final EvsStatusListenerImpl mStatusListener = new EvsStatusListenerImpl(); 84 85 @Before setUp()86 public void setUp() { 87 assumeTrue(mCar.isFeatureEnabled(Car.CAR_EVS_SERVICE)); 88 assertThat(mEvsManager).isNotNull(); 89 assumeTrue(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)); 90 assertThat(mStreamCallback).isNotNull(); 91 assertThat(mStatusListener).isNotNull(); 92 93 // Drains all permits 94 mFrameReceivedSignal.drainPermits(); 95 mServiceInRequestedState.drainPermits(); 96 mServiceInActiveState.drainPermits(); 97 98 // Ensures no stream is active 99 mEvsManager.stopVideoStream(); 100 } 101 102 @After tearDown()103 public void tearDown() throws Exception { 104 if (mEvsManager != null) { 105 mEvsManager.stopVideoStream(); 106 } 107 } 108 109 @Test testSessionTokenGeneration()110 public void testSessionTokenGeneration() throws Exception { 111 assertThat(mEvsManager.generateSessionToken()).isNotNull(); 112 } 113 114 @Test testSetStatusListener()115 public void testSetStatusListener() throws Exception { 116 // Registers a status listener and start monitoring the CarEvsService's state changes. 117 mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener); 118 119 // Requests to start the rearview activity. 120 assertThat( 121 mEvsManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW) 122 ).isEqualTo(CarEvsManager.ERROR_NONE); 123 124 // Waits until the CarEvsService enters the REQUESTED state. 125 assertThat( 126 mServiceInRequestedState.tryAcquire(ACTIVITY_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS) 127 ).isTrue(); 128 129 // Waits until the CarEvsService starts a video stream; it enters the ACTIVE state. 130 assertThat( 131 mServiceInActiveState.tryAcquire(STREAM_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS) 132 ).isTrue(); 133 134 // Requests to stop the rearview activity. 135 mEvsManager.stopActivity(); 136 137 // Unregisters a status listener. 138 mEvsManager.clearStatusListener(); 139 } 140 141 @Test testStartAndStopVideoStream()142 public void testStartAndStopVideoStream() throws Exception { 143 // Registers a status listener and start monitoring the CarEvsService's state changes. 144 mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener); 145 146 // Requests to start a video stream. 147 assertThat( 148 mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW, 149 /* token = */ null, mCallbackExecutor, mStreamCallback) 150 ).isEqualTo(CarEvsManager.ERROR_NONE); 151 152 // Waits until the service starts the video stream. 153 assertThat( 154 mServiceInActiveState.tryAcquire(STREAM_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS) 155 ).isTrue(); 156 157 // Then, waits for a few frames frame buffers 158 for (int i = 0; i < NUMBER_OF_FRAMES_TO_WAIT; ++i) { 159 assertThat( 160 mFrameReceivedSignal.tryAcquire(FRAME_TIMEOUT_MS, TimeUnit.MILLISECONDS) 161 ).isTrue(); 162 163 // Nothing to do; returns a buffer immediately 164 CarEvsBufferDescriptor toBeReturned = mReceivedBuffers.get(INDEX_TO_FIRST_ELEM); 165 mReceivedBuffers.remove(INDEX_TO_FIRST_ELEM); 166 mEvsManager.returnFrameBuffer(toBeReturned); 167 } 168 169 // Checks a current status 170 CarEvsStatus status = mEvsManager.getCurrentStatus(); 171 assertThat(status).isNotNull(); 172 assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE); 173 assertThat(status.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW); 174 175 // Then, requests to stop a video stream 176 mEvsManager.stopVideoStream(); 177 178 // Checks a current status a few hundreds milliseconds after. CarEvsService will move into 179 // the inactive state when it gets a stream-stopped event from the EVS manager. 180 SystemClock.sleep(SMALL_NAP_MS); 181 status = mEvsManager.getCurrentStatus(); 182 assertThat(status).isNotNull(); 183 assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE); 184 185 // Unregister a listener 186 mEvsManager.clearStatusListener(); 187 } 188 189 @Test testIsSupported()190 public void testIsSupported() throws Exception { 191 assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue(); 192 // TODO(b/179029031): Fix below test when the Surround View service is integrated into 193 // CarEvsService. 194 assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse(); 195 } 196 197 /** 198 * Class that implements the listener interface and gets called back from 199 * {@link android.car.evs.CarEvsManager.CarEvsStatusListener}. 200 */ 201 private final class EvsStatusListenerImpl implements CarEvsManager.CarEvsStatusListener { 202 @Override onStatusChanged(CarEvsStatus status)203 public void onStatusChanged(CarEvsStatus status) { 204 switch (status.getState()) { 205 case CarEvsManager.SERVICE_STATE_REQUESTED: 206 mServiceInRequestedState.release(); 207 break; 208 209 case CarEvsManager.SERVICE_STATE_ACTIVE: 210 mServiceInActiveState.release(); 211 break; 212 213 case CarEvsManager.SERVICE_STATE_UNAVAILABLE: 214 // Nothing to do 215 break; 216 217 default: 218 // Nothing to do 219 break; 220 } 221 } 222 } 223 224 /** 225 * Class that implements the listener interface and gets called back from 226 * {@link android.hardware.automotive.evs.IEvsCameraStream}. 227 */ 228 private final class EvsStreamCallbackImpl implements CarEvsManager.CarEvsStreamCallback { 229 @Override onStreamEvent(@arEvsStreamEvent int event)230 public void onStreamEvent(@CarEvsStreamEvent int event) { 231 switch(event) { 232 case CarEvsManager.STREAM_EVENT_STREAM_STARTED: 233 // Ignores this event for now because our reference EVS HAL does not send this 234 // event. 235 break; 236 237 case CarEvsManager.STREAM_EVENT_STREAM_STOPPED: 238 break; 239 240 default: 241 // Ignores other stream events in this test. 242 break; 243 } 244 } 245 246 @Override onNewFrame(CarEvsBufferDescriptor buffer)247 public void onNewFrame(CarEvsBufferDescriptor buffer) { 248 // Enqueues a new frame 249 mReceivedBuffers.add(buffer); 250 251 // Notifies a new frame's arrival 252 mFrameReceivedSignal.release(); 253 } 254 } 255 } 256