Merge "Do not use "system_*" colors" into sc-v2-dev
diff --git a/car-lib/src/android/car/ICarUserService.aidl b/car-lib/src/android/car/ICarUserService.aidl
index bee3bba..80a8e3d 100644
--- a/car-lib/src/android/car/ICarUserService.aidl
+++ b/car-lib/src/android/car/ICarUserService.aidl
@@ -30,7 +30,8 @@
     AndroidFuture<UserCreationResult> createDriver(@nullable String name, boolean admin);
     UserInfo createPassenger(@nullable String name, int driverId);
     void switchDriver(int driverId, in AndroidFuture<UserSwitchResult> receiver);
-    void switchUser(int tagerUserId, int timeoutMs, in AndroidFuture<UserSwitchResult> receiver);
+    void switchUser(int targetUserId, int timeoutMs, in AndroidFuture<UserSwitchResult> receiver);
+    void logoutUser(int timeoutMs, in AndroidFuture<UserSwitchResult> receiver);
     void setUserSwitchUiCallback(in IResultReceiver callback);
     void createUser(@nullable String name, String userType, int flags, int timeoutMs,
       in AndroidFuture<UserCreationResult> receiver);
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
index db1b6e6..cdf5c5a 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -378,6 +378,40 @@
         }
     }
 
+    /**
+     * Logouts the current user (if it was switched to by a device admin).
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
+    public AsyncFuture<UserSwitchResult> logoutUser() {
+        int uid = myUid();
+        try {
+            AndroidFuture<UserSwitchResult> future = new AndroidFuture<UserSwitchResult>() {
+                @Override
+                protected void onCompleted(UserSwitchResult result, Throwable err) {
+                    if (result != null) {
+                        EventLog.writeEvent(EventLogTags.CAR_USER_MGR_LOGOUT_USER_RESP, uid,
+                                result.getStatus(), result.getErrorMessage());
+                    } else {
+                        Log.w(TAG, "logoutUser() failed: " + err);
+                    }
+                    super.onCompleted(result, err);
+                }
+            };
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_LOGOUT_USER_REQ, uid);
+            mService.logoutUser(HAL_TIMEOUT_MS, future);
+            return new AndroidAsyncFuture<>(future);
+        } catch (SecurityException e) {
+            throw e;
+        } catch (RemoteException | RuntimeException e) {
+            AsyncFuture<UserSwitchResult> future =
+                    newSwitchResuiltForFailure(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+            return handleExceptionFromCarService(e, future);
+        }
+    }
+
     private AndroidAsyncFuture<UserSwitchResult> newSwitchResuiltForFailure(
             @UserSwitchResult.Status int status) {
         AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
diff --git a/car-lib/src/android/car/user/UserSwitchResult.java b/car-lib/src/android/car/user/UserSwitchResult.java
index 695511d..e0aadbc 100644
--- a/car-lib/src/android/car/user/UserSwitchResult.java
+++ b/car-lib/src/android/car/user/UserSwitchResult.java
@@ -96,6 +96,12 @@
             CommonResults.LAST_COMMON_STATUS + 4;
 
     /**
+     * When logout was called but the current user was not switched by a device admin.
+     */
+    public static final int STATUS_NOT_LOGGED_IN =
+            CommonResults.LAST_COMMON_STATUS + 5;
+
+    /**
      * Gets the user switch result status.
      *
      * @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
@@ -106,8 +112,9 @@
      *         {@link UserSwitchResult#STATUS_UX_RESTRICTION_FAILURE},
      *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
      *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
-     *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
-     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
+     *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST},
+     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}, or
+     *         {@link UserSwitchResult#STATUS_NOT_LOGGED_IN}.
      */
     private final @Status int mStatus;
 
@@ -124,8 +131,7 @@
 
 
 
-
-    // Code below generated by codegen v1.0.18.
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -149,7 +155,8 @@
         STATUS_OK_USER_ALREADY_IN_FOREGROUND,
         STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO,
         STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST,
-        STATUS_NOT_SWITCHABLE
+        STATUS_NOT_SWITCHABLE,
+        STATUS_NOT_LOGGED_IN
     })
     @Retention(RetentionPolicy.SOURCE)
     @DataClass.Generated.Member
@@ -179,6 +186,8 @@
                     return "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST";
             case STATUS_NOT_SWITCHABLE:
                     return "STATUS_NOT_SWITCHABLE";
+            case STATUS_NOT_LOGGED_IN:
+                    return "STATUS_NOT_LOGGED_IN";
             default: return Integer.toHexString(value);
         }
     }
