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 =