Merge "ABA should dismiss if activity to block is gone" into rvc-dev
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 1af4c36..4e979a2 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -1294,7 +1294,7 @@
     method @RequiresPermission(android.car.Car.PERMISSION_VMS_PUBLISHER) public void unregisterProvider(int);
   }
 
-  public class VmsClientManager {
+  public final class VmsClientManager {
     method @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public void registerVmsClientCallback(@NonNull java.util.concurrent.Executor, @NonNull android.car.vms.VmsClientManager.VmsClientCallback);
     method @RequiresPermission(anyOf={android.car.Car.PERMISSION_VMS_PUBLISHER, android.car.Car.PERMISSION_VMS_SUBSCRIBER}) public void unregisterVmsClientCallback(@NonNull android.car.vms.VmsClientManager.VmsClientCallback);
   }
diff --git a/car-lib/src/android/car/ICarUserService.aidl b/car-lib/src/android/car/ICarUserService.aidl
index 1561ad9..d59c17b 100644
--- a/car-lib/src/android/car/ICarUserService.aidl
+++ b/car-lib/src/android/car/ICarUserService.aidl
@@ -30,6 +30,5 @@
     boolean stopPassenger(int passengerId);
     oneway void setLifecycleListenerForUid(in IResultReceiver listener);
     oneway void resetLifecycleListenerForUid();
-    oneway void getInitialUserInfo(int requestType, int timeoutMs, in UserInfo[] existingUsers,
-        int currentUserId, in IResultReceiver receiver);
+    oneway void getInitialUserInfo(int requestType, int timeoutMs, in IResultReceiver receiver);
 }
diff --git a/car-lib/src/android/car/vms/VmsClientManager.java b/car-lib/src/android/car/vms/VmsClientManager.java
index cf7b013..c6f8be8 100644
--- a/car-lib/src/android/car/vms/VmsClientManager.java
+++ b/car-lib/src/android/car/vms/VmsClientManager.java
@@ -41,7 +41,7 @@
  */
 @RequiredFeature(Car.VEHICLE_MAP_SERVICE)
 @SystemApi
-public class VmsClientManager extends CarManagerBase {
+public final class VmsClientManager extends CarManagerBase {
     private static final boolean DBG = false;
     private static final String TAG = VmsClientManager.class.getSimpleName();
 
diff --git a/service/src/com/android/car/hal/UserHalHelper.java b/service/src/com/android/car/hal/UserHalHelper.java
index 9b3e320..18f9a58 100644
--- a/service/src/com/android/car/hal/UserHalHelper.java
+++ b/service/src/com/android/car/hal/UserHalHelper.java
@@ -16,7 +16,10 @@
 package com.android.car.hal;
 
 import android.annotation.NonNull;
+import android.content.pm.UserInfo;
 import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
+import android.hardware.automotive.vehicle.V2_0.UserFlags;
+import android.os.UserHandle;
 
 import com.android.car.hal.UserHalService.HalCallback;
 import com.android.car.hal.UserHalService.HalCallback.HalCallbackStatus;
@@ -71,6 +74,28 @@
         }
     }
 
+    /**
+     * Converts Android user flags to HALs.
+     */
+    public static int convertFlags(@NonNull UserInfo user) {
+        // TODO(b/146207078): add unit test
+        int flags = UserFlags.NONE;
+        if (user.id == UserHandle.USER_SYSTEM) {
+            flags |= UserFlags.SYSTEM;
+        }
+        if (user.isAdmin()) {
+            flags |= UserFlags.ADMIN;
+        }
+        if (user.isGuest()) {
+            flags |= UserFlags.GUEST;
+        }
+        if (user.isEphemeral()) {
+            flags |= UserFlags.EPHEMERAL;
+        }
+
+        return flags;
+    }
+
     private UserHalHelper() {
         throw new UnsupportedOperationException("contains only static methods");
     }