@@ -197,8 +206,9 @@
      *           {@link UserSwitchResult#STATUS_UX_RESTRICTION_FAILURE},
      *           {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
      *           {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
-     *           {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
-     *           {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
+     *           {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST},
+     *           {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}, or
+     *           {@link UserSwitchResult#STATUS_NOT_LOGGED_IN}.
      * @param errorMessage
      *   Gets the error message, if any.
      * @hide
@@ -218,7 +228,8 @@
                 && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
                 && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
                 && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
-                && !(mStatus == STATUS_NOT_SWITCHABLE)) {
+                && !(mStatus == STATUS_NOT_SWITCHABLE)
+                && !(mStatus == STATUS_NOT_LOGGED_IN)) {
             throw new java.lang.IllegalArgumentException(
                     "status was " + mStatus + " but must be one of: "
                             + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
@@ -230,7 +241,8 @@
                             + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
                             + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
                             + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
-                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + ")");
+                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + "), "
+                            + "STATUS_NOT_LOGGED_IN(" + STATUS_NOT_LOGGED_IN + ")");
         }
 
         this.mErrorMessage = errorMessage;
@@ -249,8 +261,9 @@
      *         {@link UserSwitchResult#STATUS_UX_RESTRICTION_FAILURE},
      *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
      *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
-     *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
-     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
+     *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST},
+     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}, or
+     *         {@link UserSwitchResult#STATUS_NOT_LOGGED_IN}.
      */
     @DataClass.Generated.Member
     public @Status int getStatus() {
@@ -316,7 +329,8 @@
                 && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
                 && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
                 && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
-                && !(mStatus == STATUS_NOT_SWITCHABLE)) {
+                && !(mStatus == STATUS_NOT_SWITCHABLE)
+                && !(mStatus == STATUS_NOT_LOGGED_IN)) {
             throw new java.lang.IllegalArgumentException(
                     "status was " + mStatus + " but must be one of: "
                             + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
@@ -328,7 +342,8 @@
                             + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
                             + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
                             + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
-                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + ")");
+                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + "), "
+                            + "STATUS_NOT_LOGGED_IN(" + STATUS_NOT_LOGGED_IN + ")");
         }
 
         this.mErrorMessage = errorMessage;
@@ -351,10 +366,10 @@
     };
 
     @DataClass.Generated(
-            time = 1603921276651L,
-            codegenVersion = "1.0.18",
+            time = 1642629779623L,
+            codegenVersion = "1.0.23",
             sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserSwitchResult.java",
-            inputSignatures = "public static final  int STATUS_SUCCESSFUL\npublic static final  int STATUS_ANDROID_FAILURE\npublic static final  int STATUS_HAL_FAILURE\npublic static final  int STATUS_HAL_INTERNAL_FAILURE\npublic static final  int STATUS_INVALID_REQUEST\npublic static final  int STATUS_OK_USER_ALREADY_IN_FOREGROUND\npublic static final  int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO\npublic static final  int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST\npublic static final  int STATUS_NOT_SWITCHABLE\nprivate final @android.car.user.UserSwitchResult.Status int mStatus\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic @java.lang.Override boolean isSuccess()\nclass UserSwitchResult extends java.lang.Object implements [android.os.Parcelable, android.car.user.OperationResult]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+            inputSignatures = "public static final  int STATUS_SUCCESSFUL\npublic static final  int STATUS_ANDROID_FAILURE\npublic static final  int STATUS_HAL_FAILURE\npublic static final  int STATUS_HAL_INTERNAL_FAILURE\npublic static final  int STATUS_INVALID_REQUEST\npublic static final  int STATUS_UX_RESTRICTION_FAILURE\npublic static final  int STATUS_OK_USER_ALREADY_IN_FOREGROUND\npublic static final  int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO\npublic static final  int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST\npublic static final  int STATUS_NOT_SWITCHABLE\npublic static final  int STATUS_NOT_LOGGED_IN\nprivate final @android.car.user.UserSwitchResult.Status int mStatus\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic @java.lang.Override boolean isSuccess()\nclass UserSwitchResult extends java.lang.Object implements [android.os.Parcelable, android.car.user.OperationResult]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
index ce07e2b..2fe1a08 100644
--- a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
+++ b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
@@ -95,6 +95,8 @@
 150127 car_user_svc_stop_user_req (user_id|1)
 150128 car_user_svc_stop_user_resp (user_id|1),(result|1)
 150129 car_user_svc_initial_user_info_req_complete (request_type|1)
+150130 car_user_svc_logout_user_req (user_id|1),(timeout|1)
+150131 car_user_svc_logout_user_resp (hal_callback_status|1),(user_switch_status|1),(error_message|3)
 
 150140 car_user_hal_initial_user_info_req (request_id|1),(request_type|1),(timeout|1)
 150141 car_user_hal_initial_user_info_resp (request_id|1),(status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
@@ -126,6 +128,8 @@
 150183 car_user_mgr_remove_user_resp (uid|1),(status|1)
 150184 car_user_mgr_notify_lifecycle_listener (number_listeners|1),(event_type|1),(from_user_id|1),(to_user_id|1)
 150185 car_user_mgr_pre_create_user_req (uid|1)
+150186 car_user_mgr_logout_user_req (uid|1)
+150187 car_user_mgr_logout_user_resp (uid|1),(status|1),(error_message|3)
 
 #### Device policy related tags (range 150200 - 150299)
 150200 car_dp_mgr_remove_user_req (uid|1),(user_id|1)
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 29b1471..ce608ea 100644
--- a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
+++ b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
@@ -212,6 +212,15 @@
     }
 
     /**
+     * Mocks a call to {@code UserManager#mockUmHasUserRestrictionForUser(String, UserHandle)} that
+     * returns {@code value}.
+     */
+    public static void mockUmHasUserRestrictionForUser(@NonNull UserManager um,
+            @NonNull UserHandle user, @NonNull String restrictionKey, boolean value) {
+        when(um.hasUserRestrictionForUser(restrictionKey, user)).thenReturn(value);
+    }
+
+    /**
      * Mocks a call to {@link ServiceManager#getService(name)}.
      *
      * <p><b>Note: </b>it must be made inside a
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/Android.bp
new file mode 100644
index 0000000..1511086
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+android_app {
+    name: "CarUiPortraitMediaCommonRRO",
+    resource_dirs: ["res"],
+    platform_apis: true,
+    aaptflags: [
+        "--no-resource-deduping",
+        "--no-resource-removal"
+    ],
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/AndroidManifest.xml
new file mode 100644
index 0000000..e9dd47b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.media.common.caruiportrait.rro">
+    <application android:hasCode="false"/>
+    <overlay android:priority="20"
+             android:targetName="CarMediaCommon"
+             android:targetPackage="com.android.car.media"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true" />
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/res/values/config.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/res/values/config.xml
new file mode 100644
index 0000000..f83f442
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/res/values/config.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<resources>
+    <!-- Intent used to launch the app selector as popup.
+        This should be overlaid to match the actual launcher included in the car. -->
+    <string name="launcher_popup_intent" translatable="false">
+    </string>
+
+    <!-- Intent used to launch the app selector full screen.
+        This should be overlaid to match the actual launcher included in the car. -->
+    <string name="launcher_intent" translatable="false">
+    </string>
+
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..93f1f92
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaCommonRRO/res/xml/overlays.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<overlay>
+    <item target="string/launcher_popup_intent" value="@string/launcher_popup_intent"/>
+    <item target="string/launcher_intent" value="@string/launcher_intent"/>
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk b/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
index 5b06ed2..de7a46c 100644
--- a/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
+++ b/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
@@ -23,6 +23,7 @@
     CarUiPortraitDialerRRO \
     CarUiPortraitSettingsRRO \
     CarUiPortraitMediaRRO \
+    CarUiPortraitMediaCommonRRO \
     CarUiPortraitLauncherRRO \
     CarUiPortraitNotificationRRO \
     CarUiPortraitCarServiceRRO \
diff --git a/cpp/powerpolicy/server/src/PolicyManager.cpp b/cpp/powerpolicy/server/src/PolicyManager.cpp
index 2681f51..32366c5 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.cpp
+++ b/cpp/powerpolicy/server/src/PolicyManager.cpp
@@ -122,6 +122,7 @@
                                                                      PowerComponent::BLUETOOTH,
                                                                      PowerComponent::WIFI,
                                                                      PowerComponent::LOCATION,
+                                                                     PowerComponent::MICROPHONE,
                                                                      PowerComponent::CPU};
 const std::unordered_set<PowerComponent> kNoUserInteractionConfigurableComponents =
         {PowerComponent::BLUETOOTH, PowerComponent::NFC, PowerComponent::TRUSTED_DEVICE_DETECTION};
diff --git a/packages/CarManagedProvisioning/res/values/themes.xml b/packages/CarManagedProvisioning/res/values/themes.xml
index ba4337c..114272b 100644
--- a/packages/CarManagedProvisioning/res/values/themes.xml
+++ b/packages/CarManagedProvisioning/res/values/themes.xml
@@ -15,20 +15,7 @@
     limitations under the License.
 -->
 <resources>
-  <style name="Theme.CarManagedProvisioning" parent="Theme.Car.Dark.NoActionBar">
-    <!-- Explicitly set this attribute -->
-    <item name="android:textAllCaps">false</item>
-    <!-- TODO(b/204577686) Button style is not customizable -->
-    <item name="android:buttonStyle">@style/Button</item>
-    <item name="buttonStyle">@style/Button</item>
-    <item name="android:borderlessButtonStyle">@style/Button.Borderless</item>
-    <item name="borderlessButtonStyle">@style/Button.Borderless</item>
-
-  </style>
-  <style name="Button" parent="Widget.Car.Button.DarkText">
-    <item name="android:maxWidth">@dimen/primary_button_max_width</item>
-  </style>
-  <style name="Button.Borderless"
-      parent="Widget.Car.Button.Borderless.Colored">
+  <style name="Theme.CarManagedProvisioning"
+      parent="Theme.Car.SetupWizard.NoActionBar.Accent">
   </style>
 </resources>
\ No newline at end of file
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index d70151d..c973374 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -156,6 +156,7 @@
     private static final String COMMAND_INJECT_CUSTOM_INPUT = "inject-custom-input";
     private static final String COMMAND_GET_INITIAL_USER_INFO = "get-initial-user-info";
     private static final String COMMAND_SWITCH_USER = "switch-user";
+    private static final String COMMAND_LOGOUT_USER = "logout-user";
     private static final String COMMAND_REMOVE_USER = "remove-user";
     private static final String COMMAND_CREATE_USER = "create-user";
     private static final String COMMAND_GET_INITIAL_USER = "get-initial-user";
@@ -229,6 +230,8 @@
                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_SWITCH_USER,
                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
+        USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_LOGOUT_USER,
+                CREATE_OR_MANAGE_USERS_PERMISSIONS);
         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_REMOVE_USER,
                 CREATE_OR_MANAGE_USERS_PERMISSIONS);
         USER_BUILD_COMMAND_TO_PERMISSIONS_MAP.put(COMMAND_CREATE_USER,
@@ -547,6 +550,10 @@
         pw.println("\t  The --hal-only option only calls HAL, without switching the user,");
         pw.println("\t  while the --timeout defines how long to wait for the response.");
 
+        pw.printf("\t%s [--timeout TIMEOUT_MS]\n", COMMAND_LOGOUT_USER);
+        pw.println("\t  Logout the current user (if the user was switched toby a device admin).");
+        pw.println("\t  The --timeout option defines how long to wait for the UserHal response.");
+
         pw.printf("\t%s <USER_ID> [--hal-only]\n", COMMAND_REMOVE_USER);
         pw.println("\t  Removes user with USER_ID using the HAL integration.");
         pw.println("\t  The --hal-only option only calls HAL, without removing the user,");
@@ -936,6 +943,9 @@
             case COMMAND_SWITCH_USER:
                 switchUser(args, writer);
                 break;
+            case COMMAND_LOGOUT_USER:
+                logoutUser(args, writer);
+                break;
             case COMMAND_REMOVE_USER:
                 removeUser(args, writer);
                 break;
@@ -1453,6 +1463,12 @@
         }
         CarUserManager carUserManager = getCarUserManager(mContext);
         AsyncFuture<UserSwitchResult> future = carUserManager.switchUser(targetUserId);
+
+        showUserSwitchResult(writer, future, timeout);
+    }
+
+    private void showUserSwitchResult(IndentingPrintWriter writer,
+            AsyncFuture<UserSwitchResult> future, int timeout) {
         UserSwitchResult result = waitForFuture(writer, future, timeout);
         if (result == null) return;
         writer.printf("UserSwitchResult: status=%s",
@@ -1464,6 +1480,30 @@
         writer.println();
     }
 
+    private void logoutUser(String[] args, IndentingPrintWriter writer) {
+        int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
+
+        if (args.length > 1) {
+            for (int i = 1; i < args.length; i++) {
+                String arg = args[i];
+                switch (arg) {
+                    case "--timeout":
+                        timeout = Integer.parseInt(args[++i]);
+                        break;
+                    default:
+                        writer.println("Invalid option at index " + i + ": " + arg);
+                        return;
+                }
+            }
+        }
+
+        Slog.d(TAG, "logoutUser(): timeout=" + timeout);
+
+        CarUserManager carUserManager = getCarUserManager(mContext);
+        AsyncFuture<UserSwitchResult> future = carUserManager.logoutUser();
+        showUserSwitchResult(writer, future, timeout);
+    }
+
     private void createUser(String[] args, IndentingPrintWriter writer) {
         int timeout = DEFAULT_HAL_TIMEOUT_MS + DEFAULT_CAR_USER_SERVICE_TIMEOUT_MS;
         int flags = 0;
diff --git a/service/src/com/android/car/power/PolicyReader.java b/service/src/com/android/car/power/PolicyReader.java
index afd8648..5bdd885 100644
--- a/service/src/com/android/car/power/PolicyReader.java
+++ b/service/src/com/android/car/power/PolicyReader.java
@@ -123,7 +123,7 @@
             PowerComponent.TRUSTED_DEVICE_DETECTION));
     private static final int[] SUSPEND_TO_RAM_DISABLED_COMPONENTS = {
             PowerComponent.AUDIO, PowerComponent.BLUETOOTH, PowerComponent.WIFI,
-            PowerComponent.LOCATION
+            PowerComponent.LOCATION, PowerComponent.MICROPHONE, PowerComponent.CPU
     };
     private static final CarPowerPolicy POWER_POLICY_ALL_ON;
     private static final CarPowerPolicy POWER_POLICY_INITIAL_ON;
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 54d4d07..a13c971 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -31,6 +31,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
 import android.car.CarOccupantZoneManager;
 import android.car.CarOccupantZoneManager.OccupantTypeEnum;
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
@@ -164,6 +165,7 @@
     private final Context mContext;
     private final IActivityManager mAm;
     private final UserManager mUserManager;
+    private final DevicePolicyManager mDpm;
     private final int mMaxRunningUsers;
     private final InitialUserSetter mInitialUserSetter;
     private final boolean mEnablePassengerSupport;
@@ -302,14 +304,14 @@
             @NonNull UserManager userManager,
             @NonNull IActivityManager am, int maxRunningUsers,
             @NonNull CarUxRestrictionsManagerService uxRestrictionService) {
-        this(context, hal, userManager, am, maxRunningUsers,
-                /* initialUserSetter= */ null, /* userPreCreator= */ null, uxRestrictionService,
-                null);
+        this(context, hal, userManager, context.getSystemService(DevicePolicyManager.class), am,
+                maxRunningUsers, /* initialUserSetter= */ null, /* userPreCreator= */ null,
+                uxRestrictionService, /* handler= */null);
     }
 
     @VisibleForTesting
     CarUserService(@NonNull Context context, @NonNull UserHalService hal,
-            @NonNull UserManager userManager,
+            @NonNull UserManager userManager, @NonNull DevicePolicyManager dpm,
             @NonNull IActivityManager am, int maxRunningUsers,
             @Nullable InitialUserSetter initialUserSetter,
             @Nullable UserPreCreator userPreCreator,
@@ -323,6 +325,7 @@
         mAm = am;
         mMaxRunningUsers = maxRunningUsers;
         mUserManager = userManager;
+        mDpm = dpm;
         mLastPassengerId = UserHandle.USER_NULL;
         mHandler = handler == null ? new Handler(mHandlerThread.getLooper()) : handler;
         mInitialUserSetter =
@@ -562,13 +565,15 @@
         if (UserHelperLite.isHeadlessSystemUser(driverId)) {
             // System user doesn't associate with real person, can not be switched to.
             Slog.w(TAG, "switching to system user in headless system user mode is not allowed");
-            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
+            sendUserSwitchResult(receiver, EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP,
+                    UserSwitchResult.STATUS_INVALID_REQUEST);
             return;
         }
         int userSwitchable = mUserManager.getUserSwitchability();
         if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
             Slog.w(TAG, "current process is not allowed to switch user");
-            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_INVALID_REQUEST);
+            sendUserSwitchResult(receiver, EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP,
+                    UserSwitchResult.STATUS_INVALID_REQUEST);
             return;
         }
         switchUser(driverId, mHalTimeoutMs, receiver);
