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);
     }