diff --git a/service/src/com/android/car/hal/UserHalService.java b/service/src/com/android/car/hal/UserHalService.java
index ab44046..4ce7c16 100644
--- a/service/src/com/android/car/hal/UserHalService.java
+++ b/service/src/com/android/car/hal/UserHalService.java
@@ -37,7 +37,6 @@
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
-import com.android.car.hal.UserHalService.HalCallback.HalCallbackStatus;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
@@ -54,6 +53,8 @@
  */
 public final class UserHalService extends HalServiceBase {
 
+    private static final String UNSUPPORTED_MSG = "Vehicle HAL does not support user management";
+
     private static final String TAG = CarLog.TAG_USER;
 
     // TODO(b/146207078): STOPSHIP - change to false before R is launched
@@ -64,7 +65,8 @@
     private final VehicleHal mHal;
 
     @GuardedBy("mLock")
-    private final SparseArray<VehiclePropConfig> mProperties = new SparseArray<>(1);
+    @Nullable
+    private SparseArray<VehiclePropConfig> mProperties;
 
     // NOTE: handler is currently only used to check if HAL times out replying to requests, by
     // posting messages whose id is the request id. If it needs to be used for more messages, we'll
@@ -131,19 +133,28 @@
     @Nullable
     public Collection<VehiclePropConfig> takeSupportedProperties(
             Collection<VehiclePropConfig> allProperties) {
-        ArrayList<VehiclePropConfig> supported = new ArrayList<>();
-        synchronized (mLock) {
-            for (VehiclePropConfig config : allProperties) {
-                switch (config.prop) {
-                    case INITIAL_USER_INFO:
-                        supported.add(config);
-                        mProperties.put(config.prop, config);
-                        break;
-                }
-
+        boolean supported = false;
+        // TODO(b/146207078): increase capacity once it supports more
+        SparseArray<VehiclePropConfig> properties = new SparseArray<>(1);
+        ArrayList<VehiclePropConfig> taken = new ArrayList<>();
+        for (VehiclePropConfig config : allProperties) {
+            switch (config.prop) {
+                case INITIAL_USER_INFO:
+                    supported = true;
+                    taken.add(config);
+                    properties.put(config.prop, config);
+                    break;
             }
+
         }
-        return supported.isEmpty() ? null : supported;
+        if (!supported) {
+            Log.w(TAG, UNSUPPORTED_MSG);
+            return null;
+        }
+        synchronized (mLock) {
+            mProperties = properties;
+        }
+        return taken;
     }
 
     /**
@@ -179,6 +190,19 @@
     }
 
     /**
+     * Checks if the Vehicle HAL supports user management.
+     */
+    public boolean isSupported() {
+        synchronized (mLock) {
+            return mProperties != null;
+        }
+    }
+
+    private void checkSupportedLocked() {
+        Preconditions.checkState(isSupported(), UNSUPPORTED_MSG);
+    }
+
+    /**
      * Calls HAL to asynchronously get info about the initial user.
      *
      * @param requestType type of request (as defined by
@@ -186,6 +210,9 @@
      * @param timeoutMs how long to wait (in ms) for the property change event.
      * @param usersInfo current state of Android users.
      * @param callback callback to handle the response.
+     *
+     * @throws IllegalStateException if the HAL does not support user management (callers should
+     * call {@link #isSupported()} first to avoid this exception).
      */
     public void getInitialUserInfo(int requestType, int timeoutMs, @NonNull UsersInfo usersInfo,
             @NonNull HalCallback<InitialUserInfoResponse> callback) {
@@ -199,6 +226,7 @@
         propRequest.prop = INITIAL_USER_INFO;
         int requestId;
         synchronized (mLock) {
+            checkSupportedLocked();
             requestId = mNextRequestId++;
             // TODO(b/146207078): use helper method to convert request to prop value
             propRequest.value.int32Values.add(requestId);
@@ -307,6 +335,16 @@
     public void dump(PrintWriter writer) {
         writer.printf("*User HAL*\n");
         synchronized (mLock) {
+            if (!isSupported()) {
+                writer.println(UNSUPPORTED_MSG);
+                return;
+            }
+            int numberProperties = mProperties.size();
+            String indent = "  ";
+            writer.printf("%d supported properties\n", numberProperties);
+            for (int i = 0; i < numberProperties; i++) {
+                writer.printf("%s%s\n", indent, mProperties.valueAt(i));
+            }
             writer.printf("next request id: %d\n", mNextRequestId);
             if (mPendingCallbacks.size() == 0) {
                 writer.println("no pending callbacks");
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 5ec0933..706f6e5 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -35,7 +35,6 @@
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction;
-import android.hardware.automotive.vehicle.V2_0.UserFlags;
 import android.hardware.automotive.vehicle.V2_0.UsersInfo;
 import android.location.LocationManager;
 import android.os.Binder;
@@ -51,11 +50,11 @@
 
 import com.android.car.CarServiceBase;
 import com.android.car.R;
+import com.android.car.hal.UserHalHelper;
 import com.android.car.hal.UserHalService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IResultReceiver;
-import com.android.internal.util.Preconditions;
 import com.android.internal.util.UserIcons;
 
 import java.io.PrintWriter;
@@ -78,12 +77,14 @@
  */
 public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
 
-    /** Extra used to represent a user id in a {@link IResultReceiver} response. */
+    /** {@code int} extra used to represent a user id in a {@link IResultReceiver} response. */
     public static final String BUNDLE_USER_ID = "user.id";
-    /** Extra used to represent user flags in a {@link IResultReceiver} response. */
+    /** {@code int} extra used to represent user flags in a {@link IResultReceiver} response. */
     public static final String BUNDLE_USER_FLAGS = "user.flags";
-    /** Extra used to represent a user name in a {@link IResultReceiver} response. */
+    /** {@code String} extra used to represent a user name in a {@link IResultReceiver} response. */
     public static final String BUNDLE_USER_NAME = "user.name";
+    /** {@code int} extra used to represent the info action {@link IResultReceiver} response. */
+    public static final String BUNDLE_INITIAL_INFO_ACTION = "initial_info.action";
 
     private final Context mContext;
     private final CarUserManagerHelper mCarUserManagerHelper;
@@ -478,44 +479,8 @@
 
     @Override
     public void getInitialUserInfo(int requestType, int timeoutMs,
-            @NonNull UserInfo[] existingUsers, @UserIdInt int currentUserId,
             @NonNull IResultReceiver receiver) {
-
-        // TODO(b/144120654): use helper to generate USerInfo
-        UsersInfo usersInfo = new UsersInfo();
-        usersInfo.numberUsers = existingUsers.length;
-        boolean foundCurrentUser = false;
-        for (int i = 0; i < existingUsers.length; i++) {
-            UserInfo user = existingUsers[i];
-            android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
-                    new android.hardware.automotive.vehicle.V2_0.UserInfo();
-            halUser.userId = user.id;
-            int flags = UserFlags.NONE;
-            if (user.id == UserHandle.USER_SYSTEM) {
-                flags |= UserFlags.SYSTEM;
-            }
-            if (user.isAdmin()) {
-                flags |= UserFlags.ADMIN;
-            }
-            if (user.isGuest()) {
-                flags |= UserFlags.GUEST;
-            }
-            if (user.isEphemeral()) {
-                flags |= UserFlags.EPHEMERAL;
-            }
-            halUser.flags = flags;
-            usersInfo.existingUsers.add(halUser);
-            if (user.id == currentUserId) {
-                // TODO(b/144120654): unit test for when it isn't there (on helper method), or
-                // change signature so the currentUser argument is a UserInfo)
-                foundCurrentUser = true;
-                usersInfo.currentUser.userId = currentUserId;
-                usersInfo.currentUser.flags = flags;
-            }
-        }
-        Preconditions.checkArgument(foundCurrentUser,
-                "no user with id " + currentUserId + " on " + existingUsers);
-
+        UsersInfo usersInfo = getUsersInfo();
         mHal.getInitialUserInfo(requestType, timeoutMs, usersInfo, (status, resp) -> {
             try {
                 Bundle resultData = null;
@@ -523,10 +488,12 @@
                     switch (resp.action) {
                         case InitialUserInfoResponseAction.SWITCH:
                             resultData = new Bundle();
+                            resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
                             resultData.putInt(BUNDLE_USER_ID, resp.userToSwitchOrCreate.userId);
                             break;
                         case InitialUserInfoResponseAction.CREATE:
                             resultData = new Bundle();
+                            resultData.putInt(BUNDLE_INITIAL_INFO_ACTION, resp.action);
                             resultData.putInt(BUNDLE_USER_FLAGS, resp.userToSwitchOrCreate.flags);
                             resultData.putString(BUNDLE_USER_NAME, resp.userNameToCreate);
                             break;
@@ -545,6 +512,35 @@
         });
     }
 
+    // TODO(b/144120654): use helper to generate UsersInfo
+    private UsersInfo getUsersInfo() {
+        UserInfo currentUser;
+        try {
+            currentUser = mAm.getCurrentUser();
+        } catch (RemoteException e) {
+            // shouldn't happen
+            throw new IllegalStateException("Could not get current user: ", e);
+        }
+        List<UserInfo> existingUsers = mUserManager.getUsers();
+        int size = existingUsers.size();
+
+        UsersInfo usersInfo = new UsersInfo();
+        usersInfo.numberUsers = size;
+        usersInfo.currentUser.userId = currentUser.id;
+        usersInfo.currentUser.flags = UserHalHelper.convertFlags(currentUser);
+
+        for (int i = 0; i < size; i++) {
+            UserInfo androidUser = existingUsers.get(i);
+            android.hardware.automotive.vehicle.V2_0.UserInfo halUser =
+                    new android.hardware.automotive.vehicle.V2_0.UserInfo();
+            halUser.userId = androidUser.id;
+            halUser.flags = UserHalHelper.convertFlags(androidUser);
+            usersInfo.existingUsers.add(halUser);
+        }
+
+        return usersInfo;
+    }
+
     /** Returns whether the given user is a system user. */
     private static boolean isSystemUser(@UserIdInt int userId) {
         return userId == UserHandle.USER_SYSTEM;
diff --git a/service/src/com/android/car/user/UserMetrics.java b/service/src/com/android/car/user/UserMetrics.java
index ef45433..dad71fd 100644
--- a/service/src/com/android/car/user/UserMetrics.java
+++ b/service/src/com/android/car/user/UserMetrics.java
@@ -92,10 +92,10 @@
                     onUserSwitchingEventLocked(timestampMs, fromUserId, toUserId);
                     return;
                 case USER_LIFECYCLE_EVENT_TYPE_UNLOCKING:
-                    onUserUnlockingEventUnlocked(timestampMs, toUserId);
+                    onUserUnlockingEventLocked(timestampMs, toUserId);
                     return;
                 case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
-                    onUserUnlockedEventUnlocked(timestampMs, toUserId);
+                    onUserUnlockedEventLocked(timestampMs, toUserId);
                     return;
                 case USER_LIFECYCLE_EVENT_TYPE_STOPPING:
                     onUserStoppingEventLocked(timestampMs, toUserId);
@@ -132,14 +132,14 @@
         metrics.switchTime = timestampMs;
     }
 
-    private void onUserUnlockingEventUnlocked(long timestampMs, @UserIdInt int userId) {
+    private void onUserUnlockingEventLocked(long timestampMs, @UserIdInt int userId) {
         UserStartingMetric metrics = getExistingMetricsLocked(mUserStartingMetrics, userId);
         if (metrics == null) return;
 
         metrics.unlockingTime = timestampMs;
     }
 
-    private void onUserUnlockedEventUnlocked(long timestampMs, @UserIdInt int userId) {
+    private void onUserUnlockedEventLocked(long timestampMs, @UserIdInt int userId) {
         UserStartingMetric metrics = getExistingMetricsLocked(mUserStartingMetrics, userId);
         if (metrics == null) return;
 
diff --git a/surround_view/OWNERS b/surround_view/OWNERS
new file mode 100644
index 0000000..2c5c8a7
--- /dev/null
+++ b/surround_view/OWNERS
@@ -0,0 +1,3 @@
+haoxiangl@google.com
+tanmayp@google.com
+swan@google.com
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
index a18a73d..9e3c4e3 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
@@ -99,6 +99,8 @@
     @Before
     public void setFixtures() {
         mUserHalService = new UserHalService(mVehicleHal);
+        mUserHalService
+                .takeSupportedProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO)));
 
         mUser0.userId = 0;
         mUser0.flags = 100;
@@ -114,24 +116,32 @@
 
     @Test
     public void testTakeSupportedProperties_unsupportedOnly() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
         List<VehiclePropConfig> input = Arrays.asList(newConfig(CURRENT_GEAR));
-        Collection<VehiclePropConfig> output = mUserHalService.takeSupportedProperties(input);
+        Collection<VehiclePropConfig> output = myHalService.takeSupportedProperties(input);
+        assertThat(myHalService.isSupported()).isFalse();
         assertThat(output).isNull();
     }
 
     @Test
     public void testTakeSupportedPropertiesAndInit() {
+        // Cannot use mUserHalService because it's already set with supported properties
+        UserHalService myHalService = new UserHalService(mVehicleHal);
+
         VehiclePropConfig unsupportedConfig = newConfig(CURRENT_GEAR);
         VehiclePropConfig userInfoConfig = newSubscribableConfig(INITIAL_USER_INFO);
         List<VehiclePropConfig> input = Arrays.asList(unsupportedConfig, userInfoConfig);
-        Collection<VehiclePropConfig> output = mUserHalService.takeSupportedProperties(input);
+        Collection<VehiclePropConfig> output = myHalService.takeSupportedProperties(input);
+        assertThat(mUserHalService.isSupported()).isTrue();
         assertThat(output).containsExactly(userInfoConfig);
 
         // Ideally there should be 2 test methods (one for takeSupportedProperties() and one for
         // init()), but on "real life" VehicleHal calls these 2 methods in sequence, and the latter
         // depends on the properties set by the former, so it's ok to test both here...
-        mUserHalService.init();
-        verify(mVehicleHal).subscribeProperty(mUserHalService, INITIAL_USER_INFO);
+        myHalService.init();
+        verify(mVehicleHal).subscribeProperty(myHalService, INITIAL_USER_INFO);
     }
 
     @Test
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 3124a60..2e307b9 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
@@ -136,9 +136,8 @@
             .setGuest(true)
             .setEphemeral(true)
             .build();
-    private final UserInfo[] mExistingUsers = new UserInfo[] {
-            mSystemUser, mAdminUser, mGuestUser
-    };
+    private final List<UserInfo> mExistingUsers = Arrays.asList(mSystemUser, mAdminUser,
+            mGuestUser);
 
     /**
      * Initialize all of the objects with the @Mock annotation.
@@ -580,13 +579,12 @@
 
     @Test
     public void testGetUserInfo_defaultResponse() throws Exception {
-        int currentUserId = mAdminUser.id;
+        mockCurrentUsers(mAdminUser);
 
         mGetUserInfoResponse.action = InitialUserInfoResponseAction.DEFAULT;
-        mockGetInitialInfo(currentUserId, mGetUserInfoResponse);
+        mockGetInitialInfo(mAdminUser.id, mGetUserInfoResponse);
 
-        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs,
-                mExistingUsers, currentUserId, mReceiver);
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
 
         assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
         assertThat(mReceiver.getResultData()).isNull();
@@ -594,46 +592,56 @@
 
     @Test
     public void testGetUserInfo_switchUserResponse() throws Exception {
-        int currentUserId = mAdminUser.id;
         int switchUserId = mGuestUser.id;
+        mockCurrentUsers(mAdminUser);
 
         mGetUserInfoResponse.action = InitialUserInfoResponseAction.SWITCH;
         mGetUserInfoResponse.userToSwitchOrCreate.userId = switchUserId;
-        mockGetInitialInfo(currentUserId, mGetUserInfoResponse);
+        mockGetInitialInfo(mAdminUser.id, mGetUserInfoResponse);
 
-        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs,
-                mExistingUsers, currentUserId, mReceiver);
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
 
         assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
         Bundle resultData = mReceiver.getResultData();
         assertThat(resultData).isNotNull();
+        assertInitialInfoAction(resultData, mGetUserInfoResponse.action);
         assertUserId(resultData, switchUserId);
         assertNoUserFlags(resultData);
         assertNoUserName(resultData);
     }
 
+
     @Test
     public void testGetUserInfo_createUserResponse() throws Exception {
-        int currentUserId = mAdminUser.id;
         int newUserFlags = 42;
         String newUserName = "TheDude";
 
+        mockCurrentUsers(mAdminUser);
+
         mGetUserInfoResponse.action = InitialUserInfoResponseAction.CREATE;
         mGetUserInfoResponse.userToSwitchOrCreate.flags = newUserFlags;
         mGetUserInfoResponse.userNameToCreate = newUserName;
-        mockGetInitialInfo(currentUserId, mGetUserInfoResponse);
+        mockGetInitialInfo(mAdminUser.id, mGetUserInfoResponse);
 
-        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs,
-                mExistingUsers, currentUserId, mReceiver);
+        mCarUserService.getInitialUserInfo(mGetUserInfoRequestType, mAsyncCallTimeoutMs, mReceiver);
 
         assertThat(mReceiver.getResultCode()).isEqualTo(HalCallback.STATUS_OK);
         Bundle resultData = mReceiver.getResultData();
         assertThat(resultData).isNotNull();
+        assertInitialInfoAction(resultData, mGetUserInfoResponse.action);
         assertNoUserId(resultData);
         assertUserFlags(resultData, newUserFlags);
         assertUserName(resultData, newUserName);
     }
 
+    /**
+     * Mock calls that generate a {@code UsersInfo}.
+     */
+    private void mockCurrentUsers(@NonNull UserInfo user) throws Exception {
+        when(mMockedIActivityManager.getCurrentUser()).thenReturn(user);
+        when(mMockedUserManager.getUsers()).thenReturn(mExistingUsers);
+    }
+
     private void mockGetInitialInfo(@UserIdInt int currentUserId,
             @NonNull InitialUserInfoResponse response) {
         UsersInfo usersInfo = newUsersInfo(currentUserId);
@@ -651,7 +659,7 @@
     @NonNull
     private UsersInfo newUsersInfo(@UserIdInt int currentUserId) {
         UsersInfo infos = new UsersInfo();
-        infos.numberUsers = mExistingUsers.length;
+        infos.numberUsers = mExistingUsers.size();
         boolean foundCurrentUser = false;
         for (UserInfo info : mExistingUsers) {
             android.hardware.automotive.vehicle.V2_0.UserInfo existingUser =
@@ -718,6 +726,13 @@
         assertWithMessage("should not have extra %s", extra).that(value).isNull();
     }
 
+    private void assertInitialInfoAction(@NonNull Bundle resultData, int expectedAction) {
+        int actualAction = resultData.getInt(CarUserService.BUNDLE_INITIAL_INFO_ACTION);
+        assertWithMessage("wrong request type on bundle extra %s",
+                CarUserService.BUNDLE_INITIAL_INFO_ACTION).that(actualAction)
+            .isEqualTo(expectedAction);
+    }
+
     static final class FakeCarOccupantZoneService {
         private final SparseArray<Integer> mZoneUserMap = new SparseArray<Integer>();
         private final CarUserService.ZoneUserBindingHelper mZoneUserBindigHelper =