@@ -1064,14 +1069,47 @@
         UserInfo targetUser = mUserManager.getUserInfo(targetUserId);
         Preconditions.checkArgument(targetUser != null, "Target user doesn't exist");
         if (mUserManager.getUserSwitchability() != UserManager.SWITCHABILITY_STATUS_OK) {
-            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_NOT_SWITCHABLE);
+            sendUserSwitchResult(receiver, EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP,
+                    UserSwitchResult.STATUS_NOT_SWITCHABLE);
             return;
         }
-        mHandler.post(() -> handleSwitchUser(targetUser, timeoutMs, receiver));
+        mHandler.post(() -> handleSwitchUser(targetUser, timeoutMs, receiver,
+                /* isLogout= */ false));
+    }
+
+    @Override
+    public void logoutUser(int timeoutMs, @NonNull AndroidFuture<UserSwitchResult> receiver) {
+        checkManageOrCreateUsersPermission("logoutUser");
+        Objects.requireNonNull(receiver);
+
+        int logoutUserId = mDpm.getLogoutUserId();
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_LOGOUT_USER_REQ, logoutUserId, timeoutMs);
+
+        if (logoutUserId == UserHandle.USER_NULL) {
+            Slog.w(TAG, "logoutUser() called when current user is not logged in");
+            sendUserSwitchResult(receiver, EventLogTags.CAR_USER_SVC_LOGOUT_USER_RESP,
+                    UserSwitchResult.STATUS_NOT_LOGGED_IN);
+            return;
+        }
+
+        UserInfo targetUser = mUserManager.getUserInfo(logoutUserId);
+        if (targetUser == null) {
+            // It shouldn't happen, but according to the Law of Descartes-Murphy:
+            //    "I shouldn't, therefore I will!"
+            Slog.wtf(TAG, "logout failed because user " + logoutUserId + " doesn't exist");
+            sendUserSwitchResult(receiver, EventLogTags.CAR_USER_SVC_LOGOUT_USER_RESP,
+                    UserSwitchResult.STATUS_ANDROID_FAILURE);
+            return;
+        }
+
+        mHandler.post(() -> handleSwitchUser(targetUser, timeoutMs, receiver,
+                /* isLogout= */ true));
     }
 
     private void handleSwitchUser(@NonNull UserInfo targetUser, int timeoutMs,
-            @NonNull AndroidFuture<UserSwitchResult> receiver) {
+            @NonNull AndroidFuture<UserSwitchResult> receiver, boolean isLogout) {
+        int eventLogTag = isLogout ? EventLogTags.CAR_USER_SVC_LOGOUT_USER_RESP
+                : EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP;
         int currentUser = ActivityManager.getCurrentUser();
         int targetUserId = targetUser.id;
         if (currentUser == targetUserId) {
@@ -1079,12 +1117,13 @@
                 Slog.d(TAG, "Current user is same as requested target user: " + targetUserId);
             }
             int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
-            sendUserSwitchResult(receiver, resultStatus);
+            sendUserSwitchResult(receiver, eventLogTag, resultStatus);
             return;
         }
 
         if (isUxRestricted()) {
-            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
+            sendUserSwitchResult(receiver, eventLogTag,
+                    UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
             return;
         }
 
@@ -1092,20 +1131,23 @@
         if (!isUserHalSupported()) {
             try {
                 if (mAm.switchUser(targetUserId)) {
-                    sendUserSwitchResult(receiver, UserSwitchResult.STATUS_SUCCESSFUL);
+                    sendUserSwitchResult(receiver, eventLogTag, UserSwitchResult.STATUS_SUCCESSFUL);
+                    clearLogoutUserIfNeeded(isLogout);
                     return;
                 }
             } catch (RemoteException e) {
                 // ignore
                 Slog.w(TAG, "error while switching user " + targetUser.toFullString(), e);
             }
-            sendUserSwitchResult(receiver, UserSwitchResult.STATUS_ANDROID_FAILURE);
+            Slog.w(TAG, "failed to switch to user " + targetUser.toFullString() + " using AM");
+            sendUserSwitchResult(receiver, eventLogTag, UserSwitchResult.STATUS_ANDROID_FAILURE);
             return;
         }
 
         synchronized (mLockUser) {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Slog.d(TAG, "switchUser(" + targetUserId + "): currentuser=" + currentUser
+                Slog.d(TAG, "handleSwitchUser(" + targetUserId + "): currentuser=" + currentUser
+                        + ", isLogout=" + isLogout
                         + ", mUserIdForUserSwitchInProcess=" + mUserIdForUserSwitchInProcess);
             }
 
@@ -1122,7 +1164,7 @@
                 }
 
                 int resultStatus = UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO;
-                sendUserSwitchResult(receiver, resultStatus);
+                sendUserSwitchResult(receiver, eventLogTag, resultStatus);
                 return;
             } else {
                 mUserIdForUserSwitchInProcess = targetUserId;
@@ -1133,6 +1175,9 @@
         UsersInfo usersInfo = UserHalHelper.newUsersInfo(mUserManager);
         SwitchUserRequest request = createUserSwitchRequest(targetUserId, usersInfo);
 
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Slog.d(TAG, "calling mHal.switchUser(" + request + ")");
+        }
         mHal.switchUser(request, timeoutMs, (halCallbackStatus, resp) -> {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Slog.d(TAG, "switch response: status="
@@ -1147,7 +1192,7 @@
                     Slog.w(TAG, "invalid callback status ("
                             + UserHalHelper.halCallbackStatusToString(halCallbackStatus)
                             + ") for response " + resp);
-                    sendUserSwitchResult(receiver, resultStatus);
+                    sendUserSwitchResult(receiver, eventLogTag, resultStatus);
                     mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
                     return;
                 }
@@ -1162,7 +1207,7 @@
                     }
                     resultStatus =
                             UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST;
-                    sendUserSwitchResult(receiver, resultStatus);
+                    sendUserSwitchResult(receiver, eventLogTag, resultStatus);
                     mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
                     return;
                 }
@@ -1175,6 +1220,7 @@
                             if (switched) {
                                 sendUserSwitchUiCallback(targetUserId);
                                 resultStatus = UserSwitchResult.STATUS_SUCCESSFUL;
+                                clearLogoutUserIfNeeded(isLogout);
                                 mRequestIdForUserSwitchInProcess = resp.requestId;
                             } else {
                                 resultStatus = UserSwitchResult.STATUS_ANDROID_FAILURE;
@@ -1199,10 +1245,20 @@
                     mUserIdForUserSwitchInProcess = UserHandle.USER_NULL;
                 }
             }
