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