blob: cb15747ce592fb3668dde8b1e2721b1e94a009c2 [file] [log] [blame]
/*
* Copyright (C) 2021 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.car;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;
import android.car.Car;
import android.car.evs.CarEvsBufferDescriptor;
import android.car.evs.CarEvsManager;
import android.car.evs.CarEvsManager.CarEvsServiceState;
import android.car.evs.CarEvsManager.CarEvsServiceType;
import android.car.evs.CarEvsManager.CarEvsStreamEvent;
import android.car.evs.CarEvsStatus;
import android.content.Context;
import android.os.SystemClock;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/*
* IMPORTANT NOTE:
* This test assumes that EVS HAL is running at the time of test. Depending on the test target, the
* reference EVS HAL ($ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver) may be needed.
* Please add below line to the target's build script to add the reference EVS HAL to the build:
* ENABLE_EVS_SAMPLE := true
*
* The test will likely fail if no EVS HAL is running on the target device.
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
public final class CarEvsManagerTest extends MockedCarTestBase {
private static final String TAG = CarEvsManagerTest.class.getSimpleName();
// We'd expect that underlying stream runs @10fps at least.
private static final int NUMBER_OF_FRAMES_TO_WAIT = 10;
private static final int FRAME_TIMEOUT_MS = 1000;
private static final int SMALL_NAP_MS = 500;
private static final int ACTIVITY_REQUEST_TIMEOUT_SEC = 3;
// Will return frame buffers in the order they arrived.
private static final int INDEX_TO_FIRST_ELEM = 0;
private final ArrayList<CarEvsBufferDescriptor> mReceivedBuffers = new ArrayList<>();
private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1);
private final Semaphore mFrameReceivedSignal = new Semaphore(0);
private final Car mCar = Car.createCar(ApplicationProvider.getApplicationContext());
private final CarEvsManager mEvsManager =
(CarEvsManager) mCar.getCarManager(Car.CAR_EVS_SERVICE);
private final EvsStreamCallbackImpl mStreamCallback = new EvsStreamCallbackImpl();
private final EvsStatusListenerImpl mStatusListener = new EvsStatusListenerImpl();
private CountDownLatch mActivityRequested;
@Before
public void setUp() {
assumeTrue(mCar.isFeatureEnabled(Car.CAR_EVS_SERVICE));
assertThat(mEvsManager).isNotNull();
assumeTrue(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW));
assertThat(mStreamCallback).isNotNull();
assertThat(mStatusListener).isNotNull();
// Ensures no stream is active
mEvsManager.stopVideoStream();
}
@After
public void tearDown() throws Exception {
if (mEvsManager != null) {
mEvsManager.stopVideoStream();
}
}
@Test
public void testSessionTokenGeneration() throws Exception {
assertThat(mEvsManager.generateSessionToken()).isNotNull();
}
@Test
public void testSetStatusListener() throws Exception {
// Set a status listener
mEvsManager.setStatusListener(mCallbackExecutor, mStatusListener);
// Request to start a service
assertThat(
mEvsManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW)
).isEqualTo(CarEvsManager.ERROR_NONE);
// Wait for a notification
mActivityRequested = new CountDownLatch(1);
assertThat(mActivityRequested.await(ACTIVITY_REQUEST_TIMEOUT_SEC, TimeUnit.SECONDS))
.isTrue();
// Then, requests to stop a video stream started upon a receipt of STATE_REQUESTED
// transition notification.
mEvsManager.stopVideoStream();
// Unregister a listener
mEvsManager.clearStatusListener();
}
@Test
public void testStartAndStopVideoStream() throws Exception {
// Requests to start a video stream. We're intentionally using the listener that
// is registered during the test setup.
assertThat(
mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
/* token = */ null, mCallbackExecutor, mStreamCallback)
).isEqualTo(CarEvsManager.ERROR_NONE);
// Waits for a few frames frame buffers
for (int i = 0; i < NUMBER_OF_FRAMES_TO_WAIT; ++i) {
assertThat(
mFrameReceivedSignal.tryAcquire(
FRAME_TIMEOUT_MS, TimeUnit.MILLISECONDS)
).isTrue();
// Nothing to do; returns a buffer immediately
CarEvsBufferDescriptor toBeReturned = mReceivedBuffers.get(INDEX_TO_FIRST_ELEM);
mReceivedBuffers.remove(INDEX_TO_FIRST_ELEM);
mEvsManager.returnFrameBuffer(toBeReturned);
}
// Checks a current status
CarEvsStatus status = mEvsManager.getCurrentStatus();
assertThat(status).isNotNull();
assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_ACTIVE);
assertThat(status.getServiceType()).isEqualTo(CarEvsManager.SERVICE_TYPE_REARVIEW);
// Then, requests to stop a video stream
mEvsManager.stopVideoStream();
// Checks a current status a few hundreds milliseconds after. CarEvsService will move into
// the inactive state when it gets a stream-stopped event from the EVS manager.
SystemClock.sleep(SMALL_NAP_MS);
status = mEvsManager.getCurrentStatus();
assertThat(status).isNotNull();
assertThat(status.getState()).isEqualTo(CarEvsManager.SERVICE_STATE_INACTIVE);
// Unregister a listener
mEvsManager.clearStatusListener();
}
@Test
public void testIsSupported() throws Exception {
assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_REARVIEW)).isTrue();
// TODO(b/179029031): Fix below test when the Surround View service is integrated into
// CarEvsService.
assertThat(mEvsManager.isSupported(CarEvsManager.SERVICE_TYPE_SURROUNDVIEW)).isFalse();
}
/**
* Class that implements the listener interface and gets called back from
* {@link android.car.evs.CarEvsManager.CarEvsStatusListener}.
*/
private final class EvsStatusListenerImpl implements CarEvsManager.CarEvsStatusListener {
@Override
public void onStatusChanged(CarEvsStatus status) {
switch (status.getState()) {
case CarEvsManager.SERVICE_STATE_REQUESTED:
// Request to start a video stream
assertThat(
mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
/* token = */ null, mCallbackExecutor, mStreamCallback)
).isEqualTo(CarEvsManager.ERROR_NONE);
mActivityRequested.countDown();
break;
case CarEvsManager.SERVICE_STATE_ACTIVE:
// Nothing to do
break;
case CarEvsManager.SERVICE_STATE_UNAVAILABLE:
// Nothing to do
break;
default:
// Nothing to do
break;
}
}
}
/**
* Class that implements the listener interface and gets called back from
* {@link android.hardware.automotive.evs.IEvsCameraStream}.
*/
private final class EvsStreamCallbackImpl implements CarEvsManager.CarEvsStreamCallback {
@Override
public void onStreamEvent(@CarEvsStreamEvent int event) {
switch(event) {
case CarEvsManager.STREAM_EVENT_STREAM_STARTED:
// Ignores this event for now because our reference EVS HAL does not send this
// event.
break;
case CarEvsManager.STREAM_EVENT_STREAM_STOPPED:
break;
default:
// Ignores other stream events in this test.
break;
}
}
@Override
public void onNewFrame(CarEvsBufferDescriptor buffer) {
// Enqueues a new frame
mReceivedBuffers.add(buffer);
// Notifies a new frame's arrival
mFrameReceivedSignal.release();
}
}
}