-            sendUserSwitchResult(receiver, halCallbackStatus, resultStatus, resp.errorMessage);
+            sendUserSwitchResult(receiver, eventLogTag, halCallbackStatus, resultStatus,
+                    resp.errorMessage);
         });
     }
 
+    private void clearLogoutUserIfNeeded(boolean isLogout) {
+        if (!isLogout) return;
+
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Slog.d(TAG, "Calling DPM to clear logout user");
+        }
+        mDpm.clearLogoutUser();
+    }
+
     @Override
     public void removeUser(@UserIdInt int userId, AndroidFuture<UserRemovalResult> receiver) {
         removeUser(userId, /* hasCallerRestrictions= */ false, receiver);
@@ -1404,15 +1460,23 @@
         EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ,
                 UserHelperLite.safeName(name), userType, flags, timeoutMs,
                 hasCallerRestrictions ? 1 : 0);
-        mHandler.post(() -> handleCreateUser(name, userType, flags, timeoutMs, receiver,
-                hasCallerRestrictions));
 
+        UserHandle callingUser = Binder.getCallingUserHandle();
+        if (mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_ADD_USER, callingUser)) {
+            Slogf.w(TAG, "Cannot create user because calling user %s has the '%s' restriction",
+                    callingUser, UserManager.DISALLOW_ADD_USER);
+            sendUserCreationResultFailure(receiver, UserCreationResult.STATUS_ANDROID_FAILURE);
+            return;
+        }
+
+        mHandler.post(() -> handleCreateUser(name, userType, flags, timeoutMs, receiver,
+                callingUser.getIdentifier(), hasCallerRestrictions));
     }
 
     private void handleCreateUser(@Nullable String name, @NonNull String userType,
             @UserInfoFlag int flags, int timeoutMs,
             @NonNull AndroidFuture<UserCreationResult> receiver,
-            boolean hasCallerRestrictions) {
+            @UserIdInt int callingUserId, boolean hasCallerRestrictions) {
         if (hasCallerRestrictions) {
             // Restrictions:
             // - type/flag can only be normal user, admin, or guest
@@ -1441,7 +1505,6 @@
 
             }
 
-            int callingUserId = Binder.getCallingUserHandle().getIdentifier();
             UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
             if (!callingUser.isAdmin() && (flags & UserInfo.FLAG_ADMIN) == UserInfo.FLAG_ADMIN) {
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -1688,20 +1751,18 @@
     }
 
     private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
-            @UserSwitchResult.Status int userSwitchStatus) {
-        sendUserSwitchResult(receiver, HalCallback.STATUS_INVALID, userSwitchStatus,
+            int eventLogTag, @UserSwitchResult.Status int userSwitchStatus) {
+        sendUserSwitchResult(receiver, HalCallback.STATUS_INVALID, eventLogTag, userSwitchStatus,
                 /* errorMessage= */ null);
     }
 
     private void sendUserSwitchResult(@NonNull AndroidFuture<UserSwitchResult> receiver,
-            @HalCallback.HalCallbackStatus int halCallbackStatus,
+            int eventLogTag, @HalCallback.HalCallbackStatus int halCallbackStatus,
             @UserSwitchResult.Status int userSwitchStatus, @Nullable String errorMessage) {
         if (errorMessage != null) {
-            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, halCallbackStatus,
-                    userSwitchStatus, errorMessage);
+            EventLog.writeEvent(eventLogTag, halCallbackStatus, userSwitchStatus, errorMessage);
         } else {
-            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SWITCH_USER_RESP, halCallbackStatus,
-                    userSwitchStatus);
+            EventLog.writeEvent(eventLogTag, halCallbackStatus, userSwitchStatus);
         }
         receiver.complete(new UserSwitchResult(userSwitchStatus, errorMessage));
     }
@@ -2245,8 +2306,7 @@
         TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
         t.traceBegin("onUserSwitching-" + toUserId);
 
-        // Switch HAL users if user switch is not requested by CarUserService
-        notifyHalLegacySwitch(fromUserId, toUserId);
+        notifyLegacyUserSwitch(fromUserId, toUserId);
 
         mInitialUserSetter.setLastActiveUser(toUserId);
 
@@ -2260,17 +2320,24 @@
         t.traceEnd();
     }
 
-    private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
+    private void notifyLegacyUserSwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
         synchronized (mLockUser) {
             if (mUserIdForUserSwitchInProcess != UserHandle.USER_NULL) {
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Slog.d(TAG, "notifyHalLegacySwitch(" + fromUserId + ", " + toUserId
+                    Slogf.d(TAG, "notifyLegacyUserSwitch(" + fromUserId + ", " + toUserId
                             + "): not needed, normal switch for " + mUserIdForUserSwitchInProcess);
                 }
                 return;
             }
         }
 
