Merge "Add CarServiceUtils.finishAllHandlerTasks for test" into rvc-dev
diff --git a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
index a0f6066..35f0274 100644
--- a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
+++ b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
@@ -132,6 +132,8 @@
beginTrace("finishMocking()");
mSession.finishMocking();
endTrace();
+ } else {
+ Log.w(TAG, getClass().getSimpleName() + ".finishSession(): no session");
}
endTrace();
}
@@ -309,11 +311,17 @@
return builder.initMocks(this);
}
- private String getLogPrefix() {
+ /**
+ * Gets a prefix for {@link Log} calls
+ */
+ protected String getLogPrefix() {
return getClass().getSimpleName() + ".";
}
- private void assertSpied(Class<?> clazz) {
+ /**
+ * Asserts the given class is being spied in the Mockito session.
+ */
+ protected void assertSpied(Class<?> clazz) {
Preconditions.checkArgument(mStaticSpiedClasses.contains(clazz),
"did not call spyStatic() on %s", clazz.getName());
}
diff --git a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
index 390a739..d05b013 100644
--- a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
+++ b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
@@ -24,6 +24,8 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.car.test.util.UserTestingHelper;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo.UserInfoFlag;
import android.os.IBinder;
@@ -170,6 +172,17 @@
}
/**
+ * Mocks a call to {@link Context#getSystemService(Class)}.
+ */
+ public static <T> void mockContextGetService(@NonNull Context context,
+ @NonNull Class<T> serviceClass, @NonNull T service) {
+ when(context.getSystemService(serviceClass)).thenReturn(service);
+ if (serviceClass.equals(PackageManager.class)) {
+ when(context.getPackageManager()).thenReturn(PackageManager.class.cast(service));
+ }
+ }
+
+ /**
* Gets the result of a future, or throw a {@link IllegalStateException} if it times out after
* {@value #ASYNC_TIMEOUT_MS} ms.
*/
diff --git a/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
index f50d80a..5ed572f 100644
--- a/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
+++ b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
@@ -23,17 +23,30 @@
import android.car.user.CarUserManager.UserLifecycleEvent;
import android.car.user.CarUserManager.UserLifecycleEventType;
import android.car.user.CarUserManager.UserLifecycleListener;
-import android.os.UserHandle;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
- * UserLifecycleListener that blocks until an event is received.
+ * {@link UserLifecycleListener} that blocks until the proper events are received.
+ *
+ * <p>It can be used in 2 "modes":
+ *
+ * <ul>
+ * <li>{@link #forAnyEvent()}: it blocks (through the {@link #waitForAnyEvent()} call) until any
+ * any event is received. It doesn't allow any customization (other than
+ * {@link Builder#setTimeout(long)}).
+ * <li>{@link #forSpecificEvents()}: it blocks (through the {@link #waitForEvents()} call) until
+ * all events specified by the {@link Builder} are received.
+ * </ul>
*/
public final class BlockingUserLifecycleListener implements UserLifecycleListener {
@@ -41,31 +54,55 @@
private static final long DEFAULT_TIMEOUT_MS = 2_000;
+ private final Object mLock = new Object();
+
private final CountDownLatch mLatch = new CountDownLatch(1);
+
+ @GuardedBy("mLock")
private final List<UserLifecycleEvent> mAllReceivedEvents = new ArrayList<>();
+ @GuardedBy("mLock")
private final List<UserLifecycleEvent> mExpectedEventsReceived = new ArrayList<>();
@UserLifecycleEventType
private final List<Integer> mExpectedEventTypes;
+ @UserLifecycleEventType
+ private final List<Integer> mExpectedEventTypesLeft;
+
@UserIdInt
- private final int mForUserId;
+ @Nullable
+ private final Integer mForUserId;
+
+ @UserIdInt
+ @Nullable
+ private final Integer mForPreviousUserId;
private final long mTimeoutMs;
private BlockingUserLifecycleListener(Builder builder) {
- mExpectedEventTypes = builder.mExpectedEventTypes;
+ mExpectedEventTypes = Collections
+ .unmodifiableList(new ArrayList<>(builder.mExpectedEventTypes));
+ mExpectedEventTypesLeft = builder.mExpectedEventTypes;
mTimeoutMs = builder.mTimeoutMs;
mForUserId = builder.mForUserId;
+ mForPreviousUserId = builder.mForPreviousUserId;
+ Log.d(TAG, "constructor: " + this);
}
/**
- * Builds a new instance with default timeout of {@value #DEFAULT_TIMEOUT_MS} and
- * which waits for one - and any one - event.
+ * Creates a builder for tests that need to wait for an arbitrary event.
*/
@NonNull
- public static BlockingUserLifecycleListener newDefaultListener() {
- return new Builder().build();
+ public static Builder forAnyEvent() {
+ return new Builder(/* forAnyEvent= */ true);
+ }
+
+ /**
+ * Creates a builder for tests that need to wait for specific events.
+ */
+ @NonNull
+ public static Builder forSpecificEvents() {
+ return new Builder(/* forAnyEvent= */ false);
}
/**
@@ -73,12 +110,22 @@
*/
public static final class Builder {
private long mTimeoutMs = DEFAULT_TIMEOUT_MS;
+ private final boolean mForAnyEvent;
+
+ private Builder(boolean forAnyEvent) {
+ mForAnyEvent = forAnyEvent;
+ }
@UserLifecycleEventType
- private List<Integer> mExpectedEventTypes = new ArrayList<>();
+ private final List<Integer> mExpectedEventTypes = new ArrayList<>();
@UserIdInt
- private int mForUserId = UserHandle.USER_NULL;
+ @Nullable
+ private Integer mForUserId;
+
+ @UserIdInt
+ @Nullable
+ private Integer mForPreviousUserId;
/**
* Sets the timeout.
@@ -90,8 +137,12 @@
/**
* Sets the expected type - once the given event is received, the listener will unblock.
+ *
+ * @throws IllegalStateException if builder is {@link #forAnyEvent}.
+ * @throws IllegalArgumentException if the expected type was already added.
*/
public Builder addExpectedEvent(@UserLifecycleEventType int eventType) {
+ assertNotForAnyEvent();
mExpectedEventTypes.add(eventType);
return this;
}
@@ -100,11 +151,21 @@
* Filters received events just for the given user.
*/
public Builder forUser(@UserIdInt int userId) {
+ assertNotForAnyEvent();
mForUserId = userId;
return this;
}
/**
+ * Filters received events just for the given previous user.
+ */
+ public Builder forPreviousUser(@UserIdInt int userId) {
+ assertNotForAnyEvent();
+ mForPreviousUserId = userId;
+ return this;
+ }
+
+ /**
* Builds a new instance.
*/
@NonNull
@@ -112,114 +173,144 @@
return new BlockingUserLifecycleListener(Builder.this);
}
+ private void assertNotForAnyEvent() {
+ Preconditions.checkState(!mForAnyEvent, "not allowed forAnyEvent()");
+ }
}
@Override
public void onEvent(UserLifecycleEvent event) {
- Log.d(TAG, "onEvent(): expecting=" + expectedEventsToString()
- + ", received=" + event);
- mAllReceivedEvents.add(event);
+ synchronized (mLock) {
+ Log.d(TAG, "onEvent(): expecting=" + mExpectedEventTypesLeft + ", received=" + event);
- if (expectingSpecificUser() && event.getUserId() != mForUserId) {
- Log.w(TAG, "ignoring event for different user");
- return;
- }
+ mAllReceivedEvents.add(event);
- Integer actualType = event.getEventType();
- boolean removed = mExpectedEventTypes.remove(actualType);
- if (removed) {
- Log.v(TAG, "event removed; still expecting for " + expectedEventsToString());
- mExpectedEventsReceived.add(event);
- } else {
- Log.v(TAG, "event not removed");
- }
+ if (expectingSpecificUser() && event.getUserId() != mForUserId) {
+ Log.w(TAG, "ignoring event for different user (expecting " + mForUserId + ")");
+ return;
+ }
- if (mExpectedEventTypes.isEmpty()) {
- Log.d(TAG, "all expected events received, counting down " + mLatch);
- mLatch.countDown();
+ if (expectingSpecificPreviousUser()
+ && event.getPreviousUserId() != mForPreviousUserId) {
+ Log.w(TAG, "ignoring event for different previous user (expecting "
+ + mForPreviousUserId + ")");
+ return;
+ }
+
+ Integer actualType = event.getEventType();
+ boolean removed = mExpectedEventTypesLeft.remove(actualType);
+ if (removed) {
+ Log.v(TAG, "event removed; still expecting for "
+ + toString(mExpectedEventTypesLeft));
+ mExpectedEventsReceived.add(event);
+ } else {
+ Log.v(TAG, "event not removed");
+ }
+
+ if (mExpectedEventTypesLeft.isEmpty() && mLatch.getCount() == 1) {
+ Log.d(TAG, "all expected events received, counting down " + mLatch);
+ mLatch.countDown();
+ }
}
}
/**
- * Helper method for {@link #waitForEvents()} when caller is expecting just one event.
+ * Blocks until any event is received, and returns it.
+ *
+ * @throws IllegalStateException if listener was built using {@link #forSpecificEvents()}.
+ * @throws IllegalStateException if it times out before any event is received.
+ * @throws InterruptedException if interrupted before any event is received.
*/
@Nullable
- public UserLifecycleEvent waitForEvent() throws InterruptedException {
- List<UserLifecycleEvent> receivedEvents = waitForEvents();
- UserLifecycleEvent event = receivedEvents.isEmpty() ? null : receivedEvents.get(0);
- Log.v(TAG, "waitForEvent(): returning " + event);
+ public UserLifecycleEvent waitForAnyEvent() throws InterruptedException {
+ Preconditions.checkState(isForAnyEvent(),
+ "cannot call waitForEvent() when built with expected events");
+ waitForExpectedEvents();
+
+ UserLifecycleEvent event;
+ synchronized (mLock) {
+ event = mAllReceivedEvents.isEmpty() ? null : mAllReceivedEvents.get(0);
+ Log.v(TAG, "waitForAnyEvent(): returning " + event);
+ }
return event;
}
/**
- * Blocks until all expected {@link #onEvent(UserLifecycleEvent)} are received.
+ * Blocks until the events specified in the {@link Builder} are received, and returns them.
*
- * @throws IllegalStateException if it times out before all events are received.
- * @throws InterruptedException if interrupted before all events are received.
+ * @throws IllegalStateException if listener was built without any call to
+ * {@link Builder#addExpectedEvent(int)} or using {@link #forAnyEvent().
+ * @throws IllegalStateException if it times out before all specified events are received.
+ * @throws InterruptedException if interrupted before all specified events are received.
*/
@NonNull
public List<UserLifecycleEvent> waitForEvents() throws InterruptedException {
- if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) {
- String errorMessage = "did not receive all events in " + mTimeoutMs + " seconds; "
- + "received only " + allReceivedEventsToString() + ", still waiting for "
- + expectedEventsToString();
- Log.e(TAG, errorMessage);
- throw new IllegalStateException(errorMessage);
+ Preconditions.checkState(!isForAnyEvent(),
+ "cannot call waitForEvents() when built without specific expected events");
+ waitForExpectedEvents();
+ List<UserLifecycleEvent> events;
+ synchronized (mLock) {
+ events = mExpectedEventsReceived;
}
- Log.v(TAG, "waitForEvents(): returning " + mAllReceivedEvents);
- return getAllReceivedEvents();
+ Log.v(TAG, "waitForEvents(): returning " + events);
+ return events;
}
/**
- * Gets a list with all received events.
+ * Gets a list with all received events until now.
*/
@NonNull
public List<UserLifecycleEvent> getAllReceivedEvents() {
- return mAllReceivedEvents;
- }
-
- /**
- * Gets a list with just the received events set by the builder.
- */
- @NonNull
- public List<UserLifecycleEvent> getExpectedEventsReceived() {
- return mExpectedEventsReceived;
+ Preconditions.checkState(!isForAnyEvent(),
+ "cannot call getAllReceivedEvents() when built without specific expected events");
+ synchronized (mLock) {
+ return Collections.unmodifiableList(new ArrayList<>(mAllReceivedEvents));
+ }
}
@Override
public String toString() {
- return "[" + getClass().getSimpleName() + ": "
- + "timeout=" + mTimeoutMs + "ms, "
- + (expectingSpecificUser() ? "forUser=" + mForUserId : "")
- + ",received=" + allReceivedEventsToString()
- + ", waiting=" + expectedEventsToString()
- + "]";
+ return "[" + getClass().getSimpleName() + ": " + stateToString() + "]";
}
- private String allReceivedEventsToString() {
- String receivedEvents = mAllReceivedEvents
- .stream()
- .map((e) -> CarUserManager.lifecycleEventTypeToString(e.getEventType()))
- .collect(Collectors.toList())
- .toString();
- return expectingSpecificUser()
- ? "{user=" + mForUserId + ", events=" + receivedEvents + "}"
- : receivedEvents;
+ @NonNull
+ private String stateToString() {
+ synchronized (mLock) {
+ return "timeout=" + mTimeoutMs + "ms"
+ + ",expectedEventTypes=" + toString(mExpectedEventTypes)
+ + ",expectedEventTypesLeft=" + toString(mExpectedEventTypesLeft)
+ + (expectingSpecificUser() ? ",forUser=" + mForUserId : "")
+ + (expectingSpecificPreviousUser() ? ",forPrevUser=" + mForPreviousUserId : "")
+ + ",received=" + mAllReceivedEvents
+ + ",waiting=" + mExpectedEventTypesLeft;
+ }
}
- private String expectedEventsToString() {
- String expectedTypes = mExpectedEventTypes
- .stream()
- .map((type) -> CarUserManager.lifecycleEventTypeToString(type))
+ private void waitForExpectedEvents() throws InterruptedException {
+ if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) {
+ String errorMessage = "did not receive all expected events (" + stateToString() + ")";
+ Log.e(TAG, errorMessage);
+ throw new IllegalStateException(errorMessage);
+ }
+ }
+
+ @NonNull
+ private static String toString(@NonNull List<Integer> eventTypes) {
+ return eventTypes.stream()
+ .map((i) -> CarUserManager.lifecycleEventTypeToString(i))
.collect(Collectors.toList())
.toString();
- return expectingSpecificUser()
- ? "{user=" + mForUserId + ", types=" + expectedTypes + "}"
- : expectedTypes;
+ }
+
+ private boolean isForAnyEvent() {
+ return mExpectedEventTypes.isEmpty();
}
private boolean expectingSpecificUser() {
- return mForUserId != UserHandle.USER_NULL;
+ return mForUserId != null;
}
+ private boolean expectingSpecificPreviousUser() {
+ return mForPreviousUserId != null;
+ }
}
diff --git a/computepipe/runner/engine/DefaultEngine.cpp b/computepipe/runner/engine/DefaultEngine.cpp
index f10f74a..ab812d2 100644
--- a/computepipe/runner/engine/DefaultEngine.cpp
+++ b/computepipe/runner/engine/DefaultEngine.cpp
@@ -57,7 +57,8 @@
void DefaultEngine::setPrebuiltGraph(std::unique_ptr<PrebuiltGraph>&& graph) {
mGraph = std::move(graph);
mGraphDescriptor = mGraph->GetSupportedGraphConfigs();
- if (mGraph->GetGraphType() == graph::PrebuiltGraphType::REMOTE) {
+ if (mGraph->GetGraphType() == graph::PrebuiltGraphType::REMOTE ||
+ mGraphDescriptor.input_configs_size() == 0) {
mIgnoreInputManager = true;
}
}
@@ -577,6 +578,7 @@
if (mIgnoreInputManager) {
return Status::SUCCESS;
}
+
proto::InputConfig inputDescriptor;
int selectedId;
diff --git a/service/res/values-ne/strings.xml b/service/res/values-ne/strings.xml
index a03753b..df9f269 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -46,7 +46,7 @@
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"कारका अडियो सेटिङ व्यवस्थित गर्ने"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"सवारी साधनको HAL को अनुकरण गर्ने"</string>
<string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"अडियो डकिङ कार्यक्रमहरू प्राप्त गर्नुहोस्"</string>
- <string name="car_permission_desc_receive_ducking" msgid="776376388266656512">"कारमा अन्य अडियो प्ले भइरहेका हुनाले अनुप्रयोगको भोल्युम कम भइरहेको कुराबारे एपलाई सूचित हुन दिन्छ।"</string>
+ <string name="car_permission_desc_receive_ducking" msgid="776376388266656512">"कारमा अन्य अडियो प्ले भइरहेका हुनाले एपको भोल्युम कम भइरहेको कुराबारे एपलाई सूचित हुन दिन्छ।"</string>
<string name="car_permission_desc_mock_vehicle_hal" msgid="5235596491098649155">"आन्तरिक परीक्षण गर्ने प्रयोजनका लागि तपाईंको कारको सवारी साधन HAL को अनुकरण गर्ने।"</string>
<string name="car_permission_desc_audio_volume" msgid="536626185654307889">"तपाईंको कारको अडियोको भोल्युम नियन्त्रण गर्ने।"</string>
<string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"आफ्नो कारको अडियोसम्बन्धी सेटिङहरू नियन्त्रण गर्नुहोस्।"</string>
diff --git a/surround_view/service-impl/Android.bp b/surround_view/service-impl/Android.bp
index b4dac9f..8ae7bba 100644
--- a/surround_view/service-impl/Android.bp
+++ b/surround_view/service-impl/Android.bp
@@ -70,14 +70,17 @@
srcs: ["lib/arm64/libcore_lib_shared.so"]
},
x86: {
- srcs: ["lib/x86/libcore_lib.so"]
+ srcs: ["lib/x86/libcore_lib_shared.so"]
},
x86_64: {
- srcs: ["lib/x86-64/libcore_lib.so"]
+ srcs: ["lib/x86-64/libcore_lib_shared.so"]
},
},
shared_libs: [
- "libEGL",
+ "libutils",
+ "libcutils",
+ "libbase",
+ "libEGL",
"libGLESv2",
"libGLESv3",
"libc",
diff --git a/surround_view/service-impl/SurroundView2dSession.cpp b/surround_view/service-impl/SurroundView2dSession.cpp
index f1a789b..c94400a 100644
--- a/surround_view/service-impl/SurroundView2dSession.cpp
+++ b/surround_view/service-impl/SurroundView2dSession.cpp
@@ -345,8 +345,15 @@
// description.
mSurroundView = unique_ptr<SurroundView>(Create());
- mSurroundView->SetStaticData(GetCameras(), Get2dParams(), Get3dParams(),
- GetUndistortionScales(), GetBoundingBox());
+ SurroundViewStaticDataParams params =
+ SurroundViewStaticDataParams(GetCameras(),
+ Get2dParams(),
+ Get3dParams(),
+ GetUndistortionScales(),
+ GetBoundingBox(),
+ map<string, CarTexture>(),
+ map<string, CarPart>());
+ mSurroundView->SetStaticData(params);
// TODO(b/150412555): remove after EVS camera is used
mInputPointers = mSurroundView->ReadImages(
diff --git a/surround_view/service-impl/SurroundView3dSession.cpp b/surround_view/service-impl/SurroundView3dSession.cpp
index 0204b55..88913af 100644
--- a/surround_view/service-impl/SurroundView3dSession.cpp
+++ b/surround_view/service-impl/SurroundView3dSession.cpp
@@ -19,9 +19,11 @@
#include <android/hardware_buffer.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
-#include <set>
#include <utils/SystemClock.h>
+#include <array>
+#include <set>
+
#include "SurroundView3dSession.h"
#include "sv_3d_params.h"
@@ -37,6 +39,7 @@
static const uint8_t kGrayColor = 128;
static const int kNumChannels = 4;
+static const int kFrameDelayInMilliseconds = 30;
SurroundView3dSession::SurroundView3dSession() :
mStreamState(STOPPED){
@@ -285,15 +288,18 @@
}
void SurroundView3dSession::generateFrames() {
+ if (mSurroundView->Start3dPipeline()) {
+ LOG(INFO) << "Start3dPipeline succeeded";
+ } else {
+ LOG(ERROR) << "Start3dPipeline failed";
+ return;
+ }
+
int sequenceId = 0;
// TODO(b/150412555): do not use the setViews for frames generation
// since there is a discrepancy between the HIDL APIs and core lib APIs.
- vector<vector<float>> matrix;
- matrix.resize(4);
- for (int i=0; i<4; i++) {
- matrix[i].resize(4);
- }
+ array<array<float, 4>, 4> matrix;
while(true) {
{
@@ -349,9 +355,9 @@
}
}
- // TODO(b/150412555): use hard-coded views for now. Change view every 10
- // frames.
- int recViewId = sequenceId / 10 % 16;
+ // TODO(b/150412555): use hard-coded views for now. Change view every
+ // frame.
+ int recViewId = sequenceId % 16;
for (int i=0; i<4; i++)
for (int j=0; j<4; j++) {
matrix[i][j] = kRecViews[recViewId][i*4+j];
@@ -426,6 +432,11 @@
mStream->receiveFrames(framesRecord.frames);
}
}
+
+ // TODO(b/150412555): adding delays explicitly. This delay should be
+ // removed when EVS camera is used.
+ this_thread::sleep_for(chrono::milliseconds(
+ kFrameDelayInMilliseconds));
}
// If we've been asked to stop, send an event to signal the actual end of stream
@@ -442,8 +453,15 @@
// description.
mSurroundView = unique_ptr<SurroundView>(Create());
- mSurroundView->SetStaticData(GetCameras(), Get2dParams(), Get3dParams(),
- GetUndistortionScales(), GetBoundingBox());
+ SurroundViewStaticDataParams params =
+ SurroundViewStaticDataParams(GetCameras(),
+ Get2dParams(),
+ Get3dParams(),
+ GetUndistortionScales(),
+ GetBoundingBox(),
+ map<string, CarTexture>(),
+ map<string, CarPart>());
+ mSurroundView->SetStaticData(params);
// TODO(b/150412555): remove after EVS camera is used
mInputPointers = mSurroundView->ReadImages(
@@ -491,13 +509,6 @@
return false;
}
- if (mSurroundView->Start3dPipeline()) {
- LOG(INFO) << "Start3dPipeline succeeded";
- } else {
- LOG(ERROR) << "Start3dPipeline failed";
- return false;
- }
-
mIsInitialized = true;
return true;
}
diff --git a/surround_view/service-impl/core_lib.h b/surround_view/service-impl/core_lib.h
index 04ff43a..c2d31af 100644
--- a/surround_view/service-impl/core_lib.h
+++ b/surround_view/service-impl/core_lib.h
@@ -1,7 +1,10 @@
#ifndef WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
#define WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
+#include <array>
#include <cstdint>
+#include <map>
+#include <string>
#include <vector>
namespace android_auto {
@@ -341,25 +344,14 @@
// RGBA values, A is used for transparency.
uint8_t rgba[4];
- // normalized texture coordinates, in width and height direction. Range [0,
- // 1].
- float tex[2];
-
- // normalized vertex normal.
- float nor[3];
-
bool operator==(const OverlayVertex& rhs) const {
return (0 == std::memcmp(pos, rhs.pos, 3 * sizeof(float))) &&
- (0 == std::memcmp(rgba, rhs.rgba, 4 * sizeof(uint8_t))) &&
- (0 == std::memcmp(tex, rhs.tex, 2 * sizeof(float))) &&
- (0 == std::memcmp(nor, rhs.nor, 3 * sizeof(float)));
+ (0 == std::memcmp(rgba, rhs.rgba, 4 * sizeof(uint8_t)));
}
OverlayVertex& operator=(const OverlayVertex& rhs) {
std::memcpy(pos, rhs.pos, 3 * sizeof(float));
std::memcpy(rgba, rhs.rgba, 4 * sizeof(uint8_t));
- std::memcpy(tex, rhs.tex, 2 * sizeof(float));
- std::memcpy(nor, rhs.nor, 3 * sizeof(float));
return *this;
}
};
@@ -386,12 +378,253 @@
}
};
+// ----------- Structs related to car model ---------------
+
+// 3D Vertex of a car model with normal and optionally texture coordinates.
+struct CarVertex {
+ // 3d position in (x, y, z).
+ std::array<float, 3> pos;
+
+ // unit normal at vertex, used for diffuse shading.
+ std::array<float, 3> normal;
+
+ // texture coordinates, valid in range [0, 1]. (-1, -1) implies no
+ // texture sampling. Note: only a single texture coordinate is currently
+ // supported per vertex. This struct will need to be extended with another
+ // tex_coord if multiple textures are needed per vertex.
+ std::array<float, 2> tex_coord;
+
+ // Default constructor.
+ CarVertex() {
+ pos = {0, 0, 0};
+ normal = {1, 0, 0};
+ tex_coord = {-1.0f, -1.0f};
+ }
+
+ CarVertex(const std::array<float, 3>& _pos,
+ const std::array<float, 3>& _normal,
+ const std::array<float, 2> _tex_coord)
+ : pos(_pos), normal(_normal), tex_coord(_tex_coord) {}
+};
+
+// Type of texture (color, bump, procedural etc.)
+// Currently only color is supported.
+enum CarTextureType : uint32_t {
+ // Texture map is applied to all color parameters: Ka, Kd and Ks.
+ // Data type of texture is RGB with each channel a uint8_t.
+ kKa = 0,
+ kKd,
+ kKs,
+
+ // Texture for bump maps. Data type is 3 channel float.
+ kBumpMap
+};
+
+// Textures to be used for rendering car model.
+struct CarTexture {
+ // Type and number of channels are dependant on each car texture type.
+ int width;
+ int height;
+ int channels;
+ int bytes_per_channel;
+ uint8_t* data;
+
+ CarTexture() {
+ width = 0;
+ height = 0;
+ channels = 0;
+ bytes_per_channel = 0;
+ data = nullptr;
+ }
+};
+
+// Material parameters for a car part.
+// Refer to MTL properties: http://paulbourke.net/dataformats/mtl/
+struct CarMaterial {
+ // Illumination model - 0, 1, 2 currently supported
+ // 0 = Color on and Ambient off
+ // 1 = Color on and Ambient on
+ // 2 = Highlight on
+ // 3 = Reflection on and Ray trace on
+ // 4 - 10 = Reflection/Transparency options not supported,
+ // Will default to option 3.
+ uint8_t illum;
+
+ std::array<float, 3> ka; // Ambient RGB [0, 1]
+ std::array<float, 3> kd; // Diffuse RGB [0, 1]
+ std::array<float, 3> ks; // Specular RGB [0, 1]
+
+ // Dissolve factor [0, 1], 0 = full transparent, 1 = full opaque.
+ float d;
+
+ // Specular exponent typically range from 0 to 1000.
+ // A high exponent results in a tight, concentrated highlight.
+ float ns;
+
+ // Set default values of material.
+ CarMaterial() {
+ illum = 0; // Color on, ambient off
+ ka = {0.0f, 0.0f, 0.0f}; // No ambient.
+ kd = {0.0f, 0.0f, 0.0f}; // No dissolve.
+ ks = {0.0f, 0.0f, 0.0f}; // No specular.
+ d = 1.0f; // Fully opaque.
+ ns = 0; // No specular exponent.
+ }
+
+ // Map for texture type to a string id of a texture.
+ std::map<CarTextureType, std::string> textures;
+};
+
+// Type alias for 4x4 homogenous matrix, in row-major order.
+using Mat4x4 = std::array<float, 16>;
+
+// Represents a part of a car model.
+// Each car part is a object in the car that is individually animated and
+// has the same illumination properties. A car part may contain sub parts.
+struct CarPart {
+ // Car part vertices.
+ std::vector<CarVertex> vertices;
+
+ // Properties/attributes describing car material.
+ CarMaterial material;
+
+ // Model matrix to transform the car part from object space to its parent's
+ // coordinate space.
+ // The car's vertices are transformed by performing:
+ // parent_model_mat * model_mat * car_part_vertices to transform them to the
+ // global coordinate space.
+ // Model matrix must be a homogenous matrix with orthogonal rotation matrix.
+ Mat4x4 model_mat;
+
+ // Id of parent part. Parent part's model matrix is used to animate this part.
+ // empty string implies the part has no parent.
+ std::string parent_part_id;
+
+ // Ids of child parts. If current part is animated all its child parts
+ // are animated as well. Empty vector implies part has not children.
+ std::vector<std::string> child_part_ids;
+
+ CarPart(const std::vector<CarVertex>& car_vertices,
+ const CarMaterial& car_material, const Mat4x4& car_model_mat,
+ std::string car_parent_part_id,
+ const std::vector<std::string>& car_child_part_ids)
+ : vertices(car_vertices),
+ material(car_material),
+ model_mat(car_model_mat),
+ parent_part_id(car_parent_part_id),
+ child_part_ids(car_child_part_ids) {}
+
+ CarPart& operator=(const CarPart& car_part) {
+ this->vertices = car_part.vertices;
+ this->material = car_part.material;
+ this->model_mat = car_part.model_mat;
+ this->parent_part_id = car_part.parent_part_id;
+ this->child_part_ids = car_part.child_part_ids;
+ return *this;
+ }
+};
+
+struct AnimationParam {
+ // part id
+ std::string part_id;
+
+ // model matrix.
+ Mat4x4 model_matrix;
+
+ // bool flag indicating if the model matrix is updated from last
+ // SetAnimations() call.
+ bool is_model_update;
+
+ // gamma.
+ float gamma;
+
+ // bool flag indicating if gamma is updated from last
+ // SetAnimations() call.
+ bool is_gamma_update;
+
+ // texture id.
+ std::string texture_id;
+
+ // bool flag indicating if texture is updated from last
+ // SetAnimations() call.
+ bool is_texture_update;
+
+ // Default constructor, no animations are updated.
+ AnimationParam() {
+ is_model_update = false;
+ is_gamma_update = false;
+ is_texture_update = false;
+ }
+
+ // Constructor with car part name.
+ explicit AnimationParam(const std::string& _part_id)
+ : part_id(_part_id),
+ is_model_update(false),
+ is_gamma_update(false),
+ is_texture_update(false) {}
+
+ void SetModelMatrix(const Mat4x4& model_mat) {
+ is_model_update = true;
+ model_matrix = model_mat;
+ }
+
+ void SetGamma(float gamma_value) {
+ is_gamma_update = true;
+ gamma = gamma_value;
+ }
+
+ void SetTexture(const std::string& tex_id) {
+ is_texture_update = true;
+ texture_id = tex_id;
+ }
+};
+
enum Format {
GRAY = 0,
RGB = 1,
RGBA = 2,
};
+// collection of surround view static data params.
+struct SurroundViewStaticDataParams {
+ std::vector<SurroundViewCameraParams> cameras_params;
+
+ // surround view 2d parameters.
+ SurroundView2dParams surround_view_2d_params;
+
+ // surround view 3d parameters.
+ SurroundView3dParams surround_view_3d_params;
+
+ // undistortion focal length scales.
+ std::vector<float> undistortion_focal_length_scales;
+
+ // car model bounding box for 2d surround view.
+ BoundingBox car_model_bb;
+
+ // map of texture name to a car texture. Lists all textures to be
+ // used for car model rendering.
+ std::map<std::string, CarTexture> car_textures;
+
+ // map of car id to a car part. Lists all car parts to be used
+ // for car model rendering.
+ std::map<std::string, CarPart> car_parts;
+
+ SurroundViewStaticDataParams(
+ const std::vector<SurroundViewCameraParams>& sv_cameras_params,
+ const SurroundView2dParams& sv_2d_params,
+ const SurroundView3dParams& sv_3d_params,
+ const std::vector<float>& scales, const BoundingBox& bb,
+ const std::map<std::string, CarTexture>& textures,
+ const std::map<std::string, CarPart>& parts)
+ : cameras_params(sv_cameras_params),
+ surround_view_2d_params(sv_2d_params),
+ surround_view_3d_params(sv_3d_params),
+ undistortion_focal_length_scales(scales),
+ car_model_bb(bb),
+ car_textures(textures),
+ car_parts(parts) {}
+};
+
struct SurroundViewInputBufferPointers {
void* gpu_data_pointer;
void* cpu_data_pointer;
@@ -418,17 +651,41 @@
Format format;
int width;
int height;
- SurroundViewResultPointer() : data_pointer(nullptr), width(0), height(0) {}
+ bool is_data_preallocated;
+ SurroundViewResultPointer()
+ : data_pointer(nullptr),
+ width(0),
+ height(0),
+ is_data_preallocated(false) {}
+
+ // Constructor with result data pointer being allocated within core lib.
+ // Use for cases when no already existing buffer is available.
SurroundViewResultPointer(Format format_, int width_, int height_)
: format(format_), width(width_), height(height_) {
// default formate is gray.
const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
data_pointer =
static_cast<void*>(new char[width * height * byte_per_pixel]);
+ is_data_preallocated = false;
}
+
+ // Constructor with pre-allocated data.
+ // Use for cases when results must be added to an existing allocated buffer.
+ // Example, pre-allocated buffer of a display.
+ SurroundViewResultPointer(void* data_pointer_, Format format_, int width_,
+ int height_)
+ : data_pointer(data_pointer_),
+ format(format_),
+ width(width_),
+ height(height_),
+ is_data_preallocated(true) {}
+
~SurroundViewResultPointer() {
if (data_pointer) {
- // delete[] static_cast<char*>(data_pointer);
+ // TODO(b/154365307): Fix freeing up of pre-allocated memory.
+ // if (!is_data_preallocated) {
+ // delete[] static_cast<char*>(data_pointer);
+ // }
data_pointer = nullptr;
}
}
@@ -439,13 +696,10 @@
virtual ~SurroundView() = default;
// Sets SurroundView static data.
- // For each input, please refer to the definition.
+ // For details of SurroundViewStaticDataParams, please refer to the
+ // definition.
virtual bool SetStaticData(
- const std::vector<SurroundViewCameraParams>& cameras_params,
- const SurroundView2dParams& surround_view_2d_params,
- const SurroundView3dParams& surround_view_3d_params,
- const std::vector<float>& undistortion_focal_length_scales,
- const BoundingBox& car_model_bb) = 0;
+ const SurroundViewStaticDataParams& static_data_params) = 0;
// Starts 2d pipeline. Returns false if error occurs.
virtual bool Start2dPipeline() = 0;
@@ -461,29 +715,29 @@
virtual void Stop3dPipeline() = 0;
// Updates 2d output resolution on-the-fly. Starts2dPipeline() must be called
- // before this can be called. For quality assurance, the resolution should not
- // be larger than the original one. This call is not thread safe and there is
- // no sync between Get2dSurroundView() and this call.
+ // before this can be called. For quality assurance, the |resolution| should
+ // not be larger than the original one. This call is not thread safe and there
+ // is no sync between Get2dSurroundView() and this call.
virtual bool Update2dOutputResolution(const Size2dInteger& resolution) = 0;
// Updates 3d output resolution on-the-fly. Starts3dPipeline() must be called
- // before this can be called. For quality assurance, the resolution should not
- // be larger than the original one. This call is not thread safe and there is
- // no sync between Get3dSurroundView() and this call.
+ // before this can be called. For quality assurance, the |resolution| should
+ // not be larger than the original one. This call is not thread safe and there
+ // is no sync between Get3dSurroundView() and this call.
virtual bool Update3dOutputResolution(const Size2dInteger& resolution) = 0;
// Projects camera's pixel location to surround view 2d image location.
- // camera_point is the pixel location in raw camera's space.
- // camera_index is the camera's index.
- // surround_view_2d_point is the surround view 2d image pixel location.
+ // |camera_point| is the pixel location in raw camera's space.
+ // |camera_index| is the camera's index.
+ // |surround_view_2d_point| is the surround view 2d image pixel location.
virtual bool GetProjectionPointFromRawCameraToSurroundView2d(
const Coordinate2dInteger& camera_point, int camera_index,
Coordinate2dFloat* surround_view_2d_point) = 0;
// Projects camera's pixel location to surround view 3d bowl coordinate.
- // camera_point is the pixel location in raw camera's space.
- // camera_index is the camera's index.
- // surround_view_3d_point is the surround view 3d vertex.
+ // |camera_point| is the pixel location in raw camera's space.
+ // |camera_index| is the camera's index.
+ // |surround_view_3d_point| is the surround view 3d vertex.
virtual bool GetProjectionPointFromRawCameraToSurroundView3d(
const Coordinate2dInteger& camera_point, int camera_index,
Coordinate3dFloat* surround_view_3d_point) = 0;
@@ -497,19 +751,41 @@
SurroundViewResultPointer* result_pointer) = 0;
// Gets 3d surround view image.
- // It takes input_pointers and view_matrix as input, and output is
- // result_pointer. view_matrix is 4 x 4 matrix.
+ // It takes |input_pointers| and |view_matrix| as input, and output is
+ // |result_pointer|. |view_matrix| is 4 x 4 matrix.
// Please refer to the definition of
// SurroundViewInputBufferPointers and
// SurroundViewResultPointer.
virtual bool Get3dSurroundView(
const std::vector<SurroundViewInputBufferPointers>& input_pointers,
- const std::vector<std::vector<float>> view_matrix,
+ const std::array<std::array<float, 4>, 4>& view_matrix,
+ SurroundViewResultPointer* result_pointer) = 0;
+
+ // Gets 3d surround view image overload.
+ // It takes |input_pointers|, |quaternion| and |translation| as input,
+ // and output is |result_pointer|.
+ // |quaternion| is 4 x 1 array (X, Y, Z, W).
+ // It is required to be unit quaternion as rotation quaternion.
+ // |translation| is 3 X 1 array (x, y, z).
+ // Please refer to the definition of
+ // SurroundViewInputBufferPointers and
+ // SurroundViewResultPointer.
+ virtual bool Get3dSurroundView(
+ const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+ const std::array<float, 4>& quaternion,
+ const std::array<float, 3>& translation,
SurroundViewResultPointer* result_pointer) = 0;
// Sets 3d overlays.
virtual bool Set3dOverlay(const std::vector<Overlay>& overlays) = 0;
+ // Animates a set of car parts.
+ // Only updated car parts are included.
+ // |car_animations| is a vector of AnimationParam specifying updated
+ // car parts with updated animation parameters.
+ virtual bool SetAnimations(
+ const std::vector<AnimationParam>& car_animations) = 0;
+
// for test only.
// TODO(xxqian): remove thest two fns.
virtual std::vector<SurroundViewInputBufferPointers> ReadImages(
diff --git a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
old mode 100644
new mode 100755
index 0175c16..2421d41
--- a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
+++ b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86-64/libcore_lib.so b/surround_view/service-impl/lib/x86-64/libcore_lib.so
deleted file mode 100755
index 96479c6..0000000
--- a/surround_view/service-impl/lib/x86-64/libcore_lib.so
+++ /dev/null
Binary files differ
diff --git a/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
new file mode 100755
index 0000000..34d1f6a
--- /dev/null
+++ b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86/libcore_lib.so b/surround_view/service-impl/lib/x86/libcore_lib.so
deleted file mode 100755
index 34e3bcb..0000000
--- a/surround_view/service-impl/lib/x86/libcore_lib.so
+++ /dev/null
Binary files differ
diff --git a/surround_view/service-impl/lib/x86/libcore_lib_shared.so b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
new file mode 100755
index 0000000..c6ba2b6
--- /dev/null
+++ b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
Binary files differ
diff --git a/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerTest.java b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
similarity index 98%
rename from tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerTest.java
rename to tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
index 4ede567..86a2853 100644
--- a/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerTest.java
+++ b/tests/CarSecurityPermissionTest/src/com/android/car/user/CarUserManagerPermissionTest.java
@@ -49,7 +49,7 @@
* This class contains security permission tests for the {@link CarUserManager}'s system APIs.
*/
@RunWith(AndroidJUnit4.class)
-public final class CarUserManagerTest {
+public final class CarUserManagerPermissionTest {
private static final int USRE_TYPE = 1;
private CarUserManager mCarUserManager;
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
index cb58d3f..ab13c5f 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
@@ -58,7 +58,7 @@
private static final String TAG = CarUserManagerTest.class.getSimpleName();
- private static final int SWITCH_TIMEOUT_MS = 40_000;
+ private static final int SWITCH_TIMEOUT_MS = 70_000;
private static final int STOP_TIMEOUT_MS = 300_000;
/**
@@ -75,7 +75,7 @@
private CarUserManager mCarUserManager;
@BeforeClass
- public static void createUserFixture() {
+ public static void setupUsers() {
sInitialUserId = ActivityManager.getCurrentUser();
Log.i(TAG, "Running test as user " + sInitialUserId);
@@ -83,7 +83,9 @@
}
@AfterClass
- public static void removeUserFixture() {
+ public static void cleanupUsers() {
+ switchUserDirectly(sInitialUserId);
+
if (sNewUserId == UserHandle.USER_NULL) {
Log.w(TAG, "No need to remove user" + sNewUserId);
return;
@@ -108,7 +110,8 @@
int oldUserId = sInitialUserId;
int newUserId = sNewUserId;
- BlockingUserLifecycleListener startListener = new BlockingUserLifecycleListener.Builder()
+ BlockingUserLifecycleListener startListener = BlockingUserLifecycleListener
+ .forSpecificEvents()
.forUser(newUserId)
.setTimeout(SWITCH_TIMEOUT_MS)
.addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
@@ -152,7 +155,8 @@
Log.d(TAG, "unregistering start listener: " + startListener);
mCarUserManager.removeListener(startListener);
- BlockingUserLifecycleListener stopListener = new BlockingUserLifecycleListener.Builder()
+ BlockingUserLifecycleListener stopListener = BlockingUserLifecycleListener
+ .forSpecificEvents()
.forUser(newUserId)
.setTimeout(STOP_TIMEOUT_MS)
.addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING)
@@ -169,12 +173,9 @@
// Must force stop the user, otherwise it can take minutes for its process to finish
forceStopUser(newUserId);
- // waitForEvents() will also return events for previous user...
- List<UserLifecycleEvent> allEvents = stopListener.waitForEvents();
- Log.d(TAG, "All received events on stopListener: " + allEvents);
- //... so we need to check for just the epected events
- List<UserLifecycleEvent> stopEvents = stopListener.getExpectedEventsReceived();
- Log.d(TAG, "Relevant stop events: " + stopEvents);
+ List<UserLifecycleEvent> stopEvents = stopListener.waitForEvents();
+ Log.d(TAG, "stopEvents: " + stopEvents + "; all events on stop listener: "
+ + stopListener.getAllReceivedEvents());
// Assert user ids
for (UserLifecycleEvent event : stopEvents) {
@@ -191,7 +192,7 @@
List<UserLifecycleEvent> allStartEvents = startListener.getAllReceivedEvents();
Log.d(TAG, "All start events: " + startEvents);
- assertThat(allStartEvents).isSameAs(startEvents);
+ assertThat(allStartEvents).containsAllIn(startEvents).inOrder();
Log.d(TAG, "unregistering stop listener: " + stopListener);
mCarUserManager.removeListener(stopListener);
diff --git a/tests/carservice_unit_test/src/android/car/AbstractExtendedMockitoCarServiceTestCase.java b/tests/carservice_unit_test/src/android/car/AbstractExtendedMockitoCarServiceTestCase.java
new file mode 100644
index 0000000..258e49e
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/AbstractExtendedMockitoCarServiceTestCase.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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 android.car;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import android.annotation.NonNull;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.util.Log;
+
+import com.android.car.CarLocalServices;
+
+/**
+ * Specialized {@link AbstractExtendedMockitoTestCase} implementation that provides
+ * CarService-related helpers.
+ */
+public abstract class AbstractExtendedMockitoCarServiceTestCase
+ extends AbstractExtendedMockitoTestCase {
+
+ private static final String TAG = AbstractExtendedMockitoCarServiceTestCase.class
+ .getSimpleName();
+
+ private static final boolean VERBOSE = false;
+
+ /**
+ * Mocks a call to {@link CarLocalServices#getService(Class)}.
+ *
+ * @throws IllegalStateException if class didn't override {@link #newSessionBuilder()} and
+ * called {@code spyStatic(CarLocalServices.class)} on the session passed to it.
+ */
+ protected final <T> void mockGetCarLocalService(@NonNull Class<T> type, @NonNull T service) {
+ if (VERBOSE) Log.v(TAG, getLogPrefix() + "mockGetLocalService(" + type.getName() + ")");
+ assertSpied(CarLocalServices.class);
+
+ beginTrace("mockGetLocalService");
+ doReturn(service).when(() -> CarLocalServices.getService(type));
+ endTrace();
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
index 3be64a5..ddea0c0 100644
--- a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java
@@ -214,13 +214,13 @@
@UserIdInt int userId) throws InterruptedException {
// Adding a blocking listener to ensure CarUserService event notification is completed
// before proceeding with test execution.
- BlockingUserLifecycleListener blockingListener = BlockingUserLifecycleListener
- .newDefaultListener();
+ BlockingUserLifecycleListener blockingListener =
+ BlockingUserLifecycleListener.forAnyEvent().build();
mCarUserService.addUserLifecycleListener(blockingListener);
runOnMainThreadAndWaitForIdle(() -> mCarUserService.onUserLifecycleEvent(eventType,
/* timestampMs= */ 0, /* fromUserId= */ UserHandle.USER_NULL, userId));
- blockingListener.waitForEvent();
+ blockingListener.waitForAnyEvent();
}
/** Overrides framework behavior to succeed on binding/starting processes. */
diff --git a/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java b/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java
new file mode 100644
index 0000000..e94bb77
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/testapi/BlockingUserLifecycleListenerTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2020 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.testapi;
+
+import static android.car.test.mocks.JavaMockitoHelper.await;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleEvent;
+import android.car.user.CarUserManager.UserLifecycleEventType;
+import android.os.UserHandle;
+import android.util.Log;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.stream.Collectors;
+
+public final class BlockingUserLifecycleListenerTest {
+
+ private static final String TAG = BlockingUserLifecycleListenerTest.class.getSimpleName();
+ private static final long TIMEOUT_MS = 500;
+
+ @Test
+ public void testListener_forAnyEvent_invalidBuilderMethods() throws Exception {
+ BlockingUserLifecycleListener.Builder builder = BlockingUserLifecycleListener.forAnyEvent()
+ .setTimeout(666);
+
+ assertThrows(IllegalStateException.class, () -> builder.forUser(10));
+ assertThrows(IllegalStateException.class, () -> builder.forPreviousUser(10));
+ assertThrows(IllegalStateException.class,
+ () -> builder.addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED));
+ }
+
+ @Test
+ public void testForAnyEvent_invalidMethods() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forAnyEvent()
+ .build();
+
+ assertThrows(IllegalStateException.class, () -> listener.waitForEvents());
+ assertThrows(IllegalStateException.class, () -> listener.getAllReceivedEvents());
+ }
+
+ @Test
+ public void testForAnyEvent_timesout() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forAnyEvent()
+ .build();
+
+ assertThrows(IllegalStateException.class, () -> listener.waitForAnyEvent());
+ }
+
+ @Test
+ public void testForAnyEvent_ok() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forAnyEvent()
+ .build();
+ sendAsyncEvents(listener, 10, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+ UserLifecycleEvent event = listener.waitForAnyEvent();
+ assertEvent(event, 10, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+ }
+
+ @Test
+ public void testForSpecificEvents_invalidMethods() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING).build();
+
+ assertThrows(IllegalStateException.class, () -> listener.waitForAnyEvent());
+ }
+
+ @Test
+ public void testForSpecificEvents_receivedOnlyExpected() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+ .build();
+
+ sendAsyncEvents(listener, 10,
+ USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ assertEvents(events, 10,
+ USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+ List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+ assertThat(allReceivedEvents).containsAllIn(events).inOrder();
+ }
+
+ @Test
+ public void testForSpecificEvents_receivedExtraEvents() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)
+ .build();
+
+ CountDownLatch latch = sendAsyncEvents(listener, 10,
+ USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+ USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+ USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ assertEvents(events, 10,
+ USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ USER_LIFECYCLE_EVENT_TYPE_UNLOCKING);
+
+ await(latch, TIMEOUT_MS);
+ List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+ assertEvents(allReceivedEvents, 10,
+ USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+ USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+ USER_LIFECYCLE_EVENT_TYPE_UNLOCKED);
+ }
+
+ @Test
+ public void testForSpecificEvents_filterByUser() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+ .forUser(10)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+ .build();
+ UserLifecycleEvent wrong1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+ UserLifecycleEvent wrong2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 11);
+ UserLifecycleEvent right1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 10);
+ UserLifecycleEvent right2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10);
+
+ CountDownLatch latch = sendAsyncEvents(listener,
+ Arrays.asList(wrong1, right1, right2, wrong2));
+
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ assertThat(events).containsExactly(right1, right2).inOrder();
+
+ await(latch, TIMEOUT_MS);
+ List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+ assertThat(allReceivedEvents)
+ .containsExactly(wrong1, right1, right2, wrong2)
+ .inOrder();
+ }
+
+ @Test
+ public void testForSpecificEvents_filterByUserDuplicatedEventTypes() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+ .forUser(10)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+ .build();
+ UserLifecycleEvent wrong1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+ UserLifecycleEvent wrong2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 11);
+ UserLifecycleEvent wrong3 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 11);
+ UserLifecycleEvent right1 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 10);
+ UserLifecycleEvent right2 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10);
+ UserLifecycleEvent right3 = new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, 10);
+
+ CountDownLatch latch = sendAsyncEvents(listener,
+ Arrays.asList(wrong1, right1, wrong2, right2, right3, wrong3));
+
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ assertThat(events).containsExactly(right1, right2, right3).inOrder();
+
+ await(latch, TIMEOUT_MS);
+ List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+ assertThat(allReceivedEvents)
+ .containsExactly(wrong1, right1, wrong2, right2, right3, wrong3)
+ .inOrder();
+ }
+
+ @Test
+ public void testForSpecificEvents_filterByPreviousUser() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+ .forPreviousUser(10)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+ .build();
+ UserLifecycleEvent wrong1 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+ UserLifecycleEvent wrong2 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 10);
+ UserLifecycleEvent wrong3 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 11, 10);
+ UserLifecycleEvent right1 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 10, 11);
+ UserLifecycleEvent right2 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10, 12);
+
+ CountDownLatch latch = sendAsyncEvents(listener,
+ Arrays.asList(wrong1, right1, wrong2, right2, wrong3));
+
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ assertThat(events).containsExactly(right1, right2).inOrder();
+
+ await(latch, TIMEOUT_MS);
+ List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+ assertThat(allReceivedEvents)
+ .containsExactly(wrong1, right1, wrong2, right2, wrong3)
+ .inOrder();
+ }
+
+ @Test
+ public void testForSpecificEvents_filterByPreviousAndTargetUsers() throws Exception {
+ BlockingUserLifecycleListener listener = BlockingUserLifecycleListener.forSpecificEvents()
+ .forPreviousUser(10)
+ .forUser(11)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING)
+ .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)
+ .build();
+ UserLifecycleEvent wrong1 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, 11);
+ UserLifecycleEvent wrong2 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, 10);
+ UserLifecycleEvent wrong3 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 10, 12);
+ UserLifecycleEvent right1 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING, 10, 11);
+ UserLifecycleEvent right2 =
+ new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, 10, 11);
+
+ CountDownLatch latch = sendAsyncEvents(listener,
+ Arrays.asList(wrong1, right1, wrong2, right2, wrong3));
+
+ List<UserLifecycleEvent> events = listener.waitForEvents();
+ assertThat(events).containsExactly(right1, right2).inOrder();
+
+ await(latch, TIMEOUT_MS);
+ List<UserLifecycleEvent> allReceivedEvents = listener.getAllReceivedEvents();
+ assertThat(allReceivedEvents)
+ .containsExactly(wrong1, right1, wrong2, right2, wrong3)
+ .inOrder();
+ }
+
+ @NonNull
+ private static CountDownLatch sendAsyncEvents(@NonNull BlockingUserLifecycleListener listener,
+ @UserIdInt int userId, @UserLifecycleEventType int... eventTypes) {
+ List<UserLifecycleEvent> events = Arrays.stream(eventTypes)
+ .mapToObj((type) -> new UserLifecycleEvent(type, userId))
+ .collect(Collectors.toList());
+ return sendAsyncEvents(listener, events);
+ }
+
+ @NonNull
+ private static CountDownLatch sendAsyncEvents(@NonNull BlockingUserLifecycleListener listener,
+ @NonNull List<UserLifecycleEvent> events) {
+ Log.d(TAG, "sendAsyncEvents(" + events + "): called on thread " + Thread.currentThread());
+ CountDownLatch latch = new CountDownLatch(1);
+ new Thread(() -> {
+ Log.d(TAG, "sending " + events.size() + " on thread " + Thread.currentThread());
+ events.forEach((e) -> listener.onEvent(e));
+ Log.d(TAG, "sent");
+ latch.countDown();
+ }, "AsyncEventsThread").start();
+ return latch;
+ }
+
+ private static void assertEvent(UserLifecycleEvent event, @UserIdInt int expectedUserId,
+ @UserLifecycleEventType int expectedType) {
+ assertThat(event).isNotNull();
+ assertWithMessage("wrong type on %s; expected %s", event,
+ CarUserManager.lifecycleEventTypeToString(expectedType)).that(event.getEventType())
+ .isEqualTo(expectedType);
+ assertThat(event.getUserId()).isEqualTo(expectedUserId);
+ assertThat(event.getUserHandle().getIdentifier()).isEqualTo(expectedUserId);
+ assertThat(event.getPreviousUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(event.getPreviousUserHandle()).isNull();
+ }
+
+ private static void assertEvents(List<UserLifecycleEvent> events, @UserIdInt int expectedUserId,
+ @UserLifecycleEventType int... expectedTypes) {
+ assertThat(events).isNotNull();
+ assertThat(events).hasSize(expectedTypes.length);
+ for (int i = 0; i < expectedTypes.length; i++) {
+ int expectedType = expectedTypes[i];
+ UserLifecycleEvent event = events.get(i);
+ assertEvent(event, expectedUserId, expectedType);
+ }
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java
index 3b95c82..f50ad32 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java
@@ -16,26 +16,25 @@
package com.android.car.user;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static android.car.test.mocks.AndroidMockitoHelper.mockContextGetService;
-import static com.google.common.truth.Truth.assertThat;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
+import android.car.AbstractExtendedMockitoCarServiceTestCase;
import android.car.hardware.power.CarPowerManager;
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
import android.car.settings.CarSettings;
-import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
import android.car.user.CarUserManager;
import android.car.user.CarUserManager.UserLifecycleEvent;
import android.car.user.CarUserManager.UserLifecycleListener;
@@ -64,13 +63,16 @@
import org.mockito.Mock;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-public class CarUserNoticeServiceTest extends AbstractExtendedMockitoTestCase {
+public class CarUserNoticeServiceTest extends AbstractExtendedMockitoCarServiceTestCase {
+
+ private static final long TIMEOUT_MS = 10_000;
@Mock
private Context mMockContext;
@Mock
+ private Context mOtherMockContext;
+ @Mock
private Resources mMockedResources;
@Mock
private CarPowerManagementService mMockCarPowerManagementService;
@@ -110,22 +112,21 @@
@Before
public void setUpMocks() throws Exception {
doReturn(mCarPowerManager).when(() -> CarLocalServices.createCarPowerManager(mMockContext));
- doReturn(mMockCarPowerManagementService)
- .when(() -> CarLocalServices.getService(CarPowerManagementService.class));
- doReturn(mMockCarUserService)
- .when(() -> CarLocalServices.getService(CarUserService.class));
+ mockGetCarLocalService(CarPowerManagementService.class, mMockCarPowerManagementService);
+ mockGetCarLocalService(CarUserService.class, mMockCarUserService);
putSettingsInt(CarSettings.Secure.KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER, 1);
- doReturn(mMockedResources).when(mMockContext).getResources();
- doReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
- .getContentResolver())
- .when(mMockContext).getContentResolver();
- doReturn("com.foo/.Blah").when(mMockedResources).getString(anyInt());
- doReturn(mMockPowerManager).when(mMockContext).getSystemService(PowerManager.class);
- doReturn(mMockAppOpsManager).when(mMockContext).getSystemService(AppOpsManager.class);
- doReturn(mMockPackageManager).when(mMockContext).getPackageManager();
- doReturn(1).when(mMockPackageManager).getPackageUidAsUser(any(), anyInt());
+ when(mMockContext.getResources()).thenReturn(mMockedResources);
+ when(mMockContext.getContentResolver())
+ .thenReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getContentResolver());
+ when(mMockedResources.getString(anyInt())).thenReturn("com.foo/.Blah");
+
+ mockContextGetService(mMockContext, PowerManager.class, mMockPowerManager);
+ mockContextGetService(mMockContext, AppOpsManager.class, mMockAppOpsManager);
+ mockContextGetService(mMockContext, PackageManager.class, mMockPackageManager);
+ when(mMockPackageManager.getPackageUidAsUser(any(), anyInt())).thenReturn(1);
mCarUserNoticeService = new CarUserNoticeService(mMockContext, mHandler);
mCarUserNoticeService.init();
verify(mMockCarUserService).addUserLifecycleListener(
@@ -137,14 +138,14 @@
@Test
public void featureDisabledTest() {
- Context mockContext = mock(Context.class);
- // if feature is disabled, Resources.getString will return an
- // empty string
- doReturn("").when(mMockedResources).getString(R.string.config_userNoticeUiService);
- doReturn(mMockedResources).when(mockContext).getResources();
- CarUserNoticeService carUserNoticeService = new CarUserNoticeService(mockContext);
- carUserNoticeService.init();
- verify(mockContext, never()).registerReceiver(any(), any());
+ // Feature is disabled when the string is empty
+ when(mMockedResources.getString(R.string.config_userNoticeUiService)).thenReturn("");
+ when(mOtherMockContext.getResources()).thenReturn(mMockedResources);
+
+ CarUserNoticeService otherService = new CarUserNoticeService(mOtherMockContext);
+ otherService.init();
+
+ verify(mOtherMockContext, never()).registerReceiver(any(), any());
}
@Test
@@ -154,7 +155,7 @@
setDisplayOff();
CountDownLatch latch = mockUnbindService();
sendBroadcast(Intent.ACTION_SCREEN_OFF);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
}
@Test
@@ -164,13 +165,13 @@
setDisplayOff();
CountDownLatch latch = mockUnbindService();
sendBroadcast(Intent.ACTION_SCREEN_OFF);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
// send screen on broadcast
setDisplayOn();
latch = mockBindService();
sendBroadcast(Intent.ACTION_SCREEN_ON);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
}
@Test
@@ -180,7 +181,7 @@
setDisplayOff();
CountDownLatch latch = mockUnbindService();
sendPowerStateChange(CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
}
@Test
@@ -190,13 +191,13 @@
setDisplayOff();
CountDownLatch latch = mockUnbindService();
sendPowerStateChange(CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
// send Power On
setDisplayOn();
latch = mockBindService();
sendPowerStateChange(CarPowerManager.CarPowerStateListener.ON);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
}
@Test
@@ -206,20 +207,20 @@
setDisplayOff();
CountDownLatch latch = mockUnbindService();
sendBroadcast(Intent.ACTION_SCREEN_OFF);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
// UI not shown if key is disabled
setDisplayOn();
latch = mockKeySettings(
CarSettings.Secure.KEY_ENABLE_INITIAL_NOTICE_SCREEN_TO_USER, 0);
sendBroadcast(Intent.ACTION_SCREEN_ON);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
// invoked only once, when user switched
verify(mMockContext, times(1)).bindServiceAsUser(any(), any(), anyInt(), any());
}
- private void assetLatchCalled(CountDownLatch latch) throws Exception {
- assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
+ private static void assertLatchCalled(CountDownLatch latch) throws Exception {
+ JavaMockitoHelper.await(latch, TIMEOUT_MS);
}
private void switchUser(int userId) throws Exception {
@@ -260,11 +261,11 @@
}
private void setDisplayOn() {
- doReturn(true).when(mMockPowerManager).isInteractive();
+ when(mMockPowerManager.isInteractive()).thenReturn(true);
}
private void setDisplayOff() {
- doReturn(false).when(mMockPowerManager).isInteractive();
+ when(mMockPowerManager.isInteractive()).thenReturn(false);
}
private void sendBroadcast(String action) {
@@ -282,6 +283,6 @@
setDisplayOn();
CountDownLatch latch = mockBindService();
switchUser(UserHandle.MIN_SECONDARY_USER_ID);
- assetLatchCalled(latch);
+ assertLatchCalled(latch);
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index eaf8d54..87fdc18 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -151,7 +151,7 @@
@Mock PackageManager mPackageManager;
private final BlockingUserLifecycleListener mUserLifecycleListener =
- BlockingUserLifecycleListener.newDefaultListener();
+ BlockingUserLifecycleListener.forAnyEvent().build();
@Captor private ArgumentCaptor<UsersInfo> mUsersInfoCaptor;
@@ -270,7 +270,7 @@
private void verifyListenerOnEventInvoked(int expectedNewUserId, int expectedEventType)
throws Exception {
- UserLifecycleEvent actualEvent = mUserLifecycleListener.waitForEvent();
+ UserLifecycleEvent actualEvent = mUserLifecycleListener.waitForAnyEvent();
assertThat(actualEvent.getEventType()).isEqualTo(expectedEventType);
assertThat(actualEvent.getUserId()).isEqualTo(expectedNewUserId);
}