+        sendUserSwitchUiCallback(toUserId);
+
+        // Switch HAL users if user switch is not requested by CarUserService
+        notifyHalLegacySwitch(fromUserId, toUserId);
+    }
+
+    private void notifyHalLegacySwitch(@UserIdInt int fromUserId, @UserIdInt int toUserId) {
         if (!isUserHalSupported()) return;
 
         // switch HAL user
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/device_policy.xml b/tests/EmbeddedKitchenSinkApp/res/layout/device_policy.xml
index fdb29fa..6c6600d 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/device_policy.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/device_policy.xml
@@ -13,182 +13,178 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
-    <ScrollView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+    android:orientation="vertical">
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:orientation="vertical" >
+
         <!--  Current user info -->
-        <LinearLayout
-            android:layout_width="match_parent"
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="Current User"/>
+        <com.google.android.car.kitchensink.users.UserInfoView
+            android:id="@+id/current_user"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+
+        <!--  Existing users... -->
+        <com.google.android.car.kitchensink.users.ExistingUsersView
+            android:layout_marginTop="80dp"
+            android:id="@+id/current_users"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <!--  ...and actions on them -->
+        <LinearLayout android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:orientation="vertical" >
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" android:text="Current User"/>
-            <com.google.android.car.kitchensink.users.UserInfoView
-                android:id="@+id/current_user"
-                android:layout_width="wrap_content" android:layout_height="wrap_content"/>
-
-            <!--  Existing users... -->
-            <com.google.android.car.kitchensink.users.ExistingUsersView
-                android:layout_marginTop="80dp"
-                android:id="@+id/current_users"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-
-            <!--  ...and actions on them -->
-            <LinearLayout android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-                <Button
-                    android:id="@+id/remove_user"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Remove"/>
-                <Button
-                    android:id="@+id/start_user_in_background"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Start In Background"/>
-                <Button
-                    android:id="@+id/stop_user"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Stop"/>
-            </LinearLayout>
-
-            <!-- New user section -->
-            <TextView
-                android:layout_marginTop="80dp"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" android:text="New User"/>
-            <LinearLayout android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content" android:text="Name: "/>
-                <EditText
-                    android:id="@+id/new_user_name"
-                    android:layout_width="150dp"
-                    android:layout_height="wrap_content"
-                    android:maxLength="25"
-                    android:text=""/>
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content" android:text="Is admin? "/>
-                <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
-                    android:id="@+id/new_user_is_admin"/>
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content" android:text="Is guest? "/>
-                <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
-                    android:id="@+id/new_user_is_guest"/>
-            </LinearLayout>
-            <LinearLayout android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-                <Button
-                    android:id="@+id/create_user"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content" android:text="Create"/>
-            </LinearLayout>
-
-            <!-- Non user-related actions -->
-            <TextView
-                android:layout_marginTop="80dp"
+            android:orientation="horizontal" >
+            <Button
+                android:id="@+id/remove_user"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:text="Other actions"/>
-            <LinearLayout android:layout_width="match_parent"
+                android:text="Remove"/>
+            <Button
+                android:id="@+id/start_user_in_background"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Password"/>
-                <EditText
-                    android:id="@+id/password"
-                    android:layout_width="150dp"
-                    android:layout_height="wrap_content"
-                    android:maxLength="10"
-                    android:text=""/>
-                <Button
-                    android:id="@+id/reset_password"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Reset"/>
-                <Button
-                    android:id="@+id/lock_now"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Lock Now"/>
-            </LinearLayout>
-
-            <LinearLayout android:layout_width="match_parent"
+                android:text="Start In Background"/>
+            <Button
+                android:id="@+id/stop_user"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Wipe data"/>
-                <EditText
-                    android:id="@+id/wipe_data_flags"
-                    android:layout_width="150dp"
-                    android:layout_height="wrap_content"
-                    android:maxLength="10"
-                    android:text=""/>
-                <Button
-                    android:id="@+id/wipe_data"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Do it"/>
-            </LinearLayout>
-
-            <LinearLayout android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Lock tasks"/>
-                <Button
-                    android:id="@+id/check_lock_tasks"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Check"/>
-                <Button
-                    android:id="@+id/start_lock_tasks"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Start"/>
-                <Button
-                    android:id="@+id/stop_lock_tasks"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Stop"/>
-            </LinearLayout>
-
-            <LinearLayout android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal" >
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Add admin"/>
-                <Spinner
-                    android:id="@+id/device_admin_apps"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"/>
-                <Button
-                    android:id="@+id/set_device_admin_app"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Set"/>
-            </LinearLayout>
+                android:text="Stop"/>
         </LinearLayout>
-    </ScrollView>
-</LinearLayout>
+
+        <!-- New user section -->
+        <TextView
+            android:layout_marginTop="80dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:text="New User"/>
+        <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Name: "/>
+            <EditText
+                android:id="@+id/new_user_name"
+                android:layout_width="150dp"
+                android:layout_height="wrap_content"
+                android:maxLength="25"
+                android:text=""/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Is admin? "/>
+            <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:id="@+id/new_user_is_admin"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Is guest? "/>
+            <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:id="@+id/new_user_is_guest"/>
+        </LinearLayout>
+        <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <Button
+                android:id="@+id/create_user"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Create"/>
+        </LinearLayout>
+
+        <!-- Non user-related actions -->
+        <TextView
+            android:layout_marginTop="80dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Other actions"/>
+        <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Password"/>
+            <EditText
+                android:id="@+id/password"
+                android:layout_width="150dp"
+                android:layout_height="wrap_content"
+                android:maxLength="10"
+                android:text=""/>
+            <Button
+                android:id="@+id/reset_password"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Reset"/>
+            <Button
+                android:id="@+id/lock_now"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Lock Now"/>
+        </LinearLayout>
+
+        <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Wipe data"/>
+            <EditText
+                android:id="@+id/wipe_data_flags"
+                android:layout_width="150dp"
+                android:layout_height="wrap_content"
+                android:maxLength="10"
+                android:text=""/>
+            <Button
+                android:id="@+id/wipe_data"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Do it"/>
+        </LinearLayout>
+
+        <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Lock tasks"/>
+            <Button
+                android:id="@+id/check_lock_tasks"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Check"/>
+            <Button
+                android:id="@+id/start_lock_tasks"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Start"/>
+            <Button
+                android:id="@+id/stop_lock_tasks"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Stop"/>
+        </LinearLayout>
+
+        <LinearLayout android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Add admin"/>
+            <Spinner
+                android:id="@+id/device_admin_apps"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+            <Button
+                android:id="@+id/set_device_admin_app"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Set"/>
+        </LinearLayout>
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/user.xml b/tests/EmbeddedKitchenSinkApp/res/layout/user.xml
index 3707bc4..2a97de7 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/user.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/user.xml
@@ -13,112 +13,123 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical" >
-
-    <!--  Current user info -->
+<!--
     <ScrollView
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content" android:text="Current User"/>
-    <com.google.android.car.kitchensink.users.UserInfoView
-        android:id="@+id/current_user"
-        android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+        android:layout_height="wrap_content">
+-->
 
-    <!--  Actions on current user -->
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:orientation="horizontal">
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Is admin? "/>
-        <CheckBox
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/is_admin"/>
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Associate Key Fob?"/>
-        <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
-              android:id="@+id/is_associated_key_fob"/>
-    </LinearLayout>
-
-    <!--  Existing users... -->
-    <com.google.android.car.kitchensink.users.ExistingUsersView
-        android:layout_marginTop="80dp"
-        android:id="@+id/current_users"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-
-    <!--  ...and actions on them -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
     <LinearLayout android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:orientation="horizontal" >
-        <Button
-            android:id="@+id/switch_user"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Switch"/>
-        <Button
-            android:id="@+id/remove_user"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Remove"/>
-        <Button
-            android:id="@+id/lock_user_data"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Lock Data"/>
-    </LinearLayout>
+                  android:layout_height="match_parent"
+                  android:orientation="vertical" >
 
-    <!-- New user section -->
-    <TextView
-        android:layout_marginTop="80dp"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" android:text="New User"/>
-    <LinearLayout android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:orientation="horizontal" >
+        <!--  Current user info -->
         <TextView
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:text="Name: "/>
-        <EditText
-            android:id="@+id/new_user_name"
-            android:layout_width="150dp"
             android:layout_height="wrap_content"
-            android:maxLength="25"
-            android:text=""/>
-        <TextView
+            android:text="Current User "/>
+        <com.google.android.car.kitchensink.users.UserInfoView
+            android:id="@+id/current_user"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"/>
+
+        <!--  Actions on current user -->
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Is admin? "/>
+            <CheckBox
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/is_admin"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Associate Key Fob?"/>
+            <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:id="@+id/is_associated_key_fob"/>
+        </LinearLayout>
+
+        <!--  Existing users... -->
+        <com.google.android.car.kitchensink.users.ExistingUsersView
+            android:layout_marginTop="80dp"
+            android:id="@+id/current_users"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:text="Is admin? "/>
-        <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
-              android:id="@+id/new_user_is_admin"/>
+            android:layout_height="wrap_content" />
+
+        <!--  ...and actions on them -->
+        <LinearLayout android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal" >
+            <Button
+                android:id="@+id/switch_user"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Switch"/>
+            <Button
+                android:id="@+id/remove_user"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Remove"/>
+            <Button
+                android:id="@+id/lock_user_data"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Lock Data"/>
+        </LinearLayout>
+
+        <!-- New user section -->
         <TextView
+            android:layout_marginTop="80dp"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:text="Is guest? "/>
-        <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
-              android:id="@+id/new_user_is_guest"/>
+            android:layout_height="wrap_content" android:text="New User"/>
+        <LinearLayout android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Name: "/>
+            <EditText
+                android:id="@+id/new_user_name"
+                android:layout_width="150dp"
+                android:layout_height="wrap_content"
+                android:maxLength="25"
+                android:text=""/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Is admin? "/>
+            <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:id="@+id/new_user_is_admin"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Is guest? "/>
+            <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:id="@+id/new_user_is_guest"/>
+        </LinearLayout>
+        <LinearLayout android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Extra flags: "/>
+            <EditText
+                android:id="@+id/new_user_flags"
+                android:layout_width="30dp"
+                android:layout_height="wrap_content"
+                android:maxLength="3"
+                android:inputType="numberDecimal"
+                android:text=""/>
+            <Button
+                android:id="@+id/create_user"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" android:text="Create"/>
+        </LinearLayout>
+
     </LinearLayout>
-    <LinearLayout android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:orientation="horizontal" >
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:text="Extra flags: "/>
-        <EditText
-            android:id="@+id/new_user_flags"
-            android:layout_width="30dp"
-            android:layout_height="wrap_content"
-            android:maxLength="3"
-            android:inputType="numberDecimal"
-            android:text=""/>
-        <Button
-            android:id="@+id/create_user"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:text="Create"/>
-    </LinearLayout>
-</LinearLayout>
+</ScrollView>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/user_restrictions.xml b/tests/EmbeddedKitchenSinkApp/res/layout/user_restrictions.xml
index 3c57e71..210fb86 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/user_restrictions.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/user_restrictions.xml
@@ -17,12 +17,6 @@
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:orientation="vertical" >
-    <ListView
-        android:id="@+id/user_restrictions_list"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:scrollbars="vertical"/>
-
     <Button
         android:id="@+id/apply_button"
         android:layout_width="wrap_content"
@@ -30,4 +24,9 @@
         android:padding="@dimen/users_button_padding"
         android:textSize="@dimen/users_button_text_size"
         android:text="@string/users_apply_button" />
+    <ListView
+        android:id="@+id/user_restrictions_list"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scrollbars="vertical"/>
 </LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java
index 1ce98d0..4e8a3e0 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/users/UserRestrictionsFragment.java
@@ -31,6 +31,7 @@
 
 import com.google.android.car.kitchensink.R;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -83,17 +84,27 @@
             UserManager userManager = getUserManager();
 
             // Iterate through all of the user restrictions and set their values
+            List<String> restrictions = new ArrayList<>(count);
             for (int i = 0; i < count; i++) {
                 UserRestrictionListItem item = (UserRestrictionListItem) adapter.getItem(i);
-                userManager.setUserRestriction(item.getKey(), item.getIsChecked());
+                String restriction = item.getKey();
+                boolean added = item.getIsChecked();
+                userManager.setUserRestriction(restriction, added);
+                if (added) {
+                    restrictions.add(restriction);
+                }
             }
-
-            Toast.makeText(
-                    getContext(), "User restrictions have been set!", Toast.LENGTH_SHORT)
-                    .show();
+            toast("%d restrictions (%s) have been set on user %d!", restrictions.size(),
+                    restrictions, getContext().getUserId());
         });
     }
 
+    private void toast(String format, Object...args) {
+        String msg = String.format(format, args);
+        Log.i(TAG, msg);
+        Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
+    }
+
     private List<UserRestrictionListItem> createUserRestrictionItems() {
         int userId = getContext().getUserId();
         UserHandle user = UserHandle.of(userId);
diff --git a/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java b/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
index b495220..c824df7 100644
--- a/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/test/mocks/AndroidMockitoHelperTest.java
@@ -26,6 +26,7 @@
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetSystemUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserHandles;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserInfo;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmHasUserRestrictionForUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsHeadlessSystemUserMode;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmIsUserRunning;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmRemoveUserOrSetEphemeral;
@@ -62,6 +63,8 @@
 
     private static final int TEST_USER_ID = 100;
 
+    private final UserHandle mTestUserHandle = UserHandle.of(TEST_USER_ID);
+
     private UserInfo mTestUser;
 
     private StaticMockitoSession mMockSession;
@@ -208,6 +211,16 @@
         assertThat(visitor.mVisited).isEqualTo(mTestUser);
     }
 
+    @Test
+    public void testMockUmHasUserRestrictionForUser() {
+        VisitorImpl<UserInfo> visitor = new VisitorImpl<>();
+        mockUmHasUserRestrictionForUser(mMockedUserManager, mTestUserHandle, "no_Homers_club",
+                /* value= */ true);
+
+        assertThat(mMockedUserManager.hasUserRestrictionForUser("no_Homers_club", mTestUserHandle))
+                .isTrue();
+    }
+
     private static final class VisitorImpl<T> implements Visitor<T> {
 
         T mVisited;
diff --git a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
index b9501be..c850e2f 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
@@ -66,6 +66,7 @@
     private static final String POLICY_GROUP_ID_MIXED = "mixed_policy_group";
     private static final String NO_USER_INTERACTION_POLICY_ID =
             "system_power_policy_no_user_interaction";
+    private static final String SUSPEND_TO_RAM_POLICY_ID = "system_power_policy_suspend_to_ram";
 
     private static final CarPowerPolicy POLICY_OTHER_OFF = new CarPowerPolicy(POLICY_ID_OTHER_OFF,
             new int[]{WIFI},
@@ -94,6 +95,10 @@
                     new int[]{BLUETOOTH, WIFI, CELLULAR, ETHERNET, NFC, CPU},
                     new int[]{AUDIO, MEDIA, DISPLAY, PROJECTION, INPUT, VOICE_INTERACTION,
                             VISUAL_INTERACTION, TRUSTED_DEVICE_DETECTION, LOCATION, MICROPHONE});
+    private static final CarPowerPolicy SYSTEM_POWER_POLICY_SUSPEND_TO_RAM =
+            new CarPowerPolicy(SUSPEND_TO_RAM_POLICY_ID,
+                    new int[]{},
+                    new int[]{AUDIO, BLUETOOTH, WIFI, LOCATION, MICROPHONE, CPU});
 
     private final Resources mResources =
             InstrumentationRegistry.getInstrumentation().getTargetContext().getResources();
@@ -107,7 +112,13 @@
 
     @Test
     public void testSystemPowerPolicyNoUserInteraction() throws Exception {
-        assertSystemPowerPolicy(SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
+        assertSystemPowerPolicy(NO_USER_INTERACTION_POLICY_ID,
+                SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
+    }
+
+    @Test
+    public void testSystemPowerPolicySuspendToRam() throws Exception {
+        assertSystemPowerPolicy(SUSPEND_TO_RAM_POLICY_ID, SYSTEM_POWER_POLICY_SUSPEND_TO_RAM);
     }
 
     @Test
@@ -115,8 +126,7 @@
         readPowerPolicyXml(R.raw.valid_power_policy);
 
         assertValidPolicyPart();
-        assertValidPolicyPart();
-        assertSystemPowerPolicy(SYSTEM_POWER_POLICY_MODIFIED);
+        assertSystemPowerPolicy(NO_USER_INTERACTION_POLICY_ID, SYSTEM_POWER_POLICY_MODIFIED);
     }
 
     @Test
@@ -125,7 +135,7 @@
 
         assertValidPolicyPart();
         assertNoPolicyGroupPart();
-        assertSystemPowerPolicy(SYSTEM_POWER_POLICY_MODIFIED);
+        assertSystemPowerPolicy(NO_USER_INTERACTION_POLICY_ID, SYSTEM_POWER_POLICY_MODIFIED);
     }
 
     @Test
@@ -134,7 +144,8 @@
 
         assertValidPolicyPart();
         assertValidPolicyGroupPart();
-        assertSystemPowerPolicy(SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
+        assertSystemPowerPolicy(NO_USER_INTERACTION_POLICY_ID,
+                SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
     }
 
     @Test
@@ -143,7 +154,8 @@
 
         assertValidPolicyPart();
         assertNoPolicyGroupPart();
-        assertSystemPowerPolicy(SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
+        assertSystemPowerPolicy(NO_USER_INTERACTION_POLICY_ID,
+                SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
     }
 
     @Test
@@ -152,7 +164,7 @@
 
         assertNoPolicyPart();
         assertNoPolicyGroupPart();
-        assertSystemPowerPolicy(SYSTEM_POWER_POLICY_MODIFIED);
+        assertSystemPowerPolicy(NO_USER_INTERACTION_POLICY_ID, SYSTEM_POWER_POLICY_MODIFIED);
     }
 
     @Test
@@ -241,9 +253,9 @@
                 VehicleApPowerStateReport.ON)).isNull();
     }
 
-    private void assertSystemPowerPolicy(CarPowerPolicy expectedSystemPolicy) throws Exception {
-        CarPowerPolicy systemPolicy = mPolicyReader.getPreemptivePowerPolicy(
-                NO_USER_INTERACTION_POLICY_ID);
+    private void assertSystemPowerPolicy(String policyId, CarPowerPolicy expectedSystemPolicy)
+            throws Exception {
+        CarPowerPolicy systemPolicy = mPolicyReader.getPreemptivePowerPolicy(policyId);
         assertThat(systemPolicy).isNotNull();
         assertPolicyIdentical(systemPolicy, expectedSystemPolicy);
     }
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
index 92182fd..14c3ddc 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
@@ -211,14 +211,14 @@
 
     @Test
     public void testSwitchUser_success() throws Exception {
-        expectServiceSwitchUserSucceeds(11, UserSwitchResult.STATUS_SUCCESSFUL, "D'OH!");
+        expectServiceSwitchUserSucceeds(11, UserSwitchResult.STATUS_SUCCESSFUL);
 
         AsyncFuture<UserSwitchResult> future = mMgr.switchUser(11);
 
         assertThat(future).isNotNull();
         UserSwitchResult result = getResult(future);
         assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
-        assertThat(result.getErrorMessage()).isEqualTo("D'OH!");
+        assertThat(result.getErrorMessage()).isNull();
     }
 
     @Test
@@ -247,6 +247,43 @@
     }
 
     @Test
+    public void testLogoutUser_success() throws Exception {
+        expectServiceLogoutUserSucceeds(UserSwitchResult.STATUS_SUCCESSFUL);
+
+        AsyncFuture<UserSwitchResult> future = mMgr.logoutUser();
+
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testLogoutUser_remoteException() throws Exception {
+        expectServiceLogoutUserFails(new RemoteException("D'OH!"));
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AsyncFuture<UserSwitchResult> future = mMgr.logoutUser();
+
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
+    public void testLogoutUser_runtimeException() throws Exception {
+        expectServiceLogoutUserFails(new RuntimeException("D'OH!"));
+
+        AsyncFuture<UserSwitchResult> future = mMgr.logoutUser();
+
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
     public void testRemoveUser_success() throws Exception {
         expectServiceRemoveUserSucceeds(100);
 
@@ -589,13 +626,12 @@
     }
 
     private void expectServiceSwitchUserSucceeds(@UserIdInt int userId,
-            @UserSwitchResult.Status int status, @Nullable String errorMessage)
-            throws RemoteException {
+            @UserSwitchResult.Status int status) throws RemoteException {
         doAnswer((invocation) -> {
             @SuppressWarnings("unchecked")
             AndroidFuture<UserSwitchResult> future =
                     (AndroidFuture<UserSwitchResult>) invocation.getArguments()[2];
-            future.complete(new UserSwitchResult(status, errorMessage));
+            future.complete(new UserSwitchResult(status, /* errorMessage= */ null));
             return null;
         }).when(mService).switchUser(eq(userId), anyInt(), notNull());
     }
@@ -604,6 +640,21 @@
         doThrow(e).when(mService).switchUser(eq(userId), anyInt(), notNull());
     }
 
+    private void expectServiceLogoutUserSucceeds(@UserSwitchResult.Status int status)
+            throws RemoteException {
+        doAnswer((invocation) -> {
+            @SuppressWarnings("unchecked")
+            AndroidFuture<UserSwitchResult> future =
+                    (AndroidFuture<UserSwitchResult>) invocation.getArguments()[1];
+            future.complete(new UserSwitchResult(status, /* errorMessage= */ null));
+            return null;
+        }).when(mService).logoutUser(anyInt(), notNull());
+    }
+
+    private void expectServiceLogoutUserFails(Exception e) throws Exception {
+        doThrow(e).when(mService).logoutUser(anyInt(), notNull());
+    }
+
     private void expectServiceRemoveUserSucceeds(@UserIdInt int userId) throws RemoteException {
         doAnswer((invocation) -> {
             @SuppressWarnings("unchecked")
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 32e8b8d..571b604 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
@@ -19,6 +19,7 @@
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmCreateUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUserInfo;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetUsers;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmHasUserRestrictionForUser;
 import static android.car.test.mocks.AndroidMockitoHelper.mockUmRemoveUserOrSetEphemeral;
 import static android.car.test.mocks.JavaMockitoHelper.getResult;
 import static android.car.test.util.UserTestingHelper.UserInfoBuilder;
@@ -57,12 +58,14 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
 import android.car.CarOccupantZoneManager.OccupantTypeEnum;
 import android.car.CarOccupantZoneManager.OccupantZoneInfo;
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
 import android.car.settings.CarSettings;
 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase.ExpectWtf;
 import android.car.test.mocks.BlockingAnswer;
 import android.car.test.util.BlockingResultReceiver;
 import android.car.testapi.BlockingUserLifecycleListener;
@@ -105,11 +108,14 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManager.RemoveResult;
+import android.os.UserManager.UserSwitchabilityResult;
 import android.sysprop.CarProperties;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
@@ -171,6 +177,7 @@
     @Mock private UserHalService mUserHal;
     @Mock private IActivityManager mMockedIActivityManager;
     @Mock private UserManager mMockedUserManager;
+    @Mock private DevicePolicyManager mMockedDevicePolicyManager;
     @Mock private Resources mMockedResources;
     @Mock private Drawable mMockedDrawable;
     @Mock private InitialUserSetter mInitialUserSetter;
@@ -222,6 +229,9 @@
             getClass().getSimpleName());
     private final Handler mHandler = new Handler(mHandlerThread.getLooper());
 
+    private final @UserIdInt int mAdminUserId = mAdminUser.id;
+    private final @UserIdInt int mGuestUserId = mGuestUser.id;
+
     @Override
     protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
         builder
@@ -787,6 +797,8 @@
         mCarUserService.switchDriver(mRegularUser.id, mUserSwitchFuture);
         assertThat(getUserSwitchResult().getStatus())
                 .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -801,15 +813,16 @@
                 .isEqualTo(UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
         verifyNoUserSwitch();
         assertNoHalUserSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
     public void testSwitchDriver_IfUserSwitchIsNotAllowed() throws Exception {
-        when(mMockedUserManager.getUserSwitchability())
-                .thenReturn(UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED);
+        mockUmGetUserSwitchability(UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED);
         mCarUserService.switchDriver(mRegularUser.id, mUserSwitchFuture);
         assertThat(getUserSwitchResult().getStatus())
                 .isEqualTo(UserSwitchResult.STATUS_INVALID_REQUEST);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -820,6 +833,7 @@
         mCarUserService.switchDriver(mAdminUser.id, mUserSwitchFuture);
         assertThat(getUserSwitchResult().getStatus())
                 .isEqualTo(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1144,13 +1158,12 @@
     public void testSwitchUser_noUserSwitchability() throws Exception {
         UserInfo currentUser = mAdminUser;
         mockExistingUsersAndCurrentUser(mExistingUsers, currentUser);
-        doReturn(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED).when(mMockedUserManager)
-                .getUserSwitchability();
+        mockUmGetUserSwitchability(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED);
 
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_NOT_SWITCHABLE);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_NOT_SWITCHABLE);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1159,10 +1172,10 @@
 
         switchUser(mAdminUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
-
+        assertUserSwitchResult(getUserSwitchResult(),
+                UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
         verifyNoUserSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1173,15 +1186,14 @@
 
         switchUser(mRegularUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
         verify(mUserHal, never()).switchUser(any(), anyInt(), any());
-
         // update current user due to successful user switch
         mockCurrentUser(mRegularUser);
         sendUserUnlockedEvent(mRegularUser.id);
         assertNoHalUserSwitch();
         assertNoPostSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1191,9 +1203,9 @@
 
         switchUser(mRegularUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_ANDROID_FAILURE);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_ANDROID_FAILURE);
         assertNoHalUserSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1207,12 +1219,12 @@
 
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
-
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
         // update current user due to successful user switch
         mockCurrentUser(mGuestUser);
         sendUserUnlockedEvent(mGuestUser.id);
         assertPostSwitch(requestId, mGuestUser.id, mGuestUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1226,9 +1238,9 @@
 
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_ANDROID_FAILURE);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_ANDROID_FAILURE);
         assertPostSwitch(requestId, mAdminUser.id, mGuestUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1241,9 +1253,10 @@
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
         UserSwitchResult result = getUserSwitchResult();
-        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_FAILURE);
+        assertUserSwitchResult(result.getStatus(), UserSwitchResult.STATUS_HAL_FAILURE);
         assertThat(result.getErrorMessage()).isEqualTo(mSwitchUserResponse.errorMessage);
         verifyNoUserSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1255,9 +1268,9 @@
 
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
         verifyNoUserSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1268,10 +1281,11 @@
         initService();
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
-        assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
+        assertUserSwitchResult(getUserSwitchResult(),
+                UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
         assertNoHalUserSwitch();
         verifyNoUserSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1286,19 +1300,20 @@
         // Should be ok first time...
         ICarUxRestrictionsChangeListener listener = initService();
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
-        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
 
         // ...but then fail after the state changed
         mockCurrentUser(mGuestUser);
         updateUxRestrictions(listener, /* restricted= */ true); // changed state
         switchUser(mAdminUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture2);
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
+        assertUserSwitchResult(getUserSwitchResult2(),
+                UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
 
         // Verify only initial call succeeded (if second was also called the mocks, verify() would
         // fail because it was called more than once()
         assertHalSwitchAnyUser();
         verifyAnyUserSwitch();
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1321,12 +1336,12 @@
         mockAmSwitchUser(mRegularUser, true);
         switchUser(mRegularUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture2);
 
-        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult2(), UserSwitchResult.STATUS_SUCCESSFUL);
         assertNoPostSwitch();
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
         assertHalSwitch(mAdminUser.id, mRegularUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1351,11 +1366,11 @@
         mockCurrentUser(mRegularUser);
         sendUserUnlockedEvent(mRegularUser.id);
 
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult2(), UserSwitchResult.STATUS_SUCCESSFUL);
         assertPostSwitch(newRequestId, mRegularUser.id, mRegularUser.id);
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
         assertHalSwitch(mAdminUser.id, mRegularUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1376,11 +1391,11 @@
         mockAmSwitchUser(mRegularUser, true);
         switchUser(mRegularUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture2);
 
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult2(), UserSwitchResult.STATUS_SUCCESSFUL);
         assertNoPostSwitch();
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
         assertHalSwitch(mAdminUser.id, mRegularUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1404,11 +1419,11 @@
         mockCurrentUser(mRegularUser);
         sendUserUnlockedEvent(mRegularUser.id);
 
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult2(), UserSwitchResult.STATUS_SUCCESSFUL);
         assertPostSwitch(newRequestId, mRegularUser.id, mRegularUser.id);
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
         assertHalSwitch(mAdminUser.id, mRegularUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1435,14 +1450,13 @@
         sendUserUnlockedEvent(mRegularUser.id);
         blockingAnswer.unblock();
 
-        UserSwitchResult result = getUserSwitchResult();
-        assertThat(result.getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST);
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult(),
+                UserSwitchResult.STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST);
+        assertUserSwitchResult(getUserSwitchResult2(), UserSwitchResult.STATUS_SUCCESSFUL);
         assertPostSwitch(newRequestId, mRegularUser.id, mRegularUser.id);
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
         assertHalSwitch(mAdminUser.id, mRegularUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1457,10 +1471,11 @@
         // calling another user switch before unlock
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture2);
 
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
+        assertUserSwitchResult(getUserSwitchResult2(),
+                UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
         assertNoPostSwitch();
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1476,11 +1491,12 @@
         // calling another user switch before unlock
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture2);
 
-        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult2(),
+                UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
         assertNoPostSwitch();
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1502,16 +1518,18 @@
         mockCurrentUser(mGuestUser);
         sendUserUnlockedEvent(mGuestUser.id);
 
-        assertThat(getUserSwitchResult().getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL);
-        assertThat(getUserSwitchResult2().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
+        assertUserSwitchResult(getUserSwitchResult2(),
+                UserSwitchResult.STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO);
         assertPostSwitch(requestId, mGuestUser.id, mGuestUser.id);
         assertHalSwitch(mAdminUser.id, mGuestUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
     public void testSwitchUser_InvalidPermission() throws Exception {
         mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
+
         assertThrows(SecurityException.class, () -> mCarUserService
                 .switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture));
     }
@@ -1519,10 +1537,18 @@
     @Test
     public void testLegacyUserSwitch_ok() throws Exception {
         mockExistingUsers(mExistingUsers);
+        int targetUserId = mRegularUser.id;
+        int sourceUserId = mAdminUser.id;
 
-        sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
+        mockCallerUid(Binder.getCallingUid(), true);
+        mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver);
 
-        verify(mUserHal).legacyUserSwitch(isSwitchUserRequest(0, mAdminUser.id, mRegularUser.id));
+        sendUserSwitchingEvent(sourceUserId, targetUserId);
+
+        verify(mUserHal).legacyUserSwitch(
+                isSwitchUserRequest(/* requestId= */ 0, sourceUserId, targetUserId));
+        verify(mSwitchUserUiReceiver).send(targetUserId, null);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1534,13 +1560,18 @@
         mSwitchUserResponse.requestId = requestId;
         mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mGuestUser, true);
-        switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
+        int targetUserId = mGuestUser.id;
+        mockCallerUid(Binder.getCallingUid(), true);
+        mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver);
+        switchUser(targetUserId, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
         // Act - trigger legacy switch
-        sendUserSwitchingEvent(mAdminUser.id, mGuestUser.id);
+        sendUserSwitchingEvent(mAdminUser.id, targetUserId);
 
         // Assert
         verify(mUserHal, never()).legacyUserSwitch(any());
+        verify(mSwitchUserUiReceiver).send(targetUserId, null);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1549,12 +1580,13 @@
         int callerId = Binder.getCallingUid();
         mockCallerUid(callerId, true);
         int requestId = 42;
+        mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver);
+
         mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
         mSwitchUserResponse.requestId = requestId;
         mockHalSwitch(mAdminUser.id, mGuestUser, mSwitchUserResponse);
         mockAmSwitchUser(mGuestUser, true);
 
-        mCarUserService.setUserSwitchUiCallback(mSwitchUserUiReceiver);
         switchUser(mGuestUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
         // update current user due to successful user switch
@@ -1581,6 +1613,7 @@
         sendUserUnlockedEvent(mRegularUser.id);
 
         assertPostSwitch(requestId, mRegularUser.id, mRegularUser.id);
+        assertLogoutUserNotCleared();
     }
 
     @Test
@@ -1592,6 +1625,148 @@
         mCarUserService.switchAndroidUserFromHal(requestId, mRegularUser.id);
 
         assertPostSwitch(requestId, mAdminUser.id, mRegularUser.id);
+        assertLogoutUserNotCleared();
+    }
+
+    @Test
+    public void testLogoutUser_currentUserNotSwitchedByDeviceAdmin() throws Exception {
+        mockNoLogoutUserId();
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_NOT_LOGGED_IN);
+        assertLogoutUserNotCleared();
+    }
+
+    @Test
+    @ExpectWtf
+    public void testLogoutUser_logoutUserDoesntExist() throws Exception {
+        mockLogoutUserId(mAdminUserId);
+        // No need to mock um.getUser(mAdminUserId) - it will return null by default
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_ANDROID_FAILURE);
+        assertLogoutUserNotCleared();
+    }
+
+    @Test
+    public void testLogoutUser_halNotSupported_noUserSwitchability() throws Exception {
+        mockLogoutUser(mAdminUser);
+        mockUserHalSupported(false);
+        mockAmSwitchUser(mAdminUser, true);
+
+        mockUmGetUserSwitchability(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED);
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
+        assertLogoutUserCleared();
+    }
+
+    @Test
+    public void testLogoutUser_halNotSupported_success() throws Exception {
+        mockLogoutUser(mAdminUser);
+        mockUserHalSupported(false);
+        mockAmSwitchUser(mAdminUser, true);
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
+        assertLogoutUserCleared();
+    }
+
+    @Test
+    public void testLogoutUser_halNotSupported_failure() throws Exception {
+        mockLogoutUser(mAdminUser);
+        mockUserHalSupported(false);
+        // Don't need to call mockAmSwitchUser() because it returns false by default
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_ANDROID_FAILURE);
+        assertLogoutUserNotCleared();
+    }
+
+    @Test
+    public void testLogoutUser_halSuccessAndroidSuccess() throws Exception {
+        mockExistingUsersAndCurrentUser(mGuestUser);
+        mockLogoutUser(mAdminUser);
+        mockUserHalSupported(true);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mGuestUserId, mAdminUser, mSwitchUserResponse);
+        mockAmSwitchUser(mAdminUser, true);
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_SUCCESSFUL);
+        assertLogoutUserCleared();
+
+        // update current user due to successful user switch
+        mockCurrentUser(mAdminUser);
+        sendUserUnlockedEvent(mAdminUserId);
+        assertPostSwitch(requestId, mAdminUserId, mAdminUserId);
+    }
+
+    @Test
+    public void testLogoutUser_halSuccessAndroidFailure() throws Exception {
+        mockExistingUsersAndCurrentUser(mGuestUser);
+        mockLogoutUser(mAdminUser);
+        mockUserHalSupported(true);
+        int requestId = 42;
+        mSwitchUserResponse.status = SwitchUserStatus.SUCCESS;
+        mSwitchUserResponse.requestId = requestId;
+        mockHalSwitch(mGuestUserId, mAdminUser, mSwitchUserResponse);
+        // Don't need to call mockAmSwitchUser() because it returns false by default
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(), UserSwitchResult.STATUS_ANDROID_FAILURE);
+        assertLogoutUserNotCleared();
+        assertPostSwitch(requestId, mGuestUserId, mAdminUserId);
+    }
+
+    @Test
+    public void testLogoutUser_halFailure() throws Exception {
+        mockExistingUsersAndCurrentUser(mGuestUser);
+        mockLogoutUser(mAdminUser);
+        mockUserHalSupported(true);
+        mSwitchUserResponse.status = SwitchUserStatus.FAILURE;
+        mSwitchUserResponse.errorMessage = "Error Message";
+        mockHalSwitch(mGuestUserId, mAdminUser, mSwitchUserResponse);
+
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        UserSwitchResult result = getUserSwitchResult();
+        assertUserSwitchResult(result, UserSwitchResult.STATUS_HAL_FAILURE);
+        assertThat(result.getErrorMessage()).isEqualTo(mSwitchUserResponse.errorMessage);
+        assertLogoutUserNotCleared();
+        verifyNoUserSwitch();
+    }
+
+    @Test
+    public void testLogoutUser_failUxRestrictedOnInit() throws Exception {
+        mockGetUxRestrictions(/*restricted= */ true);
+        mockLogoutUser(mAdminUser);
+
+        initService();
+        logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture);
+
+        assertUserSwitchResult(getUserSwitchResult(),
+                UserSwitchResult.STATUS_UX_RESTRICTION_FAILURE);
+        assertLogoutUserNotCleared();
+        assertNoHalUserSwitch();
+        verifyNoUserSwitch();
+    }
+
+    @Test
+    public void testLogoutUser_InvalidPermission() throws Exception {
+        mockManageUsersPermission(android.Manifest.permission.MANAGE_USERS, false);
+
+        assertThrows(SecurityException.class, () -> mCarUserService
+                .logoutUser(mAsyncCallTimeoutMs, mUserSwitchFuture));
     }
 
     @Test
@@ -1713,6 +1888,22 @@
     }
 
     @Test
+    public void testCreateUser_disallowAddUser() throws Exception {
+        mockUmHasUserRestrictionForUser(mMockedUserManager, Process.myUserHandle(),
+                UserManager.DISALLOW_ADD_USER, /* value= */ true);
+        mockUmCreateUser(mMockedUserManager, "dude", UserManager.USER_TYPE_FULL_SECONDARY,
+                /* flags= */ 0, 42);
+
+        createUser("dude", UserManager.USER_TYPE_FULL_SECONDARY, /* flags= */ 0,
+                mAsyncCallTimeoutMs, mUserCreationFuture, NO_CALLER_RESTRICTIONS);
+
+        UserCreationResult result = getUserCreationResult();
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_ANDROID_FAILURE);
+        assertNoHalUserCreation();
+        assertNoHalUserRemoval();
+    }
+
+    @Test
     public void testCreateUser_success() throws Exception {
         mockExistingUsersAndCurrentUser(mAdminUser);
         int userId = mGuestUser.id;
@@ -2390,6 +2581,11 @@
         waitForHandlerThreadToFinish();
     }
 
+    private void logoutUser(int timeoutMs, @NonNull AndroidFuture<UserSwitchResult> receiver) {
+        mCarUserService.logoutUser(timeoutMs, receiver);
+        waitForHandlerThreadToFinish();
+    }
+
     private void removeUser(@UserIdInt int userId,
             @NonNull AndroidFuture<UserRemovalResult> userRemovalFuture) {
         mCarUserService.removeUser(userId, userRemovalFuture);
@@ -2449,6 +2645,7 @@
                 mMockContext,
                 mUserHal,
                 mMockedUserManager,
+                mMockedDevicePolicyManager,
                 mMockedIActivityManager,
                 /* maxRunningUsers= */ 3,
                 mInitialUserSetter,
@@ -2507,6 +2704,10 @@
         when(mMockedIActivityManager.switchUser(user.id)).thenReturn(result);
     }
 
+    private void mockUmGetUserSwitchability(@UserSwitchabilityResult int result) {
+        when(mMockedUserManager.getUserSwitchability()).thenReturn(result);
+    }
+
     private void mockRemoveUser(@NonNull UserInfo user) {
         mockRemoveUser(user, UserManager.REMOVE_RESULT_REMOVED);
     }
@@ -2770,6 +2971,19 @@
         when(mCarUxRestrictionService.getCurrentUxRestrictions()).thenReturn(restrictions);
     }
 
+    private void mockNoLogoutUserId() {
+        mockLogoutUserId(UserHandle.USER_NULL);
+    }
+
+    private void mockLogoutUser(UserInfo user) {
+        mockLogoutUserId(user.id);
+        mockUmGetUserInfo(mMockedUserManager, user);
+    }
+
+    private void mockLogoutUserId(@UserIdInt int userId) {
+        when(mMockedDevicePolicyManager.getLogoutUserId()).thenReturn(userId);
+    }
+
     /**
      * Asserts a {@link UsersInfo} that was created based on {@link #mockCurrentUsers(UserInfo)}.
      */
@@ -2899,6 +3113,14 @@
         }
     }
 
+    private void assertLogoutUserCleared() {
+        verify(mMockedDevicePolicyManager).clearLogoutUser();
+    }
+
+    private void assertLogoutUserNotCleared() {
+        verify(mMockedDevicePolicyManager, never()).clearLogoutUser();
+    }
+
     @NonNull
     private static SwitchUserRequest isSwitchUserRequest(int requestId,
             @UserIdInt int currentUserId, @UserIdInt int targetUserId) {
@@ -2963,6 +3185,21 @@
                 CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
     }
 
+    private void assertUserSwitchResult(UserSwitchResult result, int expected) {
+        assertUserSwitchResult(result.getStatus(), expected);
+    }
+
+    private void assertUserSwitchResult(int actual, int expected) {
+        assertWithMessage("user switch result (where %s=%s and %s=%s)",
+                expected, userSwitchResultToString(expected),
+                actual, userSwitchResultToString(actual))
+                        .that(actual).isEqualTo(expected);
+    }
+
+    private static String userSwitchResultToString(int status) {
+        return DebugUtils.constantToString(UserSwitchResult.class, "STATUS_", status);
+    }
+
     @NonNull
     private static UserIdentificationGetRequest isUserIdentificationGetRequest(
             @NonNull UserInfo user, @NonNull int[] types) {