[automerger skipped] Merge "Import translations. DO NOT MERGE ANYWHERE" into rvc-qpr-dev am: 669566151a -s ours am: 7a27af29a2 -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Car/+/15349383

Change-Id: I85ebc055416c942d34ffaac5676ccd3a211e093f
diff --git a/Android.mk b/Android.mk
index 8b1efbf..0d59692 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,5 +15,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+# Include car_ui_portrait
+include $(LOCAL_PATH)/car_product/car_ui_portrait/Android.mk
+
 # Include the sub-makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/car-lib/src/android/car/ICarUserService.aidl b/car-lib/src/android/car/ICarUserService.aidl
index 267044d..bee3bba 100644
--- a/car-lib/src/android/car/ICarUserService.aidl
+++ b/car-lib/src/android/car/ICarUserService.aidl
@@ -40,8 +40,8 @@
     List<UserInfo> getPassengers(int driverId);
     boolean startPassenger(int passengerId, int zoneId);
     boolean stopPassenger(int passengerId);
-    void setLifecycleListenerForUid(in IResultReceiver listener);
-    void resetLifecycleListenerForUid();
+    void setLifecycleListenerForApp(String pkgName, in IResultReceiver listener);
+    void resetLifecycleListenerForApp(in IResultReceiver listener);
     UserIdentificationAssociationResponse getUserIdentificationAssociation(in int[] types);
     void setUserIdentificationAssociation(int timeoutMs, in int[] types, in int[] values,
       in AndroidFuture<UserIdentificationAssociationResponse> result);
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
index dace5a8..f42da45 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -307,13 +307,20 @@
     public @interface UserIdentificationAssociationValue{}
 
     private final Object mLock = new Object();
+
     private final ICarUserService mService;
     private final UserManager mUserManager;
 
+    /**
+     * Map of listeners registers by the app.
+     */
     @Nullable
     @GuardedBy("mLock")
     private ArrayMap<UserLifecycleListener, Executor> mListeners;
 
+    /**
+     * Receiver used to receive user-lifecycle callbacks from the service.
+     */
     @Nullable
     @GuardedBy("mLock")
     private LifecycleResultReceiver mReceiver;
@@ -332,6 +339,7 @@
     public CarUserManager(@NonNull Car car, @NonNull ICarUserService service,
             @NonNull UserManager userManager) {
         super(car);
+
         mService = service;
         mUserManager = userManager;
     }
@@ -524,20 +532,31 @@
         Objects.requireNonNull(listener, "listener cannot be null");
 
         int uid = myUid();
+        String packageName = getContext().getPackageName();
+        if (DBG) {
+            Log.d(TAG, "addListener(): uid=" + uid + ", pkg=" + packageName
+                    + ", listener=" + listener);
+        }
         synchronized (mLock) {
             Preconditions.checkState(mListeners == null || !mListeners.containsKey(listener),
                     "already called for this listener");
             if (mReceiver == null) {
                 mReceiver = new LifecycleResultReceiver();
                 try {
-                    EventLog.writeEvent(EventLogTags.CAR_USER_MGR_ADD_LISTENER, uid);
-                    if (DBG) Log.d(TAG, "Setting lifecycle receiver for uid " + uid);
-                    mService.setLifecycleListenerForUid(mReceiver);
+                    EventLog.writeEvent(EventLogTags.CAR_USER_MGR_ADD_LISTENER, uid, packageName);
+                    if (DBG) {
+                        Log.d(TAG, "Setting lifecycle receiver for uid " + uid + " and package "
+                                + packageName);
+                    }
+                    mService.setLifecycleListenerForApp(packageName, mReceiver);
                 } catch (RemoteException e) {
                     handleRemoteExceptionFromCarService(e);
                 }
             } else {
-                if (DBG) Log.d(TAG, "Already set receiver for uid " + uid);
+                if (DBG) {
+                    Log.d(TAG, "Already set receiver for uid " + uid + " and package "
+                            + packageName);
+                }
             }
 
             if (mListeners == null) {
@@ -547,7 +566,7 @@
                         + " already has " + mListeners.size() + " listeners: "
                         + mListeners.keySet().stream()
                                 .map((l) -> getLambdaName(l))
-                                .collect(Collectors.toList()), new Exception());
+                                .collect(Collectors.toList()), new Exception("caller's stack"));
             }
             if (DBG) Log.d(TAG, "Adding listener: " + listener);
             mListeners.put(listener, executor);
@@ -568,6 +587,11 @@
         Objects.requireNonNull(listener, "listener cannot be null");
 
         int uid = myUid();
+        String packageName = getContext().getPackageName();
+        if (DBG) {
+            Log.d(TAG, "removeListener(): uid=" + uid + ", pkg=" + packageName
+                    + ", listener=" + listener);
+        }
         synchronized (mLock) {
             Preconditions.checkState(mListeners != null && mListeners.containsKey(listener),
                     "not called for this listener yet");
@@ -584,10 +608,13 @@
                 return;
             }
 
-            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_LISTENER, uid);
-            if (DBG) Log.d(TAG, "Removing lifecycle receiver for uid=" + uid);
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_LISTENER, uid, packageName);
+            if (DBG) {
+                Log.d(TAG, "Removing lifecycle receiver for uid=" + uid + " and package "
+                        + packageName);
+            }
             try {
-                mService.resetLifecycleListenerForUid();
+                mService.resetLifecycleListenerForApp(mReceiver);
                 mReceiver = null;
             } catch (RemoteException e) {
                 handleRemoteExceptionFromCarService(e);
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 65a3fb1..45fdfe9 100644
--- a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
+++ b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
@@ -69,8 +69,8 @@
 150100 car_user_svc_initial_user_info_req (request_type|1),(timeout|1)
 150101 car_user_svc_initial_user_info_resp (status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
 150103 car_user_svc_set_initial_user (user_id|1)
-150104 car_user_svc_set_lifecycle_listener (uid|1)
-150105 car_user_svc_reset_lifecycle_listener (uid|1)
+150104 car_user_svc_set_lifecycle_listener (uid|1),(package_name|3)
+150105 car_user_svc_reset_lifecycle_listener (uid|1),(package_name|3)
 150106 car_user_svc_switch_user_req (user_id|1),(timeout|1)
 150107 car_user_svc_switch_user_resp (hal_callback_status|1),(user_switch_status|1),(error_message|3)
 150108 car_user_svc_post_switch_user_req (target_user_id|1),(current_user_id|1)
@@ -86,7 +86,7 @@
 150118 car_user_svc_create_user_user_removed (user_id|1),(reason|3)
 150119 car_user_svc_remove_user_req (user_id|1),(hasCallerRestrictions|1)
 150120 car_user_svc_remove_user_resp (user_id|1),(result|1)
-150121 car_user_svc_notify_app_lifecycle_listener (uid|1),(event_type|1),(from_user_id|1),(to_user_id|1)
+150121 car_user_svc_notify_app_lifecycle_listener (uid|1),(package_name|3),(event_type|1),(from_user_id|1),(to_user_id|1)
 150122 car_user_svc_notify_internal_lifecycle_listener (listener_name|3),(event_type|1),(from_user_id|1),(to_user_id|1)
 150123 car_user_svc_pre_creation_requested (number_users|1),(number_guests|1)
 150124 car_user_svc_pre_creation_status (number_existing_users|1),(number_users_to_add|1),(number_users_to_remove|1),(number_existing_guests|1),(number_guests_to_add|1),(number_guests_to_remove|1),(number_invalid_users_to_remove|1)
@@ -111,8 +111,8 @@
 150152 car_user_hal_create_user_resp (request_id|1),(status|1),(result|1),(error_message|3)
 150153 car_user_hal_remove_user_req (target_user_id|1),(current_user_id|1)
 
-150171 car_user_mgr_add_listener (uid|1)
-150172 car_user_mgr_remove_listener (uid|1)
+150171 car_user_mgr_add_listener (uid|1),(package_name|3)
+150172 car_user_mgr_remove_listener (uid|1),(package_name|3)
 150173 car_user_mgr_disconnected (uid|1)
 150174 car_user_mgr_switch_user_req (uid|1),(user_id|1)
 150175 car_user_mgr_switch_user_resp (uid|1),(status|1),(error_message|3)
diff --git a/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
index 627aa86..3693ebc 100644
--- a/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
+++ b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
@@ -54,6 +54,8 @@
 
     private static final long DEFAULT_TIMEOUT_MS = 2_000;
 
+    private static int sNextId;
+
     private final Object mLock = new Object();
 
     private final CountDownLatch mLatch = new CountDownLatch(1);
@@ -79,6 +81,8 @@
 
     private final long mTimeoutMs;
 
+    private final int mId = ++sNextId;
+
     private BlockingUserLifecycleListener(Builder builder) {
         mExpectedEventTypes = Collections
                 .unmodifiableList(new ArrayList<>(builder.mExpectedEventTypes));
@@ -276,7 +280,7 @@
     @NonNull
     private String stateToString() {
         synchronized (mLock) {
-            return "timeout=" + mTimeoutMs + "ms"
+            return "id=" + mId + ",timeout=" + mTimeoutMs + "ms"
                     + ",expectedEventTypes=" + toString(mExpectedEventTypes)
                     + ",expectedEventTypesLeft=" + toString(mExpectedEventTypesLeft)
                     + (expectingSpecificUser() ? ",forUser=" + mForUserId : "")
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index df09aae..5b99320 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -45,6 +45,7 @@
     BugReportApp \
     NetworkPreferenceApp \
     SampleCustomInputService \
+    AdasLocationTestApp \
 
 # SEPolicy for test apps / services
 BOARD_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/test
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 71803d3..41194f4 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -306,9 +306,11 @@
     </install-in-user-type>
     <install-in-user-type package="com.android.pacprocessor">
         <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
     </install-in-user-type>
     <install-in-user-type package="com.android.proxyhandler">
         <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
     </install-in-user-type>
     <install-in-user-type package="com.android.vpndialogs">
         <install-in user-type="FULL" />
diff --git a/car_product/car_ui_portrait/Android.mk b/car_product/car_ui_portrait/Android.mk
new file mode 100644
index 0000000..c75d51a
--- /dev/null
+++ b/car_product/car_ui_portrait/Android.mk
@@ -0,0 +1,20 @@
+# 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.
+#
+
+car_ui_portrait_modules := \
+    rro/car-ui-customizations \
+    apps/HideApps
+
+include $(call all-named-subdir-makefiles,$(car_ui_portrait_modules))
diff --git a/car_product/car_ui_portrait/OWNERS b/car_product/car_ui_portrait/OWNERS
new file mode 100644
index 0000000..f539bfb
--- /dev/null
+++ b/car_product/car_ui_portrait/OWNERS
@@ -0,0 +1,6 @@
+# Car UI Portrait Reference OWNERS
+hseog@google.com
+priyanksingh@google.com
+juliakawano@google.com
+stenning@google.com
+igorr@google.com
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/Android.bp b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/Android.bp
new file mode 100644
index 0000000..3c5fb85
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/Android.bp
@@ -0,0 +1,53 @@
+// 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: "CarUiPortraitSettings",
+    overrides: ["CarSettings"],
+    platform_apis: true,
+
+    manifest: "AndroidManifest.xml",
+
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "CarSettings-core",
+    ],
+
+    certificate: "platform",
+
+    optimize: {
+        enabled: false,
+    },
+
+    privileged: true,
+
+    dex_preopt: {
+        enabled: false,
+    },
+
+    required: ["allowed_privapp_com.android.car.settings"],
+
+    dxflags: ["--multi-dex"],
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml
new file mode 100644
index 0000000..82fcdf5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?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.settings"
+          android:sharedUserId="android.uid.system"
+          coreApp="true">
+</manifest>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/settings_recyclerview_default.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/settings_recyclerview_default.xml
new file mode 100644
index 0000000..4616fdf
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/settings_recyclerview_default.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.android.car.ui.FocusArea
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/settings_car_ui_focus_area"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <com.android.car.ui.recyclerview.CarUiRecyclerView
+            android:id="@+id/settings_recycler_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:tag="carUiPreferenceRecyclerView"
+            app:carUiSize="small"
+            app:enableDivider="true" />
+    </com.android.car.ui.FocusArea>
+</merge>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/top_level_recyclerview.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/top_level_recyclerview.xml
new file mode 100644
index 0000000..4dbe9be
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/top_level_recyclerview.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.android.car.ui.FocusArea
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/settings_car_ui_focus_area"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <com.android.car.ui.recyclerview.CarUiRecyclerView
+            android:id="@+id/top_level_recycler_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:tag="carUiPreferenceRecyclerView"
+            app:carUiSize="small"
+            app:enableDivider="true" />
+    </com.android.car.ui.FocusArea>
+</merge>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/config.xml
new file mode 100644
index 0000000..eaf603f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/config.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+
+<resources>
+    <bool name="config_global_force_single_pane">false</bool>
+    <string name="config_homepage_fragment_class" translatable="false">com.android.car.settings.bluetooth.BluetoothSettingsFragment</string>
+    <bool name="config_top_level_enable_chevrons">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/dimens.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/dimens.xml
new file mode 100644
index 0000000..f2a58a4
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2018 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>
+    <!-- Top-level menu -->
+    <dimen name="top_level_menu_width">400dp</dimen>
+    <dimen name="top_level_recyclerview_margin_right">@*android:dimen/car_padding_2</dimen>
+    <dimen name="top_level_foreground_icon_inset">8dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp
new file mode 100644
index 0000000..c195412
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp
@@ -0,0 +1,73 @@
+// 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.
+
+android_app {
+    name: "CarUiPortraitSystemUI",
+
+    srcs: ["src/**/*.java"],
+
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "CarSystemUI-core",
+    ],
+
+    libs: [
+        "android.car",
+    ],
+
+    manifest: "AndroidManifest.xml",
+
+    overrides: [
+        "CarSystemUI",
+    ],
+
+    platform_apis: true,
+    system_ext_specific: true,
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        proguard_flags_files: [
+            "proguard.flags",
+        ],
+    },
+    dxflags: ["--multi-dex"],
+
+    plugins: ["dagger2-compiler"],
+
+    required: ["privapp_whitelist_com.android.systemui", "allowed_privapp_com.android.carsystemui"],
+}
+
+//####################################################################################
+// Build a static library to help mocking in testing. This is meant to be used
+// for internal unit tests.
+//####################################################################################
+android_library {
+    name: "CarUiPortraitSystemUI-tests",
+
+    srcs: ["src/**/*.java"],
+
+    resource_dirs: ["res"],
+
+    libs: [
+        "android.car",
+    ],
+
+    static_libs: [
+        "CarSystemUI-tests",
+    ],
+
+    plugins: ["dagger2-compiler"],
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
new file mode 100644
index 0000000..fc2e241
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?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"
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          package="com.android.systemui"
+          android:sharedUserId="android.uid.systemui"
+          coreApp="true">
+</manifest>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
new file mode 100644
index 0000000..3de0064
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
@@ -0,0 +1,6 @@
+-keep class com.android.systemui.CarUiPortraitSystemUIFactory
+
+-keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent { *; }
+-keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent$CarUiPortraitSysUIComponentImpl { *; }
+
+-include ../../../../../../../packages/apps/Car/SystemUI/proguard.flags
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_apps.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_apps.xml
new file mode 100644
index 0000000..a98b3a7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_apps.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M6,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM16,6c0,1.1 0.9,2 2,2s2,-0.9 2,-2 -0.9,-2 -2,-2 -2,0.9 -2,2zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_hvac.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_hvac.xml
new file mode 100644
index 0000000..b42c86c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_hvac.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24"
+                android:viewportHeight="24">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_mic.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_mic.xml
new file mode 100644
index 0000000..f282b65
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_mic.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M12,14c1.66,0 3,-1.34 3,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,5zM17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5L5,11c0,3.53 2.61,6.43 6,6.92L11,21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92h-2z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_notification.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_notification.xml
new file mode 100644
index 0000000..27b69a8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_notification.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M18,17v-6c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v6L4,17v2h16v-2h-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6zM12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml
new file mode 100644
index 0000000..45887dc
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/system_bar_user_icon_drawing_size"
+    android:height="@dimen/system_bar_user_icon_drawing_size"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="@color/system_bar_icon_color"
+      android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L5.9,18.1L5.9,17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml
new file mode 100644
index 0000000..cac886c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml
@@ -0,0 +1,34 @@
+<?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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <size android:width="@dimen/rear_view_camera_exit_button_width"
+                  android:height="@dimen/rear_view_camera_exit_button_height"/>
+            <solid android:color="@color/rear_view_camera_button_background"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape android:shape="oval">
+                    <solid android:color="?android:colorAccent"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar.xml
new file mode 100644
index 0000000..7e72373
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:id="@android:id/background">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/hvac_off_background_color" />
+        </shape>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape android:shape="rectangle">
+                <solid android:color="@color/hvac_on_background_color" />
+            </shape>
+        </clip>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_background.xml
new file mode 100644
index 0000000..d6efa1b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_background.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+            <solid android:color="@color/hvac_off_background_color" />
+        </shape>
+    </item>
+    <item
+        android:gravity="left"
+        android:width="@dimen/hvac_panel_button_dimen">
+        <selector>
+            <item android:state_selected="true">
+                <shape android:shape="rectangle">
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                    <solid android:color="@color/hvac_on_background_color" />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="rectangle">
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                    <solid android:color="@color/hvac_off_background_color" />
+                </shape>
+            </item>
+        </selector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb.xml
new file mode 100644
index 0000000..63b731f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb.xml
@@ -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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_1.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_1.xml
new file mode 100644
index 0000000..a0befd8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_1.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_1"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_2.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_2.xml
new file mode 100644
index 0000000..c0725c3
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_2.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_2"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_3.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_3.xml
new file mode 100644
index 0000000..d11d90b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_3.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_3"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_4.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_4.xml
new file mode 100644
index 0000000..177d9a4
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_4.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_4"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_5.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_5.xml
new file mode 100644
index 0000000..c87f92a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_5.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_5"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_6.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_6.xml
new file mode 100644
index 0000000..fc8452d
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_6.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_6"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_7.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_7.xml
new file mode 100644
index 0000000..4531e65
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_7.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_7"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_8.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_8.xml
new file mode 100644
index 0000000..9905a24
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_8.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_8"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_off.xml
new file mode 100644
index 0000000..b6c1cb9
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_off.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_off_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_off"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_cool_on_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_cool_on_bg.xml
new file mode 100644
index 0000000..711158c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_cool_on_bg.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <solid android:color="@color/hvac_on_cooling_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_heat_on_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_heat_on_bg.xml
new file mode 100644
index 0000000..d069bd9
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_heat_on_bg.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <solid android:color="@color/hvac_on_heating_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_off_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_off_bg.xml
new file mode 100644
index 0000000..2cc9886
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_off_bg.xml
@@ -0,0 +1,34 @@
+<?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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <solid android:color="@color/hvac_off_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_off_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_off_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_on_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_on_bg.xml
new file mode 100644
index 0000000..a5d66bc
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_on_bg.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <solid android:color="@color/hvac_on_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_cool_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_cool_background.xml
new file mode 100644
index 0000000..b1f9e79
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_cool_background.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:drawable="@drawable/hvac_button_cool_on_bg"/>
+    <item android:drawable="@drawable/hvac_button_off_bg"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_default_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_default_background.xml
new file mode 100644
index 0000000..84f502b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_default_background.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:drawable="@drawable/hvac_button_on_bg"/>
+    <item android:drawable="@drawable/hvac_button_off_bg"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_heat_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_heat_background.xml
new file mode 100644
index 0000000..09d091e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_heat_background.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:drawable="@drawable/hvac_button_heat_on_bg"/>
+    <item android:drawable="@drawable/hvac_button_off_bg"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml
new file mode 100644
index 0000000..1bdac16
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/hvac_background_color"/>
+    <corners android:radius="@dimen/hvac_panel_bg_radius"/>
+</shape>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_off.xml
new file mode 100644
index 0000000..5458c73
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_off.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M42.0001,22H35.6601L40.7401,16.92C41.5201,16.14 41.5201,14.88 40.7401,14.1C39.9601,13.32 38.6801,13.32 37.9001,14.1L30.0001,22H26.0001V18L33.9001,10.1C34.6801,9.32 34.6801,8.04 33.9001,7.26C33.1201,6.48 31.8601,6.48 31.0801,7.26L26.0001,12.34V6C26.0001,4.9 25.1001,4 24.0001,4C22.9001,4 22.0001,4.9 22.0001,6V12.34L16.9201,7.26C16.1401,6.48 14.8801,6.48 14.1001,7.26C13.3201,8.04 13.3201,9.32 14.1001,10.1L22.0001,18V20.34L27.6601,26H30.0001L37.9001,33.9C38.6801,34.68 39.9601,34.68 40.7401,33.9C41.5201,33.12 41.5201,31.86 40.7401,31.08L35.6601,26H42.0001C43.1001,26 44.0001,25.1 44.0001,24C44.0001,22.9 43.1001,22 42.0001,22Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M1.5801,11.24L12.3401,22H6.0001C4.9001,22 4.0001,22.9 4.0001,24C4.0001,25.1 4.9001,26 6.0001,26H12.3401L7.2601,31.08C6.4801,31.86 6.4801,33.12 7.2601,33.9C8.0401,34.68 9.3201,34.68 10.1001,33.9L17.1801,26.82L21.1801,30.82L14.1001,37.9C13.3201,38.68 13.3201,39.96 14.1001,40.74C14.8801,41.52 16.1401,41.52 16.9201,40.74L22.0001,35.66V42C22.0001,43.1 22.9001,44 24.0001,44C25.1001,44 26.0001,43.1 26.0001,42V35.66L38.3401,48L41.1601,45.18L4.4001,8.4L1.5801,11.24Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_on.xml
new file mode 100644
index 0000000..f86563e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_on.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M42,22H35.66L40.74,16.92C41.52,16.14 41.52,14.88 40.74,14.1C39.96,13.32 38.68,13.32 37.9,14.1L30,22H26V18L33.9,10.1C34.68,9.32 34.68,8.04 33.9,7.26C33.12,6.48 31.86,6.48 31.08,7.26L26,12.34V6C26,4.9 25.1,4 24,4C22.9,4 22,4.9 22,6V12.34L16.92,7.26C16.14,6.48 14.88,6.48 14.1,7.26C13.32,8.04 13.32,9.32 14.1,10.1L22,18V22H18L10.1,14.1C9.32,13.32 8.04,13.32 7.26,14.1C6.48,14.88 6.48,16.14 7.26,16.92L12.34,22H6C4.9,22 4,22.9 4,24C4,25.1 4.9,26 6,26H12.34L7.26,31.08C6.48,31.86 6.48,33.12 7.26,33.9C8.04,34.68 9.32,34.68 10.1,33.9L18,26H22V30L14.1,37.9C13.32,38.68 13.32,39.96 14.1,40.74C14.88,41.52 16.14,41.52 16.92,40.74L22,35.66V42C22,43.1 22.9,44 24,44C25.1,44 26,43.1 26,42V35.66L31.08,40.74C31.86,41.52 33.12,41.52 33.9,40.74C34.68,39.96 34.68,38.68 33.9,37.9L26,30V26H30L37.9,33.9C38.68,34.68 39.96,34.68 40.74,33.9C41.52,33.12 41.52,31.86 40.74,31.08L35.66,26H42C43.1,26 44,25.1 44,24C44,22.9 43.1,22 42,22Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42,22H35.66L40.74,16.92C41.52,16.14 41.52,14.88 40.74,14.1C39.96,13.32 38.68,13.32 37.9,14.1L30,22H26V18L33.9,10.1C34.68,9.32 34.68,8.04 33.9,7.26C33.12,6.48 31.86,6.48 31.08,7.26L26,12.34V6C26,4.9 25.1,4 24,4C22.9,4 22,4.9 22,6V12.34L16.92,7.26C16.14,6.48 14.88,6.48 14.1,7.26C13.32,8.04 13.32,9.32 14.1,10.1L22,18V22H18L10.1,14.1C9.32,13.32 8.04,13.32 7.26,14.1C6.48,14.88 6.48,16.14 7.26,16.92L12.34,22H6C4.9,22 4,22.9 4,24C4,25.1 4.9,26 6,26H12.34L7.26,31.08C6.48,31.86 6.48,33.12 7.26,33.9C8.04,34.68 9.32,34.68 10.1,33.9L18,26H22V30L14.1,37.9C13.32,38.68 13.32,39.96 14.1,40.74C14.88,41.52 16.14,41.52 16.92,40.74L22,35.66V42C22,43.1 22.9,44 24,44C25.1,44 26,43.1 26,42V35.66L31.08,40.74C31.86,41.52 33.12,41.52 33.9,40.74C34.68,39.96 34.68,38.68 33.9,37.9L26,30V26H30L37.9,33.9C38.68,34.68 39.96,34.68 40.74,33.9C41.52,33.12 41.52,31.86 40.74,31.08L35.66,26H42C43.1,26 44,25.1 44,24C44,22.9 43.1,22 42,22Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_off.xml
new file mode 100644
index 0000000..3cf394e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_off.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M40.209,16.7912L38.789,15.3812L36.999,17.1712L36.999,3.0012L34.999,3.0012L34.999,17.1712L33.209,15.3812L31.789,16.7912L35.999,21.0012L40.209,16.7912Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_on.xml
new file mode 100644
index 0000000..a4c1eb2
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_on.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M40.209,16.7912L38.789,15.3812L36.999,17.1712L36.999,3.0012L34.999,3.0012L34.999,17.1712L33.209,15.3812L31.789,16.7912L35.999,21.0012L40.209,16.7912Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_off.xml
new file mode 100644
index 0000000..981958a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_off.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M40.79,7.79L39.38,9.21L41.17,11H27V13H41.17L39.38,14.79L40.79,16.21L45,12L40.79,7.79Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M34.0357,32.7879L24.8843,46.6596C24.5051,47.2343 24.9173,48 25.6058,48C27.1439,48 28.6243,47.4142 29.746,46.3617L39.1144,37.5709C40.9682,35.8313 43.4149,34.8632 45.9571,34.8632H54.2339C56.5366,34.8632 58.6362,33.5453 59.6372,31.4715L66.7184,16.8024C67.3115,15.5736 66.4162,14.1474 65.0518,14.1474C64.0756,14.1474 63.157,14.6096 62.5752,15.3935L55.9986,24.2545C54.1122,26.7962 51.1338,28.2947 47.9686,28.2947H42.3829C39.0223,28.2947 35.8864,29.9828 34.0357,32.7879Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M62.0005,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_on.xml
new file mode 100644
index 0000000..4dc3272
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_on.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M40.79,7.79L39.38,9.21L41.17,11H27V13H41.17L39.38,14.79L40.79,16.21L45,12L40.79,7.79Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M34.0357,32.7879L24.8843,46.6596C24.5051,47.2343 24.9173,48 25.6058,48C27.1439,48 28.6243,47.4142 29.746,46.3617L39.1144,37.5709C40.9682,35.8313 43.4149,34.8632 45.9571,34.8632H54.2339C56.5366,34.8632 58.6362,33.5453 59.6372,31.4715L66.7184,16.8024C67.3115,15.5736 66.4162,14.1474 65.0518,14.1474C64.0756,14.1474 63.157,14.6096 62.5752,15.3935L55.9986,24.2545C54.1122,26.7962 51.1338,28.2947 47.9686,28.2947H42.3829C39.0223,28.2947 35.8864,29.9828 34.0357,32.7879Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M62.0005,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_off.xml
new file mode 100644
index 0000000..2cdfa90
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_off.xml
@@ -0,0 +1,53 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M41.5603,10.0488C37.5686,12.8863 45.4033,16.6289 41.5603,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M37.0374,10.0488C33.0456,12.8863 40.8804,16.6289 37.0374,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M32.5135,10.0488C28.5217,12.8863 36.3565,16.629 32.5135,19.0973"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M28.8859,15.7037H27.804L25.0881,6.2391C24.7768,5.1544 25.3126,4.0062 26.3439,3.5479C30.1667,1.8493 33.7188,1 37,1C40.2812,1 43.8333,1.8493 47.6561,3.5479C48.6874,4.0061 49.2232,5.1544 48.9119,6.2391L46.196,15.7037H45.1141"
+      android:strokeLineJoin="round"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_on.xml
new file mode 100644
index 0000000..a3510b1
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_on.xml
@@ -0,0 +1,53 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M41.5603,10.0488C37.5686,12.8863 45.4033,16.6289 41.5603,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M37.0374,10.0488C33.0456,12.8863 40.8804,16.6289 37.0374,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M32.5135,10.0488C28.5217,12.8863 36.3565,16.629 32.5135,19.0973"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M28.8859,15.7037H27.804L25.0881,6.2391C24.7768,5.1544 25.3126,4.0062 26.3439,3.5479C30.1667,1.8493 33.7188,1 37,1C40.2812,1 43.8333,1.8493 47.6561,3.5479C48.6874,4.0061 49.2232,5.1544 48.9119,6.2391L46.196,15.7037H45.1141"
+      android:strokeLineJoin="round"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_off.xml
new file mode 100644
index 0000000..65a4b12
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_off.xml
@@ -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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M0.2653,30L4.6853,17.828H7.3203L11.7573,30H9.2243L8.2383,27.093H3.7843L2.7983,30H0.2653ZM5.5183,21.942L4.4983,24.985H7.5243L6.5043,21.942L6.0793,20.48H5.9433L5.5183,21.942ZM17.9681,30.272C16.4721,30.272 15.2934,29.8243 14.4321,28.929C13.5821,28.0337 13.1571,26.7927 13.1571,25.206V17.828H15.4181V25.359C15.4181,26.2203 15.6334,26.8947 16.0641,27.382C16.4947,27.858 17.1294,28.096 17.9681,28.096C18.8067,28.096 19.4357,27.858 19.8551,27.382C20.2857,26.8947 20.5011,26.2203 20.5011,25.359V17.828H22.7621V25.206C22.7621,26.226 22.5694,27.1157 22.1841,27.875C21.7987,28.6343 21.2491,29.2237 20.5351,29.643C19.8211,30.0623 18.9654,30.272 17.9681,30.272ZM28.299,30V20.004H24.559V17.828H34.317V20.004H30.577V30H28.299ZM41.1274,30.272C39.926,30.272 38.8834,30 37.9994,29.456C37.1154,28.9007 36.4297,28.147 35.9424,27.195C35.455,26.2317 35.2114,25.138 35.2114,23.914C35.2114,22.6787 35.455,21.585 35.9424,20.633C36.4297,19.681 37.1154,18.933 37.9994,18.389C38.8834,17.8337 39.926,17.556 41.1274,17.556C42.3287,17.556 43.3714,17.8337 44.2554,18.389C45.1394,18.933 45.825,19.681 46.3124,20.633C46.7997,21.585 47.0434,22.6787 47.0434,23.914C47.0434,25.138 46.7997,26.2317 46.3124,27.195C45.825,28.147 45.1394,28.9007 44.2554,29.456C43.3714,30 42.3287,30.272 41.1274,30.272ZM41.1274,28.096C42.204,28.096 43.071,27.7333 43.7284,27.008C44.397,26.2827 44.7314,25.2513 44.7314,23.914C44.7314,22.5767 44.397,21.5453 43.7284,20.82C43.071,20.0947 42.204,19.732 41.1274,19.732C40.0507,19.732 39.178,20.0947 38.5094,20.82C37.852,21.5453 37.5234,22.5767 37.5234,23.914C37.5234,25.2513 37.852,26.2827 38.5094,27.008C39.178,27.7333 40.0507,28.096 41.1274,28.096Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_on.xml
new file mode 100644
index 0000000..c847a95
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_on.xml
@@ -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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M0.2653,30L4.6853,17.828H7.3203L11.7573,30H9.2243L8.2383,27.093H3.7843L2.7983,30H0.2653ZM5.5183,21.942L4.4983,24.985H7.5243L6.5043,21.942L6.0793,20.48H5.9433L5.5183,21.942ZM17.9681,30.272C16.4721,30.272 15.2934,29.8243 14.4321,28.929C13.5821,28.0337 13.1571,26.7927 13.1571,25.206V17.828H15.4181V25.359C15.4181,26.2203 15.6334,26.8947 16.0641,27.382C16.4947,27.858 17.1294,28.096 17.9681,28.096C18.8067,28.096 19.4357,27.858 19.8551,27.382C20.2857,26.8947 20.5011,26.2203 20.5011,25.359V17.828H22.7621V25.206C22.7621,26.226 22.5694,27.1157 22.1841,27.875C21.7987,28.6343 21.2491,29.2237 20.5351,29.643C19.8211,30.0623 18.9654,30.272 17.9681,30.272ZM28.299,30V20.004H24.559V17.828H34.317V20.004H30.577V30H28.299ZM41.1274,30.272C39.926,30.272 38.8834,30 37.9994,29.456C37.1154,28.9007 36.4297,28.147 35.9424,27.195C35.455,26.2317 35.2114,25.138 35.2114,23.914C35.2114,22.6787 35.455,21.585 35.9424,20.633C36.4297,19.681 37.1154,18.933 37.9994,18.389C38.8834,17.8337 39.926,17.556 41.1274,17.556C42.3287,17.556 43.3714,17.8337 44.2554,18.389C45.1394,18.933 45.825,19.681 46.3124,20.633C46.7997,21.585 47.0434,22.6787 47.0434,23.914C47.0434,25.138 46.7997,26.2317 46.3124,27.195C45.825,28.147 45.1394,28.9007 44.2554,29.456C43.3714,30 42.3287,30.272 41.1274,30.272ZM41.1274,28.096C42.204,28.096 43.071,27.7333 43.7284,27.008C44.397,26.2827 44.7314,25.2513 44.7314,23.914C44.7314,22.5767 44.397,21.5453 43.7284,20.82C43.071,20.0947 42.204,19.732 41.1274,19.732C40.0507,19.732 39.178,20.0947 38.5094,20.82C37.852,21.5453 37.5234,22.5767 37.5234,23.914C37.5234,25.2513 37.852,26.2827 38.5094,27.008C39.178,27.7333 40.0507,28.096 41.1274,28.096Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.xml
new file mode 100644
index 0000000..4df0f11
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/rear_view_camera_exit_icon_width"
+        android:height="@dimen/rear_view_camera_exit_icon_height"
+        android:viewportWidth="26"
+        android:viewportHeight="26">
+    <path
+        android:pathData="M25.8327 2.75199L23.2477 0.166992L12.9994 10.4153L2.75102 0.166992L0.166016 2.75199L10.4144 13.0003L0.166016 23.2487L2.75102 25.8337L12.9994 15.5853L23.2477 25.8337L25.8327 23.2487L15.5844 13.0003L25.8327 2.75199Z"
+        android:fillColor="@color/rear_view_camera_exit_icon_color" />
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_off.xml
new file mode 100644
index 0000000..29bae07
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_off.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M55.4836,23.5C49.4334,27.8006 61.3082,33.4732 55.4836,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M48.6281,23.5C42.5779,27.8006 54.4527,33.4732 48.6281,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M41.7707,23.5C35.7205,27.8006 47.5953,33.4732 41.7707,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M36,32.5H32C30.8954,32.5 30,31.6046 30,30.5V13C30,11.8954 30.8954,11 32,11H64.5C65.6046,11 66.5,11.8954 66.5,13V30.5C66.5,31.6046 65.6046,32.5 64.5,32.5H62"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_on.xml
new file mode 100644
index 0000000..ca35897
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_on.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M55.4836,23.5C49.4334,27.8006 61.3082,33.4732 55.4836,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M48.6281,23.5C42.5779,27.8006 54.4527,33.4732 48.6281,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M41.7707,23.5C35.7205,27.8006 47.5953,33.4732 41.7707,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M36,32.5H32C30.8954,32.5 30,31.6046 30,30.5V13C30,11.8954 30.8954,11 32,11H64.5C65.6046,11 66.5,11.8954 66.5,13V30.5C66.5,31.6046 65.6046,32.5 64.5,32.5H62"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_off.xml
new file mode 100644
index 0000000..99a55de
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_off.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M54.1007,23.7148C48.0506,28.0154 59.9254,33.6881 54.1007,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M47.2453,23.7148C41.1951,28.0154 53.0699,33.6881 47.2453,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M40.3878,23.7148C34.3377,28.0154 46.2125,33.6881 40.3878,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M34.8897,32.2857H33.2499L29.1335,17.9407C28.6618,16.2966 29.4739,14.5563 31.0369,13.8618C36.831,11.2873 42.2146,10 47.1878,10C52.161,10 57.5447,11.2873 63.3387,13.8618C64.9018,14.5563 65.7139,16.2966 65.2421,17.9406L61.1257,32.2857H59.486"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_on.xml
new file mode 100644
index 0000000..9728826
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_on.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M54.1007,23.7148C48.0506,28.0154 59.9254,33.6881 54.1007,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M47.2453,23.7148C41.1951,28.0154 53.0699,33.6881 47.2453,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M40.3878,23.7148C34.3377,28.0154 46.2125,33.6881 40.3878,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M34.8897,32.2857H33.2499L29.1335,17.9407C28.6618,16.2966 29.4739,14.5563 31.0369,13.8618C36.831,11.2873 42.2146,10 47.1878,10C52.161,10 57.5447,11.2873 63.3387,13.8618C64.9018,14.5563 65.7139,16.2966 65.2421,17.9406L61.1257,32.2857H59.486"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_high.xml
new file mode 100644
index 0000000..afc41fd
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_high.xml
@@ -0,0 +1,40 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_low.xml
new file mode 100644
index 0000000..2888403
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_low.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_med.xml
new file mode 100644
index 0000000..98c5042
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_med.xml
@@ -0,0 +1,41 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_off.xml
new file mode 100644
index 0000000..5453dd5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_off.xml
@@ -0,0 +1,43 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_high.xml
new file mode 100644
index 0000000..326b9b9
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_high.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_low.xml
new file mode 100644
index 0000000..0528b68
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_low.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_med.xml
new file mode 100644
index 0000000..326ec7f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_med.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_off.xml
new file mode 100644
index 0000000..78d0236
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_off.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_off.xml
new file mode 100644
index 0000000..649195b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_off.xml
@@ -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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_on.xml
new file mode 100644
index 0000000..62bb353
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_on.xml
@@ -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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_off.xml
new file mode 100644
index 0000000..48baaf5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_off.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M41.1457,5.5455C35.3706,9.6506 46.7056,15.0654 41.1457,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M35.6907,5.5455C29.9155,9.6506 41.2505,15.0654 35.6907,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M30.2356,5.5455C24.4604,9.6506 35.7955,15.0654 30.2356,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M24,6.5455C12,6.5455 6.5454,16.9091 6.5454,24C6.5454,31.0909 12,41.4546 24,41.4546C36,41.4546 41.4545,32.5005 41.4545,25.0005"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M14.0005,24.0005L8.0005,24.5005L8.5005,28.0005L18.296,28.7261C20.3848,28.8809 22.0005,30.6207 22.0005,32.7152V41.0005H26.0005V32.7722C26.0005,30.6543 27.6514,28.9034 29.7656,28.7791L43.0005,28.0005L43.5005,24.5005L34.0005,24.0005L30.0005,22.0005H18.0005L14.0005,24.0005Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_on.xml
new file mode 100644
index 0000000..425f2f6
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_on.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M41.1457,5.5455C35.3706,9.6506 46.7056,15.0654 41.1457,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M35.6907,5.5455C29.9155,9.6506 41.2505,15.0654 35.6907,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M30.2356,5.5455C24.4604,9.6506 35.7955,15.0654 30.2356,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M24,6.5455C12,6.5455 6.5454,16.9091 6.5454,24C6.5454,31.0909 12,41.4546 24,41.4546C36,41.4546 41.4545,32.5005 41.4545,25.0005"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M14.0005,24.0005L8.0005,24.5005L8.5005,28.0005L18.296,28.7261C20.3848,28.8809 22.0005,30.6207 22.0005,32.7152V41.0005H26.0005V32.7722C26.0005,30.6543 27.6514,28.9034 29.7656,28.7791L43.0005,28.0005L43.5005,24.5005L34.0005,24.0005L30.0005,22.0005H18.0005L14.0005,24.0005Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_hvac_close.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_hvac_close.xml
new file mode 100644
index 0000000..e9ae42e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_hvac_close.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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/hvac_panel_exit_icon_dimen"
+        android:height="@dimen/hvac_panel_exit_icon_dimen"
+        android:viewportWidth="26"
+        android:viewportHeight="26">
+    <path
+        android:pathData="M25.8327 2.75199L23.2477 0.166992L12.9994 10.4153L2.75102 0.166992L0.166016 2.75199L10.4144 13.0003L0.166016 23.2487L2.75102 25.8337L12.9994 15.5853L23.2477 25.8337L25.8327 23.2487L15.5844 13.0003L25.8327 2.75199Z"
+        android:fillColor="@color/hvac_off_icon_fill_color" />
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_1.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_1.xml
new file mode 100644
index 0000000..00a1ed8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_1.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42.9713,47V38.792L41.3233,39.992L40.2673,38.376L43.4833,36.056H45.0673V47H42.9713Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_2.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_2.xml
new file mode 100644
index 0000000..3421517
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_2.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.3867,47V45.096C39.3867,45.096 39.4987,44.984 39.7227,44.76C39.9467,44.536 40.2294,44.2533 40.5707,43.912C40.9227,43.5707 41.2854,43.2133 41.6587,42.84C42.032,42.4667 42.3734,42.12 42.6827,41.8C42.992,41.48 43.2214,41.24 43.3707,41.08C43.744,40.6747 44.0054,40.3333 44.1547,40.056C44.304,39.7787 44.3787,39.4587 44.3787,39.096C44.3787,38.744 44.2454,38.4347 43.9787,38.168C43.712,37.9013 43.3387,37.768 42.8587,37.768C42.3787,37.768 42.0054,37.9067 41.7387,38.184C41.472,38.4613 41.2854,38.7707 41.1787,39.112L39.2907,38.328C39.408,37.9333 39.616,37.544 39.9147,37.16C40.224,36.776 40.624,36.456 41.1147,36.2C41.616,35.9333 42.208,35.8 42.8907,35.8C43.6374,35.8 44.2774,35.944 44.8107,36.232C45.3547,36.52 45.7707,36.904 46.0587,37.384C46.3574,37.864 46.5067,38.4027 46.5067,39C46.5067,39.6827 46.3414,40.312 46.0107,40.888C45.68,41.464 45.2694,41.992 44.7787,42.472C44.6187,42.6213 44.5014,42.7333 44.4267,42.808C44.3627,42.872 44.2934,42.936 44.2187,43C44.1547,43.064 44.0534,43.1653 43.9147,43.304C43.7867,43.432 43.584,43.6347 43.3067,43.912C43.04,44.1893 42.6614,44.5733 42.1707,45.064L42.2187,45.16H46.6507V47H39.3867Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_3.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_3.xml
new file mode 100644
index 0000000..58f47fe
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_3.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42.9975,47.256C42.1122,47.256 41.3068,47.0213 40.5815,46.552C39.8562,46.072 39.3548,45.3467 39.0775,44.376L41.0615,43.592C41.3282,44.68 41.9735,45.224 42.9975,45.224C43.4455,45.224 43.8402,45.0907 44.1815,44.824C44.5228,44.5467 44.6935,44.1893 44.6935,43.752C44.6935,43.2827 44.5122,42.9147 44.1495,42.648C43.7868,42.3813 43.3068,42.248 42.7095,42.248H41.7655V40.344H42.6295C43.0668,40.344 43.4562,40.232 43.7975,40.008C44.1388,39.784 44.3095,39.4373 44.3095,38.968C44.3095,38.6053 44.1762,38.3067 43.9095,38.072C43.6535,37.8373 43.3122,37.72 42.8855,37.72C42.4162,37.72 42.0535,37.848 41.7975,38.104C41.5415,38.36 41.3655,38.6427 41.2695,38.952L39.3655,38.168C39.4935,37.8053 39.7068,37.4427 40.0055,37.08C40.3042,36.7173 40.6935,36.4133 41.1735,36.168C41.6535,35.9227 42.2295,35.8 42.9015,35.8C43.6055,35.8 44.2188,35.928 44.7415,36.184C45.2748,36.44 45.6908,36.792 45.9895,37.24C46.2882,37.6773 46.4375,38.1733 46.4375,38.728C46.4375,39.3573 46.2882,39.8747 45.9895,40.28C45.7015,40.6853 45.3868,40.9733 45.0455,41.144V41.272C45.5468,41.4747 45.9682,41.8 46.3095,42.248C46.6615,42.696 46.8375,43.2613 46.8375,43.944C46.8375,44.5733 46.6775,45.1387 46.3575,45.64C46.0375,46.1413 45.5895,46.536 45.0135,46.824C44.4375,47.112 43.7655,47.256 42.9975,47.256Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_4.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_4.xml
new file mode 100644
index 0000000..077d134
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_4.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M38.7282,44.984V43.288L43.5922,36.056H45.8642V43.032H47.2242V44.984H45.8642V47H43.7682V44.984H38.7282ZM41.0482,43.032H43.7682V39.176H43.6402L41.0482,43.032Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_5.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_5.xml
new file mode 100644
index 0000000..74b7fc2
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_5.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42.9365,47.256C42.3925,47.256 41.8485,47.1493 41.3045,46.936C40.7712,46.7227 40.3018,46.3973 39.8965,45.96C39.4912,45.5227 39.2085,44.968 39.0485,44.296L40.9365,43.56C41.0538,44.0827 41.2832,44.5093 41.6245,44.84C41.9658,45.16 42.3978,45.32 42.9205,45.32C43.4218,45.32 43.8432,45.1493 44.1845,44.808C44.5365,44.4667 44.7125,44.0347 44.7125,43.512C44.7125,43 44.5472,42.5733 44.2165,42.232C43.8858,41.88 43.4538,41.704 42.9205,41.704C42.5898,41.704 42.2965,41.7733 42.0405,41.912C41.7845,42.0507 41.5658,42.2267 41.3845,42.44L39.3525,41.528L39.9765,36.056H46.1525V37.896H41.7205L41.3205,40.456L41.4485,40.488C41.6618,40.3067 41.9232,40.152 42.2325,40.024C42.5525,39.896 42.9258,39.832 43.3525,39.832C43.9605,39.832 44.5258,39.9867 45.0485,40.296C45.5712,40.6053 45.9925,41.0373 46.3125,41.592C46.6432,42.136 46.8085,42.776 46.8085,43.512C46.8085,44.2373 46.6432,44.8827 46.3125,45.448C45.9818,46.0133 45.5232,46.456 44.9365,46.776C44.3605,47.096 43.6938,47.256 42.9365,47.256Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_6.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_6.xml
new file mode 100644
index 0000000..503c42a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_6.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M43.0392,47.256C42.4312,47.256 41.8765,47.1493 41.3752,46.936C40.8845,46.712 40.4685,46.4187 40.1272,46.056C39.4445,45.3413 39.1032,44.4667 39.1032,43.432C39.1032,42.696 39.2472,42.024 39.5352,41.416C39.8339,40.808 40.2072,40.1787 40.6552,39.528C41.0925,38.8987 41.5299,38.2693 41.9672,37.64C42.4152,37 42.8579,36.3653 43.2952,35.736L44.9272,36.856C44.5539,37.3787 44.1752,37.9067 43.7912,38.44C43.4179,38.9627 43.0445,39.4907 42.6712,40.024L42.7672,40.12C43.0125,40.0133 43.2899,39.96 43.5992,39.96C44.1539,39.96 44.6819,40.1093 45.1832,40.408C45.6845,40.7067 46.0952,41.1227 46.4152,41.656C46.7352,42.1893 46.8952,42.808 46.8952,43.512C46.8952,44.2373 46.7139,44.8827 46.3512,45.448C45.9885,46.0133 45.5139,46.456 44.9272,46.776C44.3405,47.096 43.7112,47.256 43.0392,47.256ZM42.9912,45.336C43.3219,45.336 43.6259,45.2613 43.9032,45.112C44.1805,44.952 44.4045,44.7387 44.5752,44.472C44.7565,44.1947 44.8472,43.88 44.8472,43.528C44.8472,43.1653 44.7565,42.8507 44.5752,42.584C44.4045,42.3067 44.1752,42.0933 43.8872,41.944C43.6099,41.784 43.3112,41.704 42.9912,41.704C42.6819,41.704 42.3832,41.784 42.0952,41.944C41.8179,42.0933 41.5885,42.3067 41.4072,42.584C41.2365,42.8507 41.1512,43.1653 41.1512,43.528C41.1512,43.88 41.2365,44.1947 41.4072,44.472C41.5885,44.7387 41.8179,44.952 42.0952,45.112C42.3725,45.2613 42.6712,45.336 42.9912,45.336Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_7.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_7.xml
new file mode 100644
index 0000000..bcf9158
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_7.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M41.5709,47.256L39.8109,46.28L44.3709,38.12L44.3069,38.024H39.2829V36.056H46.7229V38.12C45.8695,39.6347 45.0109,41.1547 44.1469,42.68C43.2829,44.2053 42.4242,45.7307 41.5709,47.256Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_8.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_8.xml
new file mode 100644
index 0000000..7d70370
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_8.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M43.0087,47.256C42.23,47.256 41.542,47.112 40.9447,46.824C40.3474,46.5253 39.878,46.1307 39.5367,45.64C39.206,45.1387 39.0407,44.5787 39.0407,43.96C39.0407,43.32 39.2114,42.776 39.5527,42.328C39.894,41.8693 40.278,41.5227 40.7047,41.288V41.16C40.3634,40.9253 40.0594,40.616 39.7927,40.232C39.5367,39.8373 39.4087,39.3893 39.4087,38.888C39.4087,38.3013 39.5634,37.7787 39.8727,37.32C40.182,36.8507 40.6087,36.4827 41.1527,36.216C41.6967,35.9387 42.3154,35.8 43.0087,35.8C43.702,35.8 44.3154,35.9387 44.8487,36.216C45.3927,36.4827 45.8194,36.8507 46.1287,37.32C46.4487,37.7787 46.6087,38.3013 46.6087,38.888C46.6087,39.3893 46.4754,39.8373 46.2087,40.232C45.9527,40.616 45.6487,40.9253 45.2967,41.16V41.288C45.734,41.5227 46.1234,41.8693 46.4647,42.328C46.806,42.776 46.9767,43.32 46.9767,43.96C46.9767,44.5787 46.806,45.1387 46.4647,45.64C46.134,46.1307 45.67,46.5253 45.0727,46.824C44.486,47.112 43.798,47.256 43.0087,47.256ZM43.0087,40.376C43.446,40.376 43.814,40.2533 44.1127,40.008C44.422,39.752 44.5767,39.4213 44.5767,39.016C44.5767,38.6 44.422,38.2747 44.1127,38.04C43.814,37.7947 43.446,37.672 43.0087,37.672C42.5607,37.672 42.182,37.7947 41.8727,38.04C41.574,38.2747 41.4247,38.6 41.4247,39.016C41.4247,39.4213 41.574,39.752 41.8727,40.008C42.182,40.2533 42.5607,40.376 43.0087,40.376ZM43.0087,45.32C43.5527,45.32 43.9954,45.176 44.3367,44.888C44.6887,44.6 44.8647,44.2213 44.8647,43.752C44.8647,43.304 44.6887,42.936 44.3367,42.648C43.9847,42.36 43.542,42.216 43.0087,42.216C42.4754,42.216 42.0274,42.36 41.6647,42.648C41.3127,42.936 41.1367,43.304 41.1367,43.752C41.1367,44.2213 41.3127,44.6 41.6647,44.888C42.0167,45.176 42.4647,45.32 43.0087,45.32Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_off.xml
new file mode 100644
index 0000000..9d55f5c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_off.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_high.xml
new file mode 100644
index 0000000..8d92c3f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_high.xml
@@ -0,0 +1,40 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_low.xml
new file mode 100644
index 0000000..eb0927a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_low.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_med.xml
new file mode 100644
index 0000000..c7471a8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_med.xml
@@ -0,0 +1,41 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_off.xml
new file mode 100644
index 0000000..f0df11c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_off.xml
@@ -0,0 +1,43 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_high.xml
new file mode 100644
index 0000000..8e5c5e3
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_high.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_low.xml
new file mode 100644
index 0000000..52cf98b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_low.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_med.xml
new file mode 100644
index 0000000..8a02789
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_med.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_off.xml
new file mode 100644
index 0000000..b407df6
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_off.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_off.xml
new file mode 100644
index 0000000..aef5c8a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_off.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M26.0001,4H22.0001V24H26.0001V4ZM33.9201,14.1L36.7401,11.28C43.7601,18.32 43.7601,29.7 36.7401,36.72C29.7201,43.76 18.3201,43.76 11.3001,36.74C4.2601,29.7 4.2601,18.3 11.2801,11.28L14.1001,14.08C8.6401,19.54 8.6601,28.44 14.1201,33.9C19.5601,39.34 28.4401,39.34 33.9001,33.88C39.3601,28.42 39.3801,19.56 33.9201,14.1Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_on.xml
new file mode 100644
index 0000000..359ab84
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_on.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M26.0001,4H22.0001V24H26.0001V4ZM33.9201,14.1L36.7401,11.28C43.7601,18.32 43.7601,29.7 36.7401,36.72C29.7201,43.76 18.3201,43.76 11.3001,36.74C4.2601,29.7 4.2601,18.3 11.2801,11.28L14.1001,14.08C8.6401,19.54 8.6601,28.44 14.1201,33.9C19.5601,39.34 28.4401,39.34 33.9001,33.88C39.3601,28.42 39.3801,19.56 33.9201,14.1Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_off.xml
new file mode 100644
index 0000000..dbe02ed
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_off.xml
@@ -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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M12,27C12,23.14 15.5,20 19.8,20H32.34L27.16,25.18L30,28L40,18L30,8L27.18,10.82L32.34,16H19.8C13.3,16 8,20.94 8,27C8,33.06 13.3,38 19.8,38H34V34H19.8C15.5,34 12,30.86 12,27Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_on.xml
new file mode 100644
index 0000000..55aa087
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_on.xml
@@ -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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M12,27C12,23.14 15.5,20 19.8,20H32.34L27.16,25.18L30,28L40,18L30,8L27.18,10.82L32.34,16H19.8C13.3,16 8,20.94 8,27C8,33.06 13.3,38 19.8,38H34V34H19.8C15.5,34 12,30.86 12,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_off.xml
new file mode 100644
index 0000000..97698d7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_off.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M33.6001,24.0001L40.8001,16.8001L33.6001,9.6001V14.4001H9.6001V19.2001H33.6001V24.0001Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M14.4002,24L7.2002,31.2L14.4002,38.4V33.6H38.4002V28.8H14.4002V24Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_on.xml
new file mode 100644
index 0000000..ab3b3ab
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_on.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M33.6001,24.0001L40.8001,16.8001L33.6001,9.6001V14.4001H9.6001V19.2001H33.6001V24.0001Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M14.4002,24L7.2002,31.2L14.4002,38.4V33.6H38.4002V28.8H14.4002V24Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
new file mode 100644
index 0000000..3f7700b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true">
+        <layer-list>
+            <item>
+                <shape android:shape="oval">
+                    <size android:width="@dimen/system_bar_button_size"
+                          android:height="@dimen/system_bar_button_size"/>
+                    <solid android:color="@color/car_nav_icon_fill_color"/>
+                </shape>
+            </item>
+            <item>
+                <ripple android:color="@color/car_ui_ripple_color"
+                        android:radius="@dimen/system_bar_icon_drawing_size"/>
+            </item>
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item>
+                <shape android:shape="oval">
+                    <size android:width="@dimen/system_bar_button_size"
+                          android:height="@dimen/system_bar_button_size"/>
+                    <solid android:color="@color/car_nav_icon_background_color"/>
+                </shape>
+            </item>
+            <item>
+                <ripple android:color="@color/car_ui_ripple_color"
+                        android:radius="@dimen/system_bar_icon_drawing_size"/>
+            </item>
+        </layer-list>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
new file mode 100644
index 0000000..63c841b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
@@ -0,0 +1,94 @@
+<?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.
+  -->
+
+<com.android.systemui.car.systembar.CarSystemBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/system_bar_background"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <com.android.systemui.car.hvac.TemperatureControlView
+            android:id="@+id/driver_hvac"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:layout_gravity="start"
+            android:gravity="start|center_vertical"
+            systemui:hvacAreaId="49">
+            <include layout="@layout/adjustable_temperature_view"/>
+        </com.android.systemui.car.hvac.TemperatureControlView>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:layoutDirection="ltr">
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/grid_nav"
+                style="@style/SystemBarButton"
+                systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_apps"
+                systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
+                systemui:clearBackStack="true"/>
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/notifications"
+                style="@style/SystemBarButton"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_notification"
+                systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/hvac"
+                style="@style/SystemBarButton"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_hvac"
+                systemui:broadcast="true"/>
+
+            <com.android.systemui.car.systembar.AssitantButton
+                android:id="@+id/assist"
+                style="@style/SystemBarButton"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_mic"
+                systemui:useDefaultAppIconForRole="false"/>
+        </LinearLayout>
+
+        <com.android.systemui.car.hvac.TemperatureControlView
+            android:id="@+id/passenger_hvac"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_gravity="end"
+            android:layout_weight="1"
+            android:gravity="end|center_vertical"
+            systemui:hvacAreaId="68">
+            <include layout="@layout/adjustable_temperature_view"/>
+        </com.android.systemui.car.hvac.TemperatureControlView>
+
+    </LinearLayout>
+</com.android.systemui.car.systembar.CarSystemBarView>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml
new file mode 100644
index 0000000..e30ec45
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml
@@ -0,0 +1,85 @@
+<?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.
+  -->
+
+<com.android.systemui.car.systembar.CarSystemBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/car_top_bar"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/status_bar_background"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <com.android.systemui.car.systembar.CarSystemBarButton
+        android:id="@+id/user_name"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/car_padding_3"
+        android:layout_gravity="start"
+        android:gravity="start"
+        android:orientation="horizontal"
+        systemui:intent="intent:#Intent;component=com.android.car.settings/.profiles.ProfileSwitcherActivity;launchFlags=0x24000000;end">
+            <ImageView
+                android:id="@+id/user_avatar"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:src="@drawable/car_ic_user_icon"
+                android:layout_marginEnd="@dimen/system_bar_user_icon_padding"/>
+            <TextView
+                android:id="@+id/user_name_text"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:textAppearance="@style/TextAppearance.SystemBar.Username"
+                android:maxLines="1"
+                android:maxLength="10"/>
+    </com.android.systemui.car.systembar.CarSystemBarButton>
+
+    <com.android.systemui.statusbar.policy.Clock
+        android:id="@+id/clock"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:layout_gravity="center"
+        android:gravity="center"
+        android:paddingStart="@dimen/car_padding_2"
+        android:paddingEnd="@dimen/car_padding_2"
+        android:elevation="5dp"
+        android:singleLine="true"
+        android:textAppearance="@style/TextAppearance.SystemBar.Clock"
+        systemui:amPmStyle="normal"/>
+
+    <com.android.systemui.car.systembar.CarSystemBarButton
+        android:id="@+id/system_icon_area"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="@dimen/car_padding_3"
+        android:layout_gravity="end"
+        android:gravity="end"
+        systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$HomepageActivity;launchFlags=0x24000000;end">
+
+        <com.android.systemui.statusbar.phone.StatusIconContainer
+            android:id="@+id/statusIcons"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="fitCenter"
+            android:gravity="center"
+            android:orientation="horizontal"
+        />
+    </com.android.systemui.car.systembar.CarSystemBarButton>
+</com.android.systemui.car.systembar.CarSystemBarView>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/fan_direction.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/fan_direction.xml
new file mode 100644
index 0000000..5cbe9e7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/fan_direction.xml
@@ -0,0 +1,110 @@
+<!--
+  ~ 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.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:systemui="http://schemas.android.com/apk/res-auto"
+       android:layout_width="match_parent"
+       android:layout_height="match_parent">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/direction_face"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="356517121"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_airflow_head_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_airflow_head_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"
+            systemui:preventToggleOff="true"/>
+        <View
+            android:layout_width="32dp"
+            android:layout_height="match_parent"/>
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/direction_floor"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="356517121"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_airflow_feet_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_airflow_feet_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="2"
+            systemui:offValue="0"
+            systemui:preventToggleOff="true"/>
+        <View
+            android:layout_width="32dp"
+            android:layout_height="match_parent"/>
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/direction_defrost_front_and_floor"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="356517121"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_airflow_windshield_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_airflow_windshield_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="6"
+            systemui:offValue="0"
+            systemui:preventToggleOff="true"/>
+    </LinearLayout>
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="32dp"/>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/direction_defrost_front"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="1"
+            systemui:hvacPropertyId="320865540"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_defroster_windshield_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_defroster_windshield_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"/>
+        <View
+            android:layout_width="32dp"
+            android:layout_height="match_parent"/>
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/direction_defrost_rear"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="2"
+            systemui:hvacPropertyId="320865540"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_defroster_rear_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_defroster_rear_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"/>
+    </LinearLayout>
+</merge>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml
new file mode 100644
index 0000000..f92c857
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml
@@ -0,0 +1,298 @@
+<?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.
+  -->
+
+<com.android.car.ui.FocusArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/hvac_panel_container"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/hvac_panel_full_expanded_height"
+    android:layout_gravity="bottom">
+    <com.android.systemui.car.hvac.HvacPanelView
+        android:id="@+id/hvac_panel"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/hvac_panel_bg">
+
+        <ImageButton
+            android:id="@+id/hvac_panel_close_button"
+            android:layout_width="@dimen/hvac_panel_exit_button_dimen"
+            android:layout_height="@dimen/hvac_panel_exit_button_dimen"
+            android:layout_marginLeft="@dimen/hvac_panel_exit_button_margin"
+            android:layout_marginTop="@dimen/hvac_panel_exit_button_margin"
+            android:background="@drawable/hvac_default_background"
+            android:scaleType="center"
+            android:src="@drawable/ic_hvac_close"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"/>
+        <FrameLayout
+            android:id="@+id/hvac_header_title"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/wrap_content"
+            android:layout_marginTop="@dimen/hvac_panel_title_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_dimen"
+            android:layout_marginRight="@dimen/hvac_panel_button_dimen"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent">
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:text="@string/hvac_panel_header"
+                android:gravity="center"/>
+        </FrameLayout>
+
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/top_guideline"
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:orientation="horizontal"
+            app:layout_constraintGuide_begin="@dimen/hvac_panel_buttons_guideline"/>
+
+        <!-- ************************ -->
+        <!-- First column of buttons. -->
+        <!-- ************************ -->
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/cooling_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toTopOf="@+id/steering_wheel_heat_on_off"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419973"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_ac_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_ac_on"
+            systemui:hvacTurnOffIfAutoOn="true"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/steering_wheel_heat_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_heat_background"
+            app:layout_constraintBottom_toTopOf="@+id/hvac_on_off"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/cooling_on_off"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="289408269"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_heated_steering_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_heated_steering_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/hvac_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/steering_wheel_heat_on_off"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419984"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_power_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_power_on"
+            systemui:hvacTurnOffIfPowerOff="false"/>
+
+        <!-- ************************* -->
+        <!-- Second column of buttons. -->
+        <!-- ************************* -->
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_cooler_driver_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_cool_background"
+            app:layout_constraintBottom_toTopOf="@+id/seat_heater_driver_on_off"
+            app:layout_constraintLeft_toRightOf="@+id/cooling_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/airflow_group"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="1"
+            systemui:seatTemperatureType="cooling"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_driver_seat_cool_icons"/>
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_heater_driver_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_heat_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toRightOf="@+id/hvac_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/fan_speed_control"
+            app:layout_constraintTop_toBottomOf="@+id/seat_cooler_driver_on_off"
+            systemui:hvacAreaId="1"
+            systemui:seatTemperatureType="heating"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_driver_seat_heat_icons"/>
+
+        <!-- ************************ -->
+        <!-- Third column of buttons. -->
+        <!-- ************************ -->
+
+        <LinearLayout
+            android:id="@+id/airflow_group"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:orientation="vertical"
+            app:layout_constraintBottom_toTopOf="@+id/fan_speed_control"
+            app:layout_constraintLeft_toRightOf="@+id/seat_cooler_driver_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/seat_cooler_passenger_on_off"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline">
+           <include layout="@layout/fan_direction"/>
+        </LinearLayout>
+
+        <com.android.systemui.car.hvac.custom.FanSpeedSeekBar
+            android:id="@+id/fan_speed_control"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:progressDrawable="@drawable/fan_speed_seek_bar"
+            android:thumb="@drawable/fan_speed_seek_bar_thumb"
+            android:maxHeight="@dimen/hvac_panel_button_dimen"
+            android:minHeight="@dimen/hvac_panel_button_dimen"
+            android:background="@drawable/fan_speed_seek_bar_background"
+            android:splitTrack="false"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toRightOf="@+id/seat_heater_driver_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/seat_heater_passenger_on_off"
+            app:layout_constraintTop_toBottomOf="@+id/airflow_windshield"/>
+
+        <!-- ************************* -->
+        <!-- Fourth column of buttons. -->
+        <!-- ************************* -->
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_cooler_passenger_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_cool_background"
+            app:layout_constraintBottom_toTopOf="@+id/seat_heater_passenger_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/recycle_air_on_off"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="4"
+            systemui:seatTemperatureType="cooling"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_passenger_seat_cool_icons"/>
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_heater_passenger_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_heat_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toLeftOf="@+id/hvac_driver_passenger_sync"
+            app:layout_constraintTop_toBottomOf="@+id/seat_cooler_passenger_on_off"
+            systemui:hvacAreaId="4"
+            systemui:seatTemperatureType="heating"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_passenger_seat_heat_icons"/>
+
+        <!-- ************************ -->
+        <!-- Fifth column of buttons. -->
+        <!-- ************************ -->
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/recycle_air_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toTopOf="@+id/hvac_driver_passenger_sync"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419986"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_recirculate_on"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_recirculate_off"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/hvac_driver_passenger_sync"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toTopOf="@+id/auto_temperature_on_off"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/recycle_air_on_off"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419977"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_sync_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_sync_on"
+            systemui:hvacTurnOffIfAutoOn="true"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/auto_temperature_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/hvac_driver_passenger_sync"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419978"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_auto_on"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_auto_off"/>
+
+        <include
+            layout="@layout/hvac_panel_handle_bar"
+            app:layout_constraintTop_toTopOf="parent"/>
+    </com.android.systemui.car.hvac.HvacPanelView>
+</com.android.car.ui.FocusArea>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_handle_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_handle_bar.xml
new file mode 100644
index 0000000..0ebd055
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_handle_bar.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <View
+        android:id="@+id/handle_bar"
+        android:layout_width="@dimen/hvac_panel_handle_bar_width"
+        android:layout_height="@dimen/hvac_panel_handle_bar_height"
+        android:layout_marginTop="@dimen/hvac_panel_handle_bar_margin_top"
+        android:layout_gravity="top|center_horizontal"
+        android:background="@drawable/hvac_panel_handle_bar"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml
new file mode 100644
index 0000000..a7631d7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml
@@ -0,0 +1,36 @@
+<?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.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/transparent">
+    <LinearLayout
+        android:id="@+id/rear_view_camera_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"/>
+    <ImageButton
+        android:id="@+id/close_button"
+        android:layout_width="@dimen/rear_view_camera_exit_button_width"
+        android:layout_height="@dimen/rear_view_camera_exit_button_height"
+        android:layout_marginStart="@dimen/rear_view_camera_exit_button_margin"
+        android:layout_marginTop="@dimen/rear_view_camera_exit_button_margin"
+        android:scaleType="center"
+        android:src="@drawable/ic_close"
+        android:background="@drawable/exit_icon_background"/>
+</FrameLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/arrays.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/arrays.xml
new file mode 100644
index 0000000..c1c2119
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/arrays.xml
@@ -0,0 +1,54 @@
+<?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.
+ -->
+
+<resources>
+    <array name="hvac_driver_seat_heat_icons">
+        <item>@drawable/ic_driver_seat_heat_off</item>
+        <item>@drawable/ic_driver_seat_heat_low</item>
+        <item>@drawable/ic_driver_seat_heat_med</item>
+        <item>@drawable/ic_driver_seat_heat_high</item>
+    </array>
+    <array name="hvac_passenger_seat_heat_icons">
+        <item>@drawable/ic_passenger_seat_heat_off</item>
+        <item>@drawable/ic_passenger_seat_heat_low</item>
+        <item>@drawable/ic_passenger_seat_heat_med</item>
+        <item>@drawable/ic_passenger_seat_heat_high</item>
+    </array>
+    <array name="hvac_driver_seat_cool_icons">
+        <item>@drawable/ic_driver_seat_cool_off</item>
+        <item>@drawable/ic_driver_seat_cool_low</item>
+        <item>@drawable/ic_driver_seat_cool_med</item>
+        <item>@drawable/ic_driver_seat_cool_high</item>
+    </array>
+    <array name="hvac_passenger_seat_cool_icons">
+        <item>@drawable/ic_passenger_seat_cool_off</item>
+        <item>@drawable/ic_passenger_seat_cool_low</item>
+        <item>@drawable/ic_passenger_seat_cool_med</item>
+        <item>@drawable/ic_passenger_seat_cool_high</item>
+    </array>
+    <array name="hvac_fan_speed_icons">
+        <item>@drawable/fan_speed_seek_bar_thumb_off</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_1</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_2</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_3</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_4</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_5</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_6</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_7</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_8</item>
+    </array>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/attrs.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/attrs.xml
new file mode 100644
index 0000000..120905f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/attrs.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <declare-styleable name="FanSpeedSeekBar">
+        <!-- List of drawables that will be shown when the seat heat level button is clicked.
+             This list should have exactly R.integer.hvac_seat_heat_level_count items.
+             The first item should have the "off" drawable. -->
+        <attr name="fanSpeedThumbIcons" format="reference"/>
+    </declare-styleable>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
new file mode 100644
index 0000000..248a2c8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
@@ -0,0 +1,38 @@
+<?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.
+  -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <color name="rear_view_camera_button_background">#CCFFFFFF</color>
+    <color name="rear_view_camera_exit_icon_color">@android:color/black</color>
+
+    <color name="car_nav_icon_fill_color">#FFFFFF</color>
+    <color name="car_nav_icon_background_color">#3C4043</color>
+
+    <drawable name="system_bar_background">#000000</drawable>
+
+    <color name="status_bar_background_color">#00000000</color>
+    <drawable name="status_bar_background">@color/status_bar_background_color</drawable>
+
+    <color name="hvac_background_color">#202124</color>
+    <color name="hvac_master_switch_color">@color/car_nav_icon_fill_color</color>
+    <color name="hvac_on_icon_fill_color">@android:color/black</color>
+    <color name="hvac_off_icon_fill_color">@android:color/white</color>
+    <color name="hvac_on_cooling_background_color">#669DF6</color>
+    <color name="hvac_on_heating_background_color">#EE675C</color>
+    <color name="hvac_on_background_color">#50E3C2</color>
+    <color name="hvac_off_background_color">#3C4043</color>
+
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
new file mode 100644
index 0000000..ecd31f7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
@@ -0,0 +1,44 @@
+<?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.
+  -->
+
+<resources>
+    <string name="config_systemUIFactoryComponent" translatable="false">
+        com.android.systemui.CarUiPortraitSystemUIFactory
+    </string>
+
+    <!-- Car System UI's OverlayViewsMediator.
+         Whenever a new class is added, make sure to also add that class to OverlayWindowModule. -->
+    <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
+        <item>@string/config_notificationPanelViewMediator</item>
+        <item>com.android.systemui.car.hvac.HvacPanelOverlayViewMediator</item>
+        <item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
+        <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
+        <item>com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator</item>
+    </string-array>
+
+    <!-- Show heads-up notifications on the bottom -->
+    <bool name="config_showHeadsUpNotificationOnBottom">true</bool>
+
+    <string name="config_notificationPanelViewMediator" translatable="false">
+        com.android.systemui.car.notification.BottomNotificationPanelViewMediator</string>
+
+    <!-- Animation helper for animating heads-up notification showing on screen and leaving the screen from the bottom -->
+    <string name="config_headsUpNotificationAnimationHelper" translatable="false">
+        com.android.car.notification.headsup.animationhelper.CarHeadsUpNotificationBottomAnimationHelper</string>
+
+    <integer name="hvac_num_fan_speeds">9</integer>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
new file mode 100644
index 0000000..6a961fd
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
@@ -0,0 +1,68 @@
+<?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.
+  -->
+
+<resources>
+    <!-- dimensions for rear view camera -->
+    <dimen name="rear_view_camera_width">1020dp</dimen>
+    <dimen name="rear_view_camera_height">720dp</dimen>
+
+    <dimen name="rear_view_camera_exit_button_width">48dp</dimen>
+    <dimen name="rear_view_camera_exit_button_height">48dp</dimen>
+    <dimen name="rear_view_camera_exit_button_margin">24dp</dimen>
+    <dimen name="rear_view_camera_exit_icon_width">26dp</dimen>
+    <dimen name="rear_view_camera_exit_icon_height">26dp</dimen>
+
+    <dimen name="hvac_container_padding">16dp</dimen>
+    <dimen name="hvac_temperature_text_size">48sp</dimen>
+    <dimen name="hvac_temperature_text_padding">0dp</dimen>
+
+    <dimen name="system_bar_icon_drawing_size">56dp</dimen>
+    <dimen name="system_bar_button_size">88dp</dimen>
+    <!-- Margin between the system bar buttons -->
+    <dimen name="system_bar_button_margin">32dp</dimen>
+    <!-- Padding between the system bar button and the icon within it -->
+    <dimen name="system_bar_button_padding">16dp</dimen>
+
+    <dimen name="system_bar_user_icon_drawing_size">44dp</dimen>
+    <dimen name="status_bar_system_icon_spacing">32dp</dimen>
+
+    <dimen name="hvac_panel_handle_bar_height">6dp</dimen>
+    <dimen name="hvac_panel_handle_bar_margin_top">8dp</dimen>
+    <dimen name="hvac_panel_handle_bar_width">64dp</dimen>
+    <dimen name="hvac_panel_bg_radius">24dp</dimen>
+    <dimen name="hvac_panel_off_button_radius">24dp</dimen>
+    <dimen name="hvac_panel_on_button_radius">44dp</dimen>
+    <dimen name="hvac_panel_full_expanded_height">472dp</dimen>
+    <dimen name="hvac_panel_exit_icon_dimen">21dp</dimen>
+    <dimen name="hvac_panel_exit_button_dimen">64dp</dimen>
+    <dimen name="hvac_panel_exit_button_margin">24dp</dimen>
+    <dimen name="hvac_panel_title_margin">36dp</dimen>
+    <dimen name="hvac_panel_buttons_guideline">120dp</dimen>
+    <dimen name="hvac_panel_icon_dimen">48dp</dimen>
+    <dimen name="hvac_panel_tall_icon_dimen">108dp</dimen>
+    <dimen name="hvac_panel_wide_icon_dimen">96dp</dimen>
+    <dimen name="hvac_panel_icon_inset_dimen">22dp</dimen>
+    <dimen name="hvac_panel_icon_inset_wide_dimen">92dp</dimen>
+    <dimen name="hvac_panel_icon_inset_extra_wide_dimen">140dp</dimen>
+    <dimen name="hvac_panel_button_dimen">88dp</dimen>
+    <dimen name="hvac_panel_tall_button_height">148dp</dimen>
+    <dimen name="hvac_panel_wide_button_width">374dp</dimen>
+    <dimen name="hvac_panel_slider_width">696dp</dimen>
+    <dimen name="hvac_panel_button_external_margin">24dp</dimen>
+    <dimen name="hvac_panel_button_internal_margin">16dp</dimen>
+    <item name="hvac_heat_or_cool_off_alpha" format="float" type="dimen">0.3</item>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml
new file mode 100644
index 0000000..c9cff07
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Format for temperature in the temperature control view (No decimal) -->
+    <string name="hvac_temperature_format_fahrenheit" translatable="false">%.0f</string>
+
+    <!-- HVAC panel header [CHAR LIMIT=40]-->
+    <string name="hvac_panel_header">Comfort controls</string>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
new file mode 100644
index 0000000..6e400e5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
@@ -0,0 +1,33 @@
+<!--
+  ~ 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.
+  -->
+
+<resources
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="SystemBarButton">
+        <item name="android:layout_width">@dimen/system_bar_button_size</item>
+        <item name="android:layout_height">@dimen/system_bar_button_size</item>
+        <item name="android:background">@drawable/nav_bar_button_background</item>
+        <item name="android:gravity">center</item>
+        <item name="unselectedAlpha">1.0</item>
+    </style>
+
+    <style name="TextAppearance.SystemBar.Username"
+           parent="@android:style/TextAppearance.DeviceDefault">
+        <item name="android:textSize">@dimen/car_body1_size</item>
+        <item name="android:textColor">@color/system_bar_text_color</item>
+    </style>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitGlobalRootComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitGlobalRootComponent.java
new file mode 100644
index 0000000..af85885
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitGlobalRootComponent.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.android.systemui;
+
+import com.android.systemui.dagger.GlobalModule;
+import com.android.systemui.dagger.WMModule;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+/**
+ * Root Component for Dagger injection for CarUiPortraitSystemUI
+ */
+@Singleton
+@Component(
+        modules = {
+                GlobalModule.class,
+                CarUiPortraitSysUIComponentModule.class,
+                WMModule.class
+        })
+interface CarUiPortraitGlobalRootComponent extends CarGlobalRootComponent {
+    @Component.Builder
+    interface Builder extends CarGlobalRootComponent.Builder {
+        CarUiPortraitGlobalRootComponent build();
+    }
+
+    @Override
+    CarUiPortraitSysUIComponent.Builder getSysUIComponent();
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java
new file mode 100644
index 0000000..25e488f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java
@@ -0,0 +1,43 @@
+/*
+ * 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 com.android.systemui;
+
+import com.android.systemui.dagger.DependencyProvider;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.SystemUIModule;
+
+import dagger.Subcomponent;
+
+/**
+ * Dagger Subcomponent for Core SysUI.
+ */
+@SysUISingleton
+@Subcomponent(modules = {
+        CarComponentBinder.class,
+        DependencyProvider.class,
+        SystemUIModule.class,
+        CarSystemUIModule.class,
+        CarUiPortraitSystemUIBinder.class})
+public interface CarUiPortraitSysUIComponent extends CarSysUIComponent {
+    /**
+     * Builder for a CarSysUIComponent.
+     */
+    @Subcomponent.Builder
+    interface Builder extends CarSysUIComponent.Builder {
+        CarUiPortraitSysUIComponent build();
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponentModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponentModule.java
new file mode 100644
index 0000000..196c917
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponentModule.java
@@ -0,0 +1,32 @@
+/*
+ * 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 com.android.systemui;
+
+import dagger.Binds;
+import dagger.Module;
+
+/**
+ * Dagger module for including the CarUiPortraitSysUIComponent.
+ *
+ * TODO(b/162923491): Remove or otherwise refactor this module. This is a stop gap.
+ */
+@Module(subcomponents = {CarUiPortraitSysUIComponent.class})
+public abstract class CarUiPortraitSysUIComponentModule {
+    @Binds
+    abstract CarGlobalRootComponent bindSystemUIRootComponent(
+            CarUiPortraitGlobalRootComponent systemUIRootComponent);
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
new file mode 100644
index 0000000..a7cddb8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
@@ -0,0 +1,24 @@
+/*
+ * 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 com.android.systemui;
+
+import dagger.Module;
+
+/** Binder for AAECarSystemUI specific {@link SystemUI} modules and components. */
+@Module
+abstract class CarUiPortraitSystemUIBinder extends CarSystemUIBinder {
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java
new file mode 100644
index 0000000..ef75f48
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java
@@ -0,0 +1,31 @@
+/*
+ * 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 com.android.systemui;
+
+import android.content.Context;
+
+import com.android.systemui.dagger.GlobalRootComponent;
+
+/**
+ * Class factory to provide AAECarSystemUI specific SystemUI components.
+ */
+public class CarUiPortraitSystemUIFactory extends CarSystemUIFactory {
+    @Override
+    protected GlobalRootComponent buildGlobalRootComponent(Context context) {
+        return DaggerCarUiPortraitGlobalRootComponent.builder().context(context).build();
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/custom/FanSpeedSeekBar.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/custom/FanSpeedSeekBar.java
new file mode 100644
index 0000000..c7f2b5f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/custom/FanSpeedSeekBar.java
@@ -0,0 +1,196 @@
+/*
+ * 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 com.android.systemui.car.hvac.custom;
+
+import static android.car.VehiclePropertyIds.HVAC_AUTO_ON;
+import static android.car.VehiclePropertyIds.HVAC_FAN_SPEED;
+import static android.car.VehiclePropertyIds.HVAC_POWER_ON;
+
+import android.car.hardware.CarPropertyValue;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.widget.SeekBar;
+
+import androidx.annotation.ArrayRes;
+
+import com.android.systemui.R;
+import com.android.systemui.car.hvac.HvacController;
+import com.android.systemui.car.hvac.HvacPropertySetter;
+import com.android.systemui.car.hvac.HvacView;
+
+/** Custom seek bar to control fan speed. */
+public class FanSpeedSeekBar extends SeekBar implements HvacView {
+
+    private final SparseArray<Drawable> mIcons = new SparseArray<>();
+
+    private HvacPropertySetter mHvacPropertySetter;
+    private int mHvacGlobalAreaId;
+
+    private boolean mPowerOn;
+    private boolean mAutoOn;
+
+    private float mOnAlpha;
+    private float mOffAlpha;
+
+    private final OnSeekBarChangeListener mSeekBarChangeListener = new OnSeekBarChangeListener() {
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+            int prevProgress = getProgress();
+            // Limit updates to the hvac property to be only those that come from the user in order
+            // to avoid an infinite loop.
+            if (shouldAllowControl() && fromUser && progress == prevProgress) {
+                mHvacPropertySetter.setHvacProperty(HVAC_FAN_SPEED, getAreaId(), progress);
+            } else if (progress != prevProgress) {
+                // There is an edge case with seek bar touch handling that can lead to an
+                // inconsistent state of the progress state and UI. We need to set the progress to
+                // a different value before setting it to the value we expect in order to ensure
+                // that the update doesn't get dropped.
+                setProgress(progress);
+                setProgress(prevProgress);
+                updateUI();
+            }
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+            // no-op.
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            // no-op.
+        }
+    };
+
+    public FanSpeedSeekBar(Context context) {
+        super(context);
+        init(null);
+    }
+
+    public FanSpeedSeekBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(attrs);
+    }
+
+    public FanSpeedSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(attrs);
+    }
+
+    public FanSpeedSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(attrs);
+    }
+
+    private void init(AttributeSet attrs) {
+        int speeds = mContext.getResources().getInteger(R.integer.hvac_num_fan_speeds);
+        setMin(0);
+        incrementProgressBy(1);
+        // Subtract 1 since we're starting from 0.
+        setMax(speeds - 1);
+        int thumbRadius = mContext.getResources().getDimensionPixelSize(
+                R.dimen.hvac_panel_on_button_radius);
+        setPadding(thumbRadius, 0, thumbRadius, 0);
+        mHvacGlobalAreaId = mContext.getResources().getInteger(R.integer.hvac_global_area_id);
+
+        mOnAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_on_alpha);
+        mOffAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_off_alpha);
+
+        if (attrs == null) {
+            return;
+        }
+
+        // Get fan speed thumb drawables.
+        TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.FanSpeedSeekBar);
+        @ArrayRes int drawableListRes = typedArray.getResourceId(
+                R.styleable.FanSpeedSeekBar_fanSpeedThumbIcons,
+                R.array.hvac_fan_speed_icons);
+
+        TypedArray fanSpeedThumbIcons = mContext.getResources().obtainTypedArray(drawableListRes);
+        if (fanSpeedThumbIcons.length() != speeds) {
+            throw new IllegalArgumentException(
+                    "R.styeable.SeatHeatLevelButton_seatHeaterIconDrawableList should have the "
+                            + "same length as R.integer.hvac_seat_heat_level_count");
+        }
+
+        for (int i = 0; i < speeds; i++) {
+            mIcons.set(i, fanSpeedThumbIcons.getDrawable(i));
+        }
+        fanSpeedThumbIcons.recycle();
+        typedArray.recycle();
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        setOnSeekBarChangeListener(mSeekBarChangeListener);
+    }
+
+    @Override
+    public void setHvacPropertySetter(HvacPropertySetter hvacPropertySetter) {
+        mHvacPropertySetter = hvacPropertySetter;
+    }
+
+    @Override
+    public void onHvacTemperatureUnitChanged(boolean usesFahrenheit) {
+        // no-op.
+    }
+
+    @Override
+    public void onPropertyChanged(CarPropertyValue value) {
+        if (value.getPropertyId() == HVAC_FAN_SPEED) {
+            int level = (int) value.getValue();
+            setProgress(level, /* animate= */ true);
+        }
+
+        if (value.getPropertyId() == HVAC_POWER_ON) {
+            mPowerOn = (boolean) value.getValue();
+        }
+
+        if (value.getPropertyId() == HVAC_AUTO_ON) {
+            mAutoOn = (boolean) value.getValue();
+        }
+
+        updateUI();
+    }
+
+    @Override
+    public @HvacController.HvacProperty Integer getHvacPropertyToView() {
+        return HVAC_FAN_SPEED;
+    }
+
+    @Override
+    public @HvacController.AreaId Integer getAreaId() {
+        return mHvacGlobalAreaId;
+    }
+
+    private void updateUI() {
+        int progress = getProgress();
+        setThumb(mIcons.get(progress));
+        setSelected(progress > 0);
+        setAlpha(shouldAllowControl() ? mOnAlpha : mOffAlpha);
+        // Steal touch events if shouldn't allow control.
+        setOnTouchListener(shouldAllowControl() ? null : (v, event) -> true);
+    }
+
+    private boolean shouldAllowControl() {
+        return mPowerOn && !mAutoOn;
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/HideApps/Android.mk b/car_product/car_ui_portrait/apps/HideApps/Android.mk
new file mode 100644
index 0000000..3dc4adf
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/HideApps/Android.mk
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_PACKAGE_NAME := CarUiPortraitHideApps
+LOCAL_SDK_VERSION := current
+
+# Add packages here to remove them from the build
+LOCAL_OVERRIDES_PACKAGES := \
+    CarRotaryController \
+    RotaryPlayground \
+    RotaryIME \
+    CarRotaryImeRRO \
+
+include $(BUILD_PACKAGE)
diff --git a/car_product/car_ui_portrait/apps/HideApps/AndroidManifest.xml b/car_product/car_ui_portrait/apps/HideApps/AndroidManifest.xml
new file mode 100644
index 0000000..a234af5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/HideApps/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.caruiportrait.hideapps">
+    <application
+        android:allowBackup="false"
+        android:debuggable="false"
+        android:label="CarUiPortraitHideApps">
+    </application>
+</manifest>
diff --git a/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk b/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk
new file mode 100644
index 0000000..1a3d48a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+# All apps that should be included in CarUiPortrait builds
+PRODUCT_PACKAGES += \
+    CarUiPortraitSettings \
+    CarUiPortraitSystemUI \
+
+# All apps to be excluded in car_ui_portrait builds should be specified as part of CarUiPortraitHideApps.
+PRODUCT_PACKAGES += \
+    CarUiPortraitHideApps
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/car_ui_portrait.ini b/car_product/car_ui_portrait/car_ui_portrait.ini
new file mode 100644
index 0000000..ec34d7f
--- /dev/null
+++ b/car_product/car_ui_portrait/car_ui_portrait.ini
@@ -0,0 +1,11 @@
+hw.audioInput=yes
+hw.lcd.density=160
+hw.gpu.enabled=yes
+hw.camera.back=none
+hw.camera.front=none
+hw.mainKeys=no
+skin.dynamic=yes
+skin.name=1080x1920
+skin.path=1080x1920
+hw.lcd.width=1080
+hw.lcd.height=1920
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/overlay/README b/car_product/car_ui_portrait/overlay/README
new file mode 100644
index 0000000..e49b1b0
--- /dev/null
+++ b/car_product/car_ui_portrait/overlay/README
@@ -0,0 +1,2 @@
+This project currently using the old approach for static RROs targeting the android package due to
+b/186753067. Please use the current approach for RROs for any other application/package.
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values-sw900dp/dimens.xml b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values-sw900dp/dimens.xml
new file mode 100644
index 0000000..a4aa16b
--- /dev/null
+++ b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values-sw900dp/dimens.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+<resources>
+    <!-- Height of the bottom navigation / climate bar. -->
+    <dimen name="navigation_bar_height">160dp</dimen>
+    <dimen name="navigation_bar_height_landscape">160dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/config.xml b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/config.xml
new file mode 100644
index 0000000..55cac9f
--- /dev/null
+++ b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/config.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- IME should not hide nav bar -->
+    <bool name="config_automotiveHideNavBarForKeyboard">false</bool>
+
+    <!-- Class name of the device specific implementation of DisplayAreaPolicy.Provider
+    or empty if the default should be used. -->
+    <string translatable="false" name="config_deviceSpecificDisplayAreaPolicyProvider">
+        com.android.server.wm.CarDisplayAreaPolicyProvider
+    </string>
+</resources>
diff --git a/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/dimens.xml b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/dimens.xml
new file mode 100644
index 0000000..e78a77f
--- /dev/null
+++ b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/dimens.xml
@@ -0,0 +1,23 @@
+<?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.
+  -->
+<resources>
+    <!-- Height of the status bar -->
+    <dimen name="status_bar_height">92dp</dimen>
+    <!-- Height of the bottom navigation / climate bar. -->
+    <dimen name="navigation_bar_height">160dp</dimen>
+    <dimen name="navigation_bar_height_landscape">160dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
new file mode 100644
index 0000000..051115c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
@@ -0,0 +1,30 @@
+// 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: "CarUiPortraitLauncherRRO",
+    resource_dirs: ["res"],
+    platform_apis: true,
+    aaptflags: [
+        "--no-resource-deduping",
+        "--no-resource-removal"
+    ],
+    static_libs: [
+        "androidx.cardview_cardview",
+        "car-media-common",
+        "car-apps-common",
+    ],
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/AndroidManifest.xml
new file mode 100644
index 0000000..1969da8
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/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.carlauncher.caruiportrait.rro">
+    <application android:hasCode="false"/>
+    <overlay android:priority="20"
+             android:targetName="CarLauncher"
+             android:targetPackage="com.android.car.carlauncher"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true" />
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout-land/car_launcher.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout-land/car_launcher.xml
new file mode 100644
index 0000000..7f79ef1
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout-land/car_launcher.xml
@@ -0,0 +1,32 @@
+<?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.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:layoutDirection="ltr">
+
+    <com.android.car.ui.FocusArea
+        android:id="@+id/bottom_card"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:padding="10dp"
+        android:layoutDirection="locale"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml
new file mode 100644
index 0000000..fbd91ba
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml
@@ -0,0 +1,38 @@
+<?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.
+  -->
+
+<!-- Layout for a DescriptiveTextView. Required by HomeCardFragment, but currently not used by the CarUiPortrait launcher. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="horizontal">
+
+    <include layout="@layout/descriptive_text"
+             android:layout_height="match_parent"
+             android:layout_width="wrap_content"/>
+
+    <TextView
+        android:id="@+id/tap_for_more_text"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:singleLine="true"
+        android:text="Tap for more"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:visibility="gone"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml
new file mode 100644
index 0000000..7a879a1
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml
@@ -0,0 +1,53 @@
+<?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.
+  -->
+
+<!-- Layout for a DescriptiveTextWithControlsView. Required by HomeCardFragment, but currently not used by the CarUiPortrait launcher. -->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <include layout="@layout/descriptive_text"
+             android:layout_height="match_parent"
+             android:layout_width="wrap_content"/>
+
+    <LinearLayout
+        android:gravity="center"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:orientation="horizontal"
+        android:id="@+id/button_trio">
+
+    <ImageButton
+        android:id="@+id/button_left"
+        android:layout_height="@dimen/control_bar_action_icon_size"
+        android:layout_width="@dimen/control_bar_action_icon_size"
+        android:scaleType="fitCenter"/>
+
+    <ImageButton
+        android:id="@+id/button_center"
+        android:layout_height="@dimen/control_bar_action_icon_size"
+        android:layout_width="@dimen/control_bar_action_icon_size"
+        android:scaleType="fitCenter"/>
+
+    <ImageButton
+        android:id="@+id/button_right"
+        android:layout_height="@dimen/control_bar_action_icon_size"
+        android:layout_width="@dimen/control_bar_action_icon_size"
+        android:scaleType="fitCenter"/>
+    </LinearLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml
new file mode 100644
index 0000000..34fe61d
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml
@@ -0,0 +1,45 @@
+<?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.
+  -->
+
+<!-- Layout specifically for the media card, which uses media-specific playback_controls.xml -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="horizontal">
+
+    <include layout="@layout/descriptive_text"
+             android:id="@+id/media_descriptive_text"
+             android:layout_height="match_parent"
+             android:layout_width="0dp"
+             android:layout_weight="1"
+             android:layout_gravity="start|center_vertical"/>
+
+    <FrameLayout
+        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_gravity="end|center_vertical">
+
+        <com.android.car.media.common.PlaybackControlsActionBar
+            android:id="@+id/media_playback_controls_bar"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            app:columns="@integer/playback_controls_bar_columns"/>
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml
new file mode 100644
index 0000000..f08886b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml
@@ -0,0 +1,41 @@
+<?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.
+  -->
+
+<!-- Layout for a TextBlockView. Required by HomeCardFragment, but currently not used by the CarUiPortrait launcher. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/text_block"
+        android:gravity="start"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+    <TextView
+        android:id="@+id/tap_for_more_text"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:singleLine="true"
+        android:text="Tap for more"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:visibility="gone"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml
new file mode 100644
index 0000000..ccc8b80
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml
@@ -0,0 +1,111 @@
+<?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.
+  -->
+
+<androidx.cardview.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/card_view"
+    android:foreground="?android:attr/selectableItemBackground"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:visibility="gone">
+
+    <FrameLayout
+        android:id="@+id/card_background"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <!-- card_background_image is required by HomeCardFragment. Intentionally not shown by
+         setting visibility="gone" -->
+        <com.android.car.apps.common.CrossfadeImageView
+            android:id="@+id/card_background_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            android:scaleType="centerCrop"/>
+
+        <View
+            android:id="@+id/card_background_scrim"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:focusable="false"
+            android:background="@color/card_background_scrim"
+            android:alpha="@dimen/card_background_scrim_alpha"/>
+    </FrameLayout>
+
+    <RelativeLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent">
+
+        <ImageView
+            android:id="@+id/card_icon"
+            android:layout_height="@dimen/control_bar_image_size"
+            android:layout_width="@dimen/control_bar_image_size"
+            android:layout_marginStart="@dimen/card_icon_margin_start"
+            android:layout_alignParentStart="true"
+            android:layout_centerVertical="true"/>
+
+        <!-- Do not show -->
+        <TextView
+            android:id="@+id/card_name"
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:visibility="gone"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/card_icon"/>
+
+        <FrameLayout
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/card_name"
+            android:layout_alignParentEnd="true"
+            android:layout_marginStart="@dimen/card_content_margin_start">
+
+            <ViewStub android:id="@+id/media_layout"
+                      android:inflatedId="@+id/media_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_media"/>
+
+            <!-- Following ViewStubs are required by the HomeCardFragment, but are currently unused
+            as the portrait launcher only shows an audio card and the respective media layout. -->
+            <ViewStub android:id="@+id/descriptive_text_layout"
+                      android:inflatedId="@+id/descriptive_text_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_descriptive_text_only"/>
+
+            <ViewStub android:id="@+id/text_block_layout"
+                      android:inflatedId="@+id/text_block_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_text_block"/>
+
+            <ViewStub android:id="@+id/descriptive_text_with_controls_layout"
+                      android:inflatedId="@+id/descriptive_text_with_controls_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_descriptive_text_with_controls"/>
+
+        </FrameLayout>
+    </RelativeLayout>
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
new file mode 100644
index 0000000..156ee41
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
@@ -0,0 +1,72 @@
+<?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.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <!-- optional_image is required by the HomeCardFragment. Intentionally not shown by setting
+    0 height and width. -->
+    <ImageView
+        android:id="@+id/optional_image"
+        android:layout_height="0dp"
+        android:layout_width="0dp"
+        android:visibility="gone"
+        android:layout_alignParentStart="true"/>
+
+    <TextView
+        android:id="@+id/primary_text"
+        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:singleLine="true"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentTop="true"
+        android:layout_marginTop="@dimen/descriptive_text_vertical_margin"/>
+
+    <Chronometer
+        android:id="@+id/optional_timer"
+        android:visibility="gone"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
+
+    <TextView
+        android:id="@+id/optional_timer_separator"
+        android:visibility="gone"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:text="@string/ongoing_call_duration_text_separator"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:layout_toEndOf="@id/optional_timer"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
+
+    <TextView
+        android:id="@+id/secondary_text"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:singleLine="true"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
new file mode 100644
index 0000000..0604222
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+
+<resources>
+    <color name="card_background_scrim">#000000</color>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml
new file mode 100644
index 0000000..afc5169
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/config.xml
@@ -0,0 +1,24 @@
+<?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.
+  -->
+
+<resources>
+    <!-- A list of package names that provide the cards to display on the home screen -->
+    <string-array name="config_homeCardModuleClasses" translatable="false">
+        <item>com.android.car.carlauncher.homescreen.audio.AudioCard</item>
+    </string-array>
+
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml
new file mode 100644
index 0000000..976d16c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml
@@ -0,0 +1,30 @@
+<?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.
+  -->
+
+<resources>
+    <dimen name="card_icon_margin_start">24dp</dimen>
+    <dimen name="card_content_margin_start">32dp</dimen>
+
+    <dimen name="descriptive_text_vertical_margin">22dp</dimen>
+
+    <dimen name="control_bar_image_size">56dp</dimen>
+
+    <dimen name="control_bar_action_icon_size">56dp</dimen>
+
+    <!-- Percent transparency of the scrim applied to the image used for the card's background as a float between 0 and 1, where 0 applies no darkening scrim-->
+    <dimen name="card_background_scrim_alpha" format="float">0.72</dimen>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
new file mode 100644
index 0000000..7d54116
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
@@ -0,0 +1,23 @@
+<?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.
+  -->
+<resources>
+    <!-- Number of buttons shown for the media playback controls bar -->
+    <integer name="playback_controls_bar_columns">3</integer>
+    <!--  Entry/exit animation transition speed in milliseconds.  This is the animation of foreground DA.-->
+    <integer name="enter_exit_animation_foreground_display_area_duration_ms">500</integer>
+</resources>
+
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
new file mode 100644
index 0000000..2c0a471
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+
+<resources>
+    <string name="ongoing_call_duration_text_separator">&#160;&#8226;&#160;</string>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..8482e1e
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
@@ -0,0 +1,45 @@
+<!--
+  ~ 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.
+  -->
+<overlay>
+    <item target="id/bottom_card" value="@id/bottom_card" />
+    <item target="id/card_background" value="@id/card_background" />
+    <item target="id/card_background_image" value="@id/card_background_image" />
+    <item target="id/card_background_scrim" value="@id/card_background_scrim" />
+    <item target="id/card_icon" value="@id/card_icon" />
+    <item target="id/card_name" value="@id/card_name" />
+    <item target="id/card_view" value="@id/card_view" />
+    <item target="id/descriptive_text_layout" value="@id/descriptive_text_layout" />
+    <item target="id/text_block_layout" value="@id/text_block_layout" />
+    <item target="id/descriptive_text_with_controls_layout" value="@id/descriptive_text_with_controls_layout" />
+    <item target="id/media_descriptive_text" value="@id/media_descriptive_text" />
+    <item target="id/media_layout" value="@id/media_layout"/>
+    <item target="id/media_playback_controls_bar" value="@id/media_playback_controls_bar" />
+    <item target="id/optional_image" value="@id/optional_image" />
+    <item target="id/optional_timer" value="@id/optional_timer"/>
+    <item target="id/optional_timer_separator" value="@id/optional_timer_separator"/>
+    <item target="id/primary_text" value="@id/primary_text" />
+    <item target="id/secondary_text" value="@id/secondary_text"/>
+
+    <item target="layout/card_content_media" value="@layout/card_content_media" />
+    <item target="layout/card_fragment" value="@layout/card_fragment" />
+    <item target="layout/car_launcher" value="@layout/car_launcher"/>
+    <item target="layout/descriptive_text" value="@layout/descriptive_text" />
+
+    <item target="integer/enter_exit_animation_foreground_display_area_duration_ms" value="@integer/enter_exit_animation_foreground_display_area_duration_ms"/>
+
+    <item target="array/config_homeCardModuleClasses" value="@array/config_homeCardModuleClasses"/>
+
+</overlay>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/Android.bp
new file mode 100644
index 0000000..a36ec21
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/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: "CarUiPortraitMediaRRO",
+    resource_dirs: ["res"],
+    platform_apis: true,
+    aaptflags: [
+        "--no-resource-deduping",
+        "--no-resource-removal"
+    ],
+}
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml
new file mode 100644
index 0000000..fa12e4f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/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.caruiportrait.rro">
+    <application android:hasCode="false"/>
+    <overlay android:priority="20"
+             android:targetName="CarMediaApp"
+             android:targetPackage="com.android.car.media"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true" />
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/bools.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/bools.xml
new file mode 100644
index 0000000..8f979df
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/values/bools.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Now playing and mini playback controls will be shown in sysui instead of media center. -->
+    <bool name="show_mini_playback_controls">false</bool>
+    <bool name="switch_to_playback_view_when_playable_item_is_clicked">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..744f5c1
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/res/xml/overlays.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ 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.
+  -->
+
+<overlay>
+    <item target="bool/show_mini_playback_controls" value="@bool/show_mini_playback_controls" />
+    <item target="bool/switch_to_playback_view_when_playable_item_is_clicked" value="@bool/switch_to_playback_view_when_playable_item_is_clicked" />
+</overlay>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/Android.mk b/car_product/car_ui_portrait/rro/car-ui-customizations/Android.mk
new file mode 100644
index 0000000..a8e3b25
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/Android.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+CAR_UI_RRO_SET_NAME := generatedcaruiportrait
+CAR_UI_RRO_MANIFEST_FILE := $(LOCAL_PATH)/AndroidManifest.xml
+CAR_UI_RESOURCE_DIR := $(LOCAL_PATH)/res
+CAR_UI_RRO_TARGETS := \
+    com.android.car.media \
+    com.android.car.dialer \
+
+include packages/apps/Car/libs/car-ui-lib/generate_rros.mk
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml
new file mode 100644
index 0000000..9d3a1a4
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?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="{{RRO_PACKAGE_NAME}}">
+    <application android:hasCode="false"/>
+    <overlay android:priority="10"
+             android:targetName="car-ui-lib"
+             android:targetPackage="{{TARGET_PACKAGE_NAME}}"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true"
+             android:requiredSystemPropertyName="ro.build.characteristics"
+             android:requiredSystemPropertyValue="automotive"/>
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk b/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk
new file mode 100644
index 0000000..a4c86bd
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+# Inherit from this product to include the "Car Ui Portrait" RROs for CarUi
+# Include generated RROs
+PRODUCT_PACKAGES += \
+    generatedcaruiportrait-com-android-car-media \
+    generatedcaruiportrait-com-android-car-dialer \
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_primary.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_primary.xml
new file mode 100644
index 0000000..860f219
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_primary.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<!-- Copy of ?android:attr/textColorPrimary (frameworks/base/res/res/color/text_color_primary.xml)
+     but with a ux restricted state. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item android:state_enabled="false"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item app:state_ux_restricted="true"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item android:color="?android:attr/colorForeground"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_secondary.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_secondary.xml
new file mode 100644
index 0000000..f99fc86
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_secondary.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<!-- Copy of ?android:attr/textColorSecondary (frameworks/base/res/res/color/text_color_secondary.xml)
+     but with a ux restricted state. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item android:state_enabled="false"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item app:state_ux_restricted="true"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item android:color="?android:attr/colorForeground"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_toolbar_tab_item_selector.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_toolbar_tab_item_selector.xml
new file mode 100644
index 0000000..02d4374
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_toolbar_tab_item_selector.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/car_ui_text_color_primary" android:state_activated="true"/>
+    <item android:color="@color/car_ui_text_color_secondary"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml
new file mode 100644
index 0000000..4412c36
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#4285F4" android:state_activated="true"/>
+    <item android:color="@android:color/transparent"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_down.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_down.xml
new file mode 100644
index 0000000..e2d1b93
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_down.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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M14.83,16.42L24,25.59l9.17,-9.17L36,19.25l-12,12 -12,-12z"
+        android:fillColor="#000000"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_up.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_up.xml
new file mode 100644
index 0000000..c8cc84f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_up.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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M14.83,30.83L24,21.66l9.17,9.17L36,28 24,16 12,28z"
+        android:fillColor="#000000"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_scrollbar_thumb.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_scrollbar_thumb.xml
new file mode 100644
index 0000000..54922cf
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_scrollbar_thumb.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#99000000" />
+    <corners android:radius="100dp"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_divider.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_divider.xml
new file mode 100644
index 0000000..9b47736
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_divider.xml
@@ -0,0 +1,21 @@
+<?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.
+  ~
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <size android:width="16dp"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_ripple.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_ripple.xml
new file mode 100644
index 0000000..9ac2a1f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_ripple.xml
@@ -0,0 +1,20 @@
+<?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.
+  ~
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="#27ffffff"
+        android:radius="48dp"/>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml
new file mode 100644
index 0000000..5aa301b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml
@@ -0,0 +1,199 @@
+<?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.
+  -->
+<!-- This is for the two-row version of the toolbar -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:tag="CarUiBaseLayoutToolbar">
+
+    <!-- When not in touch mode, if we clear focus in current window, Android will re-focus the
+         first focusable view in the window automatically. Adding a FocusParkingView to the window
+         can fix this issue, because it can take focus, and it is transparent and its default focus
+         highlight is disabled, so it's invisible to the user no matter whether it's focused or not.
+         -->
+    <com.android.car.ui.FocusParkingView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <FrameLayout
+        android:id="@+id/car_ui_base_layout_content_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toEndOf="@id/left_part_of_toolbar_focus_area"
+        app:layout_constraintEnd_toEndOf="parent"/>
+
+    <com.android.car.ui.FocusArea
+        android:id="@+id/top_part_of_toolbar_focus_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="90dp"
+            android:background="?android:attr/colorBackground"
+            android:tag="car_ui_top_inset"
+            app:layout_constraintTop_toTopOf="parent">
+            <com.android.car.ui.baselayout.ClickBlockingView
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"/>
+
+            <FrameLayout
+                android:id="@+id/car_ui_toolbar_nav_icon_container"
+                android:layout_width="90dp"
+                android:layout_height="0dp"
+                android:layout_marginStart="88dp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent">
+
+                <ImageView
+                    android:id="@+id/car_ui_toolbar_nav_icon"
+                    android:layout_width="@dimen/car_ui_toolbar_nav_icon_size"
+                    android:layout_height="@dimen/car_ui_toolbar_nav_icon_size"
+                    android:layout_gravity="center"
+                    android:scaleType="fitXY"
+                    android:background="@drawable/car_ui_toolbar_menu_item_icon_ripple"
+                    android:tint="@color/car_ui_text_color_primary"/>
+
+                <ImageView
+                    android:id="@+id/car_ui_toolbar_logo"
+                    android:layout_width="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_height="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_gravity="center"
+                    android:scaleType="fitXY" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/car_ui_toolbar_title_logo_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/car_ui_toolbar_title_container"
+                app:layout_constraintHorizontal_chainStyle="packed">
+
+                <ImageView
+                    android:id="@+id/car_ui_toolbar_title_logo"
+                    android:layout_width="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_height="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_gravity="center"
+                    android:scaleType="fitXY" />
+            </FrameLayout>
+
+            <LinearLayout android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:id="@+id/car_ui_toolbar_title_container"
+                          android:orientation="vertical"
+                          android:layout_marginStart="16dp"
+                          app:layout_goneMarginStart="0dp"
+                          app:layout_constraintBottom_toBottomOf="parent"
+                          app:layout_constraintTop_toTopOf="parent"
+                          app:layout_constraintEnd_toEndOf="parent"
+                          app:layout_constraintStart_toEndOf="@id/car_ui_toolbar_title_logo_container">
+                <TextView android:id="@+id/car_ui_toolbar_title"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:singleLine="true"
+                          android:textAlignment="viewStart"
+                          android:textAppearance="@style/TextAppearance.CarUi.Widget.Toolbar.Title"/>
+                <TextView android:id="@+id/car_ui_toolbar_subtitle"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:visibility="gone"
+                          android:textAlignment="viewStart"
+                          android:textAppearance="?android:attr/textAppearanceSmall"/>
+            </LinearLayout>
+
+            <FrameLayout
+                android:id="@+id/car_ui_toolbar_search_view_container"
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@+id/car_ui_toolbar_menu_items_container"
+                app:layout_constraintStart_toEndOf="@+id/car_ui_toolbar_nav_icon_container"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <LinearLayout
+                android:id="@+id/car_ui_toolbar_menu_items_container"
+                android:divider="@drawable/car_ui_toolbar_menu_item_divider"
+                android:showDividers="beginning|middle|end"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:orientation="horizontal"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <ProgressBar
+                android:id="@+id/car_ui_toolbar_progress_bar"
+                style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:indeterminate="true"
+                android:visibility="gone"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent" />
+
+            <!-- Hairline across bottom of toolbar -->
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="2dp"
+                android:background="#F1F3F4"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </com.android.car.ui.FocusArea>
+
+    <com.android.car.ui.FocusArea
+        android:id="@+id/left_part_of_toolbar_focus_area"
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        android:tag="car_ui_left_inset"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/top_part_of_toolbar_focus_area"
+        app:layout_constraintBottom_toBottomOf="parent">
+
+        <com.android.car.ui.toolbar.TabLayout
+            android:id="@+id/car_ui_toolbar_tabs"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:orientation="vertical"/>
+    </com.android.car.ui.FocusArea>
+
+    <!-- Hairline to the right of the tabs -->
+    <View
+        android:layout_width="2dp"
+        android:layout_height="0dp"
+        android:background="#F1F3F4"
+        app:layout_constraintBottom_toBottomOf="@id/left_part_of_toolbar_focus_area"
+        app:layout_constraintTop_toTopOf="@id/left_part_of_toolbar_focus_area"
+        app:layout_constraintEnd_toEndOf="@id/left_part_of_toolbar_focus_area" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml
new file mode 100644
index 0000000..7386e2c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml
@@ -0,0 +1,64 @@
+<?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.
+  -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="260dp"
+    android:layout_height="96dp"
+    android:background="?android:attr/selectableItemBackground">
+
+    <View
+        android:layout_width="6dp"
+        android:layout_height="match_parent"
+        android:background="@color/tab_side_indicator_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <ImageView
+        android:id="@+id/car_ui_toolbar_tab_item_icon"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
+        android:layout_marginStart="24dp"
+        android:layout_marginEnd="24dp"
+        android:scaleType="fitCenter"
+        android:tint="@color/car_ui_toolbar_tab_item_selector"
+        android:tintMode="src_in"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/car_ui_toolbar_tab_item_text"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"/>
+
+    <TextView
+        android:id="@+id/car_ui_toolbar_tab_item_text"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textSize="24sp"
+        android:singleLine="true"
+        app:layout_constraintStart_toEndOf="@id/car_ui_toolbar_tab_item_icon"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"/>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="2dp"
+        android:background="#F1F3F4"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-port/values.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-port/values.xml
new file mode 100644
index 0000000..299d726
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-port/values.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<resources>
+    <bool name="car_ui_toolbar_tab_flexible_layout">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/attrs.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/attrs.xml
new file mode 100644
index 0000000..ee658e3
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/attrs.xml
@@ -0,0 +1,80 @@
+<?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.
+  -->
+<resources>
+    <attr name="state_ux_restricted" format="boolean" />
+
+    <attr name="layout_constraintGuide_begin" format="dimension"/>
+    <attr name="layout_constraintGuide_end" format="dimension"/>
+    <attr name="layout_constraintGuide_percent" format="float"/>
+
+    <attr name="layout_constraintLeft_toLeftOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintLeft_toRightOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintRight_toLeftOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintRight_toRightOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintTop_toTopOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintTop_toBottomOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintBottom_toTopOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintBottom_toBottomOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintBaseline_toBaselineOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintStart_toEndOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintStart_toStartOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintEnd_toStartOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintEnd_toEndOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+
+    <attr name="layout_constraintHorizontal_bias" format="float"/>
+    <attr name="layout_constraintVertical_bias" format="float"/>
+
+    <attr name="layout_goneMarginLeft" format="dimension"/>
+    <attr name="layout_goneMarginTop" format="dimension"/>
+    <attr name="layout_goneMarginRight" format="dimension"/>
+    <attr name="layout_goneMarginBottom" format="dimension"/>
+    <attr name="layout_goneMarginStart" format="dimension"/>
+    <attr name="layout_goneMarginEnd" format="dimension"/>
+
+    <attr name="layout_constraintHorizontal_chainStyle" format="enum">
+        <enum name="spread" value="0"/>
+        <enum name="spread_inside" value="1"/>
+        <enum name="packed" value="2"/>
+    </attr>
+
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/drawables.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/drawables.xml
new file mode 100644
index 0000000..7bf9ad7
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/drawables.xml
@@ -0,0 +1,19 @@
+<?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.
+  -->
+<resources>
+    <drawable name="car_ui_activity_background">#FDFDFD</drawable>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/values.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/values.xml
new file mode 100644
index 0000000..e68a3f8
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/values.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+<resources>
+    <bool name="car_ui_toolbar_logo_fills_nav_icon_space">false</bool>
+    <bool name="car_ui_toolbar_tab_flexible_layout">false</bool>
+    <bool name="car_ui_scrollbar_enable">false</bool>
+
+    <style name="TextAppearance.CarUi.Widget" parent="android:TextAppearance.Material.Widget">
+        <item name="android:textAlignment">viewStart</item>
+    </style>
+
+    <style name="TextAppearance.CarUi.Widget.Toolbar"/>
+
+    <style name="TextAppearance.CarUi.Widget.Toolbar.Title">
+        <item name="android:singleLine">true</item>
+        <item name="android:textSize">32sp</item>
+    </style>
+
+    <dimen name="car_ui_toolbar_logo_size">44dp</dimen>
+    <dimen name="car_ui_toolbar_nav_icon_size">44dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
new file mode 100644
index 0000000..9df6001
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
@@ -0,0 +1,69 @@
+<?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.
+  -->
+<overlay>
+    <item target="layout/car_ui_base_layout_toolbar" value="@layout/car_ui_base_layout_toolbar"/>
+    <item target="layout/car_ui_toolbar_tab_item" value="@layout/car_ui_toolbar_tab_item"/>
+
+    <item target="bool/car_ui_toolbar_logo_fills_nav_icon_space" value="@bool/car_ui_toolbar_logo_fills_nav_icon_space" />
+    <item target="bool/car_ui_toolbar_tab_flexible_layout" value="@bool/car_ui_toolbar_tab_flexible_layout" />
+    <item target="bool/car_ui_scrollbar_enable" value="@bool/car_ui_scrollbar_enable" />
+
+    <item target="id/car_ui_toolbar_nav_icon_container" value="@id/car_ui_toolbar_nav_icon_container" />
+    <item target="id/car_ui_toolbar_nav_icon" value="@id/car_ui_toolbar_nav_icon" />
+    <item target="id/car_ui_toolbar_logo" value="@id/car_ui_toolbar_logo" />
+    <item target="id/car_ui_toolbar_title_logo_container" value="@id/car_ui_toolbar_title_logo_container" />
+    <item target="id/car_ui_toolbar_title_logo" value="@id/car_ui_toolbar_title_logo" />
+    <item target="id/car_ui_toolbar_title" value="@id/car_ui_toolbar_title" />
+    <item target="id/car_ui_toolbar_title_container" value="@id/car_ui_toolbar_title_container" />
+    <item target="id/car_ui_toolbar_subtitle" value="@id/car_ui_toolbar_subtitle" />
+    <item target="id/car_ui_toolbar_tabs" value="@id/car_ui_toolbar_tabs" />
+    <item target="id/car_ui_toolbar_menu_items_container" value="@id/car_ui_toolbar_menu_items_container" />
+    <item target="id/car_ui_toolbar_search_view_container" value="@id/car_ui_toolbar_search_view_container" />
+    <item target="id/car_ui_toolbar_progress_bar" value="@id/car_ui_toolbar_progress_bar" />
+    <item target="id/car_ui_base_layout_content_container" value="@id/car_ui_base_layout_content_container" />
+    <item target="id/car_ui_toolbar_tab_item_icon" value="@id/car_ui_toolbar_tab_item_icon" />
+    <item target="id/car_ui_toolbar_tab_item_text" value="@id/car_ui_toolbar_tab_item_text" />
+
+    <item target="drawable/car_ui_recyclerview_ic_up" value="@drawable/car_ui_recyclerview_ic_up" />
+    <item target="drawable/car_ui_recyclerview_ic_down" value="@drawable/car_ui_recyclerview_ic_down" />
+    <item target="drawable/car_ui_recyclerview_scrollbar_thumb" value="@drawable/car_ui_recyclerview_scrollbar_thumb" />
+    <item target="drawable/car_ui_activity_background" value="@drawable/car_ui_activity_background" />
+
+    <item target="attr/state_ux_restricted" value="@attr/state_ux_restricted"/>
+    <item target="attr/layout_constraintGuide_begin" value="@attr/layout_constraintGuide_begin"/>
+    <item target="attr/layout_constraintGuide_end" value="@attr/layout_constraintGuide_end"/>
+    <item target="attr/layout_constraintStart_toStartOf" value="@attr/layout_constraintStart_toStartOf"/>
+    <item target="attr/layout_constraintStart_toEndOf" value="@attr/layout_constraintStart_toEndOf"/>
+    <item target="attr/layout_constraintEnd_toStartOf" value="@attr/layout_constraintEnd_toStartOf"/>
+    <item target="attr/layout_constraintEnd_toEndOf" value="@attr/layout_constraintEnd_toEndOf"/>
+    <item target="attr/layout_constraintLeft_toLeftOf" value="@attr/layout_constraintLeft_toLeftOf"/>
+    <item target="attr/layout_constraintLeft_toRightOf" value="@attr/layout_constraintLeft_toRightOf"/>
+    <item target="attr/layout_constraintRight_toLeftOf" value="@attr/layout_constraintRight_toLeftOf"/>
+    <item target="attr/layout_constraintRight_toRightOf" value="@attr/layout_constraintRight_toRightOf"/>
+    <item target="attr/layout_constraintTop_toTopOf" value="@attr/layout_constraintTop_toTopOf"/>
+    <item target="attr/layout_constraintTop_toBottomOf" value="@attr/layout_constraintTop_toBottomOf"/>
+    <item target="attr/layout_constraintBottom_toTopOf" value="@attr/layout_constraintBottom_toTopOf"/>
+    <item target="attr/layout_constraintBottom_toBottomOf" value="@attr/layout_constraintBottom_toBottomOf"/>
+    <item target="attr/layout_constraintHorizontal_bias" value="@attr/layout_constraintHorizontal_bias"/>
+    <item target="attr/layout_goneMarginLeft" value="@attr/layout_goneMarginLeft"/>
+    <item target="attr/layout_goneMarginRight" value="@attr/layout_goneMarginRight"/>
+    <item target="attr/layout_goneMarginTop" value="@attr/layout_goneMarginTop"/>
+    <item target="attr/layout_goneMarginBottom" value="@attr/layout_goneMarginBottom"/>
+    <item target="attr/layout_goneMarginStart" value="@attr/layout_goneMarginStart"/>
+    <item target="attr/layout_goneMarginEnd" value="@attr/layout_goneMarginEnd"/>
+    <item target="attr/layout_constraintHorizontal_chainStyle" value="@attr/layout_constraintHorizontal_chainStyle"/>
+</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
new file mode 100644
index 0000000..93a998e
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car_ui_portrait_rro.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+$(call inherit-product, packages/services/Car/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk)
+
+# All RROs to be included in car_ui_portrait builds.
+PRODUCT_PACKAGES += \
+    CarUiPortraitMediaRRO \
+    CarUiPortraitLauncherRRO \
diff --git a/car_product/car_ui_portrait/tools/export_emulator.py b/car_product/car_ui_portrait/tools/export_emulator.py
new file mode 100755
index 0000000..aa75f3a
--- /dev/null
+++ b/car_product/car_ui_portrait/tools/export_emulator.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+
+import subprocess
+import os
+import sys
+from shutil import copy2, copytree, rmtree
+from argparse import ArgumentParser as AP
+
+# Mostly adapted from https://cs.android.com/android/platform/superproject/+/master:device/generic/car/tools/run_local_avd.sh
+
+def fromTop(path):
+    return os.path.join(os.environ['ANDROID_BUILD_TOP'], path)
+
+def fromProductOut(path):
+    return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], path)
+
+def copyImages(outputDir, abi):
+    outputDir = os.path.join(outputDir, abi)
+    os.mkdir(outputDir)
+
+    try:
+        copy2(fromProductOut('system-qemu.img'), os.path.join(outputDir, 'system.img'))
+        copy2(fromProductOut('vendor-qemu.img'), os.path.join(outputDir, 'vendor.img'))
+        if os.path.isfile(fromProductOut('kernel-ranchu-64')):
+            copy2(fromProductOut('kernel-ranchu-64'), outputDir)
+        else:
+            copy2(fromProductOut('kernel-ranchu'), outputDir)
+        copy2(fromProductOut('ramdisk-qemu.img'), os.path.join(outputDir, 'ramdisk.img'))
+        copy2(fromProductOut('encryptionkey.img'), outputDir)
+        # take prebuilt userdata.img
+        # Ref: https://cs.android.com/android/platform/superproject/+/master:development/build/sdk.atree?q=userdata.img&ss=android%2Fplatform%2Fsuperproject:development%2Fbuild%2F
+        copy2(fromTop('device/generic/goldfish/data/etc/userdata.img'), outputDir)
+        copytree(fromProductOut('data'), os.path.join(outputDir, 'data'), dirs_exist_ok=True)
+        copy2(fromProductOut('system/build.prop'), os.path.join(outputDir, 'build.prop'))
+        copy2(fromProductOut('VerifiedBootParams.textproto'), outputDir)
+        copy2(fromProductOut('config.ini'), outputDir)
+        copy2(fromProductOut('advancedFeatures.ini'), outputDir)
+    except FileNotFoundError as f:
+        print("File not found: "+f.filename+", did you build android first?")
+        sys.exit(1)
+
+def readScreenDimens(configini):
+    width = 1080
+    height = 1920
+    density = 160
+    with open(configini, 'r') as f:
+        for line in f.readlines():
+            parts = line.split(' = ')
+            if len(parts) != 2:
+                continue
+            if parts[0] == 'hw.lcd.width':
+                width = parts[1]
+            if parts[0] == 'hw.lcd.height':
+                height = parts[1]
+    return (width, height, density)
+
+def buildAVD(outputDir, abi):
+    os.makedirs(os.path.join(outputDir, '.android/avd/my_car_avd.avd/'), exist_ok=True)
+    with open(os.path.join(outputDir, '.android/avd/my_car_avd.ini'), 'w') as f:
+        f.write('avd.ini.encoding=UTF-8\n')
+        f.write('path=required_but_we_want_to_use_path.rel_instead\n')
+        f.write('path.rel=avd/my_car_avd.avd\n')
+
+    width, height, density = readScreenDimens(fromProductOut('config.ini'))
+
+    with open(os.path.join(outputDir, '.android/avd/my_car_avd.avd/config.ini'), 'w') as f:
+        f.write(f'''
+image.sysdir.1 = unused_because_passing_-sysdir_to_emulator
+hw.lcd.density = {density}
+hw.lcd.width = {width}
+hw.lcd.height = {height}
+AvdId = my_car_avd
+avd.ini.displayname = my_car_avd
+hw.ramSize = 3584
+abi.type = {abi}
+
+tag.display = Automotive
+tag.id = android-automotive
+hw.device.manufacturer = google
+hw.device.name = hawk
+avd.ini.encoding = UTF-8
+disk.dataPartition.size = 6442450944
+fastboot.chosenSnapshotFile =
+fastboot.forceChosenSnapshotBoot = no
+fastboot.forceColdBoot = no
+fastboot.forceFastBoot = yes
+hw.accelerometer = no
+hw.arc = false
+hw.audioInput = yes
+hw.battery = no
+hw.camera.back = None
+hw.camera.front = None
+hw.cpu.arch = x86_64
+hw.cpu.ncore = 4
+hw.dPad = no
+hw.device.hash2 = MD5:1fdb01985c7b4d7c19ec309cc238b0f9
+hw.gps = yes
+hw.gpu.enabled = yes
+hw.gpu.mode = auto
+hw.initialOrientation = landscape
+hw.keyboard = yes
+hw.keyboard.charmap = qwerty2
+hw.keyboard.lid = false
+hw.mainKeys = no
+hw.sdCard = no
+hw.sensors.orientation = no
+hw.sensors.proximity = no
+hw.trackBall = no
+runtime.network.latency = none
+runtime.network.speed = full
+''')
+
+def genStartScript(outputDir):
+    filepath = os.path.join(outputDir, 'start_emu.sh')
+    with open(os.open(filepath, os.O_CREAT | os.O_WRONLY, 0o750), 'w') as f:
+        f.write(f'''
+# This file is auto-generated from export_emulator.py
+OS="$(uname -s)"
+if [[ $OS == "Linux" ]]; then
+    DEFAULT_ANDROID_SDK_ROOT="$HOME/Android/Sdk"
+elif [[ $OS == "Darwin" ]]; then
+    DEFAULT_ANDROID_SDK_ROOT="/Users/$USER/Library/Android/sdk"
+else
+    echo Sorry, this does not work on $OS
+    exit
+fi
+if [[ -z $ANDROID_SDK_ROOT ]]; then
+    ANDROID_SDK_ROOT="$DEFAULT_ANDROID_SDK_ROOT"
+fi
+if ! [[ -d $ANDROID_SDK_ROOT ]]; then
+    echo Could not find android SDK root. Did you install an SDK with android studio?
+    exit
+fi
+
+# TODO: this ANDROID_EMULATOR_HOME may need to not be changed.
+# we had to change it so we could find the avd by a relative path,
+# but changing it means makes it give an "emulator is out of date"
+# warning
+
+# TODO: You shouldn't need to pass -sysdir, it should be specified
+# in the avd ini file. But I couldn't figure out how to make that work
+# with a relative path.
+
+ANDROID_EMULATOR_HOME=$(dirname $0)/.android \
+ANDROID_AVD_HOME=.android/avd \
+ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT \
+$ANDROID_SDK_ROOT/emulator/emulator \
+-avd my_car_avd -sysdir x86_64 $@
+''')
+
+
+def main():
+    parser = AP(description="Export the current build as a sharable emulator")
+    parser.add_argument('-o', '--output', default="/tmp/exported_emulator",
+                        help='Output folder. Defaults to /tmp/exported_emulator. Will wipe any existing contents!')
+    args = parser.parse_args()
+
+    if 'ANDROID_BUILD_TOP' not in os.environ or 'ANDROID_PRODUCT_OUT' not in os.environ:
+        print("Please run lunch first")
+        sys.exit(1)
+
+    if os.path.isfile(args.output):
+        print("Something already exists at "+args.output)
+        sys.exit(1)
+
+    if not os.path.isdir(os.path.dirname(args.output)):
+        print("Parent directory of "+args.output+" must already exist")
+        sys.exit(1)
+
+    rmtree(args.output, ignore_errors=True)
+    os.mkdir(args.output)
+
+    copyImages(args.output, 'x86_64')
+    buildAVD(args.output, 'x86_64')
+    genStartScript(args.output)
+    print("Done. Exported to "+args.output)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
index abf8fd2..6bd87c4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Bestuurder"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"kry benaderde ligging net op die voorgrond"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktiveer mikrofoon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
index 0f190c4..f73000b 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ነጂ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ከፊት ለፊት ብቻ ግምታዊ አካባቢን ድረስ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"ማይክሮፎንን አንቃ"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
index aa51d5d..5efe621 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"السائق"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"الوصول إلى الموقع الجغرافي التقريبي في الواجهة الأمامية فقط"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"تشغيل الميكروفون"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml
index ea877d4..bd333ad 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"চালক"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"কেৱল অগ্ৰভূমিত আনুমানিক অৱস্থান এক্সেছ কৰক"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
index 3e2ccc1..65ec685 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sürücü"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"yalnız ön planda təqribi məkana daxil olun"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonu aktiv edin"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
index a20c58e..346f0e2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vozač"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristup približnoj lokaciji samo u prvom planu"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogući mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
index d6e8de4..dc483db 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Вадзіцель"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"доступ да прыблізнага месцазнаходжання толькі ў асноўным рэжыме"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Уключыць мікрафон"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
index 7a2fd23..9842971 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Шофьор"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"достъп до приблизителното местоположение само на преден план"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Активиране на микрофона"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
index e9725c8..71e7a7c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ড্রাইভার"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"শুধুমাত্র অ্যাপটি খোলা থাকলে আপনার আনুমানিক লোকেশন অ্যাক্সেস করা"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
index a20c58e..346f0e2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vozač"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristup približnoj lokaciji samo u prvom planu"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogući mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
index 8d24e22..e1a2044 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conductor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accedeix a la ubicació aproximada només en primer pla"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activa el micròfon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
index 2432df2..ce005f1 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Řidič"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"přístup k přibližné poloze jen na popředí"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivovat mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
index 4f95061..1c751f9 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Chauffør"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"få kun adgang til omtrentlig placering i forgrunden"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivér mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
index 9febde6..ba314a7 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Fahrer"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Nur bei Ausführung im Vordergrund auf den ungefähren Standort zugreifen"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofon aktivieren"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
index fcfe739..4eca60d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Οδηγός"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"πρόσβαση στην κατά προσέγγιση τοποθεσία μόνο στο προσκήνιο"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Ενεργοποίηση μικροφώνου"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
index 7778984..3e208b3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‎‎Driver‎‏‎‎‏‎"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎access approximate location only in the foreground‎‏‎‎‏‎"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎Enable Microphone‎‏‎‎‏‎"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
index 5666331..ced0bde 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conductor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder a la ubicación aproximada solo en primer plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Habilitar micrófono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
index 3e3ad48..af83a18 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conductor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder a la ubicación aproximada solo al estar en primer plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Habilitar micrófono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
index 27ae02b..1876c65 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sõitja"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"juurdepääs ligikaudsele asukohale ainult esiplaanil"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Luba mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
index f7e62cf..0e06b76 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Gidaria"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"atzitu gutxi gorabeherako kokapena aurreko planoan bakarrik"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Gaitu mikrofonoa"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
index 4d257d6..4c9f73a 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"راننده"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"دسترسی به مکان تقریبی فقط در پیش‌زمینه"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"فعال کردن میکروفن"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
index b2d5135..ce5daf3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Kuljettaja"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"käyttää likimääräistä sijaintia vain etualalla"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Laita mikrofoni päälle"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
index 2ac4be7..eb83b85 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conducteur"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accéder à votre position approximative seulement en avant-plan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activer le microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
index 81af986..02b7a24 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conducteur"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accéder à la position approximative au premier plan uniquement"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activer le micro"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
index 3754442..30b25d4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Condutor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder á localización aproximada só en primeiro plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activar micrófono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
index 5c6ff84..63524db 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ડ્રાઇવર"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ફૉરગ્રાઉન્ડમાં ફક્ત અંદાજિત સ્થાન ઍક્સેસ કરો"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
index 003478d..a5ac0f3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ड्राइवर"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"अनुमानित जगह की जानकारी सिर्फ़ तब ऐक्सेस करें, जब ऐप्लिकेशन स्क्रीन पर खुला हो"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"माइक्रोफ़ोन चालू करें"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
index 4cffd31..0ac52d4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vozač"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristupiti približnoj lokaciji samo u prednjem planu"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogući mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
index 52b7760..778f57c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sofőr"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"megközelítőleges helyadatokhoz való hozzáférés csak előtérben"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonhoz való hozzáférés engedélyezése"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
index 68df140..0dc5851 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Վարորդ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"տեղադրության մոտավոր տվյալների հասանելիություն միայն ֆոնային ռեժիմում"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Միացնել խոսափողը"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
index 21c21a8..52cda98 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Pengemudi"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"akses perkiraan lokasi hanya saat di latar depan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktifkan Mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
index 1eb3776..b922593 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Ökumaður"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"aðgangur að áætlaðri staðsetningu aðeins í forgrunni"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Kveikja á hljóðnema"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
index c704544..10c4836 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Autista"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Accesso alla posizione approssimativa solo in primo piano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Attiva il microfono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml
index a8d3bee..657ebf2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"נהג/ת"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"קבלת גישה למיקום משוער בחזית בלבד"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"הפעלת המיקרופון"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
index eb41c01..6da0c2c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ドライバー"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"フォアグラウンドでのみおおよその位置情報を取得"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"マイクを有効にする"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
index 4d26423..7fe766c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"მძღოლი"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"მიახლოებით მდებარეობაზე წვდომა მხოლოდ წინა პლანზე"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"მიკროფონის ჩართვა"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
index b12a6d5..36195f0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Көлік жүргізуші"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"болжалды орналасқан жер туралы ақпаратқа тек ашық экранда кіру"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Микрофонды қосу"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
index 4975540..1a74261 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"អ្នក​បើកបរ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ចូលប្រើ​ទីតាំង​ប្រហាក់ប្រហែល​តែនៅផ្ទៃ​ខាងមុខប៉ុណ្ណោះ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"បើក​មីក្រូហ្វូន"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
index 27e9a9e..e4ca9b9 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ಡ್ರೈವರ್"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ಮುನ್ನೆಲೆಯಲ್ಲಿ ಮಾತ್ರ ಅಂದಾಜು ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
index 20facb1..52c715d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"운전자"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"포그라운드에서만 대략적인 위치에 액세스"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"마이크 사용"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
index 1a43c49..e062223 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Айдоочу"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"болжолдуу аныкталган жайгашкан жерге активдүү режимде гана кирүүгө уруксат берүү"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Микрофонду иштетүү"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
index 877a259..fabaa3d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ຄົນຂັບລົດ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ເຂົ້າເຖິງສະຖານທີ່ໂດຍປະມານເມື່ອຢູ່ໃນພື້ນໜ້າເທົ່ານັ້ນ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"ເປີດການນຳໃຊ້ໄມໂຄຣໂຟນ"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
index 134230f..a02befb 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vairuotojas"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pasiekti apytikslę vietovę, tik kai programa veikia priekiniame plane"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Įgalinti mikrofoną"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
index 3cc5c88..333add2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vadītājs"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"piekļuve aptuvenai atrašanās vietai, tikai darbojoties priekšplānā"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Iespējot mikrofonu"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
index 3b1eda7..ed49dfe 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Возач"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"пристап до приближната локација само во преден план"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Овозможи го микрофонот"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
index 7205182..a69ea5d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ഡ്രൈവർ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ഏകദേശ ലൊക്കേഷൻ ഫോർഗ്രൗണ്ടിൽ മാത്രം ആക്‌സസ് ചെയ്യുക"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"മൈക്രോഫോൺ പ്രവർത്തനക്ഷമമാക്കുക"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
index dd1d6a2..5b3d6fb 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Жолооч"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ойролцоо байршилд зөвхөн дэлгэц дээр хандах"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Микрофоныг идэвхжүүлэх"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
index a0619ec..ff435e0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ड्रायव्हर"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"फक्त फोअरग्राउंडमध्ये अंदाजे स्थान अ‍ॅक्सेस करा"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
index 7f22021..6e830f7 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Pemandu"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"akses lokasi anggaran hanya di latar depan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Dayakan Mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
index aea1568..43c3d37 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ယာဉ်မောင်းသူ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"မျက်နှာစာတွင်သာ ခန့်မှန်းခြေ တည်နေရာ အသုံးပြုခြင်း"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"မိုက်ခရိုဖုန်း ဖွင့်ရန်"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
index 6e0de84..cbc2918 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sjåfør"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"bare tilgang til omtrentlig posisjon i forgrunnen"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Slå på mikrofonen"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml
index 76ca044..7f514a6 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"चालक"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"अग्रभूमिमा मात्र अनुमानित स्थानमाथि पहुँच राख्नुहोस्"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
index 873fb01..d79cba2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Chauffeur"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"alleen toegang tot geschatte locatie op de voorgrond"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Microfoon aanzetten"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
index 964683f..939b105 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ଡ୍ରାଇଭର୍"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"କେବଳ ଫୋର୍‌ଗ୍ରାଉଣ୍ଡରେ ହାରାହାରି ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"ମାଇକ୍ରୋଫୋନକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
index 16541d3..75bbe12 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ਡਰਾਈਵਰ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ਸਿਰਫ਼ ਫੋਰਗ੍ਰਾਊਂਡ ਵਿੱਚ ਅਨੁਮਾਨਿਤ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
index d0ff092..32fe8a4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Kierowca"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"dostęp do przybliżonej lokalizacji tylko na pierwszym planie"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Włącz mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
index 984000a..016617e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Condutor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"apenas aceder à localização aproximada em primeiro plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Ativar microfone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
index 7ac9eef..efca2bf 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Motorista"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acessar local aproximado apenas em primeiro plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Ativar microfone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
index ec78db2..adf01f0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Șofer"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"să acceseze locația aproximativă numai în prim-plan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activați microfonul"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
index ed49d76..12a3f43 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Водитель"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Доступ к приблизительному местоположению только в активном режиме"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Включить"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
index fcba27e..9d75b4f 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"රියදුරු"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"පෙරබිම තුළ පමණක් ආසන්න ස්ථානයට ප්‍රවේශය"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"මයික්‍රෆෝනය සබල කරන්න"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
index c9a990d..125cb5a 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vodič"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"prístup k približnej polohe iba v popredí"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivovať mikrofón"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
index 918dda4..52841ab 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Voznik"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"dostop do približne lokacije samo, ko deluje v ospredju"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogoči mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
index e4192e7..dc7bbe2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Drejtuesi"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"qasu në vendndodhjen e përafërt vetëm në plan të parë"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivizo mikrofonin"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
index 8cce889..2cfe36e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Возач"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"приступ приближној локацији само у првом плану"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Омогући микрофон"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
index b5b4f63..1aa7c0c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Förare"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"endast åtkomst till ungefärlig plats i förgrunden"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivera mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
index 765973c..60e5469 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Dereva"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"kufikia mahali palipokadiriwa ikiwa tu programu imefunguliwa kwenye skrini"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Washa Maikrofoni"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
index 264f0c1..38a2e03 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"கார் உரிமையாளர்"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"முன்புலத்தில் இயங்கும்போது மட்டும் தோராயமான இருப்பிடத்தைக் கண்டறிதல்"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"மைக்ரோஃபோனை இயக்கு"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml
index bf45f96..c95285e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"డ్రైవర్"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"స్క్రీన్‌పై ఉన్నప్పుడు మాత్రమే సమీప లొకేషన్‌ను యాక్సెస్ చేయండి"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"మైక్రోఫోన్‌ను ఎనేబుల్ చేయండి"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
index 8fae2ca..6f617e3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ผู้ขับรถ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"เข้าถึงตำแหน่งโดยประมาณเมื่ออยู่เบื้องหน้าเท่านั้น"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"เปิดใช้ไมโครโฟน"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
index d425a87..c42b2c8 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"i-access lang ang tinatantyang lokasyon sa foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"I-enable ang Mikropono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
index 244564e..0a13258 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sürücü"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"yalnızca ön planda yaklaşık konuma erişme"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonu Etkinleştir"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
index b46d679..c15df06 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Водій"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"отримувати доступ до даних про приблизне місцезнаходження лише в активному режимі"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Увімкнути мікрофон"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
index 89fd655..d3cea05 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ڈرائیور"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"صرف پیش منظر میں تخمینی مقام تک رسائی"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"مائیکروفون فعال کریں"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
index 9914c10..d15ff7c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Haydovchi"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"taxminiy joylashuv axborotini olishga faqat old fonda ruxsat"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonni yoqish"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
index d478052..1e19523 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Tài xế"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"chỉ truy cập thông tin vị trí gần đúng khi ứng dụng mở trên màn hình"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Cấp quyền truy cập micrô"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
index 06fe50d..6556c7b 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"司机"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"只有在前台运行时才能获取大致位置信息"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"启用麦克风"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
index fd93b30..0d8543b 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"司機"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"只在前景存取概略位置"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"啟用麥克風"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
index 59f09e1..7340ecd 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"駕駛"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"僅可在前景中取得概略位置"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"啟用麥克風"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
index adb9402..c99c505 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Umshayeli"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"finyelela indawo enembile kuphela engaphambili"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Nika amandla Imakrofoni"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values/strings.xml
index 34fd92f..eff76d4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/strings.xml
@@ -19,4 +19,6 @@
     <!-- Default name of the owner user [CHAR LIMIT=20] -->
     <string name="owner_name">Driver</string>
     <string name="permlab_accessCoarseLocation">access approximate location only in the foreground</string>
+    <!--- Action button in the dialog triggered if microphone is disabled but an app tried to access it. [CHAR LIMIT=60] -->
+    <string name="sensor_privacy_start_use_dialog_turn_on_button">Enable Microphone</string>
 </resources>
diff --git a/cpp/telemetry/proto/CarData.proto b/cpp/telemetry/proto/CarData.proto
index 96e8c2e..3440689 100644
--- a/cpp/telemetry/proto/CarData.proto
+++ b/cpp/telemetry/proto/CarData.proto
@@ -31,6 +31,11 @@
 
 import "packages/services/Car/cpp/telemetry/proto/evs.proto";
 
+// Contains all the CarData messages to declare all the messages.
+// Unique protobuf number is used as an ID.
+// A message will be sent from writer clients to the cartelemetryd
+// wrapped in
+// frameworks/hardware/interfaces/automotive/telemetry/aidl/android/frameworks/automotive/telemetry/CarData.aidl
 message CarData {
   oneof pushed {
     EvsFirstFrameLatency evs_first_frame_latency = 1;
diff --git a/cpp/telemetry/script_executor/Android.bp b/cpp/telemetry/script_executor/Android.bp
index 6eaec62..9d8a05b 100644
--- a/cpp/telemetry/script_executor/Android.bp
+++ b/cpp/telemetry/script_executor/Android.bp
@@ -34,6 +34,7 @@
         "scriptexecutor_defaults",
     ],
     srcs: [
+        "src/BundleWrapper.cpp",
         "src/JniUtils.cpp",
         "src/LuaEngine.cpp",
         "src/ScriptExecutorListener.cpp",
diff --git a/cpp/telemetry/script_executor/src/BundleWrapper.cpp b/cpp/telemetry/script_executor/src/BundleWrapper.cpp
new file mode 100644
index 0000000..77d2a5f
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/BundleWrapper.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include "BundleWrapper.h"
+
+#include <android-base/logging.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+BundleWrapper::BundleWrapper(JNIEnv* env) {
+    mJNIEnv = env;
+    mBundleClass =
+            static_cast<jclass>(mJNIEnv->NewGlobalRef(mJNIEnv->FindClass("android/os/Bundle")));
+    jmethodID bundleConstructor = mJNIEnv->GetMethodID(mBundleClass, "<init>", "()V");
+    mBundle = mJNIEnv->NewGlobalRef(mJNIEnv->NewObject(mBundleClass, bundleConstructor));
+}
+
+BundleWrapper::~BundleWrapper() {
+    // Delete global JNI references.
+    if (mBundle != NULL) {
+        mJNIEnv->DeleteGlobalRef(mBundle);
+    }
+    if (mBundleClass != NULL) {
+        mJNIEnv->DeleteGlobalRef(mBundleClass);
+    }
+}
+
+void BundleWrapper::putBoolean(const char* key, bool value) {
+    jmethodID putBooleanMethod =
+            mJNIEnv->GetMethodID(mBundleClass, "putBoolean", "(Ljava/lang/String;Z)V");
+    mJNIEnv->CallVoidMethod(mBundle, putBooleanMethod, mJNIEnv->NewStringUTF(key),
+                            static_cast<jboolean>(value));
+}
+
+void BundleWrapper::putInteger(const char* key, int value) {
+    jmethodID putIntMethod = mJNIEnv->GetMethodID(mBundleClass, "putInt", "(Ljava/lang/String;I)V");
+    mJNIEnv->CallVoidMethod(mBundle, putIntMethod, mJNIEnv->NewStringUTF(key),
+                            static_cast<jint>(value));
+}
+
+void BundleWrapper::putDouble(const char* key, double value) {
+    jmethodID putDoubleMethod =
+            mJNIEnv->GetMethodID(mBundleClass, "putDouble", "(Ljava/lang/String;D)V");
+    mJNIEnv->CallVoidMethod(mBundle, putDoubleMethod, mJNIEnv->NewStringUTF(key),
+                            static_cast<jdouble>(value));
+}
+
+void BundleWrapper::putString(const char* key, const char* value) {
+    jmethodID putStringMethod = mJNIEnv->GetMethodID(mBundleClass, "putString",
+                                                     "(Ljava/lang/String;Ljava/lang/String;)V");
+    mJNIEnv->CallVoidMethod(mBundle, putStringMethod, mJNIEnv->NewStringUTF(key),
+                            mJNIEnv->NewStringUTF(value));
+}
+
+jobject BundleWrapper::getBundle() {
+    return mBundle;
+}
+
+}  // namespace script_executor
+}  // namespace telemetry
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/telemetry/script_executor/src/BundleWrapper.h b/cpp/telemetry/script_executor/src/BundleWrapper.h
new file mode 100644
index 0000000..8c42c46
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/BundleWrapper.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_BUNDLEWRAPPER_H_
+#define CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_BUNDLEWRAPPER_H_
+
+#include "jni.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+// Used to create a java bundle object and populate its fields one at a time.
+class BundleWrapper {
+public:
+    explicit BundleWrapper(JNIEnv* env);
+    // BundleWrapper is not copyable.
+    BundleWrapper(const BundleWrapper&) = delete;
+    BundleWrapper& operator=(const BundleWrapper&) = delete;
+
+    virtual ~BundleWrapper();
+
+    // Family of methods that puts the provided 'value' into the Bundle under provided 'key'.
+    void putBoolean(const char* key, bool value);
+    void putInteger(const char* key, int value);
+    void putDouble(const char* key, double value);
+    void putString(const char* key, const char* value);
+
+    jobject getBundle();
+
+private:
+    // The class asks Java to create Bundle object and stores the reference.
+    // When the instance of this class is destroyed the actual Java Bundle object behind
+    // this reference stays on and is managed by Java.
+    jobject mBundle;
+
+    // Reference to java Bundle class cached for performance reasons.
+    jclass mBundleClass;
+
+    // Stores a JNIEnv* pointer.
+    JNIEnv* mJNIEnv;  // not owned
+};
+
+}  // namespace script_executor
+}  // namespace telemetry
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_BUNDLEWRAPPER_H_
diff --git a/cpp/telemetry/script_executor/src/JniUtils.cpp b/cpp/telemetry/script_executor/src/JniUtils.cpp
index 93c1af8..cfe1da4 100644
--- a/cpp/telemetry/script_executor/src/JniUtils.cpp
+++ b/cpp/telemetry/script_executor/src/JniUtils.cpp
@@ -21,8 +21,8 @@
 namespace telemetry {
 namespace script_executor {
 
-void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
-    lua_newtable(luaEngine->GetLuaState());
+void pushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
+    lua_newtable(luaEngine->getLuaState());
     // null bundle object is allowed. We will treat it as an empty table.
     if (bundle == nullptr) {
         return;
@@ -62,19 +62,19 @@
         if (env->IsInstanceOf(value, booleanClass)) {
             jmethodID boolMethod = env->GetMethodID(booleanClass, "booleanValue", "()Z");
             bool boolValue = static_cast<bool>(env->CallBooleanMethod(value, boolMethod));
-            lua_pushboolean(luaEngine->GetLuaState(), boolValue);
+            lua_pushboolean(luaEngine->getLuaState(), boolValue);
         } else if (env->IsInstanceOf(value, integerClass)) {
             jmethodID intMethod = env->GetMethodID(integerClass, "intValue", "()I");
-            lua_pushinteger(luaEngine->GetLuaState(), env->CallIntMethod(value, intMethod));
+            lua_pushinteger(luaEngine->getLuaState(), env->CallIntMethod(value, intMethod));
         } else if (env->IsInstanceOf(value, numberClass)) {
             // Condense other numeric types using one class. Because lua supports only
             // integer or double, and we handled integer in previous if clause.
             jmethodID numberMethod = env->GetMethodID(numberClass, "doubleValue", "()D");
             /* Pushes a double onto the stack */
-            lua_pushnumber(luaEngine->GetLuaState(), env->CallDoubleMethod(value, numberMethod));
+            lua_pushnumber(luaEngine->getLuaState(), env->CallDoubleMethod(value, numberMethod));
         } else if (env->IsInstanceOf(value, stringClass)) {
             const char* rawStringValue = env->GetStringUTFChars((jstring)value, nullptr);
-            lua_pushstring(luaEngine->GetLuaState(), rawStringValue);
+            lua_pushstring(luaEngine->getLuaState(), rawStringValue);
             env->ReleaseStringUTFChars((jstring)value, rawStringValue);
         } else {
             // Other types are not implemented yet, skipping.
@@ -84,7 +84,7 @@
         const char* rawKey = env->GetStringUTFChars(key, nullptr);
         // table[rawKey] = value, where value is on top of the stack,
         // and the table is the next element in the stack.
-        lua_setfield(luaEngine->GetLuaState(), /* idx= */ -2, rawKey);
+        lua_setfield(luaEngine->getLuaState(), /* idx= */ -2, rawKey);
         env->ReleaseStringUTFChars(key, rawKey);
     }
 }
diff --git a/cpp/telemetry/script_executor/src/JniUtils.h b/cpp/telemetry/script_executor/src/JniUtils.h
index c3ef677..85034d7 100644
--- a/cpp/telemetry/script_executor/src/JniUtils.h
+++ b/cpp/telemetry/script_executor/src/JniUtils.h
@@ -29,7 +29,7 @@
 // converted to the corresponding key-value pairs of the Lua table as long as
 // the Bundle value types are supported. At this point, we support boolean,
 // integer, double and String types in Java.
-void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle);
+void pushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle);
 
 }  // namespace script_executor
 }  // namespace telemetry
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.cpp b/cpp/telemetry/script_executor/src/LuaEngine.cpp
index 1a074f2..e2bcef7 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.cpp
+++ b/cpp/telemetry/script_executor/src/LuaEngine.cpp
@@ -16,10 +16,15 @@
 
 #include "LuaEngine.h"
 
+#include "BundleWrapper.h"
+
+#include <android-base/logging.h>
+
 #include <utility>
 
 extern "C" {
 #include "lauxlib.h"
+#include "lua.h"
 #include "lualib.h"
 }
 
@@ -28,6 +33,16 @@
 namespace telemetry {
 namespace script_executor {
 
+namespace {
+
+enum LuaNumReturnedResults {
+    ZERO_RETURNED_RESULTS = 0,
+};
+
+}  // namespace
+
+ScriptExecutorListener* LuaEngine::sListener = nullptr;
+
 LuaEngine::LuaEngine() {
     // Instantiate Lua environment
     mLuaState = luaL_newstate();
@@ -38,15 +53,18 @@
     lua_close(mLuaState);
 }
 
-lua_State* LuaEngine::GetLuaState() {
+lua_State* LuaEngine::getLuaState() {
     return mLuaState;
 }
 
-void LuaEngine::ResetListener(ScriptExecutorListener* listener) {
-    mListener.reset(listener);
+void LuaEngine::resetListener(ScriptExecutorListener* listener) {
+    if (sListener != nullptr) {
+        delete sListener;
+    }
+    sListener = listener;
 }
 
-int LuaEngine::LoadScript(const char* scriptBody) {
+int LuaEngine::loadScript(const char* scriptBody) {
     // As the first step in Lua script execution we want to load
     // the body of the script into Lua stack and have it processed by Lua
     // to catch any errors.
@@ -61,11 +79,15 @@
         // Starting read about Lua stack: https://www.lua.org/pil/24.2.html
         // TODO(b/192284232): add test case to trigger this.
         lua_pop(mLuaState, 1);
+        return status;
     }
+
+    // Register limited set of reserved methods for Lua to call native side.
+    lua_register(mLuaState, "on_success", LuaEngine::onSuccess);
     return status;
 }
 
-bool LuaEngine::PushFunction(const char* functionName) {
+bool LuaEngine::pushFunction(const char* functionName) {
     // Interaction between native code and Lua happens via Lua stack.
     // In such model, a caller first pushes the name of the function
     // that needs to be called, followed by the function's input
@@ -78,7 +100,7 @@
     return status;
 }
 
-int LuaEngine::Run() {
+int LuaEngine::run() {
     // Performs blocking call of the provided Lua function. Assumes all
     // input arguments are in the Lua stack as well in proper order.
     // On how to call Lua functions: https://www.lua.org/pil/25.2.html
@@ -89,6 +111,54 @@
     return lua_pcall(mLuaState, /* nargs= */ 1, /* nresults= */ 0, /*errfunc= */ 0);
 }
 
+int LuaEngine::onSuccess(lua_State* lua) {
+    if (sListener == nullptr) {
+        LOG(FATAL) << "sListener object must not be null";
+    }
+    // Any script we run can call on_success only with a single argument of Lua table type.
+    if (lua_gettop(lua) != 1 || !lua_istable(lua, /* index =*/-1)) {
+        // TODO(b/193565932): Return programming error through binder callback interface.
+        LOG(ERROR) << "Only a single input argument, a Lua table object, expected here";
+    }
+
+    // Helper object to create and populate Java Bundle object.
+    BundleWrapper bundleWrapper(sListener->getCurrentJNIEnv());
+    // Iterate over Lua table which is expected to be at the top of Lua stack.
+    // lua_next call pops the key from the top of the stack and finds the next
+    // key-value pair for the popped key. It returns 0 if the next pair was not found.
+    // More on lua_next in: https://www.lua.org/manual/5.3/manual.html#lua_next
+    lua_pushnil(lua);  // First key is a null value.
+    while (lua_next(lua, /* index =*/-2) != 0) {
+        //  'key' is at index -2 and 'value' is at index -1
+        // -1 index is the top of the stack.
+        // remove 'value' and keep 'key' for next iteration
+        // Process each key-value depending on a type and push it to Java Bundle.
+        const char* key = lua_tostring(lua, /* index =*/-2);
+        if (lua_isboolean(lua, /* index =*/-1)) {
+            bundleWrapper.putBoolean(key, static_cast<bool>(lua_toboolean(lua, /* index =*/-1)));
+        } else if (lua_isinteger(lua, /* index =*/-1)) {
+            bundleWrapper.putInteger(key, static_cast<int>(lua_tointeger(lua, /* index =*/-1)));
+        } else if (lua_isnumber(lua, /* index =*/-1)) {
+            bundleWrapper.putDouble(key, static_cast<double>(lua_tonumber(lua, /* index =*/-1)));
+        } else if (lua_isstring(lua, /* index =*/-1)) {
+            bundleWrapper.putString(key, lua_tostring(lua, /* index =*/-1));
+        } else {
+            // not supported yet...
+            LOG(WARNING) << "key=" << key << " has a Lua type which is not supported yet. "
+                         << "The bundle object will not have this key-value pair.";
+        }
+        // Pop 1 element from the stack.
+        lua_pop(lua, 1);
+        // The key is at index -1, the table is at index -2 now.
+    }
+
+    // Forward the populated Bundle object to Java callback.
+    sListener->onSuccess(bundleWrapper.getBundle());
+    // We explicitly must tell Lua how many results we return, which is 0 in this case.
+    // More on the topic: https://www.lua.org/manual/5.3/manual.html#lua_CFunction
+    return ZERO_RETURNED_RESULTS;
+}
+
 }  // namespace script_executor
 }  // namespace telemetry
 }  // namespace automotive
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.h b/cpp/telemetry/script_executor/src/LuaEngine.h
index a1d6e48..39f3a9f 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.h
+++ b/cpp/telemetry/script_executor/src/LuaEngine.h
@@ -38,30 +38,47 @@
     virtual ~LuaEngine();
 
     // Returns pointer to Lua state object.
-    lua_State* GetLuaState();
+    lua_State* getLuaState();
 
     // Loads Lua script provided as scriptBody string.
     // Returns 0 if successful. Otherwise returns non-zero Lua error code.
-    int LoadScript(const char* scriptBody);
+    int loadScript(const char* scriptBody);
 
     // Pushes a Lua function under provided name into the stack.
     // Returns true if successful.
-    bool PushFunction(const char* functionName);
+    bool pushFunction(const char* functionName);
 
     // Invokes function with the inputs provided in the stack.
-    // Assumes that the script body has been already loaded and successully
+    // Assumes that the script body has been already loaded and successfully
     // compiled and run, and all input arguments, and the function have been
     // pushed to the stack.
     // Returns 0 if successful. Otherwise returns non-zero Lua error code.
-    int Run();
+    int run();
 
     // Updates stored listener and destroys the previous one.
-    void ResetListener(ScriptExecutorListener* listener);
+    static void resetListener(ScriptExecutorListener* listener);
 
 private:
-    lua_State* mLuaState;  // owned
+    // Invoked by running Lua script to store intermediate results.
+    // The script will provide the results as a Lua table.
+    // We currently support only non-nested fields in the table and the fields can be the following
+    // Lua types: boolean, number, integer, and string.
+    // The result is converted to Android Bundle and forwarded to
+    // ScriptExecutor service via callback interface.
+    static int onSuccess(lua_State* lua);
 
-    std::unique_ptr<ScriptExecutorListener> mListener;
+    // Points to the current listener object.
+    // Lua cannot call non-static class methods. We need to access listener object instance in
+    // Lua callbacks. Therefore, callbacks callable by Lua are static class methods and the pointer
+    // to a listener object needs to be static, since static methods cannot access non-static
+    // members.
+    // Only one listener is supported at any given time.
+    // Since listeners are heap-allocated, the destructor does not need to run at shutdown
+    // of the service because the memory allocated to the current listener object will be
+    // reclaimed by the OS.
+    static ScriptExecutorListener* sListener;
+
+    lua_State* mLuaState;  // owned
 };
 
 }  // namespace script_executor
diff --git a/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp b/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp
index 500b8e2..0bdc692 100644
--- a/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp
+++ b/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp
@@ -65,9 +65,8 @@
 // More information about how to work with Lua stack: https://www.lua.org/pil/24.2.html
 // and how Lua functions are called via Lua API: https://www.lua.org/pil/25.2.html
 //
-// Finally, once parsing and pushing to Lua stack is complete, we do
-//
-// Step 6: attempt to run the provided function.
+// Finally, once parsing and pushing to Lua stack is complete, we go on to the final step,
+// Step 6: Attempt to run the provided function.
 JNIEXPORT void JNICALL Java_com_android_car_telemetry_ScriptExecutor_nativeInvokeScript(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jstring scriptBody, jstring functionName,
         jobject publishedData, jobject savedState, jobject listener) {
@@ -88,7 +87,7 @@
 
     // Load and parse the script
     const char* scriptStr = env->GetStringUTFChars(scriptBody, nullptr);
-    auto status = engine->LoadScript(scriptStr);
+    auto status = engine->loadScript(scriptStr);
     env->ReleaseStringUTFChars(scriptBody, scriptStr);
     // status == 0 if the script loads successfully.
     if (status) {
@@ -96,11 +95,11 @@
                       "Failed to load the script.");
         return;
     }
-    engine->ResetListener(new ScriptExecutorListener(env, listener));
+    LuaEngine::resetListener(new ScriptExecutorListener(env, listener));
 
     // Push the function name we want to invoke to Lua stack
     const char* functionNameStr = env->GetStringUTFChars(functionName, nullptr);
-    status = engine->PushFunction(functionNameStr);
+    status = engine->pushFunction(functionNameStr);
     env->ReleaseStringUTFChars(functionName, functionNameStr);
     // status == 1 if the name is indeed a function.
     if (!status) {
@@ -119,10 +118,10 @@
 
     // Unpack bundle in savedState, convert to Lua table and push it to Lua
     // stack.
-    PushBundleToLuaTable(env, engine, savedState);
+    pushBundleToLuaTable(env, engine, savedState);
 
     // Execute the function. This will block until complete or error.
-    if (engine->Run()) {
+    if (engine->run()) {
         env->ThrowNew(env->FindClass("java/lang/RuntimeException"),
                       "Runtime error occurred while running the function.");
         return;
diff --git a/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp b/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp
index 8c10aa4..d80aae8 100644
--- a/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp
+++ b/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp
@@ -17,7 +17,6 @@
 #include "ScriptExecutorListener.h"
 
 #include <android-base/logging.h>
-#include <android_runtime/AndroidRuntime.h>
 
 namespace android {
 namespace automotive {
@@ -25,14 +24,27 @@
 namespace script_executor {
 
 ScriptExecutorListener::~ScriptExecutorListener() {
-    if (mScriptExecutorListener != NULL) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getCurrentJNIEnv();
+    if (mScriptExecutorListener != nullptr) {
         env->DeleteGlobalRef(mScriptExecutorListener);
     }
 }
 
 ScriptExecutorListener::ScriptExecutorListener(JNIEnv* env, jobject script_executor_listener) {
     mScriptExecutorListener = env->NewGlobalRef(script_executor_listener);
+    env->GetJavaVM(&mJavaVM);
+}
+
+void ScriptExecutorListener::onSuccess(jobject bundle) {
+    JNIEnv* env = getCurrentJNIEnv();
+    if (mScriptExecutorListener == nullptr) {
+        env->FatalError(
+                "mScriptExecutorListener must point to a valid listener object, not nullptr.");
+    }
+    jclass listenerClass = env->GetObjectClass(mScriptExecutorListener);
+    jmethodID onSuccessMethod =
+            env->GetMethodID(listenerClass, "onSuccess", "(Landroid/os/Bundle;)V");
+    env->CallVoidMethod(mScriptExecutorListener, onSuccessMethod, bundle);
 }
 
 void ScriptExecutorListener::onError(const int errorType, const std::string& message,
@@ -41,6 +53,14 @@
               << ", stackTrace: " << stackTrace;
 }
 
+JNIEnv* ScriptExecutorListener::getCurrentJNIEnv() {
+    JNIEnv* env;
+    if (mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        LOG(FATAL) << "Unable to return JNIEnv from JavaVM";
+    }
+    return env;
+}
+
 }  // namespace script_executor
 }  // namespace telemetry
 }  // namespace automotive
diff --git a/cpp/telemetry/script_executor/src/ScriptExecutorListener.h b/cpp/telemetry/script_executor/src/ScriptExecutorListener.h
index 1e5c7d7..5f6c380 100644
--- a/cpp/telemetry/script_executor/src/ScriptExecutorListener.h
+++ b/cpp/telemetry/script_executor/src/ScriptExecutorListener.h
@@ -35,13 +35,20 @@
 
     void onScriptFinished() {}
 
-    void onSuccess() {}
+    void onSuccess(jobject bundle);
 
     void onError(const int errorType, const std::string& message, const std::string& stackTrace);
 
+    JNIEnv* getCurrentJNIEnv();
+
 private:
     // Stores a jni global reference to Java Script Executor listener object.
     jobject mScriptExecutorListener;
+
+    // Stores JavaVM pointer in order to be able to get JNIEnv pointer.
+    // This is done because JNIEnv cannot be shared between threads.
+    // https://developer.android.com/training/articles/perf-jni.html#javavm-and-jnienv
+    JavaVM* mJavaVM;
 };
 
 }  // namespace script_executor
diff --git a/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
index 9e2c43a..8cdf87a 100644
--- a/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
+++ b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
@@ -44,21 +44,21 @@
 
 JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativePushBundleToLuaTableCaller(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jobject bundle) {
-    PushBundleToLuaTable(env, reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr)),
+    pushBundleToLuaTable(env, reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr)),
                          bundle);
 }
 
 JNIEXPORT jint JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeGetObjectSize(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jint index) {
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
-    return lua_rawlen(engine->GetLuaState(), static_cast<int>(index));
+    return lua_rawlen(engine->getLuaState(), static_cast<int>(index));
 }
 
 JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasBooleanValue(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jboolean value) {
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
@@ -76,7 +76,7 @@
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
     // Assumes the table is on top of the stack.
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
@@ -94,7 +94,7 @@
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
     // Assumes the table is on top of the stack.
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
@@ -112,7 +112,7 @@
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
     // Assumes the table is on top of the stack.
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
index 57d82ca..c9ece21 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
@@ -128,4 +128,12 @@
    * @param actions              List of actions take on resource overusing packages.
    */
    void actionTakenOnResourceOveruse(in List<PackageResourceOveruseAction> actions);
+
+   /**
+    * Enable/disable the internal client health check process.
+    * Disabling would stop the ANR killing process.
+    *
+    * @param isEnabled            New enabled state.
+    */
+    void controlProcessHealthCheck(in boolean disable);
 }
diff --git a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
index 1810c92..e7229ba 100644
--- a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
+++ b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
@@ -291,6 +291,16 @@
         invokeDaemonMethod((daemon) -> daemon.actionTakenOnResourceOveruse(actions));
     }
 
+    /**
+     * Enable/disable the internal client health check process.
+     * Disabling would stop the ANR killing process.
+     *
+     * @param disable True to disable watchdog's health check process.
+     */
+    public void controlProcessHealthCheck(boolean disable) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.controlProcessHealthCheck(disable));
+    }
+
     private void invokeDaemonMethod(Invokable r) throws RemoteException {
         ICarWatchdog daemon;
         synchronized (mLock) {
diff --git a/cpp/watchdog/server/src/IoOveruseConfigs.cpp b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
index 6fb6633..96dd6b3 100644
--- a/cpp/watchdog/server/src/IoOveruseConfigs.cpp
+++ b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
@@ -238,6 +238,16 @@
     return {};
 }
 
+bool isSafeToKillAnyPackage(const std::vector<std::string>& packages,
+                            const std::unordered_set<std::string>& safeToKillPackages) {
+    for (const auto& packageName : packages) {
+        if (safeToKillPackages.find(packageName) != safeToKillPackages.end()) {
+            return true;
+        }
+    }
+    return false;
+}
+
 }  // namespace
 
 IoOveruseConfigs::ParseXmlFileFunction IoOveruseConfigs::sParseXmlFile =
@@ -724,11 +734,26 @@
     }
     switch (packageInfo.componentType) {
         case ComponentType::SYSTEM:
-            return mSystemConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
-                    mSystemConfig.mSafeToKillPackages.end();
+            if (mSystemConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
+                mSystemConfig.mSafeToKillPackages.end()) {
+                return true;
+            }
+            return isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
+                                          mSystemConfig.mSafeToKillPackages);
         case ComponentType::VENDOR:
-            return mVendorConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
-                    mVendorConfig.mSafeToKillPackages.end();
+            if (mVendorConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
+                mVendorConfig.mSafeToKillPackages.end()) {
+                return true;
+            }
+            /*
+             * Packages under the vendor shared UID may contain system packages because when
+             * CarWatchdogService derives the shared component type it attributes system packages
+             * as vendor packages when there is at least one vendor package.
+             */
+            return isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
+                                          mSystemConfig.mSafeToKillPackages) ||
+                    isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
+                                           mVendorConfig.mSafeToKillPackages);
         default:
             return true;
     }
diff --git a/cpp/watchdog/server/src/PackageInfoResolver.cpp b/cpp/watchdog/server/src/PackageInfoResolver.cpp
index 2b30600..84d7c67 100644
--- a/cpp/watchdog/server/src/PackageInfoResolver.cpp
+++ b/cpp/watchdog/server/src/PackageInfoResolver.cpp
@@ -179,9 +179,23 @@
         if (id.name.empty()) {
             continue;
         }
-        if (const auto it = mPackagesToAppCategories.find(id.name);
-            packageInfo.uidType == UidType::APPLICATION && it != mPackagesToAppCategories.end()) {
-            packageInfo.appCategoryType = it->second;
+        if (packageInfo.uidType == UidType::APPLICATION) {
+            if (const auto it = mPackagesToAppCategories.find(id.name);
+                it != mPackagesToAppCategories.end()) {
+                packageInfo.appCategoryType = it->second;
+            } else if (!packageInfo.sharedUidPackages.empty()) {
+                /* The recommendation for the OEMs is to define the application category mapping
+                 * by the shared package names. However, this a fallback to catch if any mapping is
+                 * defined by the individual package name.
+                 */
+                for (const auto& packageName : packageInfo.sharedUidPackages) {
+                    if (const auto it = mPackagesToAppCategories.find(packageName);
+                        it != mPackagesToAppCategories.end()) {
+                        packageInfo.appCategoryType = it->second;
+                        break;
+                    }
+                }
+            }
         }
         mUidToPackageInfoMapping[id.uid] = packageInfo;
     }
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 6da5fb5..be49ff9 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -268,6 +268,15 @@
     return Status::ok();
 }
 
+Status WatchdogInternalHandler::controlProcessHealthCheck(bool disable) {
+    Status status = checkSystemUser();
+    if (!status.isOk()) {
+        return status;
+    }
+    mWatchdogProcessService->setEnabled(!disable);
+    return Status::ok();
+}
+
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.h b/cpp/watchdog/server/src/WatchdogInternalHandler.h
index a2b4892..e23620e 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.h
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.h
@@ -91,8 +91,9 @@
                     configs) override;
     android::binder::Status actionTakenOnResourceOveruse(
             const std::vector<
-                    android::automotive::watchdog::internal::PackageResourceOveruseAction>&
-                    actions);
+                    android::automotive::watchdog::internal::PackageResourceOveruseAction>& actions)
+            override;
+    android::binder::Status controlProcessHealthCheck(bool disable) override;
 
 protected:
     void terminate() {
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp
index 97a4047..fca1174 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.cpp
+++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp
@@ -83,10 +83,11 @@
 const int32_t MSG_VHAL_WATCHDOG_ALIVE = static_cast<int>(TimeoutLength::TIMEOUT_NORMAL) + 1;
 const int32_t MSG_VHAL_HEALTH_CHECK = MSG_VHAL_WATCHDOG_ALIVE + 1;
 
-// VHAL sends heart beat every 3s. Car watchdog checks if there is the latest heart beat from VHAL
+// TODO(b/193742550): Restore the timeout to 3s after configuration by vendors is added.
+// VHAL sends heart beat every 6s. Car watchdog checks if there is the latest heart beat from VHAL
 // with 1s marginal time.
-constexpr std::chrono::nanoseconds kVhalHealthCheckDelayNs = 4s;
-constexpr int64_t kVhalHeartBeatIntervalMs = 3000;
+constexpr std::chrono::milliseconds kVhalHeartBeatIntervalMs = 6s;
+constexpr std::chrono::nanoseconds kVhalHealthCheckDelayNs = kVhalHeartBeatIntervalMs + 1s;
 
 constexpr const char kServiceName[] = "WatchdogProcessService";
 constexpr const char kVhalInterfaceName[] = "android.hardware.automotive.vehicle@2.0::IVehicle";
@@ -799,7 +800,7 @@
         Mutex::Autolock lock(mMutex);
         lastEventTime = mVhalHeartBeat.eventTime;
     }
-    if (currentUptime > lastEventTime + kVhalHeartBeatIntervalMs) {
+    if (currentUptime > lastEventTime + kVhalHeartBeatIntervalMs.count()) {
         ALOGW("VHAL failed to update heart beat within timeout. Terminating VHAL...");
         terminateVhal();
     }
diff --git a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
index 79b32fc..c03ad85 100644
--- a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
@@ -75,12 +75,14 @@
 
 PackageInfo constructPackageInfo(
         const char* packageName, const ComponentType componentType,
-        const ApplicationCategoryType appCategoryType = ApplicationCategoryType::OTHERS) {
+        const ApplicationCategoryType appCategoryType = ApplicationCategoryType::OTHERS,
+        const std::vector<std::string>& sharedUidPackages = std::vector<std::string>()) {
     PackageInfo packageInfo;
     packageInfo.packageIdentifier.name = packageName;
     packageInfo.uidType = UidType::APPLICATION;
     packageInfo.componentType = componentType;
     packageInfo.appCategoryType = appCategoryType;
+    packageInfo.sharedUidPackages = sharedUidPackages;
     return packageInfo;
 }
 
@@ -832,6 +834,28 @@
     EXPECT_THAT(actual, MEDIA_THRESHOLDS);
 }
 
+TEST_F(IoOveruseConfigsTest, TestFetchThresholdForSharedSystemPackages) {
+    const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+    auto sampleSystemConfig = sampleUpdateSystemConfig();
+    auto& ioConfig = sampleSystemConfig.resourceSpecificConfigurations[0]
+                             .get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:systemSharedPackage",
+                                         toPerStateBytes(100, 200, 300)));
+
+    ioOveruseConfigs->update({sampleSystemConfig});
+
+    auto actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("shared:systemSharedPackage", ComponentType::SYSTEM));
+
+    EXPECT_THAT(actual, toPerStateBytes(100, 200, 300));
+
+    actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("systemSharedPackage", ComponentType::SYSTEM));
+
+    EXPECT_THAT(actual, SYSTEM_COMPONENT_LEVEL_THRESHOLDS);
+}
+
 TEST_F(IoOveruseConfigsTest, TestFetchThresholdForVendorPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
 
@@ -853,6 +877,28 @@
     EXPECT_THAT(actual, MAPS_THRESHOLDS);
 }
 
+TEST_F(IoOveruseConfigsTest, TestFetchThresholdForSharedVendorPackages) {
+    const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+    auto sampleVendorConfig = sampleUpdateVendorConfig();
+    auto& ioConfig = sampleVendorConfig.resourceSpecificConfigurations[0]
+                             .get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:vendorSharedPackage",
+                                         toPerStateBytes(100, 200, 300)));
+
+    ioOveruseConfigs->update({sampleVendorConfig});
+
+    auto actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("shared:vendorSharedPackage", ComponentType::VENDOR));
+
+    EXPECT_THAT(actual, toPerStateBytes(100, 200, 300));
+
+    actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("vendorSharedPackage", ComponentType::VENDOR));
+
+    EXPECT_THAT(actual, VENDOR_COMPONENT_LEVEL_THRESHOLDS);
+}
+
 TEST_F(IoOveruseConfigsTest, TestFetchThresholdForThirdPartyPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
 
@@ -883,6 +929,36 @@
             constructPackageInfo("systemPackageA", ComponentType::SYSTEM)));
 }
 
+TEST_F(IoOveruseConfigsTest, TestIsSafeToKillSharedSystemPackages) {
+    auto sampleSystemConfig = sampleUpdateSystemConfig();
+    sampleSystemConfig.safeToKillPackages.push_back("sharedUidSystemPackageC");
+    sampleSystemConfig.safeToKillPackages.push_back("shared:systemSharedPackageD");
+    sp<IoOveruseConfigs> ioOveruseConfigs = new IoOveruseConfigs();
+
+    EXPECT_RESULT_OK(ioOveruseConfigs->update({sampleSystemConfig}));
+
+    PackageInfo packageInfo =
+            constructPackageInfo("systemSharedPackage", ComponentType::SYSTEM,
+                                 ApplicationCategoryType::OTHERS,
+                                 {"sharedUidSystemPackageA", "sharedUidSystemPackageB",
+                                  "sharedUidSystemPackageC"});
+
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when at least one package under shared UID is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("shared:systemSharedPackageD", ComponentType::SYSTEM,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidSystemPackageA"});
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when shared package is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("systemSharedPackageD", ComponentType::SYSTEM,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidSystemPackageA"});
+    EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Shouldn't be safe-to-kill when the 'shared:' prefix is missing";
+}
+
 TEST_F(IoOveruseConfigsTest, TestIsSafeToKillVendorPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
     EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(
@@ -892,6 +968,40 @@
             constructPackageInfo("vendorPackageA", ComponentType::VENDOR)));
 }
 
+TEST_F(IoOveruseConfigsTest, TestIsSafeToKillSharedVendorPackages) {
+    auto sampleVendorConfig = sampleUpdateVendorConfig();
+    sampleVendorConfig.safeToKillPackages.push_back("sharedUidVendorPackageC");
+    sampleVendorConfig.safeToKillPackages.push_back("shared:vendorSharedPackageD");
+
+    auto sampleSystemConfig = sampleUpdateSystemConfig();
+    sampleSystemConfig.safeToKillPackages.push_back("sharedUidSystemPackageC");
+
+    sp<IoOveruseConfigs> ioOveruseConfigs = new IoOveruseConfigs();
+
+    EXPECT_RESULT_OK(ioOveruseConfigs->update({sampleSystemConfig, sampleVendorConfig}));
+
+    PackageInfo packageInfo =
+            constructPackageInfo("vendorSharedPackage", ComponentType::VENDOR,
+                                 ApplicationCategoryType::OTHERS,
+                                 {"sharedUidVendorPackageA", "sharedUidVendorPackageB",
+                                  "sharedUidVendorPackageC"});
+
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when at least one package under shared UID is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("shared:vendorSharedPackageD", ComponentType::VENDOR,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidVendorPackageA"});
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when shared package is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("shared:vendorSharedPackageE", ComponentType::VENDOR,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidVendorPackageA"});
+    EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Shouldn't be safe-to-kill when the 'shared:' prefix is missing";
+}
+
 TEST_F(IoOveruseConfigsTest, TestIsSafeToKillThirdPartyPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
     EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(
@@ -931,6 +1041,32 @@
                 UnorderedElementsAre("vendorPackage", "vendorPkgB"));
 }
 
+TEST_F(IoOveruseConfigsTest, TestVendorPackagePrefixesWithSharedPackages) {
+    auto sampleVendorConfig = sampleUpdateVendorConfig();
+    sampleVendorConfig.vendorPackagePrefixes.push_back("shared:vendorSharedPackage");
+    sampleVendorConfig.safeToKillPackages.push_back("sharedUidVendorPackageD");
+    sampleVendorConfig.safeToKillPackages.push_back("shared:vendorSharedPackageE");
+    sampleVendorConfig.safeToKillPackages.push_back("shared:vndrSharedPkgF");
+
+    auto& ioConfig = sampleVendorConfig.resourceSpecificConfigurations[0]
+                             .get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:vendorSharedPackageG",
+                                         VENDOR_PACKAGE_A_THRESHOLDS));
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:vndrSharedPkgH", VENDOR_PACKAGE_A_THRESHOLDS));
+
+    sp<IoOveruseConfigs> ioOveruseConfigs = new IoOveruseConfigs();
+
+    EXPECT_RESULT_OK(ioOveruseConfigs->update({sampleVendorConfig}));
+
+    EXPECT_THAT(ioOveruseConfigs->vendorPackagePrefixes(),
+                UnorderedElementsAre("vendorPackage", "vendorPkgB", "shared:vendorSharedPackage",
+                                     "sharedUidVendorPackageD", "shared:vndrSharedPkgF",
+                                     "shared:vndrSharedPkgH"));
+}
+
 TEST_F(IoOveruseConfigsTest, TestPackagesToAppCategoriesWithSystemConfig) {
     IoOveruseConfigs ioOveruseConfigs;
     const auto resourceOveruseConfig = sampleUpdateSystemConfig();
diff --git a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
index f2fe3a6..cf282be 100644
--- a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
+++ b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
@@ -195,6 +195,8 @@
             // system.package.B is native package so this should be ignored.
             {"system.package.B", ApplicationCategoryType::MAPS},
             {"vendor.package.A", ApplicationCategoryType::MEDIA},
+            {"shared:vendor.package.C", ApplicationCategoryType::MEDIA},
+            {"vendor.package.shared.uid.D", ApplicationCategoryType::MAPS},
     };
     peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
     /*
@@ -213,23 +215,38 @@
                                   ApplicationCategoryType::OTHERS)},
             {15100,
              constructPackageInfo("vendor.package.A", 15100, UidType::APPLICATION,
-                                  ComponentType::VENDOR, ApplicationCategoryType::MEDIA)},
+                                  ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
             {16700,
              constructPackageInfo("vendor.pkg", 16700, UidType::NATIVE, ComponentType::VENDOR,
                                   ApplicationCategoryType::OTHERS)},
+            {18100,
+             constructPackageInfo("shared:vendor.package.C", 18100, UidType::APPLICATION,
+                                  ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
+            {19100,
+             constructPackageInfo("shared:vendor.package.D", 19100, UidType::APPLICATION,
+                                  ComponentType::VENDOR, ApplicationCategoryType::OTHERS,
+                                  {"vendor.package.shared.uid.D"})},
     };
 
-    std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700};
+    std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700, 18100, 19100};
     std::vector<std::string> expectedPrefixes = {"vendor.pkg"};
     std::vector<PackageInfo> injectPackageInfos = {expectedMappings.at(6100),
                                                    expectedMappings.at(7700),
                                                    expectedMappings.at(15100),
-                                                   expectedMappings.at(16700)};
+                                                   expectedMappings.at(16700),
+                                                   expectedMappings.at(18100),
+                                                   expectedMappings.at(19100)};
+
+    expectedMappings.at(15100).appCategoryType = ApplicationCategoryType::MEDIA;
+    expectedMappings.at(18100).appCategoryType = ApplicationCategoryType::MEDIA;
+    expectedMappings.at(19100).appCategoryType = ApplicationCategoryType::MAPS;
+
     EXPECT_CALL(*peer.mockWatchdogServiceHelper,
                 getPackageInfosForUids(expectedUids, expectedPrefixes, _))
             .WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos), Return(binder::Status::ok())));
 
-    auto actualMappings = packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700});
+    auto actualMappings =
+            packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
 
     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
             << "Expected: " << toString(expectedMappings)
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index efa9eef..4646a11 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -470,6 +470,19 @@
     ASSERT_FALSE(status.isOk()) << status;
 }
 
+TEST_F(WatchdogInternalHandlerTest, TestControlProcessHealthCheck) {
+    setSystemCallingUid();
+    EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/true)).Times(1);
+    Status status = mWatchdogInternalHandler->controlProcessHealthCheck(false);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestErrorOnControlProcessHealthCheckWithNonSystemCallingUid) {
+    EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(_)).Times(0);
+    Status status = mWatchdogInternalHandler->controlProcessHealthCheck(false);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
diff --git a/service/Android.bp b/service/Android.bp
index 709c928..b2456d1 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -34,6 +34,7 @@
 ]
 
 common_lib_deps = [
+    "android.automotive.telemetry.internal-java",  // ICarTelemetryInternal
     "android.car.cluster.navigation",
     "android.car.userlib",
     "android.car.watchdoglib",
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index 8cee561..1f6375e 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.car.Car;
 import android.car.hardware.power.CarPowerPolicy;
@@ -60,6 +61,7 @@
 import android.os.UserManager;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
+import android.util.DebugUtils;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Slog;
@@ -68,6 +70,7 @@
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.utils.Slogf;
 
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -76,6 +79,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.stream.Collectors;
 
 /**
@@ -87,7 +91,9 @@
  * it were being browsed only. However, that source is still considered the active source, and
  * should be the source displayed in any Media related UIs (Media Center, home screen, etc).
  */
-public class CarMediaService extends ICarMedia.Stub implements CarServiceBase {
+public final class CarMediaService extends ICarMedia.Stub implements CarServiceBase {
+
+    private static final boolean DEBUG = false;
 
     private static final String SOURCE_KEY = "media_source_component";
     private static final String SOURCE_KEY_SEPARATOR = "_";
@@ -96,6 +102,7 @@
     private static final String COMPONENT_NAME_SEPARATOR = ",";
     private static final String MEDIA_CONNECTION_ACTION = "com.android.car.media.MEDIA_CONNECTION";
     private static final String EXTRA_AUTOPLAY = "com.android.car.media.autoplay";
+    private static final String LAST_UPDATE_KEY = "last_update";
 
     private static final int MEDIA_SOURCE_MODES = 2;
 
@@ -126,6 +133,8 @@
     private boolean mWasPreviouslyDisabledByPowerPolicy;
     @GuardedBy("mLock")
     private boolean mWasPlayingBeforeDisabled;
+
+    // NOTE: must use getSharedPrefsForWriting() to write to it
     private SharedPreferences mSharedPrefs;
     private SessionChangedListener mSessionsListener;
     private int mPlayOnMediaSourceChangedConfig;
@@ -151,6 +160,7 @@
     private ComponentName[] mRemovedMediaSourceComponents = new ComponentName[MEDIA_SOURCE_MODES];
 
     private final IntentFilter mPackageUpdateFilter;
+    @GuardedBy("mLock")
     private boolean mIsPackageUpdateReceiverRegistered;
 
     /**
@@ -230,7 +240,7 @@
                 maybeInitUser(event.getUserId());
                 break;
             case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
-                onUserUnlock(event.getUserId());
+                onUserUnlocked(event.getUserId());
                 break;
         }
     };
@@ -309,8 +319,9 @@
     @Override
     // This method is called from ICarImpl after CarMediaService is created.
     public void init() {
-        int currentUser = ActivityManager.getCurrentUser();
-        maybeInitUser(currentUser);
+        int currentUserId = ActivityManager.getCurrentUser();
+        Slog.d(CarLog.TAG_MEDIA, "init(): currentUser=" + currentUserId);
+        maybeInitUser(currentUserId);
         setPowerPolicyListener();
     }
 
@@ -325,21 +336,16 @@
         }
     }
 
-    private void initUser(int userId) {
-        // SharedPreferences are shared among different users thus only need initialized once. And
-        // they should be initialized after user 0 is unlocked because SharedPreferences in
-        // credential encrypted storage are not available until after user 0 is unlocked.
-        // initUser() is called when the current foreground user is unlocked, and by that time user
-        // 0 has been unlocked already, so initializing SharedPreferences in initUser() is fine.
-        synchronized (mLock) {
-            if (mSharedPrefs == null) {
-                mSharedPrefs = mContext.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
-            }
+    private void initUser(@UserIdInt int userId) {
+        Slog.d(CarLog.TAG_MEDIA, "initUser(): userId=" + userId + ", mSharedPrefs=" + mSharedPrefs);
+        UserHandle currentUser = new UserHandle(userId);
 
+        maybeInitSharedPrefs(userId);
+
+        synchronized (mLock) {
             if (mIsPackageUpdateReceiverRegistered) {
                 mContext.unregisterReceiver(mPackageUpdateReceiver);
             }
-            UserHandle currentUser = new UserHandle(userId);
             mContext.registerReceiverAsUser(mPackageUpdateReceiver, currentUser,
                     mPackageUpdateFilter, null, null);
             mIsPackageUpdateReceiverRegistered = true;
@@ -358,6 +364,30 @@
         }
     }
 
+    private void maybeInitSharedPrefs(@UserIdInt int userId) {
+        // SharedPreferences are shared among different users thus only need initialized once. And
+        // they should be initialized after user 0 is unlocked because SharedPreferences in
+        // credential encrypted storage are not available until after user 0 is unlocked.
+        // initUser() is called when the current foreground user is unlocked, and by that time user
+        // 0 has been unlocked already, so initializing SharedPreferences in initUser() is fine.
+        if (mSharedPrefs != null) {
+            Slog.i(CarLog.TAG_MEDIA, "Shared preferences already set (on directory "
+                    + mContext.getDataDir() + ") when initializing user " + userId);
+            return;
+        }
+        Slog.i(CarLog.TAG_MEDIA, "Getting shared preferences when initializing user "
+                + userId);
+        mSharedPrefs = mContext.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
+
+        // Try to access the properties to make sure they were properly open
+        if (DEBUG) {
+            Slogf.i(CarLog.TAG_MEDIA, "Number of prefs: %d", mSharedPrefs.getAll().size());
+
+        } else if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
+            Slogf.d(CarLog.TAG_MEDIA, "Number of prefs: %d", mSharedPrefs.getAll().size());
+        }
+    }
+
     /**
      * Starts a service on the current user that binds to the media browser of the current media
      * source. We start a new service because this one runs on user 0, and MediaBrowser doesn't
@@ -373,20 +403,19 @@
     }
 
     private boolean sharedPrefsInitialized() {
-        if (mSharedPrefs == null) {
-            // It shouldn't reach this but let's be cautious.
-            Slog.e(CarLog.TAG_MEDIA, "SharedPreferences are not initialized!");
-            String className = getClass().getName();
-            for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
-                // Let's print the useful logs only.
-                String log = ste.toString();
-                if (log.contains(className)) {
-                    Slog.e(CarLog.TAG_MEDIA, log);
-                }
+        if (mSharedPrefs != null) return true;
+
+        // It shouldn't reach this but let's be cautious.
+        Slog.e(CarLog.TAG_MEDIA, "SharedPreferences are not initialized!");
+        String className = getClass().getName();
+        for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
+            // Let's print the useful logs only.
+            String log = ste.toString();
+            if (log.contains(className)) {
+                Slog.e(CarLog.TAG_MEDIA, log);
             }
-            return false;
         }
-        return true;
+        return false;
     }
 
     private boolean isCurrentUserEphemeral() {
@@ -414,43 +443,85 @@
 
     @Override
     public void dump(IndentingPrintWriter writer) {
+        writer.println("*CarMediaService*");
+        writer.increaseIndent();
+
+        writer.printf("Pending init: %b\n", mPendingInit);
+        boolean hasSharedPrefs;
         synchronized (mLock) {
-            writer.println("*CarMediaService*");
-            writer.increaseIndent();
-            writer.printf("Current playback media component: %s\n",
-                    mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] == null ? "-"
-                    : mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK].flattenToString());
-            writer.printf("Current browse media component: %s\n",
-                    mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE] == null ? "-"
-                    : mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE].flattenToString());
+            hasSharedPrefs = mSharedPrefs != null;
+            dumpCurrentMediaComponent(writer, "playback", MEDIA_SOURCE_MODE_PLAYBACK);
+            dumpCurrentMediaComponent(writer, "browse", MEDIA_SOURCE_MODE_BROWSE);
             if (mActiveUserMediaController != null) {
                 writer.printf("Current media controller: %s\n",
                         mActiveUserMediaController.getPackageName());
                 writer.printf("Current browse service extra: %s\n",
                         getClassName(mActiveUserMediaController));
+            } else {
+                writer.println("no active user media controller");
             }
-            writer.printf("Number of active media sessions: %s\n", mMediaSessionManager
-                    .getActiveSessionsForUser(null,
-                            new UserHandle(ActivityManager.getCurrentUser())).size());
+            int userId = ActivityManager.getCurrentUser();
+            writer.printf("Number of active media sessions (for current user %d): %d\n", userId,
+                    mMediaSessionManager.getActiveSessionsForUser(/* notificationListener= */ null,
+                            new UserHandle(userId)).size());
 
-            writer.println("Playback media source history:");
-            writer.increaseIndent();
-            for (ComponentName name : getLastMediaSources(MEDIA_SOURCE_MODE_PLAYBACK)) {
-                writer.println(name.flattenToString());
-            }
-            writer.decreaseIndent();
-            writer.println("Browse media source history:");
-            writer.increaseIndent();
-            for (ComponentName name : getLastMediaSources(MEDIA_SOURCE_MODE_BROWSE)) {
-                writer.println(name.flattenToString());
-            }
-            writer.decreaseIndent();
             writer.printf("Disabled by power policy: %s\n", mIsDisabledByPowerPolicy);
             if (mIsDisabledByPowerPolicy) {
                 writer.printf("Before being disabled by power policy, audio was %s\n",
                         mWasPlayingBeforeDisabled ? "active" : "inactive");
             }
         }
+
+        if (hasSharedPrefs) {
+            dumpLastMediaSources(writer, "Playback", MEDIA_SOURCE_MODE_PLAYBACK);
+            dumpLastMediaSources(writer, "Browse", MEDIA_SOURCE_MODE_BROWSE);
+            dumpSharedPrefs(writer);
+        } else {
+            writer.println("No shared preferences");
+        }
+
+        writer.decreaseIndent();
+    }
+
+    private void dumpCurrentMediaComponent(IndentingPrintWriter writer, String name,
+            @CarMediaManager.MediaSourceMode int mode) {
+        ComponentName componentName = mPrimaryMediaComponents[mode];
+        writer.printf("Current %s media component: %s\n", name, componentName == null
+                ? "-"
+                : componentName.flattenToString());
+    }
+
+    private void dumpLastMediaSources(IndentingPrintWriter writer, String name,
+            @CarMediaManager.MediaSourceMode int mode) {
+        writer.printf("%s media source history:\n", name);
+        writer.increaseIndent();
+        List<ComponentName> lastMediaSources = getLastMediaSources(mode);
+        for (int i = 0; i < lastMediaSources.size(); i++) {
+            ComponentName componentName = lastMediaSources.get(i);
+            if (componentName == null) {
+                Slogf.e(CarLog.TAG_MEDIA, "dump(): empty last media source of %s at index %d: %s",
+                        mediaModeToString(mode), i, lastMediaSources);
+                continue;
+            }
+            writer.println(componentName.flattenToString());
+        }
+        writer.decreaseIndent();
+    }
+
+    private void dumpSharedPrefs(IndentingPrintWriter writer) {
+        Map<String, ?> allPrefs = mSharedPrefs.getAll();
+        writer.printf("%d shared preferences (saved on directory %s)",
+                allPrefs.size(), mContext.getDataDir());
+        if (!Log.isLoggable(CarLog.TAG_MEDIA, Log.VERBOSE) || allPrefs.isEmpty()) {
+            writer.println();
+            return;
+        }
+        writer.println(':');
+        writer.increaseIndent();
+        for (Entry<String, ?> pref : allPrefs.entrySet()) {
+            writer.printf("%s = %s\n", pref.getKey(), pref.getValue());
+        }
+        writer.decreaseIndent();
     }
 
     /**
@@ -531,10 +602,12 @@
     }
 
     // TODO(b/153115826): this method was used to be called from the ICar binder thread, but it's
-    // now called by UserCarService. Currently UserCarServie is calling every listener in one
+    // now called by UserCarService. Currently UserCarService is calling every listener in one
     // non-main thread, but it's not clear how the final behavior will be. So, for now it's ok
     // to post it to mMainHandler, but once b/145689885 is fixed, we might not need it.
-    private void onUserUnlock(int userId) {
+    private void onUserUnlocked(@UserIdInt int userId) {
+        Slog.d(CarLog.TAG_MEDIA, "onUserUnlocked(): userId=" + userId
+                + ", mPendingInit=" + mPendingInit);
         mMainHandler.post(() -> {
             // No need to handle system user, non current foreground user.
             if (userId == UserHandle.USER_SYSTEM
@@ -904,13 +977,28 @@
         String componentName = component.flattenToString();
         String key = getMediaSourceKey(mode);
         String serialized = mSharedPrefs.getString(key, null);
+        String modeName = null;
+        boolean debug = DEBUG || Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG);
+        if (debug) {
+            modeName = mediaModeToString(mode);
+        }
+
         if (serialized == null) {
-            mSharedPrefs.edit().putString(key, componentName).apply();
+            if (debug) {
+                Slogf.d(CarLog.TAG_MEDIA, "saveLastMediaSource(%s, %s): no value for key %s",
+                        componentName, modeName, key);
+            }
+            getSharedPrefsForWriting().putString(key, componentName).apply();
         } else {
             Deque<String> componentNames = new ArrayDeque<>(getComponentNameList(serialized));
             componentNames.remove(componentName);
             componentNames.addFirst(componentName);
-            mSharedPrefs.edit().putString(key, serializeComponentNameList(componentNames)).apply();
+            String newSerialized = serializeComponentNameList(componentNames);
+            if (debug) {
+                Slogf.d(CarLog.TAG_MEDIA, "saveLastMediaSource(%s, %s): updating %s from %s to %s",
+                        componentName, modeName,  key, serialized, newSerialized);
+            }
+            getSharedPrefsForWriting().putString(key, newSerialized).apply();
         }
     }
 
@@ -960,7 +1048,8 @@
             mCurrentPlaybackState = state;
         }
         String key = getPlaybackStateKey();
-        mSharedPrefs.edit().putInt(key, state).apply();
+        Slogf.d(CarLog.TAG_MEDIA, "savePlaybackState(): %s = %d)", key, state);
+        getSharedPrefsForWriting().putInt(key, state).apply();
     }
 
     /**
@@ -1031,6 +1120,15 @@
         }
     }
 
+    /**
+     * Gets the editor used to update shared preferences.
+     */
+    private SharedPreferences.Editor getSharedPrefsForWriting() {
+        long now = System.currentTimeMillis();
+        Slogf.i(CarLog.TAG_MEDIA, "Updating %s to %d", LAST_UPDATE_KEY, now);
+        return mSharedPrefs.edit().putLong(LAST_UPDATE_KEY, now);
+    }
+
     @NonNull
     private static String getClassName(@NonNull MediaController controller) {
         Bundle sessionExtras = controller.getExtras();
@@ -1039,4 +1137,8 @@
                         Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION);
         return value != null ? value : "";
     }
+
+    private static String mediaModeToString(@CarMediaManager.MediaSourceMode int mode) {
+        return DebugUtils.constantToString(CarMediaManager.class, "MEDIA_SOURCE_", mode);
+    }
 }
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index bad6b71..576aad2 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -18,6 +18,7 @@
 import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME;
 import static android.car.Car.PERMISSION_CAR_POWER;
 import static android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG;
+import static android.car.Car.PERMISSION_USE_CAR_WATCHDOG;
 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS;
 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER;
@@ -197,6 +198,8 @@
             "watchdog-io-set-3p-foreground-bytes";
     private static final String COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES =
             "watchdog-io-get-3p-foreground-bytes";
+    private static final String COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK =
+            "watchdog-control-health-check";
 
     private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
             android.Manifest.permission.CREATE_USERS,
@@ -269,6 +272,8 @@
                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES,
                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK,
+                PERMISSION_USE_CAR_WATCHDOG);
     }
 
     private static final String PARAM_DAY_MODE = "day";
@@ -612,6 +617,10 @@
 
         pw.printf("\t%s\n", COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES);
         pw.println("\t  Gets third-party apps foreground I/O overuse threshold");
+
+        pw.printf("\t%s true|false\n", COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK);
+        pw.println("\t  Enables/disables car watchdog process health check.");
+        pw.println("\t  Set to true to disable the process health check.");
     }
 
     private static int showInvalidArguments(IndentingPrintWriter pw) {
@@ -940,7 +949,9 @@
             case COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES:
                 getWatchdogIoThirdPartyForegroundBytes(writer);
                 break;
-
+            case COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK:
+                controlWatchdogProcessHealthCheck(args, writer);
+                break;
             default:
                 writer.println("Unknown command: \"" + cmd + "\"");
                 showHelp(writer);
@@ -2200,6 +2211,19 @@
                 .setIoOveruseConfiguration(configuration.getIoOveruseConfiguration());
     }
 
+    private void controlWatchdogProcessHealthCheck(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 2) {
+            showInvalidArguments(writer);
+            return;
+        }
+        boolean newState = Boolean.parseBoolean(args[1]);
+        if (!newState && !args[1].equalsIgnoreCase("false")) {
+            writer.println("Failed to parse argument. Valid arguments: true | false");
+            return;
+        }
+        mCarWatchdogService.controlProcessHealthCheck(newState);
+    }
+
     // Check if the given property is global
     private static boolean isPropertyAreaTypeGlobal(@Nullable String property) {
         if (property == null) {
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 62be1fd..f6a98d6 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -550,9 +550,9 @@
                 AudioManager.GET_DEVICES_INPUTS);
     }
 
+    @GuardedBy("mImplLock")
     private SparseArray<CarAudioZone> loadCarAudioConfigurationLocked(
-            List<CarAudioDeviceInfo> carAudioDeviceInfos) {
-        AudioDeviceInfo[] inputDevices = getAllInputDevices();
+            List<CarAudioDeviceInfo> carAudioDeviceInfos, AudioDeviceInfo[] inputDevices) {
         try (InputStream inputStream = new FileInputStream(mCarAudioConfigurationPath)) {
             CarAudioZonesHelper zonesHelper = new CarAudioZonesHelper(mCarAudioSettings,
                     inputStream, carAudioDeviceInfos, inputDevices, mUseCarVolumeGroupMuting);
@@ -564,8 +564,9 @@
         }
     }
 
+    @GuardedBy("mImplLock")
     private SparseArray<CarAudioZone> loadVolumeGroupConfigurationWithAudioControlLocked(
-            List<CarAudioDeviceInfo> carAudioDeviceInfos) {
+            List<CarAudioDeviceInfo> carAudioDeviceInfos, AudioDeviceInfo[] inputDevices) {
         AudioControlWrapper audioControlWrapper = getAudioControlWrapperLocked();
         if (!(audioControlWrapper instanceof AudioControlWrapperV1)) {
             throw new IllegalStateException(
@@ -574,20 +575,22 @@
         }
         CarAudioZonesHelperLegacy legacyHelper = new CarAudioZonesHelperLegacy(mContext,
                 R.xml.car_volume_groups, carAudioDeviceInfos,
-                (AudioControlWrapperV1) audioControlWrapper, mCarAudioSettings);
+                (AudioControlWrapperV1) audioControlWrapper, mCarAudioSettings, inputDevices);
         return legacyHelper.loadAudioZones();
     }
 
     @GuardedBy("mImplLock")
     private void loadCarAudioZonesLocked() {
         List<CarAudioDeviceInfo> carAudioDeviceInfos = generateCarAudioDeviceInfos();
+        AudioDeviceInfo[] inputDevices = getAllInputDevices();
 
         mCarAudioConfigurationPath = getAudioConfigurationPath();
         if (mCarAudioConfigurationPath != null) {
-            mCarAudioZones = loadCarAudioConfigurationLocked(carAudioDeviceInfos);
+            mCarAudioZones = loadCarAudioConfigurationLocked(carAudioDeviceInfos, inputDevices);
         } else {
-            mCarAudioZones = loadVolumeGroupConfigurationWithAudioControlLocked(
-                    carAudioDeviceInfos);
+            mCarAudioZones =
+                    loadVolumeGroupConfigurationWithAudioControlLocked(carAudioDeviceInfos,
+                            inputDevices);
         }
 
         CarAudioZonesValidator.validate(mCarAudioZones);
diff --git a/service/src/com/android/car/audio/CarAudioUtils.java b/service/src/com/android/car/audio/CarAudioUtils.java
index b787efb..ad74587 100644
--- a/service/src/com/android/car/audio/CarAudioUtils.java
+++ b/service/src/com/android/car/audio/CarAudioUtils.java
@@ -16,6 +16,10 @@
 
 package com.android.car.audio;
 
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
+
+import android.media.AudioDeviceInfo;
+
 final class CarAudioUtils {
     private CarAudioUtils() {
     }
@@ -23,4 +27,8 @@
     static boolean hasExpired(long startTimeMs, long currentTimeMs, int timeoutMs) {
         return (currentTimeMs - startTimeMs) > timeoutMs;
     }
+
+    static boolean isMicrophoneInputDevice(AudioDeviceInfo device) {
+        return device.getType() == TYPE_BUILTIN_MIC;
+    }
 }
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelper.java b/service/src/com/android/car/audio/CarAudioZonesHelper.java
index 7956ea2..2e25325 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelper.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelper.java
@@ -17,10 +17,14 @@
 
 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
 
+import static com.android.car.audio.CarAudioUtils.isMicrophoneInputDevice;
+
 import android.annotation.NonNull;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.Xml;
@@ -35,8 +39,6 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -73,7 +75,7 @@
     private static final Map<String, Integer> CONTEXT_NAME_MAP;
 
     static {
-        CONTEXT_NAME_MAP = new HashMap<>(CarAudioContext.CONTEXTS.length);
+        CONTEXT_NAME_MAP = new ArrayMap<>(CarAudioContext.CONTEXTS.length);
         CONTEXT_NAME_MAP.put("music", CarAudioContext.MUSIC);
         CONTEXT_NAME_MAP.put("navigation", CarAudioContext.NAVIGATION);
         CONTEXT_NAME_MAP.put("voice_command", CarAudioContext.VOICE_COMMAND);
@@ -128,11 +130,11 @@
 
     private final CarAudioSettings mCarAudioSettings;
     private final Map<String, CarAudioDeviceInfo> mAddressToCarAudioDeviceInfo;
-    private final Map<String, AudioDeviceInfo> mAddressToInputAudioDeviceInfo;
+    private final Map<String, AudioDeviceInfo> mAddressToInputAudioDeviceInfoForAllInputDevices;
     private final InputStream mInputStream;
     private final SparseIntArray mZoneIdToOccupantZoneIdMapping;
     private final Set<Integer> mAudioZoneIds;
-    private final Set<String> mInputAudioDevices;
+    private final Set<String> mAssignedInputAudioDevices;
     private final boolean mUseCarVolumeGroupMute;
 
     private int mNextSecondaryZoneId;
@@ -152,12 +154,12 @@
         Objects.requireNonNull(inputDeviceInfo);
         mAddressToCarAudioDeviceInfo = CarAudioZonesHelper.generateAddressToInfoMap(
                 carAudioDeviceInfos);
-        mAddressToInputAudioDeviceInfo =
+        mAddressToInputAudioDeviceInfoForAllInputDevices =
                 CarAudioZonesHelper.generateAddressToInputAudioDeviceInfoMap(inputDeviceInfo);
         mNextSecondaryZoneId = PRIMARY_AUDIO_ZONE + 1;
         mZoneIdToOccupantZoneIdMapping = new SparseIntArray();
-        mAudioZoneIds = new HashSet<>();
-        mInputAudioDevices = new HashSet<>();
+        mAudioZoneIds = new ArraySet<>();
+        mAssignedInputAudioDevices = new ArraySet<>();
         mUseCarVolumeGroupMute = useCarVolumeGroupMute;
     }
 
@@ -178,8 +180,8 @@
 
     private static Map<String, AudioDeviceInfo> generateAddressToInputAudioDeviceInfoMap(
             @NonNull AudioDeviceInfo[] inputAudioDeviceInfos) {
-        HashMap<String, AudioDeviceInfo> deviceAddressToInputDeviceMap =
-                new HashMap<>(inputAudioDeviceInfos.length);
+        Map<String, AudioDeviceInfo> deviceAddressToInputDeviceMap =
+                new ArrayMap<>(inputAudioDeviceInfos.length);
         for (int i = 0; i < inputAudioDeviceInfos.length; ++i) {
             AudioDeviceInfo device = inputAudioDeviceInfos[i];
             if (device.isSource()) {
@@ -238,9 +240,20 @@
         }
 
         verifyPrimaryZonePresent(carAudioZones);
+        addRemainingMicrophonesToPrimaryZone(carAudioZones);
         return carAudioZones;
     }
 
+    private void addRemainingMicrophonesToPrimaryZone(SparseArray<CarAudioZone> carAudioZones) {
+        CarAudioZone primaryAudioZone = carAudioZones.get(PRIMARY_AUDIO_ZONE);
+        for (AudioDeviceInfo info : mAddressToInputAudioDeviceInfoForAllInputDevices.values()) {
+            if (!mAssignedInputAudioDevices.contains(info.getAddress())
+                    && isMicrophoneInputDevice(info)) {
+                primaryAudioZone.addInputAudioDevice(new AudioDeviceAttributes(info));
+            }
+        }
+    }
+
     private void verifyOnlyOnePrimaryZone(CarAudioZone newZone, SparseArray<CarAudioZone> zones) {
         if (newZone.getId() == PRIMARY_AUDIO_ZONE && zones.contains(PRIMARY_AUDIO_ZONE)) {
             throw new RuntimeException("More than one zone parsed with primary audio zone ID: "
@@ -347,7 +360,8 @@
                 String audioDeviceAddress =
                         parser.getAttributeValue(NAMESPACE, ATTR_DEVICE_ADDRESS);
                 validateInputAudioDeviceAddress(audioDeviceAddress);
-                AudioDeviceInfo info = mAddressToInputAudioDeviceInfo.get(audioDeviceAddress);
+                AudioDeviceInfo info =
+                        mAddressToInputAudioDeviceInfoForAllInputDevices.get(audioDeviceAddress);
                 Preconditions.checkArgument(info != null,
                         "%s %s of %s does not exist, add input device to"
                                 + " audio_policy_configuration.xml.",
@@ -364,11 +378,11 @@
         Preconditions.checkArgument(!audioDeviceAddress.isEmpty(),
                 "%s %s attribute can not be empty.",
                 TAG_INPUT_DEVICE, ATTR_DEVICE_ADDRESS);
-        if (mInputAudioDevices.contains(audioDeviceAddress)) {
+        if (mAssignedInputAudioDevices.contains(audioDeviceAddress)) {
             throw new IllegalArgumentException(TAG_INPUT_DEVICE + " " + audioDeviceAddress
                     + " repeats, " + TAG_INPUT_DEVICES + " can not repeat.");
         }
-        mInputAudioDevices.add(audioDeviceAddress);
+        mAssignedInputAudioDevices.add(audioDeviceAddress);
     }
 
     private void validateOccupantZoneIdIsUnique(int occupantZoneId) {
diff --git a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
index 6bbd6c9..7ce2538 100644
--- a/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
+++ b/service/src/com/android/car/audio/CarAudioZonesHelperLegacy.java
@@ -17,6 +17,7 @@
 
 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
 
+import static com.android.car.audio.CarAudioUtils.isMicrophoneInputDevice;
 import static com.android.car.audio.CarAudioZonesHelper.LEGACY_CONTEXTS;
 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DEPRECATED_CODE;
 
@@ -25,6 +26,8 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -62,15 +65,21 @@
     private final SparseIntArray mLegacyAudioContextToBus;
     private final SparseArray<CarAudioDeviceInfo> mBusToCarAudioDeviceInfo;
     private final CarAudioSettings mCarAudioSettings;
+    private final AudioDeviceInfo[] mInputDevices;
 
-    CarAudioZonesHelperLegacy(@NonNull  Context context, @XmlRes int xmlConfiguration,
+    CarAudioZonesHelperLegacy(@NonNull Context context, @XmlRes int xmlConfiguration,
             @NonNull List<CarAudioDeviceInfo> carAudioDeviceInfos,
             @NonNull AudioControlWrapperV1 audioControlWrapper,
-            @NonNull CarAudioSettings carAudioSettings) {
-        Objects.requireNonNull(context);
-        Objects.requireNonNull(carAudioDeviceInfos);
-        Objects.requireNonNull(audioControlWrapper);
-        mCarAudioSettings = Objects.requireNonNull(carAudioSettings);
+            @NonNull CarAudioSettings carAudioSettings,
+            AudioDeviceInfo[] inputDevices) {
+        Objects.requireNonNull(context, "Context must not be null.");
+        Objects.requireNonNull(carAudioDeviceInfos,
+                "Car Audio Device Info must not be null.");
+        Objects.requireNonNull(audioControlWrapper,
+                "Car Audio Control must not be null.");
+        Objects.requireNonNull(inputDevices, "Input Devices must not be null.");
+        mCarAudioSettings = Objects.requireNonNull(carAudioSettings,
+                "Car Audio Settings can not be null.");
         mContext = context;
         mXmlConfiguration = xmlConfiguration;
         mBusToCarAudioDeviceInfo =
@@ -78,6 +87,7 @@
 
         mLegacyAudioContextToBus =
                 loadBusesForLegacyContexts(audioControlWrapper);
+        mInputDevices = inputDevices;
     }
 
     /* Loads mapping from {@link CarAudioContext} values to bus numbers
@@ -135,7 +145,9 @@
             zone.addVolumeGroup(volumeGroup);
         }
         SparseArray<CarAudioZone> carAudioZones = new SparseArray<>();
+        addMicrophonesToPrimaryZone(zone);
         carAudioZones.put(PRIMARY_AUDIO_ZONE, zone);
+
         return carAudioZones;
     }
 
@@ -221,6 +233,15 @@
         return contexts;
     }
 
+    private void addMicrophonesToPrimaryZone(CarAudioZone primaryAudioZone) {
+        for (int index = 0; index < mInputDevices.length; index++) {
+            AudioDeviceInfo info = mInputDevices[index];
+            if (isMicrophoneInputDevice(info)) {
+                primaryAudioZone.addInputAudioDevice(new AudioDeviceAttributes(info));
+            }
+        }
+    }
+
     /**
      * Parse device address. Expected format is BUS%d_%s, address, usage hint
      *
diff --git a/service/src/com/android/car/audio/CarAudioZonesValidator.java b/service/src/com/android/car/audio/CarAudioZonesValidator.java
index 5fe495d..6b7bbb9 100644
--- a/service/src/com/android/car/audio/CarAudioZonesValidator.java
+++ b/service/src/com/android/car/audio/CarAudioZonesValidator.java
@@ -16,9 +16,16 @@
 package com.android.car.audio;
 
 
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
+
+import android.media.AudioDeviceAttributes;
 import android.util.SparseArray;
 
+import com.android.internal.util.Preconditions;
+
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 final class CarAudioZonesValidator {
@@ -29,6 +36,20 @@
         validateAtLeastOneZoneDefined(carAudioZones);
         validateVolumeGroupsForEachZone(carAudioZones);
         validateEachAddressAppearsAtMostOnce(carAudioZones);
+        validatePrimaryZoneHasInputDevice(carAudioZones);
+    }
+
+    private static void validatePrimaryZoneHasInputDevice(SparseArray<CarAudioZone> carAudioZones) {
+        CarAudioZone primaryZone = carAudioZones.get(PRIMARY_AUDIO_ZONE);
+        List<AudioDeviceAttributes> devices = primaryZone.getInputAudioDevices();
+        Preconditions.checkCollectionNotEmpty(devices, "Primary Zone Input Devices");
+        for (int index = 0; index < devices.size(); index++) {
+            AudioDeviceAttributes device = devices.get(index);
+            if (device.getType() == TYPE_BUILTIN_MIC) {
+                return;
+            }
+        }
+        throw new RuntimeException("Primary Zone must have at least one microphone input device");
     }
 
     private static void validateAtLeastOneZoneDefined(SparseArray<CarAudioZone> carAudioZones) {
diff --git a/service/src/com/android/car/garagemode/Controller.java b/service/src/com/android/car/garagemode/Controller.java
index 81c8c10..fdf0c05 100644
--- a/service/src/com/android/car/garagemode/Controller.java
+++ b/service/src/com/android/car/garagemode/Controller.java
@@ -16,6 +16,8 @@
 
 package com.android.car.garagemode;
 
+import static com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.app.job.JobScheduler;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
@@ -28,6 +30,7 @@
 
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
+import com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.utils.Slogf;
@@ -116,6 +119,7 @@
     /**
      * Prints Garage Mode's status, including what jobs it is waiting for
      */
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     void dump(PrintWriter writer) {
         mGarageMode.dump(writer);
     }
diff --git a/service/src/com/android/car/garagemode/GarageMode.java b/service/src/com/android/car/garagemode/GarageMode.java
index f315dca..5936391 100644
--- a/service/src/com/android/car/garagemode/GarageMode.java
+++ b/service/src/com/android/car/garagemode/GarageMode.java
@@ -16,6 +16,8 @@
 
 package com.android.car.garagemode;
 
+import static com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
+
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
 import android.app.job.JobSnapshot;
@@ -30,6 +32,7 @@
 import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.CarStatsLogHelper;
+import com.android.car.internal.testing.ExcludeFromCodeCoverageGeneratedReport;
 import com.android.car.power.CarPowerManagementService;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
@@ -242,6 +245,7 @@
         }
     }
 
+    @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
     void dump(PrintWriter writer) {
         if (!mGarageModeActive) {
             return;
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index 5de5a81..726f34f 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -39,6 +39,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -86,8 +87,8 @@
     public static final int NO_AREA = -1;
     public static final float NO_SAMPLE_RATE = -1;
 
-    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
-            VehicleHal.class.getSimpleName());
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
     private final PowerHalService mPowerHal;
     private final PropertyHalService mPropertyHal;
     private final InputHalService mInputHal;
@@ -124,6 +125,9 @@
      * both passed as parameters.
      */
     public VehicleHal(Context context, IVehicle vehicle) {
+        mHandlerThread = CarServiceUtils.getHandlerThread(
+                VehicleHal.class.getSimpleName());
+        mHandler = new Handler(mHandlerThread.getLooper());
         mPowerHal = new PowerHalService(this);
         mPropertyHal = new PropertyHalService(this);
         mInputHal = new InputHalService(this);
@@ -156,7 +160,10 @@
             UserHalService userHal,
             DiagnosticHalService diagnosticHal,
             ClusterHalService clusterHalService,
-            HalClient halClient) {
+            HalClient halClient,
+            HandlerThread handlerThread) {
+        mHandlerThread = handlerThread;
+        mHandler = new Handler(mHandlerThread.getLooper());
         mPowerHal = powerHal;
         mPropertyHal = propertyHal;
         mInputHal = inputHal;
@@ -581,6 +588,7 @@
 
     private final ArraySet<HalServiceBase> mServicesToDispatch = new ArraySet<>();
 
+    // should be posted to the mHandlerThread
     @Override
     public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
         synchronized (mLock) {
@@ -614,6 +622,7 @@
         // No need to handle on-property-set events in HAL service yet.
     }
 
+    // should be posted to the mHandlerThread
     @Override
     public void onPropertySetError(@CarPropertyManager.CarSetPropertyErrorCode int errorCode,
             int propId, int areaId) {
@@ -800,7 +809,7 @@
         }
         // update timestamp
         v.timestamp = SystemClock.elapsedRealtimeNanos() + TimeUnit.SECONDS.toNanos(delayTime);
-        onPropertyEvent(Lists.newArrayList(v));
+        mHandler.post(() -> onPropertyEvent(Lists.newArrayList(v)));
     }
 
     /**
@@ -838,7 +847,7 @@
                     // Avoid the fake events be covered by real Event
                     v.timestamp = SystemClock.elapsedRealtimeNanos()
                             + TimeUnit.SECONDS.toNanos(timeDurationInSec);
-                    onPropertyEvent(Lists.newArrayList(v));
+                    mHandler.post(() -> onPropertyEvent(Lists.newArrayList(v)));
                 }
             }
         }, /* delay= */0, period);
diff --git a/service/src/com/android/car/telemetry/databroker/DataBroker.java b/service/src/com/android/car/telemetry/databroker/DataBroker.java
index 44f2f61..f22a8ca 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBroker.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBroker.java
@@ -22,6 +22,18 @@
 public interface DataBroker {
 
     /**
+     * Interface for receiving notification that script finished.
+     */
+    interface ScriptFinishedCallback {
+        /**
+         * Listens to script finished event.
+         *
+         * @param configName the name of the config whose script finished.
+         */
+        void onScriptFinished(String configName);
+    }
+
+    /**
      * Adds an active {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} that is pending
      * execution. When updating the MetricsConfig to a newer version, the caller must call
      * {@link #removeMetricsConfiguration(TelemetryProto.MetricsConfig)} first to clear the old
@@ -29,29 +41,42 @@
      * TODO(b/191378559): Define behavior when metricsConfig contains invalid config
      *
      * @param metricsConfig to be added and queued for execution.
-     * @return true for success, false for failure.
      */
-    boolean addMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
+    void addMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
 
     /**
      * Removes a {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} and all its
      * relevant subscriptions.
      *
      * @param metricsConfig to be removed from DataBroker.
-     * @return true for success, false for failure.
      */
-    boolean removeMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
+    void removeMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
+
+    /**
+     * Adds a {@link ScriptExecutionTask} to the priority queue. This method will schedule the
+     * next task if a task is not currently running.
+     * This method can be called from any thread, and it is thread-safe.
+     */
+    void addTaskToQueue(ScriptExecutionTask task);
+
+    /**
+     * Sends a message to the handler to poll and execute a task.
+     * This method is thread-safe.
+     */
+    void scheduleNextTask();
 
     /**
      * Sets callback for notifying script finished.
      *
      * @param callback script finished callback.
      */
-    void setOnScriptFinishedCallback(DataBrokerController.ScriptFinishedCallback callback);
+    void setOnScriptFinishedCallback(ScriptFinishedCallback callback);
 
     /**
-     * Invoked by controller to indicate system health state and which subscribers can be consumed.
-     * A smaller priority number indicates higher priority. Range 1 - 100.
+     * Sets the priority which affects which subscribers can consume data. Invoked by controller to
+     * indicate system health state and which subscribers can be consumed. If controller does not
+     * set the priority, it will be defaulted to 1. A smaller priority number indicates higher
+     * priority. Range 1 - 100.
      */
     void setTaskExecutionPriority(int priority);
 }
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
index 7663667..a5fa1cb 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
@@ -34,18 +34,6 @@
     private final DataBroker mDataBroker;
     private final SystemMonitor mSystemMonitor;
 
-    /**
-     * Interface for receiving notification that script finished.
-     */
-    public interface ScriptFinishedCallback {
-        /**
-         * Listens to script finished event.
-         *
-         * @param configName the name of the config whose script finished.
-         */
-        void onScriptFinished(String configName);
-    }
-
     public DataBrokerController(DataBroker dataBroker, SystemMonitor systemMonitor) {
         mDataBroker = dataBroker;
         mDataBroker.setOnScriptFinishedCallback(this::onScriptFinished);
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
index 86d725e..7ac7cf8 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -16,55 +16,106 @@
 
 package com.android.car.telemetry.databroker;
 
+import android.car.telemetry.IScriptExecutorListener;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
 import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
+import com.android.car.telemetry.CarTelemetryService;
 import com.android.car.telemetry.TelemetryProto;
 import com.android.car.telemetry.TelemetryProto.MetricsConfig;
 import com.android.car.telemetry.publisher.AbstractPublisher;
 import com.android.car.telemetry.publisher.PublisherFactory;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Implementation of the data path component of CarTelemetryService. Forwards the published data
  * from publishers to consumers subject to the Controller's decision.
+ * TODO(b/187743369): Handle thread-safety of member variables.
  */
 public class DataBrokerImpl implements DataBroker {
 
-    // Maps MetricsConfig's name to its subscriptions. This map is useful when removing a
-    // MetricsConfig.
-    private final Map<String, List<DataSubscriber>> mSubscriptionMap = new ArrayMap<>();
+    @VisibleForTesting
+    static final int MSG_HANDLE_TASK = 1;
 
-    private DataBrokerController.ScriptFinishedCallback mScriptFinishedCallback;
+    private final Object mLock = new Object();
+    private final HandlerThread mWorkerThread = CarServiceUtils.getHandlerThread(
+            CarTelemetryService.class.getSimpleName());
+    private final Handler mWorkerHandler = new TaskHandler(mWorkerThread.getLooper());
+
+    /** Thread-safe int to determine which data can be processed. */
+    private final AtomicInteger mPriority = new AtomicInteger(1);
+
+    /**
+     * Thread-safe boolean to indicate whether a script is running, which can prevent DataBroker
+     * from making multiple ScriptExecutor binder calls.
+     * TODO(b/187743369): replace flag with current script name
+     */
+    private final AtomicBoolean mTaskRunning = new AtomicBoolean(false);
+
+    /** Thread-safe priority queue for scheduling tasks. */
+    private final PriorityBlockingQueue<ScriptExecutionTask> mTaskQueue =
+            new PriorityBlockingQueue<>();
+
+    /**
+     * Maps MetricsConfig's name to its subscriptions. This map is useful when removing a
+     * MetricsConfig.
+     */
+    @GuardedBy("mLock")
+    private final Map<String, List<DataSubscriber>> mSubscriptionMap = new ArrayMap<>();
     private final PublisherFactory mPublisherFactory;
+    private ScriptFinishedCallback mScriptFinishedCallback;
 
     public DataBrokerImpl(PublisherFactory publisherFactory) {
         mPublisherFactory = publisherFactory;
     }
 
-    // current task priority, used to determine which data can be processed
-    private int mTaskExecutionPriority;
-
     @Override
-    public boolean addMetricsConfiguration(MetricsConfig metricsConfig) {
-        // if metricsConfig already exists, it should not be added again
-        if (mSubscriptionMap.containsKey(metricsConfig.getName())) {
-            return false;
+    public void addMetricsConfiguration(MetricsConfig metricsConfig) {
+        // TODO(b/187743369): pass status back to caller
+        mWorkerHandler.post(() -> addMetricsConfigurationOnHandlerThread(metricsConfig));
+    }
+
+    private void addMetricsConfigurationOnHandlerThread(MetricsConfig metricsConfig) {
+        // this method can only be called from the thread that the handler is running at
+        if (Looper.myLooper() != mWorkerHandler.getLooper()) {
+            throw new RuntimeException(
+                    "addMetricsConfigurationOnHandlerThread is not called from handler thread");
+        }
+        synchronized (mLock) {
+            // if metricsConfig already exists, it should not be added again
+            if (mSubscriptionMap.containsKey(metricsConfig.getName())) {
+                return;
+            }
         }
         // Create the subscribers for this metrics configuration
-        List<DataSubscriber> dataSubscribers = new ArrayList<>();
+        List<DataSubscriber> dataSubscribers = new ArrayList<>(
+                metricsConfig.getSubscribersList().size());
         for (TelemetryProto.Subscriber subscriber : metricsConfig.getSubscribersList()) {
             // protobuf publisher to a concrete Publisher
             AbstractPublisher publisher = mPublisherFactory.getPublisher(
                     subscriber.getPublisher().getPublisherCase());
-
             // create DataSubscriber from TelemetryProto.Subscriber
-            DataSubscriber dataSubscriber = new DataSubscriber(metricsConfig, subscriber);
+            DataSubscriber dataSubscriber = new DataSubscriber(
+                    this,
+                    metricsConfig,
+                    subscriber,
+                    /* priority= */ 1); // TODO(b/187743369): remove hardcoded priority
             dataSubscribers.add(dataSubscriber);
 
             try {
@@ -73,20 +124,36 @@
                 publisher.addDataSubscriber(dataSubscriber);
             } catch (IllegalArgumentException e) {
                 Slog.w(CarLog.TAG_TELEMETRY, "Invalid config", e);
-                return false;
+                return;
             }
         }
-        mSubscriptionMap.put(metricsConfig.getName(), dataSubscribers);
-        return true;
+        synchronized (mLock) {
+            mSubscriptionMap.put(metricsConfig.getName(), dataSubscribers);
+        }
     }
 
     @Override
-    public boolean removeMetricsConfiguration(MetricsConfig metricsConfig) {
-        if (!mSubscriptionMap.containsKey(metricsConfig.getName())) {
-            return false;
+    public void removeMetricsConfiguration(MetricsConfig metricsConfig) {
+        // TODO(b/187743369): pass status back to caller
+        mWorkerHandler.post(() -> removeMetricsConfigurationOnHandlerThread(metricsConfig));
+    }
+
+    private void removeMetricsConfigurationOnHandlerThread(MetricsConfig metricsConfig) {
+        // this method can only be called from the thread that the handler is running at
+        if (Looper.myLooper() != mWorkerHandler.getLooper()) {
+            throw new RuntimeException(
+                    "removeMetricsConfigurationOnHandlerThread is not called from handler thread");
+        }
+        synchronized (mLock) {
+            if (!mSubscriptionMap.containsKey(metricsConfig.getName())) {
+                return;
+            }
         }
         // get the subscriptions associated with this MetricsConfig, remove it from the map
-        List<DataSubscriber> dataSubscribers = mSubscriptionMap.remove(metricsConfig.getName());
+        List<DataSubscriber> dataSubscribers;
+        synchronized (mLock) {
+            dataSubscribers = mSubscriptionMap.remove(metricsConfig.getName());
+        }
         // for each subscriber, remove it from publishers
         for (DataSubscriber subscriber : dataSubscribers) {
             AbstractPublisher publisher = mPublisherFactory.getPublisher(
@@ -97,23 +164,161 @@
                 // It shouldn't happen, but if happens, let's just log it.
                 Slog.w(CarLog.TAG_TELEMETRY, "Failed to remove subscriber from publisher", e);
             }
-            // TODO(b/187743369): remove related tasks from the queue
         }
-        return true;
+        // Remove all the tasks associated with this metrics config. The underlying impl uses the
+        // weakly consistent iterator, which is thread-safe but does not freeze the collection while
+        // iterating, so it may or may not reflect any updates since the iterator was created.
+        // But since adding & polling from queue should happen in the same thread, the task queue
+        // should not be changed while tasks are being iterated and removed.
+        mTaskQueue.removeIf(task -> task.isAssociatedWithMetricsConfig(metricsConfig));
     }
 
     @Override
-    public void setOnScriptFinishedCallback(DataBrokerController.ScriptFinishedCallback callback) {
+    public void addTaskToQueue(ScriptExecutionTask task) {
+        mTaskQueue.add(task);
+        scheduleNextTask();
+    }
+
+    /**
+     * This method can be called from any thread. It is thread-safe because atomic values and the
+     * blocking queue are thread-safe. It is possible for this method to be invoked from different
+     * threads at the same time, but it is not possible to schedule the same task twice, because
+     * the handler handles message in the order they come in, this means the task will be polled
+     * sequentially instead of concurrently. Every task that is scheduled and run will be distinct.
+     * TODO(b/187743369): If the threading behavior in DataSubscriber changes, ScriptExecutionTask
+     *                    will also have different threading behavior. Update javadoc when the
+     *                    behavior is decided.
+     */
+    @Override
+    public void scheduleNextTask() {
+        if (mTaskRunning.get() || mTaskQueue.peek() == null) {
+            return;
+        }
+        mWorkerHandler.sendMessage(mWorkerHandler.obtainMessage(MSG_HANDLE_TASK));
+    }
+
+    @Override
+    public void setOnScriptFinishedCallback(ScriptFinishedCallback callback) {
+        // TODO(b/187743369): move the interface on databroker surface and pass it in constructor
         mScriptFinishedCallback = callback;
     }
 
     @Override
     public void setTaskExecutionPriority(int priority) {
-        mTaskExecutionPriority = priority;
+        mPriority.set(priority);
+        scheduleNextTask(); // when priority updates, schedule a task which checks task queue
     }
 
     @VisibleForTesting
     Map<String, List<DataSubscriber>> getSubscriptionMap() {
-        return mSubscriptionMap;
+        synchronized (mLock) {
+            return new ArrayMap<>((ArrayMap<String, List<DataSubscriber>>) mSubscriptionMap);
+        }
+    }
+
+    @VisibleForTesting
+    Handler getWorkerHandler() {
+        return mWorkerHandler;
+    }
+
+    @VisibleForTesting
+    PriorityBlockingQueue<ScriptExecutionTask> getTaskQueue() {
+        return mTaskQueue;
+    }
+
+    /**
+     * Polls and runs a task from the head of the priority queue if the queue is nonempty and the
+     * head of the queue has priority higher than or equal to the current priority. A higher
+     * priority is denoted by a lower priority number, so head of the queue should have equal or
+     * lower priority number to be polled.
+     */
+    private void pollAndExecuteTask() {
+        // this method can only be called from the thread that the handler is running at
+        if (Looper.myLooper() != mWorkerHandler.getLooper()) {
+            throw new RuntimeException("pollAndExecuteTask is not called from handler thread");
+        }
+        // atomic boolean, atomic int, blocking queue, and the task are thread-safe.
+        if (mTaskRunning.get()
+                || mTaskQueue.peek() == null
+                || mTaskQueue.peek().getPriority() > mPriority.get()) {
+            return;
+        }
+        ScriptExecutionTask task = mTaskQueue.poll();
+        if (task == null) {
+            return;
+        }
+        mTaskRunning.set(true); // signal the start of script execution
+        // TODO(b/187743369): scriptExecutor.invokeScript(...);
+    }
+
+    /**
+     * Signals the end of script execution and schedules the next task. This method is thread-safe.
+     */
+    private void scriptExecutionFinished() {
+        mTaskRunning.set(false);
+        scheduleNextTask();
+    }
+
+    /** Listens for script execution status. Methods are called on the binder thread. */
+    private static final class ScriptExecutorListener extends IScriptExecutorListener.Stub {
+        private final WeakReference<DataBrokerImpl> mWeakDataBroker;
+
+        private ScriptExecutorListener(DataBrokerImpl dataBroker) {
+            mWeakDataBroker = new WeakReference<>(dataBroker);
+        }
+
+        @Override
+        public void onScriptFinished(byte[] result) {
+            DataBrokerImpl dataBroker = mWeakDataBroker.get();
+            if (dataBroker == null) {
+                return;
+            }
+            dataBroker.scriptExecutionFinished();
+            // TODO(b/187743369): implement update config store and push results
+        }
+
+        @Override
+        public void onSuccess(Bundle stateToPersist) {
+            DataBrokerImpl dataBroker = mWeakDataBroker.get();
+            if (dataBroker == null) {
+                return;
+            }
+            dataBroker.scriptExecutionFinished();
+            // TODO(b/187743369): implement persist states
+        }
+
+        @Override
+        public void onError(int errorType, String message, String stackTrace) {
+            DataBrokerImpl dataBroker = mWeakDataBroker.get();
+            if (dataBroker == null) {
+                return;
+            }
+            dataBroker.scriptExecutionFinished();
+            // TODO(b/187743369): implement push errors
+        }
+    }
+
+    /** Callback handler to handle scheduling and rescheduling of {@link ScriptExecutionTask}s. */
+    class TaskHandler extends Handler {
+        TaskHandler(Looper looper) {
+            super(looper);
+        }
+
+        /**
+         * Handles a message by polling a task from the priority queue and executing a
+         * {@link ScriptExecutionTask}. There are multiple places where a message is sent: when
+         * priority updates, when a new task is added to the priority queue, and when a task
+         * finishes running.
+         */
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_HANDLE_TASK:
+                    pollAndExecuteTask(); // run the next task
+                    break;
+                default:
+                    Slog.w(CarLog.TAG_TELEMETRY, "TaskHandler received unknown message.");
+            }
+        }
     }
 }
diff --git a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
index 0c713c5..4650309 100644
--- a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
+++ b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
@@ -17,18 +17,34 @@
 package com.android.car.telemetry.databroker;
 
 import android.os.Bundle;
+import android.os.SystemClock;
 
 import com.android.car.telemetry.TelemetryProto;
 
 /**
- * Subscriber class that receive published data and schedules tasks for execution on the data.
+ * Subscriber class that receives published data and schedules tasks for execution.
+ * The class is thread-safe as long as
+ * {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} does not change during runtime.
+ * TODO(b/187743369): thread-safety can change if priority can be updated in runtime. Update
+ *                    javadoc once priority is concretely defined.
+ *                    Must be thread-safe, as #push() method may be called by multiple threads.
  */
 public class DataSubscriber {
+
+    private final int mPriority;
+    private final DataBroker mDataBroker;
+    private final TelemetryProto.MetricsConfig mMetricsConfig;
     private final TelemetryProto.Subscriber mSubscriber;
 
-    public DataSubscriber(TelemetryProto.MetricsConfig metricsConfig,
-            TelemetryProto.Subscriber subscriber) {
+    public DataSubscriber(
+            DataBroker dataBroker,
+            TelemetryProto.MetricsConfig metricsConfig,
+            TelemetryProto.Subscriber subscriber,
+            int priority) {
+        mDataBroker = dataBroker;
+        mMetricsConfig = metricsConfig;
         mSubscriber = subscriber;
+        mPriority = priority;
     }
 
     /**
@@ -39,8 +55,25 @@
         return mSubscriber.getPublisher();
     }
 
-    /** Pushes data to the subscriber. */
+    /**
+     * Creates a {@link ScriptExecutionTask} and pushes it to the priority queue where the task
+     * will be pending execution.
+     *
+     * <p>This method is thread-safe and doesn't block.
+     */
     public void push(Bundle data) {
-        // TODO(b/187743369): implement
+        ScriptExecutionTask task = new ScriptExecutionTask(
+                this, data, SystemClock.elapsedRealtime());
+        mDataBroker.addTaskToQueue(task); // thread-safe
+    }
+
+    /** Returns the {@link com.android.car.telemetry.TelemetryProto.MetricsConfig}. */
+    public TelemetryProto.MetricsConfig getMetricsConfig() {
+        return mMetricsConfig;
+    }
+
+    /** Returns the priority of subscriber. */
+    public int getPriority() {
+        return mPriority;
     }
 }
diff --git a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
new file mode 100644
index 0000000..91b17eb
--- /dev/null
+++ b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.android.car.telemetry.databroker;
+
+import android.os.Bundle;
+
+import com.android.car.telemetry.TelemetryProto;
+
+/**
+ * A wrapper class containing all the necessary information to invoke the ScriptExecutor API. It
+ * is enqueued into the priority queue where it pends execution by {@link DataBroker}.
+ * It implements the {@link Comparable} interface so it has a natural ordering by priority and
+ * creation timestamp in the priority queue.
+ * The object can be accessed from any thread. See {@link DataSubscriber} for thread-safety.
+ */
+public class ScriptExecutionTask implements Comparable<ScriptExecutionTask> {
+    private final long mTimestampMillis;
+    private final DataSubscriber mSubscriber;
+
+    ScriptExecutionTask(DataSubscriber subscriber, Bundle data, long elapsedRealtimeMillis) {
+        mTimestampMillis = elapsedRealtimeMillis;
+        mSubscriber = subscriber;
+    }
+
+    /** Returns the priority of the task. */
+    public int getPriority() {
+        return mSubscriber.getPriority();
+    }
+
+    /** Returns the creation timestamp of the task. */
+    public long getCreationTimestampMillis() {
+        return mTimestampMillis;
+    }
+
+    /**
+     * Indicates whether the task is associated with the given
+     * {@link com.android.car.telemetry.TelemetryProto.MetricsConfig).
+     */
+    public boolean isAssociatedWithMetricsConfig(TelemetryProto.MetricsConfig metricsConfig) {
+        return mSubscriber.getMetricsConfig().equals(metricsConfig);
+    }
+
+    @Override
+    public int compareTo(ScriptExecutionTask other) {
+        if (getPriority() < other.getPriority()) {
+            return -1;
+        } else if (getPriority() > other.getPriority()) {
+            return 1;
+        }
+        // if equal priority, compare creation timestamps
+        if (getCreationTimestampMillis() < other.getCreationTimestampMillis()) {
+            return -1;
+        }
+        return 1;
+    }
+}
diff --git a/service/src/com/android/car/telemetry/proto/telemetry.proto b/service/src/com/android/car/telemetry/proto/telemetry.proto
index 5787d62..870a00e 100644
--- a/service/src/com/android/car/telemetry/proto/telemetry.proto
+++ b/service/src/com/android/car/telemetry/proto/telemetry.proto
@@ -38,8 +38,8 @@
   optional int32 version = 2;
 
   // Required.
-  // A script that is executed in devices. Must contain all the handler functions
-  // defined in the listeners below.
+  // A script that is executed at the device side. Must contain all the handler
+  // functions defined in the listeners below.
   // The script functions must be `pure` functions.
   optional string script = 3;
 
@@ -60,19 +60,33 @@
   optional float read_rate = 2;
 }
 
+// Parameters for cartelemetryd publisher.
+// See packages/services/Car/cpp/telemetry for CarData proto and docs.
+message CarTelemetrydPublisher {
+  // Required.
+  // CarData id to subscribe to.
+  // See packages/services/Car/cpp/telemetry/proto/CarData.proto for all the
+  // messages and IDs.
+  optional int32 id = 1;
+}
+
 // Specifies data publisher and its parameters.
 message Publisher {
   oneof publisher {
     VehiclePropertyPublisher vehicle_property = 1;
+    CarTelemetrydPublisher cartelemetryd = 2;
   }
 }
 
 // Specifies publisher with its parameters and the handler function that's invoked
 // when data is received. The format of the data depends on the Publisher.
 message Subscriber {
-  // Name of the script function that's invoked when this subscriber is triggered.
+  // Required.
+  // Name of the function that handles the published data. Must be defined
+  // in the script.
   optional string handler = 1;
 
-  // Publisher and its parameters.
+  // Required.
+  // Publisher definition.
   optional Publisher publisher = 2;
 }
diff --git a/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java b/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
index f58a6fa..65bcbe9 100644
--- a/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
@@ -18,10 +18,6 @@
 
 import com.android.car.telemetry.databroker.DataSubscriber;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-
 /**
  * Abstract class for publishers. It is 1-1 with data source and manages sending data to
  * subscribers. Publisher stops itself when there are no subscribers.
@@ -30,54 +26,29 @@
  * configuration. Single publisher instance can send data as several
  * {@link com.android.car.telemetry.TelemetryProto.Publisher} to subscribers.
  *
- * <p>Not thread-safe.
+ * <p>Child classes must be thread-safe.
  */
 public abstract class AbstractPublisher {
-    private final HashSet<DataSubscriber> mDataSubscribers = new HashSet<>();
-
     /**
      * Adds a subscriber that listens for data produced by this publisher.
      *
      * @param subscriber a subscriber to receive data
-     * @throws IllegalArgumentException if an invalid subscriber was provided.
+     * @throws IllegalArgumentException if the subscriber is invalid.
      */
-    public void addDataSubscriber(DataSubscriber subscriber) {
-        // This method can throw exceptions if data is invalid - do now swap these 2 lines.
-        onDataSubscriberAdded(subscriber);
-        mDataSubscribers.add(subscriber);
-    }
+    public abstract void addDataSubscriber(DataSubscriber subscriber);
 
     /**
      * Removes the subscriber from the publisher. Publisher stops if necessary.
      *
      * @throws IllegalArgumentException if the subscriber was not found.
      */
-    public void removeDataSubscriber(DataSubscriber subscriber) {
-        if (!mDataSubscribers.remove(subscriber)) {
-            throw new IllegalArgumentException("Failed to remove, subscriber not found");
-        }
-        onDataSubscribersRemoved(Collections.singletonList(subscriber));
-    }
+    public abstract void removeDataSubscriber(DataSubscriber subscriber);
 
     /**
      * Removes all the subscribers from the publisher. The publisher may stop.
      */
-    public void removeAllDataSubscribers() {
-        onDataSubscribersRemoved(mDataSubscribers);
-        mDataSubscribers.clear();
-    }
+    public abstract void removeAllDataSubscribers();
 
-    /**
-     * Called when a new subscriber is added to the publisher.
-     *
-     * @throws IllegalArgumentException if the invalid subscriber was provided.
-     */
-    protected abstract void onDataSubscriberAdded(DataSubscriber subscriber);
-
-    /** Called when subscribers are removed from the publisher. */
-    protected abstract void onDataSubscribersRemoved(Collection<DataSubscriber> subscribers);
-
-    protected HashSet<DataSubscriber> getDataSubscribers() {
-        return mDataSubscribers;
-    }
+    /** Returns true if the publisher already has this data subscriber. */
+    public abstract boolean hasDataSubscriber(DataSubscriber subscriber);
 }
diff --git a/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
new file mode 100644
index 0000000..5fc1489
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
@@ -0,0 +1,168 @@
+/*
+ * 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 com.android.car.telemetry.publisher;
+
+import android.annotation.Nullable;
+import android.automotive.telemetry.internal.CarDataInternal;
+import android.automotive.telemetry.internal.ICarDataListener;
+import android.automotive.telemetry.internal.ICarTelemetryInternal;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.car.CarLog;
+import com.android.car.telemetry.TelemetryProto;
+import com.android.car.telemetry.databroker.DataSubscriber;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.utils.Slogf;
+
+import java.util.ArrayList;
+
+/**
+ * Publisher for cartelemtryd service (aka ICarTelemetry).
+ *
+ * <p>When a subscriber is added, the publisher binds to ICarTelemetryInternal and starts listening
+ * for incoming CarData. The matching CarData will be pushed to the subscriber. It unbinds itself
+ * from ICarTelemetryInternal if there are no subscribers.
+ *
+ * <p>See {@code packages/services/Car/cpp/telemetry/cartelemetryd} to learn more about the service.
+ */
+public class CarTelemetrydPublisher extends AbstractPublisher {
+    private static final boolean DEBUG = false;  // STOPSHIP if true
+    private static final String SERVICE_NAME = ICarTelemetryInternal.DESCRIPTOR + "/default";
+    private static final int BINDER_FLAGS = 0;
+
+    private final Object mLock = new Object();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private ICarTelemetryInternal mCarTelemetryInternal;
+
+    @GuardedBy("mLock")
+    private final ArrayList<DataSubscriber> mSubscribers = new ArrayList<>();
+
+    private final ICarDataListener mListener = new ICarDataListener.Stub() {
+        @Override
+        public void onCarDataReceived(CarDataInternal[] dataList) throws RemoteException {
+            if (DEBUG) {
+                Slog.d(CarLog.TAG_TELEMETRY,
+                        "Received " + dataList.length + " CarData from cartelemetryd");
+            }
+            onCarDataListReceived(dataList);
+        }
+    };
+
+    /** Called when binder for ICarTelemetry service is died. */
+    void onBinderDied() {
+        synchronized (mLock) {
+            if (mCarTelemetryInternal != null) {
+                mCarTelemetryInternal.asBinder().unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+            }
+            // TODO(b/193680465): try reconnecting again
+            mCarTelemetryInternal = null;
+        }
+    }
+
+    /**
+     * Returns true if connected, false if not connected.
+     *
+     * @throws IllegalStateException if it cannot connect to ICarTelemetryInternal service.
+     */
+    @GuardedBy("mLock")
+    private void connectToCarTelemetrydLocked() {
+        if (mCarTelemetryInternal != null) {
+            return;  // already connected
+        }
+        IBinder binder = ServiceManager.checkService(SERVICE_NAME);
+        if (binder == null) {
+            throw new IllegalStateException(
+                    "Failed to connect to ICarTelemetryInternal: service is not ready");
+        }
+        try {
+            binder.linkToDeath(this::onBinderDied, BINDER_FLAGS);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to connect to ICarTelemetryInternal: linkToDeath failed", e);
+        }
+        mCarTelemetryInternal = ICarTelemetryInternal.Stub.asInterface(binder);
+        try {
+            mCarTelemetryInternal.setListener(mListener);
+        } catch (RemoteException e) {
+            binder.unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+            mCarTelemetryInternal = null;
+            throw new IllegalStateException(
+                    "Failed to connect to ICarTelemetryInternal: Cannot set CarData listener",
+                    e);
+        }
+    }
+
+    @VisibleForTesting
+    boolean isConnectedToCarTelemetryd() {
+        synchronized (mLock) {
+            return mCarTelemetryInternal != null;
+        }
+    }
+
+    @Override
+    public void addDataSubscriber(DataSubscriber subscriber) {
+        TelemetryProto.Publisher publisherParam = subscriber.getPublisherParam();
+        Preconditions.checkArgument(
+                publisherParam.getPublisherCase()
+                        == TelemetryProto.Publisher.PublisherCase.CARTELEMETRYD,
+                "Subscribers only with CarTelemetryd publisher are supported by this class.");
+        int carDataId = publisherParam.getCartelemetryd().getId();
+
+        synchronized (mLock) {
+            try {
+                connectToCarTelemetrydLocked();
+            } catch (IllegalStateException e) {
+                Slog.e(CarLog.TAG_TELEMETRY, "Failed to connect to ICarTelemetry", e);
+                // TODO(b/193680465): add retry reconnecting
+            }
+            mSubscribers.add(subscriber);
+        }
+
+        Slogf.d(CarLog.TAG_TELEMETRY, "Subscribing to CarDat.id=%d", carDataId);
+    }
+
+    @Override
+    public void removeDataSubscriber(DataSubscriber subscriber) {
+        // TODO(b/189142577): implement and disconnect from cartelemetryd if necessary
+    }
+
+    @Override
+    public void removeAllDataSubscribers() {
+        // TODO(b/189142577): implement and disconnect from cartelemetryd
+    }
+
+    @Override
+    public boolean hasDataSubscriber(DataSubscriber subscriber) {
+        synchronized (mLock) {
+            return mSubscribers.contains(subscriber);
+        }
+    }
+
+    /**
+     * Called when publisher receives new car data list. It's executed on a Binder thread.
+     */
+    private void onCarDataListReceived(CarDataInternal[] dataList) {
+        // TODO(b/189142577): implement
+    }
+}
diff --git a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
index ed0b19b..34edceb 100644
--- a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
@@ -22,22 +22,27 @@
 import android.car.hardware.property.ICarPropertyEventListener;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.car.CarLog;
 import com.android.car.CarPropertyService;
 import com.android.car.telemetry.TelemetryProto;
+import com.android.car.telemetry.TelemetryProto.Publisher.PublisherCase;
 import com.android.car.telemetry.databroker.DataSubscriber;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
-import java.util.Collection;
 import java.util.List;
 
 /**
  * Publisher for Vehicle Property changes, aka {@code CarPropertyService}.
  *
- * <p>TODO(b/187525360): Add car property listener logic
+ * <p> When a subscriber is added, it registers a car property change listener for the
+ * property id of the subscriber and starts pushing the change events to the subscriber.
+ *
+ * <p>Thread-safe.
  */
 public class VehiclePropertyPublisher extends AbstractPublisher {
     private static final boolean DEBUG = false;  // STOPSHIP if true
@@ -45,9 +50,20 @@
     /** Bundle key for {@link CarPropertyEvent}. */
     public static final String CAR_PROPERTY_EVENT_KEY = "car_property_event";
 
+    // Used to synchronize add/remove DataSubscriber and CarPropertyEvent listener calls.
+    private final Object mLock = new Object();
+
     private final CarPropertyService mCarPropertyService;
+
+    // The class only reads, no need to synchronize this object.
     private final SparseArray<CarPropertyConfig> mCarPropertyList;
 
+    // SparseArray and ArraySet are memory optimized, but they can be bit slower for more
+    // than 100 items. We're expecting much less number of subscribers, so these DS are ok.
+    @GuardedBy("mLock")
+    private final SparseArray<ArraySet<DataSubscriber>> mCarPropertyToSubscribers =
+            new SparseArray<>();
+
     private final ICarPropertyEventListener mCarPropertyEventListener =
             new ICarPropertyEventListener.Stub() {
                 @Override
@@ -65,14 +81,15 @@
     public VehiclePropertyPublisher(CarPropertyService carPropertyService) {
         mCarPropertyService = carPropertyService;
         // Load car property list once, as the list doesn't change runtime.
-        mCarPropertyList = new SparseArray<>();
-        for (CarPropertyConfig property : mCarPropertyService.getPropertyList()) {
+        List<CarPropertyConfig> propertyList = mCarPropertyService.getPropertyList();
+        mCarPropertyList = new SparseArray<>(propertyList.size());
+        for (CarPropertyConfig property : propertyList) {
             mCarPropertyList.append(property.getPropertyId(), property);
         }
     }
 
     @Override
-    protected void onDataSubscriberAdded(DataSubscriber subscriber) {
+    public void addDataSubscriber(DataSubscriber subscriber) {
         TelemetryProto.Publisher publisherParam = subscriber.getPublisherParam();
         Preconditions.checkArgument(
                 publisherParam.getPublisherCase()
@@ -88,31 +105,86 @@
                         || config.getAccess()
                         == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
                 "No access. Cannot read " + VehiclePropertyIds.toString(propertyId) + ".");
-        mCarPropertyService.registerListener(
-                propertyId,
-                publisherParam.getVehicleProperty().getReadRate(),
-                mCarPropertyEventListener);
+
+        synchronized (mLock) {
+            ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
+            if (subscribers == null) {
+                subscribers = new ArraySet<>();
+                mCarPropertyToSubscribers.put(propertyId, subscribers);
+                // Register the listener only once per propertyId.
+                mCarPropertyService.registerListener(
+                        propertyId,
+                        publisherParam.getVehicleProperty().getReadRate(),
+                        mCarPropertyEventListener);
+            }
+            subscribers.add(subscriber);
+        }
     }
 
     @Override
-    protected void onDataSubscribersRemoved(Collection<DataSubscriber> subscribers) {
-        // TODO(b/190230611): Remove car property listener
+    public void removeDataSubscriber(DataSubscriber subscriber) {
+        TelemetryProto.Publisher publisherParam = subscriber.getPublisherParam();
+        Preconditions.checkArgument(
+                publisherParam.getPublisherCase() == PublisherCase.VEHICLE_PROPERTY,
+                "Subscribers only with VehicleProperty publisher are supported by this class.");
+        int propertyId = publisherParam.getVehicleProperty().getVehiclePropertyId();
+
+        synchronized (mLock) {
+            ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
+            if (subscribers == null || !subscribers.remove(subscriber)) {
+                throw new IllegalArgumentException("DataSubscriber was not found");
+            }
+            if (subscribers.isEmpty()) {
+                mCarPropertyToSubscribers.remove(propertyId);
+                // Doesn't throw exception as listener is not null. mCarPropertyService and
+                // local mCarPropertyToSubscribers will not get out of sync.
+                mCarPropertyService.unregisterListener(propertyId, mCarPropertyEventListener);
+            }
+        }
+    }
+
+    @Override
+    public void removeAllDataSubscribers() {
+        synchronized (mLock) {
+            for (int i = 0; i < mCarPropertyToSubscribers.size(); i++) {
+                int propertyId = mCarPropertyToSubscribers.keyAt(i);
+                // Doesn't throw exception as listener is not null. mCarPropertyService and
+                // local mCarPropertyToSubscribers will not get out of sync.
+                mCarPropertyService.unregisterListener(propertyId, mCarPropertyEventListener);
+            }
+            mCarPropertyToSubscribers.clear();
+        }
+    }
+
+    @Override
+    public boolean hasDataSubscriber(DataSubscriber subscriber) {
+        TelemetryProto.Publisher publisherParam = subscriber.getPublisherParam();
+        if (publisherParam.getPublisherCase() != PublisherCase.VEHICLE_PROPERTY) {
+            return false;
+        }
+        int propertyId = publisherParam.getVehicleProperty().getVehiclePropertyId();
+
+        synchronized (mLock) {
+            ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
+            return subscribers != null && subscribers.contains(subscriber);
+        }
     }
 
     /**
-     * Called when publisher receives new events. It's called on CarPropertyService's worker
-     * thread.
+     * Called when publisher receives new event. It's executed on a CarPropertyService's
+     * worker thread.
      */
     private void onVehicleEvent(CarPropertyEvent event) {
         Bundle bundle = new Bundle();
         bundle.putParcelable(CAR_PROPERTY_EVENT_KEY, event);
-        for (DataSubscriber subscriber : getDataSubscribers()) {
-            TelemetryProto.Publisher publisherParam = subscriber.getPublisherParam();
-            if (event.getCarPropertyValue().getPropertyId()
-                    != publisherParam.getVehicleProperty().getVehiclePropertyId()) {
-                continue;
+
+        synchronized (mLock) {
+            ArraySet<DataSubscriber> subscribers =
+                    mCarPropertyToSubscribers.get(event.getCarPropertyValue().getPropertyId());
+            // DataSubscriber#push() doesn't block.
+            for (DataSubscriber subscriber : subscribers) {
+                subscriber.push(bundle);
             }
-            subscriber.push(bundle);
         }
     }
 }
diff --git a/service/src/com/android/car/user/AppLifecycleListener.java b/service/src/com/android/car/user/AppLifecycleListener.java
new file mode 100644
index 0000000..153ca85
--- /dev/null
+++ b/service/src/com/android/car/user/AppLifecycleListener.java
@@ -0,0 +1,77 @@
+/*
+ * 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 com.android.car.user;
+
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+
+import com.android.car.CarLog;
+import com.android.internal.os.IResultReceiver;
+import com.android.server.utils.Slogf;
+
+import java.io.PrintWriter;
+
+/**
+ * Helper DTO to hold info about an app-based {@code UserLifecycleListener}
+ */
+final class AppLifecycleListener {
+
+    private static final String TAG = CarLog.tagFor(AppLifecycleListener.class);
+
+    private final DeathRecipient mDeathRecipient;
+
+    public final int uid;
+    public final String packageName;
+    public final IResultReceiver receiver;
+
+    AppLifecycleListener(int uid, String packageName, IResultReceiver receiver,
+            BinderDeathCallback binderDeathCallback) {
+        this.uid = uid;
+        this.packageName = packageName;
+        this.receiver = receiver;
+
+        mDeathRecipient = () -> binderDeathCallback.onBinderDeath(this);
+        Slogf.v(TAG, "linking death recipient %s", mDeathRecipient);
+        try {
+            receiver.asBinder().linkToDeath(mDeathRecipient, /* flags= */ 0);
+        } catch (RemoteException e) {
+            Slogf.wtf(TAG, "Cannot listen to death of %s", mDeathRecipient);
+        }
+    }
+
+    void onDestroy() {
+        Slogf.v(TAG, "onDestroy(): unlinking death recipient %s", mDeathRecipient);
+        receiver.asBinder().unlinkToDeath(mDeathRecipient, /* flags= */ 0);
+    }
+
+    void dump(PrintWriter writer) {
+        writer.printf("uid=%d, pkg=%s\n", uid, packageName);
+    }
+
+    String toShortString() {
+        return uid + "-" + packageName;
+    }
+
+    @Override
+    public String toString() {
+        return "AppLifecycleListener[uid=" + uid + ", pkg=" + packageName + "]";
+    }
+
+    interface BinderDeathCallback {
+        void onBinderDeath(AppLifecycleListener listener);
+    }
+}
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 1fde509..00cb893 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -77,6 +77,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.Trace;
@@ -85,11 +86,11 @@
 import android.provider.Settings;
 import android.sysprop.CarProperties;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.TimingsTraceLog;
 import android.view.Display;
@@ -195,16 +196,19 @@
     private final Handler mHandler;
 
     /**
-     * List of listeners to be notified on new user activities events.
-     * This collection should be accessed and manipulated by mHandlerThread only.
+     * Internal listeners to be notified on new user activities events.
+     *
+     * <p>This collection should be accessed and manipulated by {@code mHandlerThread} only.
      */
     private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
 
     /**
-     * List of lifecycle listeners by uid.
-     * This collection should be accessed and manipulated by mHandlerThread only.
+     * App listeners to be notified on new user activities events.
+     *
+     * <p>This collection should be accessed and manipulated by {@code mHandlerThread} only.
      */
-    private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
+    private final ArrayMap<IBinder, AppLifecycleListener> mAppLifecycleListeners =
+            new ArrayMap<>();
 
     /**
      * User Id for the user switch in process, if any.
@@ -359,8 +363,7 @@
         checkHasDumpPermissionGranted("dump()");
 
         writer.println("*CarUserService*");
-        String indent = "  ";
-        handleDumpListeners(writer, indent);
+        handleDumpListeners(writer);
         writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
         synchronized (mLockUser) {
             writer.println("User0Unlocked: " + mUser0Unlocked);
@@ -380,9 +383,10 @@
         List<UserInfo> allDrivers = getAllDrivers();
         int driversSize = allDrivers.size();
         writer.println("NumberOfDrivers: " + driversSize);
+        writer.increaseIndent();
         for (int i = 0; i < driversSize; i++) {
             int driverId = allDrivers.get(i).id;
-            writer.print(indent + "#" + i + ": id=" + driverId);
+            writer.printf("#%d: id=%d", i, driverId);
             List<UserInfo> passengers = getPassengers(driverId);
             int passengersSize = passengers.size();
             writer.print(" NumberPassengers: " + passengersSize);
@@ -398,38 +402,42 @@
             }
             writer.println();
         }
+        writer.decreaseIndent();
         writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
         writer.printf("User HAL timeout: %dms\n",  mHalTimeoutMs);
         writer.printf("Initial user: %s\n", mInitialUser);
 
         writer.println("Relevant overlayable properties");
         Resources res = mContext.getResources();
-        writer.printf("%sowner_name=%s\n", indent,
-                res.getString(com.android.internal.R.string.owner_name));
-        writer.printf("%sdefault_guest_name=%s\n", indent,
-                res.getString(R.string.default_guest_name));
+        writer.increaseIndent();
+        writer.printf("owner_name=%s\n", res.getString(com.android.internal.R.string.owner_name));
+        writer.printf("default_guest_name=%s\n", res.getString(R.string.default_guest_name));
+        writer.decreaseIndent();
         writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
         writer.printf("Request Id for the user switch in process=%d\n ",
                     mRequestIdForUserSwitchInProcess);
         writer.printf("System UI package name=%s\n", getSystemUiPackageName());
 
         writer.println("Relevant Global settings");
-        dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
-        dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
+        writer.increaseIndent();
+        dumpGlobalProperty(writer, CarSettings.Global.LAST_ACTIVE_USER_ID);
+        dumpGlobalProperty(writer, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
+        writer.decreaseIndent();
 
         mInitialUserSetter.dump(writer);
     }
 
-    private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
+    private void dumpGlobalProperty(IndentingPrintWriter writer, String property) {
         String value = Settings.Global.getString(mContext.getContentResolver(), property);
-        writer.printf("%s%s=%s\n", indent, property, value);
+        writer.printf("%s=%s\n", property, value);
     }
 
-    private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
+    private void handleDumpListeners(IndentingPrintWriter writer) {
+        writer.increaseIndent();
         CountDownLatch latch = new CountDownLatch(1);
         mHandler.post(() -> {
             handleDumpServiceLifecycleListeners(writer);
-            handleDumpAppLifecycleListeners(writer, indent);
+            handleDumpAppLifecycleListeners(writer);
             latch.countDown();
         });
         int timeout = 5;
@@ -442,9 +450,10 @@
             Thread.currentThread().interrupt();
             writer.println("Interrupted waiting for handler thread to dump app and user listeners");
         }
+        writer.decreaseIndent();
     }
 
-    private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
+    private void handleDumpServiceLifecycleListeners(PrintWriter writer) {
         if (mUserLifecycleListeners.isEmpty()) {
             writer.println("No lifecycle listeners for internal services");
             return;
@@ -452,24 +461,24 @@
         int size = mUserLifecycleListeners.size();
         writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
         String indent = "  ";
-        for (UserLifecycleListener listener : mUserLifecycleListeners) {
+        for (int i = 0; i < size; i++) {
+            UserLifecycleListener listener = mUserLifecycleListeners.get(i);
             writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
         }
     }
 
-    private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
+    private void handleDumpAppLifecycleListeners(IndentingPrintWriter writer) {
         int size = mAppLifecycleListeners.size();
         if (size == 0) {
             writer.println("No lifecycle listeners for apps");
             return;
         }
-        writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
+        writer.printf("%d lifecycle listener%s for apps\n", size, size == 1 ? "" : "s");
+        writer.increaseIndent();
         for (int i = 0; i < size; i++) {
-            int uid = mAppLifecycleListeners.keyAt(i);
-            IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
-            writer.printf("%suid: %d listener: %s\n", indent, uid,
-                    FunctionalUtils.getLambdaName(listener));
+            mAppLifecycleListeners.valueAt(i).dump(writer);
         }
+        writer.decreaseIndent();
     }
 
     /**
@@ -684,30 +693,45 @@
     }
 
     @Override
-    public void setLifecycleListenerForUid(IResultReceiver listener) {
+    public void setLifecycleListenerForApp(String packageName, IResultReceiver receiver) {
         int uid = Binder.getCallingUid();
-        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
-        checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid, packageName);
+        checkInteractAcrossUsersPermission("setLifecycleListenerForApp-" + uid + "-" + packageName);
 
-        try {
-            listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
-        } catch (RemoteException e) {
-            Slog.wtf(TAG, "Cannot listen to death of " + uid);
-        }
-        mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
+        IBinder receiverBinder = receiver.asBinder();
+        AppLifecycleListener listener = new AppLifecycleListener(uid, packageName, receiver,
+                (l) -> onListenerDeath(l));
+        Slogf.d(TAG, "Adding %s (using binder %s)", listener, receiverBinder);
+        mHandler.post(() -> mAppLifecycleListeners.put(receiverBinder, listener));
     }
 
-    private void onListenerDeath(int uid) {
-        Slog.i(TAG, "Removing listeners for uid " + uid + " on binder death");
-        mHandler.post(() -> mAppLifecycleListeners.remove(uid));
+    private void onListenerDeath(AppLifecycleListener listener) {
+        Slogf.i(TAG, "Removing listener %s on binder death", listener);
+        mHandler.post(() -> mAppLifecycleListeners.remove(listener.receiver.asBinder()));
     }
 
     @Override
-    public void resetLifecycleListenerForUid() {
+    public void resetLifecycleListenerForApp(IResultReceiver receiver) {
         int uid = Binder.getCallingUid();
-        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
-        checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
-        mHandler.post(() -> mAppLifecycleListeners.remove(uid));
+        checkInteractAcrossUsersPermission("resetLifecycleListenerForApp-" + uid);
+        IBinder receiverBinder = receiver.asBinder();
+        mHandler.post(() -> {
+            AppLifecycleListener listener = mAppLifecycleListeners.get(receiverBinder);
+            if (listener == null) {
+                Slogf.e(TAG, "resetLifecycleListenerForApp(uid=%d): no listener for receiver", uid);
+                return;
+            }
+            if (listener.uid != uid) {
+                Slogf.e(TAG, "resetLifecycleListenerForApp(): uid mismatch (called by %d) for "
+                        + "listener %s", uid, listener);
+            }
+            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid,
+                    listener.packageName);
+            Slogf.d(TAG, "Removing %s (using binder %s)", listener, receiverBinder);
+            mAppLifecycleListeners.remove(receiverBinder);
+
+            listener.onDestroy();
+        });
     }
 
     /**
@@ -2102,23 +2126,17 @@
     private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
         int listenersSize = mAppLifecycleListeners.size();
         if (listenersSize == 0) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Slog.d(TAG, "No app listener to be notified of " + event);
-            }
+            Slogf.d(TAG, "No app listener to be notified of %s", event);
             return;
         }
         // Must use a different TimingsTraceLog because it's another thread
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Slog.d(TAG, "Notifying " + listenersSize + " app listeners of " + event);
-        }
+        Slogf.d(TAG, "Notifying %d app listeners of %s", listenersSize, event);
         int userId = event.getUserId();
         TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
         int eventType = event.getEventType();
         t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
         for (int i = 0; i < listenersSize; i++) {
-            int uid = mAppLifecycleListeners.keyAt(i);
-
-            IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
+            AppLifecycleListener listener = mAppLifecycleListeners.valueAt(i);
             Bundle data = new Bundle();
             data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
 
@@ -2126,17 +2144,14 @@
             if (fromUserId != UserHandle.USER_NULL) {
                 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
             }
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Slog.d(TAG, "Notifying listener for uid " + uid);
-            }
+            Slogf.d(TAG, "Notifying listener %s", listener);
             EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
-                    uid, eventType, fromUserId, userId);
+                    listener.uid, listener.packageName, eventType, fromUserId, userId);
             try {
-                t.traceBegin("notify-app-listener-uid-" + uid);
-                listener.send(userId, data);
+                t.traceBegin("notify-app-listener-" + listener.toShortString());
+                listener.receiver.send(userId, data);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Error calling lifecycle listener", e);
+                Slogf.e(TAG, e, "Error calling lifecycle listener %s", listener);
             } finally {
                 t.traceEnd();
             }
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index fccaa8b..4bbb40a 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -326,6 +326,14 @@
         return mWatchdogPerfHandler.getResourceOveruseConfigurations(resourceOveruseFlag);
     }
 
+    /**
+     * Enables/disables the watchdog daemon client health check process.
+     */
+    public void controlProcessHealthCheck(boolean disable) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
+        mWatchdogProcessHandler.controlProcessHealthCheck(disable);
+    }
+
     private void postRegisterToDaemonMessage() {
         CarServiceUtils.runOnMain(() -> {
             synchronized (mLock) {
diff --git a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
index cce3d15..c935f0a 100644
--- a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
@@ -240,6 +240,16 @@
         }
     }
 
+    /** Enables/disables the watchdog daemon client health check process. */
+    void controlProcessHealthCheck(boolean disable) {
+        try {
+            mCarWatchdogDaemonHelper.controlProcessHealthCheck(disable);
+        } catch (RemoteException e) {
+            Slogf.w(CarWatchdogService.TAG,
+                    "Cannot enable/disable the car watchdog daemon health check process: %s", e);
+        }
+    }
+
     private void onClientDeath(ICarWatchdogServiceCallback client, int timeout) {
         synchronized (mLock) {
             removeClientLocked(client.asBinder(), timeout);
diff --git a/tests/AdasLocationTestApp/Android.bp b/tests/AdasLocationTestApp/Android.bp
new file mode 100644
index 0000000..cc52ec7
--- /dev/null
+++ b/tests/AdasLocationTestApp/Android.bp
@@ -0,0 +1,51 @@
+// 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: "AdasLocationTestApp",
+
+    srcs: ["src/**/*.java"],
+
+    resource_dirs: ["res"],
+
+    platform_apis: true,
+
+    optimize: {
+        enabled: false,
+    },
+
+    enforce_uses_libs: false,
+    dex_preopt: {
+        enabled: false,
+    },
+
+    required: ["allowed_privapp_com.google.android.car.adaslocation"],
+
+    privileged: true,
+
+    certificate: "platform",
+
+    static_libs: [
+            "com.google.android.material_material",
+            "androidx.appcompat_appcompat",
+    ],
+
+    libs: ["android.car"],
+}
\ No newline at end of file
diff --git a/tests/AdasLocationTestApp/AndroidManifest.xml b/tests/AdasLocationTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..6dcd183
--- /dev/null
+++ b/tests/AdasLocationTestApp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ 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.google.android.car.adaslocation"
+          android:sharedUserId="android.uid.system">
+
+    <!-- The app needs to access device location to verify ADAS and main location switch work as
+    expected. -->
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+
+    <application android:label="AdasLocationTestApp">
+        <activity android:name=".AdasLocationActivity"
+                  android:theme="@style/Theme.AppCompat"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/AdasLocationTestApp/res/layout/main_activity.xml b/tests/AdasLocationTestApp/res/layout/main_activity.xml
new file mode 100644
index 0000000..0173cd6
--- /dev/null
+++ b/tests/AdasLocationTestApp/res/layout/main_activity.xml
@@ -0,0 +1,102 @@
+<?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.
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:app="http://schemas.android.com/apk/res-auto"
+                android:layout_width="fill_parent"
+                android:layout_height="match_parent"
+                android:orientation="vertical">
+    <TextView
+        android:id="@+id/main_location_enabled"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="100dp"
+        android:textStyle="bold"
+        android:text="main location enabled: "/>
+    <TextView
+        android:id="@+id/main_location_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/main_location_enabled"
+        android:layout_marginTop="100dp"
+        android:textStyle="bold"/>
+    <TextView
+        android:id="@+id/adas_location_enabled"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_below="@id/main_location_enabled"
+        android:textStyle="bold"
+        android:text="adas location enabled: "/>
+    <TextView
+        android:id="@+id/adas_location_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/main_location_status"
+        android:layout_toRightOf="@id/adas_location_enabled"
+        android:textStyle="bold"/>
+    <TextView
+        android:id="@+id/current_location"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/current_location"
+        android:layout_alignParentLeft="true"
+        android:layout_marginLeft="350dp"
+        android:layout_marginTop= "200dp"
+        android:textStyle="bold"/>
+    <TextView
+        android:id="@+id/current_location_result"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/current_location"
+        android:layout_alignParentLeft="true"
+        android:layout_marginLeft="350dp"
+        android:textStyle="bold"/>
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+        android:id="@+id/observe_fab"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/current_location_result"
+        android:layout_alignParentLeft="true"
+        app:useCompatPadding="true"
+        android:layout_marginLeft="350dp"/>
+    <TextView
+        android:id="@+id/last_location"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/last_location"
+        android:layout_alignParentRight="true"
+        android:layout_marginRight="350dp"
+        android:layout_marginTop= "200dp"
+        android:textStyle="bold"/>
+    <TextView
+        android:id="@+id/last_location_result"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/last_location"
+        android:layout_alignParentRight="true"
+        android:layout_marginRight="350dp"
+        android:textStyle="bold"/>
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+        android:id="@+id/query_fab"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/last_location_result"
+        android:layout_alignParentRight="true"
+        app:useCompatPadding="true"
+        android:layout_marginRight="350dp"/>
+</RelativeLayout>
diff --git a/tests/AdasLocationTestApp/res/values/strings.xml b/tests/AdasLocationTestApp/res/values/strings.xml
new file mode 100644
index 0000000..3b97648
--- /dev/null
+++ b/tests/AdasLocationTestApp/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ 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.
+  -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="last_location" translatable="false">Last Location</string>
+    <string name="current_location" translatable="false">Current Location</string>
+    <string name="no_last_location" translatable="false">no last location</string>
+    <string name="waiting_for_location" translatable="false">waiting for location</string>
+</resources>
\ No newline at end of file
diff --git a/tests/AdasLocationTestApp/src/com/google/android/car/adaslocation/AdasLocationActivity.java b/tests/AdasLocationTestApp/src/com/google/android/car/adaslocation/AdasLocationActivity.java
new file mode 100644
index 0000000..bcb29f1
--- /dev/null
+++ b/tests/AdasLocationTestApp/src/com/google/android/car/adaslocation/AdasLocationActivity.java
@@ -0,0 +1,195 @@
+/*
+ * 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 com.google.android.car.adaslocation;
+
+import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public final class AdasLocationActivity extends AppCompatActivity {
+    private static final int KS_PERMISSIONS_REQUEST = 1;
+
+    private static final String[] REQUIRED_PERMISSIONS = new String[]{
+            Manifest.permission.ACCESS_FINE_LOCATION,
+            Manifest.permission.ACCESS_COARSE_LOCATION,
+    };
+
+    private boolean mIsRegister;
+    private LocationManager mLocationManager;
+    private FloatingActionButton mObserveFab;
+    private TextView mObserveLocationResult;
+    private LocationListener mLocationListener;
+    private FloatingActionButton mQueryFab;
+    private TextView mLastLocationResult;
+    private TextView mMainLocationEnabled;
+    private TextView mAdasLocationEnabled;
+    private BroadcastReceiver mReceiver;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main_activity);
+
+        mLocationManager = getApplicationContext().getSystemService(LocationManager.class);
+        mObserveFab = findViewById(R.id.observe_fab);
+        mObserveLocationResult = findViewById(R.id.current_location_result);
+        mLocationListener = new LocationListener() {
+            @Override
+            public void onLocationChanged(Location location) {
+                mObserveLocationResult.setText(locationToFormattedString(location));
+            }
+
+            @Override
+            public void onProviderEnabled(String provider) {
+            }
+
+            @Override
+            public void onProviderDisabled(String provider) {
+            }
+        };
+        mObserveFab.setOnClickListener(
+                v -> {
+                    if (!mIsRegister) {
+                        startListening();
+                    } else {
+                        stopListening();
+                    }
+                }
+        );
+        mQueryFab = findViewById(R.id.query_fab);
+        mLastLocationResult = findViewById(R.id.last_location_result);
+        mQueryFab.setOnClickListener(
+                v -> {
+                    Location location = mLocationManager
+                            .getLastKnownLocation(LocationManager.GPS_PROVIDER);
+                    if (location != null) {
+                        mLastLocationResult.setText(locationToFormattedString(location));
+                    } else {
+                        mLastLocationResult.setText(R.string.no_last_location);
+                    }
+                }
+        );
+
+        mReceiver =
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (LocationManager.MODE_CHANGED_ACTION == intent.getAction()) {
+                            mMainLocationEnabled.setText(Boolean.toString(mLocationManager
+                                    .isLocationEnabled()));
+                            return;
+                        }
+                        if (LocationManager.ACTION_ADAS_GNSS_ENABLED_CHANGED
+                                == intent.getAction()) {
+                            mAdasLocationEnabled
+                                    .setText(Boolean.toString(mLocationManager
+                                            .isAdasGnssLocationEnabled()));
+                            return;
+                        }
+                    }
+                };
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        initPermissions();
+
+        mMainLocationEnabled = findViewById(R.id.main_location_status);
+        mMainLocationEnabled.setText(Boolean.toString(mLocationManager.isLocationEnabled()));
+        mAdasLocationEnabled = findViewById(R.id.adas_location_status);
+        mAdasLocationEnabled.setText(Boolean.toString(mLocationManager
+                .isAdasGnssLocationEnabled()));
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
+        intentFilter.addAction(LocationManager.ACTION_ADAS_GNSS_ENABLED_CHANGED);
+        registerReceiver(mReceiver, intentFilter);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        Set<String> missingPermissions = checkExistingPermissions();
+        if (!missingPermissions.isEmpty()) {
+            return;
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (mIsRegister) {
+            stopListening();
+        }
+        mLastLocationResult.setText("");
+    }
+
+    private static String locationToFormattedString(Location location) {
+        return String.format("Location: lat=%10.6f, lon=%10.6f ",
+                location.getLatitude(),
+                location.getLongitude());
+    }
+
+    private void initPermissions() {
+        Set<String> missingPermissions = checkExistingPermissions();
+        if (!missingPermissions.isEmpty()) {
+            requestPermissions(missingPermissions);
+        }
+    }
+
+    private Set<String> checkExistingPermissions() {
+        return Arrays.stream(REQUIRED_PERMISSIONS).filter(permission -> ActivityCompat
+                .checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED)
+                .collect(Collectors.toSet());
+    }
+
+    private void requestPermissions(Set<String> permissions) {
+        requestPermissions(permissions.toArray(new String[permissions.size()]),
+                KS_PERMISSIONS_REQUEST);
+    }
+
+    private void startListening() {
+        mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
+                0, 0, mLocationListener);
+        mObserveLocationResult.setText(R.string.waiting_for_location);
+        mIsRegister = true;
+    }
+
+    private void stopListening() {
+        mLocationManager.removeUpdates(mLocationListener);
+        mObserveLocationResult.setText("");
+        mIsRegister = false;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
index 4493806..f8d19d6 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
@@ -66,25 +66,26 @@
         }
         if (mVolumeList[position] != null) {
             vh.id.setText(mVolumeList[position].id);
-            vh.maxVolume.setText(String.valueOf(mVolumeList[position].maxGain));
             vh.currentVolume.setText(String.valueOf(mVolumeList[position].currentGain));
             int color = mVolumeList[position].hasAudioFocus ? Color.GREEN : Color.GRAY;
             vh.requestButton.setBackgroundColor(color);
             if (position == 0) {
+                vh.maxVolume.setText("Max");
                 vh.upButton.setVisibility(View.INVISIBLE);
                 vh.downButton.setVisibility(View.INVISIBLE);
                 vh.requestButton.setVisibility(View.INVISIBLE);
                 vh.muteButton.setVisibility(View.INVISIBLE);
             } else {
+                vh.maxVolume.setText(String.valueOf(mVolumeList[position].maxGain));
                 vh.upButton.setVisibility(View.VISIBLE);
                 vh.downButton.setVisibility(View.VISIBLE);
                 vh.requestButton.setVisibility(View.VISIBLE);
                 vh.muteButton.setVisibility(mGroupMuteEnabled ? View.VISIBLE : View.INVISIBLE);
                 vh.upButton.setOnClickListener((view) -> {
-                    mFragment.adjustVolumeByOne(mVolumeList[position].groupId, true);
+                    mFragment.adjustVolumeUp(mVolumeList[position].groupId);
                 });
                 vh.downButton.setOnClickListener((view) -> {
-                    mFragment.adjustVolumeByOne(mVolumeList[position].groupId, false);
+                    mFragment.adjustVolumeDown(mVolumeList[position].groupId);
                 });
                 vh.muteButton.setChecked(mVolumeList[position].isMuted);
                 vh.muteButton.setOnClickListener((view) -> {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
index 675f495..2419511 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
@@ -52,7 +52,10 @@
     private static final int MSG_REQUEST_FOCUS = 1;
     private static final int MSG_FOCUS_CHANGED = 2;
     private static final int MSG_STOP_RINGTONE = 3;
+    private static final int MSG_ADJUST_VOLUME = 4;
     private static final long RINGTONE_STOP_TIME_MS = 3_000;
+    private static final int ADJUST_VOLUME_UP = 0;
+    private static final int ADJUST_VOLUME_DOWN = 1;
 
     private final int mZoneId;
     private final Object mLock = new Object();
@@ -68,10 +71,19 @@
     @GuardedBy("mLock")
     private Ringtone mRingtone;
 
-    public void sendVolumeChangedMessage(int groupId, int flags) {
+    void sendVolumeChangedMessage(int groupId, int flags) {
         mHandler.sendMessage(mHandler.obtainMessage(MSG_VOLUME_CHANGED, groupId, flags));
     }
 
+    void adjustVolumeUp(int groupId) {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_ADJUST_VOLUME, groupId, ADJUST_VOLUME_UP));
+    }
+
+    void adjustVolumeDown(int groupId) {
+        mHandler.sendMessage(mHandler
+                .obtainMessage(MSG_ADJUST_VOLUME, groupId, ADJUST_VOLUME_DOWN));
+    }
+
     private class VolumeHandler extends Handler {
         private AudioFocusListener mFocusListener;
 
@@ -105,10 +117,12 @@
                     mVolumeInfos[mGroupIdIndexMap.get(focusGroupId)].hasAudioFocus = true;
                     mCarAudioZoneVolumeAdapter.refreshVolumes(mVolumeInfos);
                     break;
-                default :
-                    Log.wtf(TAG,"VolumeHandler handleMessage called with unknown message"
+                case MSG_ADJUST_VOLUME:
+                    adjustVolumeByOne(msg.arg1, msg.arg2 == ADJUST_VOLUME_UP);
+                    break;
+                default:
+                    Log.wtf(TAG, "VolumeHandler handleMessage called with unknown message"
                             + msg.what);
-
             }
         }
     }
@@ -144,7 +158,6 @@
         CarAudioZoneVolumeInfo titlesInfo = new CarAudioZoneVolumeInfo();
         titlesInfo.id = "Group id";
         titlesInfo.currentGain = "Current";
-        titlesInfo.maxGain = "Max";
         mVolumeInfos[0] = titlesInfo;
 
         int i = 1;
@@ -155,13 +168,14 @@
             volumeInfo.id = String.valueOf(groupId);
             int current = mCarAudioManager.getGroupVolume(mZoneId, groupId);
             int max = mCarAudioManager.getGroupMaxVolume(mZoneId, groupId);
+            int min = mCarAudioManager.getGroupMinVolume(mZoneId, groupId);
             volumeInfo.currentGain = String.valueOf(current);
-            volumeInfo.maxGain = String.valueOf(max);
+            volumeInfo.maxGain = max;
+            volumeInfo.minGain = min;
             volumeInfo.isMuted = mCarAudioManager.isVolumeGroupMuted(mZoneId, groupId);
 
             mVolumeInfos[i] = volumeInfo;
-            if (DEBUG)
-            {
+            if (DEBUG) {
                 Log.d(TAG, groupId + " max: " + volumeInfo.maxGain + " current: "
                         + volumeInfo.currentGain + " is muted " + volumeInfo.isMuted);
             }
@@ -170,18 +184,38 @@
         mCarAudioZoneVolumeAdapter.refreshVolumes(mVolumeInfos);
     }
 
-    public void adjustVolumeByOne(int groupId, boolean up) {
+    private void adjustVolumeByOne(int groupId, boolean up) {
         if (mCarAudioManager == null) {
             Log.e(TAG, "CarAudioManager is null");
             return;
         }
         int current = mCarAudioManager.getGroupVolume(mZoneId, groupId);
-        int volume = current + (up ? 1 : -1);
-        mCarAudioManager.setGroupVolume(mZoneId, groupId, volume, AudioManager.FLAG_SHOW_UI);
-        if (DEBUG) {
-            Log.d(TAG, "Set group " + groupId + " volume " + volume + " in audio zone "
-                    + mZoneId);
+        CarAudioZoneVolumeInfo info = getVolumeInfo(groupId);
+        int volume = up ? current + 1 : current - 1;
+        if (volume > info.maxGain) {
+            if (DEBUG) {
+                Log.d(TAG, "Reached " + groupId + " max volume "
+                        + " limit " + volume);
+            }
+            return;
         }
+        if (volume < info.minGain) {
+            if (DEBUG) {
+                Log.d(TAG, "Reached " + groupId + " min volume "
+                        + " limit " + volume);
+            }
+            return;
+        }
+        mCarAudioManager.setGroupVolume(mZoneId, groupId, volume, /* flags= */ 0);
+        if (DEBUG) {
+            Log.d(TAG, "Set group " + groupId + " volume "
+                    + mCarAudioManager.getGroupVolume(mZoneId, groupId)
+                    + " in audio zone " + mZoneId);
+        }
+    }
+
+    private CarAudioZoneVolumeInfo getVolumeInfo(int groupId) {
+        return mVolumeInfos[mGroupIdIndexMap.get(groupId)];
     }
 
     public void toggleMute(int groupId) {
@@ -197,7 +231,7 @@
         }
     }
 
-    public void requestFocus(int groupId) {
+    void requestFocus(int groupId) {
         // Automatic volume change only works for primary audio zone.
         if (mZoneId == CarAudioManager.PRIMARY_AUDIO_ZONE) {
             mHandler.sendMessage(mHandler
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
index 2a2c38e..821d362 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
@@ -62,7 +62,8 @@
     public static final class CarAudioZoneVolumeInfo {
         public int groupId;
         public String id;
-        public String maxGain;
+        public int maxGain;
+        public int minGain;
         public String currentGain;
         public boolean hasAudioFocus;
         public boolean isMuted;
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java
index 33bc54a..36a300e 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/watchdog/CarWatchdogTestFragment.java
@@ -73,6 +73,7 @@
     private static final long TEN_MEGABYTES = 1024 * 1024 * 10;
     private static final int DISK_DELAY_MS = 3000;
     private static final String TAG = "CarWatchdogTestFragment";
+    private static final double WARN_THRESHOLD_PERCENT = 0.8;
     private static final double EXCEED_WARN_THRESHOLD_PERCENT = 0.9;
 
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@@ -133,13 +134,23 @@
                                         return;
                                     }
 
+                                    /*
+                                     * CarService notifies applications on exceeding 80% of the
+                                     * threshold. The app maybe notified before completing the
+                                     * following write. Ergo, the minimum expected written bytes
+                                     * should be the warn threshold rather than the actual amount
+                                     * of bytes written by the app.
+                                     */
+                                    long bytesToWarnThreshold = (long) Math.ceil(
+                                            (remainingBytes + TEN_MEGABYTES)
+                                                    * WARN_THRESHOLD_PERCENT);
+
+                                    listener.setExpectedMinWrittenBytes(bytesToWarnThreshold);
+
                                     long bytesToExceedWarnThreshold =
                                             (long) Math.ceil(remainingBytes
                                                     * EXCEED_WARN_THRESHOLD_PERCENT);
 
-                                    listener.setExpectedMinWrittenBytes(
-                                            TEN_MEGABYTES + bytesToExceedWarnThreshold);
-
                                     if (!writeToDisk(bytesToExceedWarnThreshold)) {
                                         mCarWatchdogManager.removeResourceOveruseListener(listener);
                                         return;
diff --git a/tests/UserSwitchMonitorApp/Android.bp b/tests/UserSwitchMonitorApp/Android.bp
index 9aa39a9..b5f29eb 100644
--- a/tests/UserSwitchMonitorApp/Android.bp
+++ b/tests/UserSwitchMonitorApp/Android.bp
@@ -27,3 +27,18 @@
 
     sdk_version: "system_current",
 }
+
+// "Cloned" app used to make sure events are received by apps with shared uid
+android_app {
+    name: "UserSwitchMonitorApp2",
+
+    manifest: "AndroidManifest2.xml",
+
+    libs: [
+        "android.car-system-stubs",
+    ],
+
+    srcs: ["src/**/*.java"],
+
+    sdk_version: "system_current",
+}
diff --git a/tests/UserSwitchMonitorApp/AndroidManifest.xml b/tests/UserSwitchMonitorApp/AndroidManifest.xml
index e78d690..fec167a 100644
--- a/tests/UserSwitchMonitorApp/AndroidManifest.xml
+++ b/tests/UserSwitchMonitorApp/AndroidManifest.xml
@@ -16,15 +16,17 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.google.android.car.userswitchmonitor">
+    package="com.google.android.car.userswitchmonitor"
+    android:sharedUserId="com.google.android.car.userswitchmonitor">
 
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
 
-    <application android:label="User Switch Monitor">
-        <service android:name=".UserSwitchMonitorService"/>
-        <receiver android:name=".BootCompletedReceiver" android:exported="true">
+    <application android:icon="@drawable/ic_launcher" android:label="User Switch Monitor">
+        <service android:name="com.google.android.car.userswitchmonitor.UserSwitchMonitorService"/>
+        <receiver android:name="com.google.android.car.userswitchmonitor.BootCompletedReceiver"
+                  android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
             </intent-filter>
diff --git a/tests/UserSwitchMonitorApp/AndroidManifest2.xml b/tests/UserSwitchMonitorApp/AndroidManifest2.xml
new file mode 100644
index 0000000..bb38752
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/AndroidManifest2.xml
@@ -0,0 +1,36 @@
+<?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
+  -->
+
+<!-- "Cloned" app used to make sure events are received by apps with shared uid -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.car.userswitchmonitor2"
+    android:sharedUserId="com.google.android.car.userswitchmonitor">
+
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+
+    <application android:icon="@drawable/ic_launcher" android:label="User Switch Monitor">
+        <service android:name="com.google.android.car.userswitchmonitor.UserSwitchMonitorService"/>
+        <receiver android:name="com.google.android.car.userswitchmonitor.BootCompletedReceiver"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
index f76b0d6..73c5cc4 100644
--- a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
+++ b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
@@ -41,6 +41,10 @@
 
     static final String TAG = "UserSwitchMonitor";
 
+    private static final String CMD_HELP = "help";
+    private static final String CMD_REGISTER = "register";
+    private static final String CMD_UNREGISTER = "unregister";
+
     private final Object mLock = new Object();
 
     private final int mUserId = android.os.Process.myUserHandle().getIdentifier();
@@ -64,11 +68,16 @@
         mContext = getApplicationContext();
         mCar = Car.createCar(mContext);
         mCarUserManager = (CarUserManager) mCar.getCarManager(Car.CAR_USER_SERVICE);
-        mCarUserManager.addListener((r)-> r.run(), mListener);
+        registerListener();
 
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
     }
 
+    private void registerListener() {
+        Log.d(TAG, "registerListener(): " + mListener);
+        mCarUserManager.addListener((r)-> r.run(), mListener);
+    }
+
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         Log.d(TAG, "onStartCommand(" + mUserId + "): " + intent);
@@ -79,11 +88,13 @@
                 NotificationManager.IMPORTANCE_MIN);
         mNotificationManager.createNotificationChannel(channel);
 
+        // Cannot use R.drawable because package name is different on app2
+        int iconResId = mContext.getApplicationInfo().icon;
         startForeground(startId,
                 new Notification.Builder(mContext, channelId)
                         .setContentText(name)
                         .setContentTitle(name)
-                        .setSmallIcon(R.drawable.ic_launcher)
+                        .setSmallIcon(iconResId)
                         .build());
 
         return super.onStartCommand(intent, flags, startId);
@@ -93,19 +104,29 @@
     public void onDestroy() {
         Log.d(TAG, "onDestroy(" + mUserId + ")");
 
-        if (mCarUserManager != null) {
-            mCarUserManager.removeListener(mListener);
-        } else {
-            Log.w(TAG, "Cannot remove listener because manager is null");
-        }
+        unregisterListener();
         if (mCar != null && mCar.isConnected()) {
             mCar.disconnect();
         }
         super.onDestroy();
     }
 
+    private void unregisterListener() {
+        Log.d(TAG, "unregisterListener(): " + mListener);
+        if (mCarUserManager != null) {
+            mCarUserManager.removeListener(mListener);
+        } else {
+            Log.w(TAG, "Cannot remove listener because manager is null");
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (args != null && args.length > 0) {
+            executeCommand(pw, args);
+            return;
+        }
+
         pw.printf("User id: %d\n", mUserId);
         synchronized (mLock) {
             if (mEvents.isEmpty()) {
@@ -127,4 +148,48 @@
         return null;
     }
 
+    private void executeCommand(PrintWriter pw, String[] args) {
+        String cmd = args[0];
+        switch (cmd) {
+            case CMD_HELP:
+                cmdHelp(pw);
+                break;
+            case CMD_REGISTER:
+                cmdRegister(pw);
+                break;
+            case CMD_UNREGISTER:
+                cmdUnregister(pw);
+                break;
+            default:
+                pw.printf("invalid command: %s\n\n",  cmd);
+                cmdHelp(pw);
+        }
+    }
+
+    private void cmdHelp(PrintWriter pw) {
+        pw.printf("Options:\n");
+        pw.printf("  help: show this help\n");
+        pw.printf("  register: register the service to receive events\n");
+        pw.printf("  unregister: unregister the service from receiving events\n");
+    }
+
+
+    private void cmdRegister(PrintWriter pw) {
+        pw.printf("registering listener %s\n", mListener);
+        runCmd(pw, () -> registerListener());
+    }
+
+    private void cmdUnregister(PrintWriter pw) {
+        pw.printf("unregistering listener %s\n", mListener);
+        runCmd(pw, () -> unregisterListener());
+    }
+
+    private void runCmd(PrintWriter pw, Runnable r) {
+        try {
+            r.run();
+        } catch (Exception e) {
+            Log.e(TAG, "error running command", e);
+            pw.printf("failed: %s\n", e);
+        }
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
index 62f2b0a..2662eaf 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
@@ -18,15 +18,22 @@
 import static android.car.test.util.UserTestingHelper.clearUserLockCredentials;
 import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
 import static android.car.test.util.UserTestingHelper.setUserLockCredentials;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.car.Car;
 import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
 import android.car.user.CarUserManager.UserLifecycleEvent;
 import android.content.pm.UserInfo;
+import android.os.Process;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
 
@@ -34,12 +41,15 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.util.List;
+
 public final class CarUserManagerTest extends CarMultiUserTestBase {
 
     private static final String TAG = CarUserManagerTest.class.getSimpleName();
 
     private static final int PIN = 2345;
 
+    private static final int START_TIMEOUT_MS = 20_000;
     private static final int SWITCH_TIMEOUT_MS = 70_000;
 
     private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
@@ -92,6 +102,75 @@
         assertUserInfo(newGuest, loadedGuest);
     }
 
+    @Test
+    public void testLifecycleMultipleListeners() throws Exception {
+        int newUserId = createUser("Test").id;
+        Car car2 = Car.createCar(getContext().getApplicationContext());
+        CarUserManager mgr2 = (CarUserManager) car2.getCarManager(Car.CAR_USER_SERVICE);
+        CarUserManager mgr1 = mCarUserManager;
+        Log.d(TAG, "myUid=" + Process.myUid() + ",mgr1=" + mgr1 + ", mgr2=" + mgr2);
+        assertWithMessage("mgrs").that(mgr1).isNotSameInstanceAs(mgr2);
+
+        BlockingUserLifecycleListener listener1 = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(START_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .build();
+        BlockingUserLifecycleListener listener2 = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(START_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .build();
+
+        Log.d(TAG, "registering listener1: " + listener1);
+        mgr1.addListener(Runnable::run, listener1);
+        Log.v(TAG, "ok");
+        try {
+            Log.d(TAG, "registering listener2: " + listener2);
+            mgr2.addListener(Runnable::run, listener2);
+            Log.v(TAG, "ok");
+            try {
+                IActivityManager am = ActivityManager.getService();
+                Log.d(TAG, "Starting user " + newUserId);
+                am.startUserInBackground(newUserId);
+                Log.v(TAG, "ok");
+
+                Log.d(TAG, "Waiting for events");
+                List<UserLifecycleEvent> events1 = listener1.waitForEvents();
+                Log.d(TAG, "events1: " + events1);
+                List<UserLifecycleEvent> events2 = listener2.waitForEvents();
+                Log.d(TAG, "events2: " + events2);
+                assertStartUserEvent(events1, newUserId);
+                assertStartUserEvent(events2, newUserId);
+            } finally {
+                Log.d(TAG, "unregistering listener2: " + listener2);
+                mgr2.removeListener(listener2);
+                Log.v(TAG, "ok");
+            }
+        } finally {
+            Log.d(TAG, "unregistering listener1: " + listener1);
+            mgr1.removeListener(listener1);
+            Log.v(TAG, "ok");
+        }
+    }
+
+    private void assertStartUserEvent(List<UserLifecycleEvent> events, @UserIdInt int userId) {
+        assertWithMessage("events").that(events).hasSize(1);
+
+        UserLifecycleEvent event = events.get(0);
+        assertWithMessage("type").that(event.getEventType())
+                .isEqualTo(USER_LIFECYCLE_EVENT_TYPE_STARTING);
+        assertWithMessage("user id on %s", event).that(event.getUserId()).isEqualTo(userId);
+        assertWithMessage("user handle on %s", event).that(event.getUserHandle().getIdentifier())
+                .isEqualTo(userId);
+        assertWithMessage("previous user id on %s", event).that(event.getPreviousUserId())
+                .isEqualTo(UserHandle.USER_NULL);
+        assertWithMessage("previous user handle on %s", event).that(event.getPreviousUserHandle())
+                .isNull();
+    }
+
     /**
      * Tests resume behavior when current user is ephemeral guest, a new guest user should be
      * created and switched to.
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
index e006387..49ca55a 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperLegacyTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.car.audio;
 
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
+import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -23,6 +27,8 @@
 
 import android.annotation.XmlRes;
 import android.content.Context;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
 import android.util.SparseArray;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -65,9 +71,10 @@
 
         RuntimeException exception = expectThrows(RuntimeException.class,
                 () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                        carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings));
+                        carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings,
+                        getInputDevices()));
 
-        assertThat(exception.getMessage()).contains("Two addresses map to same bus number:");
+        assertThat(exception).hasMessageThat().contains("Two addresses map to same bus number:");
     }
 
     @Test
@@ -78,9 +85,79 @@
 
         RuntimeException exception = expectThrows(RuntimeException.class,
                 () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings));
+                        carAudioDeviceInfos, mMockAudioControlWrapper,
+                        mMockCarAudioSettings, getInputDevices()));
 
-        assertThat(exception.getMessage()).contains("Invalid bus -1 was associated with context");
+        assertThat(exception).hasMessageThat()
+                .contains("Invalid bus -1 was associated with context");
+    }
+
+    @Test
+    public void constructor_throwsIfNullInputDevices() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        NullPointerException exception = expectThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                        carAudioDeviceInfos, mMockAudioControlWrapper,
+                        mMockCarAudioSettings, null));
+
+        assertThat(exception).hasMessageThat().contains("Input Devices");
+    }
+
+    @Test
+    public void constructor_throwsIfNullContext() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        NullPointerException exception = expectThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(null, mCarVolumeGroups,
+                        carAudioDeviceInfos, mMockAudioControlWrapper,
+                        mMockCarAudioSettings, getInputDevices()));
+
+        assertThat(exception).hasMessageThat().contains("Context");
+    }
+
+    @Test
+    public void constructor_throwsIfNullCarAudioDeviceInfo() throws Exception {
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        NullPointerException exception = expectThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                        null, mMockAudioControlWrapper,
+                        mMockCarAudioSettings, getInputDevices()));
+
+        assertThat(exception).hasMessageThat().contains("Car Audio Device Info");
+    }
+
+    @Test
+    public void constructor_throwsIfNullCarAudioControl() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        NullPointerException exception = expectThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                        carAudioDeviceInfos, null,
+                        mMockCarAudioSettings, getInputDevices()));
+
+        assertThat(exception).hasMessageThat().contains("Car Audio Control");
+    }
+
+    @Test
+    public void constructor_throwsIfNullCarAudioSettings() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(INVALID_BUS);
+
+        NullPointerException exception = expectThrows(NullPointerException.class,
+                () -> new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                        carAudioDeviceInfos, mMockAudioControlWrapper,
+                        null, getInputDevices()));
+
+        assertThat(exception).hasMessageThat().contains("Car Audio Settings");
     }
 
     @Test
@@ -89,7 +166,8 @@
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
 
         CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+                carAudioDeviceInfos, mMockAudioControlWrapper,
+                mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
 
@@ -103,7 +181,8 @@
         when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
 
         CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+                carAudioDeviceInfos, mMockAudioControlWrapper,
+                mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
         CarVolumeGroup[] volumeGroups = zones.get(0).getVolumeGroups();
@@ -111,6 +190,38 @@
     }
 
     @Test
+    public void loadAudioZones_primaryZoneHasInputDevice() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControlWrapper,
+                mMockCarAudioSettings, getInputDevices());
+
+        SparseArray<CarAudioZone> zones = helper.loadAudioZones();
+        CarAudioZone primaryZone = zones.get(PRIMARY_AUDIO_ZONE);
+        assertThat(primaryZone.getInputAudioDevices()).hasSize(1);
+    }
+
+    @Test
+    public void loadAudioZones_primaryZoneHasMicrophoneInputDevice() throws Exception {
+        List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
+
+        when(mMockAudioControlWrapper.getBusForContext(anyInt())).thenReturn(1);
+
+        CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
+                carAudioDeviceInfos, mMockAudioControlWrapper,
+                mMockCarAudioSettings, getInputDevices());
+
+        SparseArray<CarAudioZone> zones = helper.loadAudioZones();
+        CarAudioZone primaryZone = zones.get(PRIMARY_AUDIO_ZONE);
+        List<AudioDeviceAttributes> audioDeviceInfos =
+                primaryZone.getInputAudioDevices();
+        assertThat(audioDeviceInfos.get(0).getType()).isEqualTo(TYPE_BUILTIN_MIC);
+    }
+
+    @Test
     public void loadAudioZones_associatesLegacyContextsWithCorrectBuses() throws Exception {
         List<CarAudioDeviceInfo> carAudioDeviceInfos = getValidCarAudioDeviceInfos();
 
@@ -118,7 +229,8 @@
         when(mMockAudioControlWrapper.getBusForContext(CarAudioContext.MUSIC)).thenReturn(1);
 
         CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+                carAudioDeviceInfos, mMockAudioControlWrapper,
+                mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
 
@@ -145,7 +257,8 @@
                 .thenReturn(1);
 
         CarAudioZonesHelperLegacy helper = new CarAudioZonesHelperLegacy(mContext, mCarVolumeGroups,
-                carAudioDeviceInfos, mMockAudioControlWrapper, mMockCarAudioSettings);
+                carAudioDeviceInfos, mMockAudioControlWrapper,
+                mMockCarAudioSettings, getInputDevices());
 
         SparseArray<CarAudioZone> zones = helper.loadAudioZones();
 
@@ -166,6 +279,18 @@
         return Lists.newArrayList(deviceInfo1, deviceInfo2);
     }
 
+    private AudioDeviceInfo[] getInputDevices() {
+        AudioDeviceInfo deviceInfo1 = Mockito.mock(AudioDeviceInfo.class);
+        when(deviceInfo1.getType()).thenReturn(TYPE_BUILTIN_MIC);
+        when(deviceInfo1.getAddress()).thenReturn("mic");
+        when(deviceInfo1.isSink()).thenReturn(false);
+        AudioDeviceInfo deviceInfo2 = Mockito.mock(AudioDeviceInfo.class);
+        when(deviceInfo2.getAddress()).thenReturn("tuner");
+        when(deviceInfo2.getType()).thenReturn(TYPE_FM_TUNER);
+        when(deviceInfo2.isSink()).thenReturn(false);
+        return new AudioDeviceInfo[]{deviceInfo1, deviceInfo2};
+    }
+
     private List<CarAudioDeviceInfo> getValidCarAudioDeviceInfos() {
         CarAudioDeviceInfo deviceInfo1 = Mockito.mock(CarAudioDeviceInfo.class);
         when(deviceInfo1.getAddress()).thenReturn("bus001_media");
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
index 74b00c7..14d3ba8 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesHelperTest.java
@@ -15,6 +15,11 @@
  */
 package com.android.car.audio;
 
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
+import static android.media.AudioDeviceInfo.TYPE_BUS;
+import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
+
 import static com.android.car.audio.CarAudioService.DEFAULT_AUDIO_CONTEXT;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -23,7 +28,6 @@
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.expectThrows;
 
-import android.car.media.CarAudioManager;
 import android.content.Context;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
@@ -104,14 +108,11 @@
 
     private AudioDeviceInfo[] generateInputDeviceInfos() {
         return new AudioDeviceInfo[]{
-                generateInputAudioDeviceInfo(PRIMARY_ZONE_MICROPHONE_ADDRESS,
-                        AudioDeviceInfo.TYPE_BUILTIN_MIC),
-                generateInputAudioDeviceInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS,
-                        AudioDeviceInfo.TYPE_FM_TUNER),
-                generateInputAudioDeviceInfo(SECONDARY_ZONE_BACK_MICROPHONE_ADDRESS,
-                        AudioDeviceInfo.TYPE_BUS),
+                generateInputAudioDeviceInfo(PRIMARY_ZONE_MICROPHONE_ADDRESS, TYPE_BUILTIN_MIC),
+                generateInputAudioDeviceInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS, TYPE_FM_TUNER),
+                generateInputAudioDeviceInfo(SECONDARY_ZONE_BACK_MICROPHONE_ADDRESS, TYPE_BUS),
                 generateInputAudioDeviceInfo(SECONDARY_ZONE_BUS_1000_INPUT_ADDRESS,
-                        AudioDeviceInfo.TYPE_BUILTIN_MIC)
+                        TYPE_BUILTIN_MIC)
         };
     }
 
@@ -169,7 +170,7 @@
 
         List<Integer> zoneIds = getListOfZoneIds(zones);
         assertThat(zones.size()).isEqualTo(2);
-        assertThat(zones.contains(CarAudioManager.PRIMARY_AUDIO_ZONE)).isTrue();
+        assertThat(zones.contains(PRIMARY_AUDIO_ZONE)).isTrue();
         assertThat(zones.contains(SECONDARY_ZONE_ID)).isTrue();
     }
 
@@ -184,7 +185,7 @@
 
         SparseIntArray audioZoneIdToOccupantZoneIdMapping =
                 cazh.getCarAudioZoneIdToOccupantZoneIdMapping();
-        assertThat(audioZoneIdToOccupantZoneIdMapping.get(CarAudioManager.PRIMARY_AUDIO_ZONE))
+        assertThat(audioZoneIdToOccupantZoneIdMapping.get(PRIMARY_AUDIO_ZONE))
                 .isEqualTo(PRIMARY_OCCUPANT_ID);
         assertThat(audioZoneIdToOccupantZoneIdMapping.get(SECONDARY_ZONE_ID, -1))
                 .isEqualTo(-1);
@@ -305,7 +306,7 @@
             SparseArray<CarAudioZone> zones = cazh.loadAudioZones();
 
             assertThat(zones.size()).isEqualTo(2);
-            assertThat(zones.contains(CarAudioManager.PRIMARY_AUDIO_ZONE)).isTrue();
+            assertThat(zones.contains(PRIMARY_AUDIO_ZONE)).isTrue();
             assertThat(zones.contains(SECONDARY_ZONE_ID)).isTrue();
         }
     }
@@ -339,6 +340,30 @@
     }
 
     @Test
+    public void loadAudioZones_primaryZoneHasInputDevices() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
+
+        SparseArray<CarAudioZone> zones = cazh.loadAudioZones();
+
+        CarAudioZone primaryZone = zones.get(PRIMARY_AUDIO_ZONE);
+        assertThat(primaryZone.getInputAudioDevices()).hasSize(2);
+    }
+
+    @Test
+    public void loadAudioZones_primaryZoneHasMicrophoneDevice() throws Exception {
+        CarAudioZonesHelper cazh = new CarAudioZonesHelper(mCarAudioSettings, mInputStream,
+                mCarAudioOutputDeviceInfos, mInputAudioDeviceInfos, false);
+
+        SparseArray<CarAudioZone> zones = cazh.loadAudioZones();
+
+        CarAudioZone primaryZone = zones.get(PRIMARY_AUDIO_ZONE);
+        for (AudioDeviceAttributes info : primaryZone.getInputAudioDevices()) {
+            assertThat(info.getType()).isEqualTo(TYPE_BUILTIN_MIC);
+        }
+    }
+
+    @Test
     public void loadAudioZones_parsesInputDevices() throws Exception {
         try (InputStream inputDevicesStream = mContext.getResources().openRawResource(
                 R.raw.car_audio_configuration_with_input_devices)) {
diff --git a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
index 9c32893..552eedb 100644
--- a/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
+++ b/tests/carservice_test/src/com/android/car/audio/CarAudioZonesValidatorTest.java
@@ -15,9 +15,18 @@
  */
 package com.android.car.audio;
 
-import static org.mockito.Mockito.when;
+import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
+import static android.media.AudioDeviceInfo.TYPE_BUS;
+import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
 
-import android.car.media.CarAudioManager;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
+
+import android.media.AudioDeviceAttributes;
 import android.util.SparseArray;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -28,6 +37,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
+import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
@@ -37,10 +47,49 @@
 
     @Test
     public void validate_thereIsAtLeastOneZone() {
-        thrown.expect(RuntimeException.class);
-        thrown.expectMessage("At least one zone should be defined");
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> CarAudioZonesValidator.validate(new SparseArray<CarAudioZone>()));
 
-        CarAudioZonesValidator.validate(new SparseArray<CarAudioZone>());
+        assertThat(exception).hasMessageThat().contains("At least one zone should be defined");
+
+    }
+
+    @Test
+    public void validate_failsOnEmptyInputDevices() {
+        CarAudioZone zone = new MockBuilder().withInputDevices(new ArrayList<>()).build();
+        SparseArray<CarAudioZone> zones = new SparseArray<>();
+        zones.put(zone.getId(), zone);
+
+        IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
+                () -> CarAudioZonesValidator.validate(zones));
+
+        assertThat(exception).hasMessageThat().contains("Primary Zone Input Devices");
+    }
+
+    @Test
+    public void validate_failsOnNullInputDevices() {
+        CarAudioZone zone = new MockBuilder().withInputDevices(null).build();
+        SparseArray<CarAudioZone> zones = new SparseArray<>();
+        zones.put(zone.getId(), zone);
+
+        NullPointerException exception = expectThrows(NullPointerException.class,
+                () -> CarAudioZonesValidator.validate(zones));
+
+        assertThat(exception).hasMessageThat().contains("Primary Zone Input Devices");
+    }
+
+    @Test
+    public void validate_failsOnMissingMicrophoneInputDevices() {
+        CarAudioZone zone = new MockBuilder().withInputDevices(
+                List.of(generateInputAudioDeviceAttributeInfo("tuner", TYPE_FM_TUNER)))
+                .build();
+        SparseArray<CarAudioZone> zones = new SparseArray<>();
+        zones.put(zone.getId(), zone);
+
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> CarAudioZonesValidator.validate(zones));
+
+        assertThat(exception).hasMessageThat().contains("Primary Zone must have");
     }
 
     @Test
@@ -52,10 +101,11 @@
                 .build();
         zones.put(zoneOne.getId(), zoneOne);
 
-        thrown.expect(RuntimeException.class);
-        thrown.expectMessage("Invalid volume groups configuration for zone " + 1);
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> CarAudioZonesValidator.validate(zones));
 
-        CarAudioZonesValidator.validate(zones);
+        assertThat(exception).hasMessageThat()
+                .contains("Invalid volume groups configuration for zone " + 1);
     }
 
     @Test
@@ -77,12 +127,11 @@
         zones.put(primaryZone.getId(), primaryZone);
         zones.put(secondaryZone.getId(), secondaryZone);
 
+        RuntimeException exception = expectThrows(RuntimeException.class,
+                () -> CarAudioZonesValidator.validate(zones));
 
-        thrown.expect(RuntimeException.class);
-        thrown.expectMessage(
+        assertThat(exception).hasMessageThat().contains(
                 "Device with address three appears in multiple volume groups or audio zones");
-
-        CarAudioZonesValidator.validate(zones);
     }
 
     @Test
@@ -93,7 +142,7 @@
     }
 
     private SparseArray<CarAudioZone> generateAudioZonesWithPrimary() {
-        CarAudioZone zone = new MockBuilder().build();
+        CarAudioZone zone = new MockBuilder().withInputDevices(getValidInputDevices()).build();
         SparseArray<CarAudioZone> zones = new SparseArray<>();
         zones.put(zone.getId(), zone);
         return zones;
@@ -105,21 +154,23 @@
         return mockVolumeGroup;
     }
 
-    private CarAudioZone getMockPrimaryZone() {
-        CarAudioZone zoneMock = Mockito.mock(CarAudioZone.class);
-        when(zoneMock.getId()).thenReturn(CarAudioManager.PRIMARY_AUDIO_ZONE);
-        return zoneMock;
+    private List<AudioDeviceAttributes> getValidInputDevices() {
+        return List.of(generateInputAudioDeviceAttributeInfo("mic", TYPE_BUILTIN_MIC),
+                generateInputAudioDeviceAttributeInfo("tuner", TYPE_FM_TUNER),
+                generateInputAudioDeviceAttributeInfo("bus", TYPE_BUS));
     }
     private static class MockBuilder {
         private boolean mHasValidVolumeGroups = true;
-        private int mZoneId = 0;
+        private int mZoneId = PRIMARY_AUDIO_ZONE;
         private CarVolumeGroup[] mVolumeGroups = new CarVolumeGroup[0];
+        private List<AudioDeviceAttributes> mInputDevices = new ArrayList<>();
 
         CarAudioZone build() {
             CarAudioZone zoneMock = Mockito.mock(CarAudioZone.class);
             when(zoneMock.getId()).thenReturn(mZoneId);
             when(zoneMock.validateVolumeGroups()).thenReturn(mHasValidVolumeGroups);
             when(zoneMock.getVolumeGroups()).thenReturn(mVolumeGroups);
+            when(zoneMock.getInputAudioDevices()).thenReturn(mInputDevices);
             return zoneMock;
         }
 
@@ -137,5 +188,17 @@
             mVolumeGroups = volumeGroups;
             return this;
         }
+
+        MockBuilder withInputDevices(List<AudioDeviceAttributes> inputDevices) {
+            mInputDevices = inputDevices;
+            return this;
+        }
+    }
+
+    private AudioDeviceAttributes generateInputAudioDeviceAttributeInfo(String address, int type) {
+        AudioDeviceAttributes inputMock = mock(AudioDeviceAttributes.class);
+        when(inputMock.getAddress()).thenReturn(address);
+        when(inputMock.getType()).thenReturn(type);
+        return inputMock;
     }
 }
\ No newline at end of file
diff --git a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
index ca3598a..64c68fc 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
@@ -24,16 +24,21 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.car.Car;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -42,6 +47,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.car.CarLocalServices;
+import com.android.car.R;
+import com.android.car.power.CarPowerManagementService;
 import com.android.car.systeminterface.SystemInterface;
 import com.android.car.user.CarUserService;
 
@@ -74,8 +81,10 @@
     @Mock private CarPowerManager mCarPowerManagerMock;
     @Mock private CarUserService mCarUserServiceMock;
     @Mock private SystemInterface mSystemInterfaceMock;
+    @Mock private CarPowerManagementService mCarPowerManagementServiceMock;
     private CarUserService mCarUserServiceOriginal;
     private SystemInterface mSystemInterfaceOriginal;
+    private CarPowerManagementService mCarPowerManagementServiceOriginal;
     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
     @Captor private ArgumentCaptor<Integer> mIntegerCaptor;
 
@@ -106,10 +115,15 @@
         mController.setCarPowerManager(mCarPowerManagerMock);
         mFuture = new CompletableFuture<>();
         mCarUserServiceOriginal = CarLocalServices.getService(CarUserService.class);
+        mCarPowerManagementServiceOriginal = CarLocalServices.getService(
+                CarPowerManagementService.class);
         CarLocalServices.removeServiceForTest(CarUserService.class);
         CarLocalServices.addService(CarUserService.class, mCarUserServiceMock);
         CarLocalServices.removeServiceForTest(SystemInterface.class);
         CarLocalServices.addService(SystemInterface.class, mSystemInterfaceMock);
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+        CarLocalServices.addService(CarPowerManagementService.class,
+                mCarPowerManagementServiceMock);
         doReturn(new ArrayList<Integer>()).when(mCarUserServiceMock)
                 .startAllBackgroundUsersInGarageMode();
         doNothing().when(mSystemInterfaceMock)
@@ -122,6 +136,9 @@
         CarLocalServices.addService(CarUserService.class, mCarUserServiceOriginal);
         CarLocalServices.removeServiceForTest(SystemInterface.class);
         CarLocalServices.addService(SystemInterface.class, mSystemInterfaceOriginal);
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+        CarLocalServices.addService(CarPowerManagementService.class,
+                mCarPowerManagementServiceOriginal);
     }
 
     @Test
@@ -219,4 +236,83 @@
         // Verify that worker that polls running jobs from JobScheduler is scheduled.
         verify(mHandlerMock).postDelayed(any(), eq(JOB_SNAPSHOT_INITIAL_UPDATE_MS));
     }
+
+    @Test
+    public void testInitAndRelease() {
+
+        GarageMode garageMode = mock(GarageMode.class);
+        Controller controller = new Controller(mContextMock, mLooperMock, mWakeupPolicy,
+                mHandlerMock, garageMode);
+
+        controller.init();
+        controller.release();
+
+        verify(garageMode).init();
+        verify(garageMode).release();
+    }
+
+    @Test
+    public void testConstructor() {
+        Resources resourcesMock = mock(Resources.class);
+        when(mContextMock.getResources()).thenReturn(resourcesMock);
+        when(resourcesMock.getStringArray(R.array.config_garageModeCadence))
+                .thenReturn(sTemplateWakeupSchedule);
+        Controller controller = new Controller(mContextMock, mLooperMock);
+
+        assertThat(controller).isNotNull();
+    }
+
+    @Test
+    public void testScheduleNextWakeup() {
+        GarageMode garageMode = mock(GarageMode.class);
+
+        // Enter GarageMode only 1 time, no wake up after that
+        WakeupPolicy wakeUpPolicy = new WakeupPolicy(new String[] { "15m,1" });
+
+        Controller controller = new Controller(mContextMock, mLooperMock, wakeUpPolicy,
+                mHandlerMock, garageMode);
+        controller.setCarPowerManager(mCarPowerManagerMock);
+
+        // Imitate entering and leavimg GarageMode
+        controller.initiateGarageMode(/* future= */ null);
+
+        controller.scheduleNextWakeup();
+
+        verify(mCarPowerManagerMock).scheduleNextWakeupTime(900);
+
+        // Imitate entering Garage mode after sleep
+        controller.initiateGarageMode(/* future= */ null);
+
+        // Should be no more calls to scheduleNextWakeupTime
+        controller.scheduleNextWakeup();
+
+        Mockito.verifyNoMoreInteractions(mCarPowerManagerMock);
+    }
+
+    @Test
+    public void testOnStateChanged() {
+        GarageMode garageMode = mock(GarageMode.class);
+
+        Controller controller = Mockito.spy(new Controller(mContextMock, mLooperMock, mWakeupPolicy,
+                mHandlerMock, garageMode));
+
+        controller.onStateChanged(CarPowerStateListener.SHUTDOWN_CANCELLED, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.SHUTDOWN_ENTER, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.SUSPEND_ENTER, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, null);
+        verify(controller).resetGarageMode();
+
+        clearInvocations(controller);
+        controller.onStateChanged(CarPowerStateListener.INVALID , null);
+        verify(controller, never()).resetGarageMode();
+    }
 }
diff --git a/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java b/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
index 6133baf..6183549 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/GarageModeTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -36,6 +37,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.car.CarLocalServices;
+import com.android.car.power.CarPowerManagementService;
 import com.android.car.user.CarUserService;
 
 import org.junit.After;
@@ -50,6 +52,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -131,6 +134,42 @@
                 105);
     }
 
+    @Test
+    public void garageModeTestExitImmediately() throws Exception {
+        CarPowerManagementService mockCarPowerManagementService =
+                mock(CarPowerManagementService.class);
+
+        // Mock CPMS to force Garage Mode early exit
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+        CarLocalServices.addService(CarPowerManagementService.class, mockCarPowerManagementService);
+        when(mockCarPowerManagementService.garageModeShouldExitImmediately()).thenReturn(true);
+
+        // Check exit immediately without future
+        GarageMode garageMode = new GarageMode(mController);
+        garageMode.init();
+        garageMode.enterGarageMode(/* future= */ null);
+        assertThat(garageMode.isGarageModeActive()).isFalse();
+
+        // Create new instance of GarageMode
+        garageMode = new GarageMode(mController);
+        garageMode.init();
+        // Check exit immediately with future
+        CompletableFuture<Void> future = new CompletableFuture<>();
+        garageMode.enterGarageMode(future);
+        assertThat(garageMode.isGarageModeActive()).isFalse();
+        assertThat(future.isDone()).isTrue();
+
+        // Create new instance of GarageMode
+        garageMode = new GarageMode(mController);
+        garageMode.init();
+        // Check exit immediately with completed future
+        garageMode.enterGarageMode(future);
+        assertThat(garageMode.isGarageModeActive()).isFalse();
+        assertThat(future.isDone()).isTrue();
+
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+    }
+
     private void waitForHandlerThreadToFinish(CountDownLatch latch) throws Exception {
         assertWithMessage("Latch has timed out.")
                 .that(latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
diff --git a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
index c67d3d8..99bbc4c 100644
--- a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
@@ -193,6 +193,13 @@
         verify(mFakeCarWatchdog).actionTakenOnResourceOveruse(eq(actions));
     }
 
+    @Test
+    public void testIndirectCall_controlProcessHealthCheck() throws Exception {
+        mCarWatchdogDaemonHelper.controlProcessHealthCheck(true);
+
+        verify(mFakeCarWatchdog).controlProcessHealthCheck(eq(true));
+    }
+
     /*
      * Test that the {@link CarWatchdogDaemonHelper} throws {@code IllegalArgumentException} when
      * trying to register already-registered service again.
diff --git a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java
index e913b53..b3d02be 100644
--- a/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/audio/CarAudioUtilsTest.java
@@ -16,14 +16,23 @@
 
 package com.android.car.audio;
 
+import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
+import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
+
 import static com.android.car.audio.CarAudioUtils.hasExpired;
+import static com.android.car.audio.CarAudioUtils.isMicrophoneInputDevice;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+
+import android.media.AudioDeviceInfo;
+
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 @RunWith(AndroidJUnit4.class)
 public class CarAudioUtilsTest {
@@ -37,4 +46,18 @@
     public void hasExpired_forCurrentTimeAfterTimeout_returnsFalse() {
         assertThat(hasExpired(0, 300, 200)).isTrue();
     }
+
+    @Test
+    public void isMicrophoneInputDevice_forMicrophoneDevice_returnsTrue() {
+        AudioDeviceInfo deviceInfo = Mockito.mock(AudioDeviceInfo.class);
+        when(deviceInfo.getType()).thenReturn(TYPE_BUILTIN_MIC);
+        assertThat(isMicrophoneInputDevice(deviceInfo)).isTrue();
+    }
+
+    @Test
+    public void isMicrophoneInputDevice_forNonMicrophoneDevice_returnsFalse() {
+        AudioDeviceInfo deviceInfo = Mockito.mock(AudioDeviceInfo.class);
+        when(deviceInfo.getType()).thenReturn(TYPE_FM_TUNER);
+        assertThat(isMicrophoneInputDevice(deviceInfo)).isFalse();
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java b/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
index ff50677..2ab14dc 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
@@ -20,6 +20,8 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
 import android.util.Log;
 
+import com.android.car.CarServiceUtils;
+
 import java.util.LinkedList;
 
 public class MockedPowerHalService extends PowerHalService {
@@ -47,7 +49,8 @@
                 mock(UserHalService.class),
                 mock(DiagnosticHalService.class),
                 mock(ClusterHalService.class),
-                mock(HalClient.class));
+                mock(HalClient.class),
+                CarServiceUtils.getHandlerThread(VehicleHal.class.getSimpleName()));
         return mockedVehicleHal;
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
index 763b680..4aa9a81 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
@@ -35,6 +35,10 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.car.CarServiceUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,6 +73,10 @@
     @Mock private ClusterHalService mClusterHalService;
     @Mock private HalClient mHalClient;
 
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            VehicleHal.class.getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
+
     private VehicleHal mVehicleHal;
 
     /** Hal services configurations */
@@ -78,7 +86,7 @@
     public void setUp() throws Exception {
         mVehicleHal = new VehicleHal(mPowerHalService,
                 mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
-                mDiagnosticHalService, mClusterHalService, mHalClient);
+                mDiagnosticHalService, mClusterHalService, mHalClient, mHandlerThread);
 
         mConfigs.clear();
 
@@ -185,7 +193,8 @@
         propValues.add(propValue);
 
         // Act
-        mVehicleHal.onPropertyEvent(propValues);
+        mHandler.post(() -> mVehicleHal.onPropertyEvent(propValues));
+        CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
 
         // Assert
         verify(dispatchList).add(propValue);
@@ -201,7 +210,8 @@
         int areaId = VehicleHal.NO_AREA;
 
         // Act
-        mVehicleHal.onPropertySetError(errorCode, propId, areaId);
+        mHandler.post(() -> mVehicleHal.onPropertySetError(errorCode, propId, areaId));
+        CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
 
         // Assert
         verify(mPowerHalService).onPropertySetError(propId, areaId, errorCode);
@@ -215,7 +225,8 @@
         int areaId = VehicleHal.NO_AREA;
 
         // Act
-        mVehicleHal.onPropertySetError(errorCode, propId, areaId);
+        mHandler.post(() -> mVehicleHal.onPropertySetError(errorCode, propId, areaId));
+        CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
 
         // Assert
         verify(mPowerHalService).onPropertySetError(propId, areaId, errorCode);
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java
index 774da25..344fb04 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java
@@ -16,6 +16,8 @@
 
 package com.android.car.telemetry;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.fail;
 
 import android.car.telemetry.IScriptExecutor;
@@ -47,12 +49,17 @@
 
 
     private static final class ScriptExecutorListener extends IScriptExecutorListener.Stub {
+        public Bundle mSavedBundle;
+        public final CountDownLatch mSuccessLatch = new CountDownLatch(1);
+
         @Override
         public void onScriptFinished(byte[] result) {
         }
 
         @Override
         public void onSuccess(Bundle stateToPersist) {
+            mSavedBundle = stateToPersist;
+            mSuccessLatch.countDown();
         }
 
         @Override
@@ -60,7 +67,7 @@
         }
     }
 
-    private final IScriptExecutorListener mFakeScriptExecutorListener =
+    private final ScriptExecutorListener mFakeScriptExecutorListener =
             new ScriptExecutorListener();
 
     // TODO(b/189241508). Parsing of publishedData is not implemented yet.
@@ -69,15 +76,16 @@
     private final Bundle mSavedState = new Bundle();
 
     private static final String LUA_SCRIPT =
-            "function hello(data, state)\n"
-            + "    print(\"Hello World\")\n"
-            + "end\n";
+            "function hello(state)\n"
+                    + "    print(\"Hello World\")\n"
+                    + "end\n";
 
     private static final String LUA_METHOD = "hello";
 
     private final CountDownLatch mBindLatch = new CountDownLatch(1);
 
     private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
+    private static final int SCRIPT_SUCCESS_TIMEOUT_SEC = 10;
 
     private final ServiceConnection mScriptExecutorConnection =
             new ServiceConnection() {
@@ -93,6 +101,22 @@
                 }
             };
 
+    // Helper method to invoke the script and wait for it to complete and return the result.
+    public void runScriptAndWaitForResult(String script, String function, Bundle previousState)
+            throws RemoteException {
+        mScriptExecutor.invokeScript(script, function, mPublishedData, previousState,
+                mFakeScriptExecutorListener);
+        try {
+            if (!mFakeScriptExecutorListener.mSuccessLatch.await(SCRIPT_SUCCESS_TIMEOUT_SEC,
+                    TimeUnit.SECONDS)) {
+                fail("Failed to get on_success called by the script on time");
+            }
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+    }
+
     @Before
     public void setUp() throws InterruptedException {
         mContext.bindIsolatedService(new Intent(mContext, ScriptExecutor.class),
@@ -119,5 +143,129 @@
             fail(e.getMessage());
         }
     }
+
+    @Test
+    public void invokeScript_returnsResult() throws RemoteException {
+        String returnResultScript =
+                "function hello(state)\n"
+                        + "    result = {hello=\"world\"}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(returnResultScript, "hello", mSavedState);
+
+        // Expect to get back a bundle with a single string key: string value pair:
+        // {"hello": "world"}
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(1);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("hello")).isEqualTo("world");
+    }
+
+    @Test
+    public void invokeScript_allSupportedTypes() throws RemoteException {
+        String script =
+                "function knows(state)\n"
+                        + "    result = {string=\"hello\", boolean=true, integer=1, number=1.1}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(script, "knows", mSavedState);
+
+        // Expect to get back a bundle with 4 keys, each corresponding to a distinct supported type.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(4);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("string")).isEqualTo("hello");
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getBoolean("boolean")).isEqualTo(true);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getInt("integer")).isEqualTo(1);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getDouble("number")).isEqualTo(1.1);
+    }
+
+    @Test
+    public void invokeScript_skipsUnsupportedTypes() throws RemoteException {
+        String script =
+                "function nested(state)\n"
+                        + "    result = {string=\"hello\", boolean=true, integer=1, number=1.1}\n"
+                        + "    result.nested_table = {x=0, y=0}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(script, "nested", mSavedState);
+
+        // Bundle does not contain any value under "nested_table" key, because nested tables are
+        // not supported yet.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(4);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("nested_table")).isNull();
+    }
+
+    @Test
+    public void invokeScript_emptyBundle() throws RemoteException {
+        String script =
+                "function empty(state)\n"
+                        + "    result = {}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(script, "empty", mSavedState);
+
+        // If a script returns empty table as the result, we get an empty bundle.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle).isNotNull();
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void invokeScript_processPreviousStateAndReturnResult() throws RemoteException {
+        // Here we verify that the script actually processes provided state from a previous run
+        // and makes calculation based on that and returns the result.
+        // TODO(b/189241508): update function signatures.
+        String script =
+                "function update(state)\n"
+                        + "    result = {y = state.x+1}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+        Bundle previousState = new Bundle();
+        previousState.putInt("x", 1);
+
+
+        runScriptAndWaitForResult(script, "update", previousState);
+
+        // Verify that y = 2, because y = x + 1 and x = 1.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(1);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getInt("y")).isEqualTo(2);
+    }
+
+    @Test
+    public void invokeScript_allSupportedTypesWorkRoundTripWithKeyNamesPreserved()
+            throws RemoteException {
+        // Here we verify that all supported types in supplied previous state Bundle are interpreted
+        // by the script as expected.
+        // TODO(b/189241508): update function signatures.
+        String script =
+                "function update_all(state)\n"
+                        + "    result = {}\n"
+                        + "    result.integer = state.integer + 1\n"
+                        + "    result.number = state.number + 0.1\n"
+                        + "    result.boolean = not state.boolean\n"
+                        + "    result.string = state.string .. \"CADABRA\"\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+        Bundle previousState = new Bundle();
+        previousState.putInt("integer", 1);
+        previousState.putDouble("number", 0.1);
+        previousState.putBoolean("boolean", false);
+        previousState.putString("string", "ABRA");
+
+
+        runScriptAndWaitForResult(script, "update_all", previousState);
+
+        // Verify that keys are preserved but the values are modified as expected.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(4);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getInt("integer")).isEqualTo(2);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getDouble("number")).isEqualTo(0.2);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getBoolean("boolean")).isEqualTo(true);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("string")).isEqualTo(
+                "ABRACADABRA");
+    }
 }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
index 931a557..89db3f6 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
@@ -81,7 +81,7 @@
         // Checks that mMockDataBroker's setOnScriptFinishedCallback is called after it's injected
         // into controller's constructor with @InjectMocks
         verify(mMockDataBroker).setOnScriptFinishedCallback(
-                any(DataBrokerController.ScriptFinishedCallback.class));
+                any(DataBroker.ScriptFinishedCallback.class));
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java
index 45c5a22..f4cde37 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java
@@ -16,11 +16,17 @@
 
 package com.android.car.telemetry.databroker;
 
+import static com.android.car.telemetry.databroker.DataBrokerImpl.MSG_HANDLE_TASK;
+
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.Mockito.when;
 
 import android.car.hardware.CarPropertyConfig;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
 
 import com.android.car.CarPropertyService;
 import com.android.car.telemetry.TelemetryProto;
@@ -33,14 +39,19 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Collections;
+import java.util.concurrent.PriorityBlockingQueue;
 
 @RunWith(MockitoJUnitRunner.class)
 public class DataBrokerUnitTest {
     private static final int PROP_ID = 100;
     private static final int PROP_AREA = 200;
+    private static final int PRIORITY_HIGH = 1;
+    private static final int PRIORITY_LOW = 10;
+    private static final long TIMEOUT_MS = 5_000L;
     private static final CarPropertyConfig<Integer> PROP_CONFIG =
             CarPropertyConfig.newBuilder(Integer.class, PROP_ID, PROP_AREA).setAccess(
                     CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
+    private static final Bundle DATA = new Bundle();
     private static final TelemetryProto.VehiclePropertyPublisher
             VEHICLE_PROPERTY_PUBLISHER_CONFIGURATION =
             TelemetryProto.VehiclePropertyPublisher.newBuilder().setReadRate(
@@ -65,6 +76,9 @@
     private CarPropertyService mMockCarPropertyService;
 
     private DataBrokerImpl mDataBroker;
+    private Handler mHandler;
+    private ScriptExecutionTask mHighPriorityTask;
+    private ScriptExecutionTask mLowPriorityTask;
 
     @Before
     public void setUp() {
@@ -72,39 +86,130 @@
                 .thenReturn(Collections.singletonList(PROP_CONFIG));
         PublisherFactory factory = new PublisherFactory(mMockCarPropertyService);
         mDataBroker = new DataBrokerImpl(factory);
+        mHandler = mDataBroker.getWorkerHandler();
+        mHighPriorityTask = new ScriptExecutionTask(
+                new DataSubscriber(mDataBroker, METRICS_CONFIG_FOO, SUBSCRIBER_FOO, PRIORITY_HIGH),
+                DATA,
+                SystemClock.elapsedRealtime());
+        mLowPriorityTask = new ScriptExecutionTask(
+                new DataSubscriber(mDataBroker, METRICS_CONFIG_FOO, SUBSCRIBER_FOO, PRIORITY_LOW),
+                DATA,
+                SystemClock.elapsedRealtime());
+    }
+
+    @Test
+    public void testSetTaskExecutionPriority_whenNoTask_shouldNotScheduleTask() {
+        mDataBroker.setTaskExecutionPriority(PRIORITY_HIGH);
+
+        assertThat(mHandler.hasMessages(MSG_HANDLE_TASK)).isFalse();
+    }
+
+    @Test
+    public void testSetTaskExecutionPriority_whenNextTaskPriorityLow_shouldNotPollTask() {
+        mDataBroker.getTaskQueue().add(mLowPriorityTask);
+
+        mDataBroker.setTaskExecutionPriority(PRIORITY_HIGH);
+
+        waitForHandlerThreadToFinish();
+        // task is not polled
+        assertThat(mDataBroker.getTaskQueue().peek()).isEqualTo(mLowPriorityTask);
+    }
+
+    @Test
+    public void testSetTaskExecutionPriority_whenNextTaskPriorityHigh_shouldPollTask() {
+        mDataBroker.getTaskQueue().add(mHighPriorityTask);
+
+        mDataBroker.setTaskExecutionPriority(PRIORITY_HIGH);
+
+        waitForHandlerThreadToFinish();
+        // task is polled and run
+        assertThat(mDataBroker.getTaskQueue().peek()).isNull();
+    }
+
+    @Test
+    public void testScheduleNextTask_whenNoTask_shouldNotSendMessageToHandler() {
+        mDataBroker.scheduleNextTask();
+
+        assertThat(mHandler.hasMessages(MSG_HANDLE_TASK)).isFalse();
+    }
+
+    @Test
+    public void testScheduleNextTask_whenTaskInProgress_shouldNotSendMessageToHandler() {
+        PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
+        taskQueue.add(mHighPriorityTask);
+        mDataBroker.scheduleNextTask(); // start a task
+        waitForHandlerThreadToFinish();
+        assertThat(taskQueue.peek()).isNull(); // assert that task is polled and running
+        taskQueue.add(mHighPriorityTask); // add another task into the queue
+
+        mDataBroker.scheduleNextTask(); // schedule next task while the last task is in progress
+
+        // verify no message is sent to handler and no task is polled
+        assertThat(mHandler.hasMessages(MSG_HANDLE_TASK)).isFalse();
+        assertThat(taskQueue.peek()).isEqualTo(mHighPriorityTask);
+    }
+
+    @Test
+    public void testAddTaskToQueue_shouldScheduleNextTask() {
+        mDataBroker.addTaskToQueue(mHighPriorityTask);
+
+        assertThat(mHandler.hasMessages(MSG_HANDLE_TASK)).isTrue();
     }
 
     @Test
     public void testAddMetricsConfiguration_newMetricsConfig() {
+        mDataBroker.addMetricsConfiguration(METRICS_CONFIG_BAR);
+
+        waitForHandlerThreadToFinish();
+        assertThat(mDataBroker.getSubscriptionMap()).hasSize(1);
+        assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_BAR.getName());
+        // there should be one data subscriber in the subscription list of METRICS_CONFIG_BAR
+        assertThat(mDataBroker.getSubscriptionMap().get(METRICS_CONFIG_BAR.getName())).hasSize(1);
+    }
+
+
+    @Test
+    public void testAddMetricsConfiguration_duplicateMetricsConfig_shouldDoNothing() {
+        // this metrics config has already been added in setUp()
         mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
 
+        waitForHandlerThreadToFinish();
+        assertThat(mDataBroker.getSubscriptionMap()).hasSize(1);
         assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_FOO.getName());
-        // there should be one data subscriber in the subscription list of METRICS_CONFIG_FOO
         assertThat(mDataBroker.getSubscriptionMap().get(METRICS_CONFIG_FOO.getName())).hasSize(1);
     }
 
     @Test
-    public void testAddMetricsConfiguration_multipleMetricsConfigsSamePublisher() {
+    public void testRemoveMetricsConfiguration_shouldRemoveAllAssociatedTasks() {
         mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
         mDataBroker.addMetricsConfiguration(METRICS_CONFIG_BAR);
+        ScriptExecutionTask taskWithMetricsConfigBar = new ScriptExecutionTask(
+                new DataSubscriber(mDataBroker, METRICS_CONFIG_BAR, SUBSCRIBER_BAR, PRIORITY_HIGH),
+                new Bundle(),
+                SystemClock.elapsedRealtime());
+        PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
+        taskQueue.add(mHighPriorityTask); // associated with METRICS_CONFIG_FOO
+        taskQueue.add(mLowPriorityTask); // associated with METRICS_CONFIG_FOO
+        taskQueue.add(taskWithMetricsConfigBar); // associated with METRICS_CONFIG_BAR
+        assertThat(taskQueue).hasSize(3);
 
-        assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_FOO.getName());
-        assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_BAR.getName());
+        mDataBroker.removeMetricsConfiguration(METRICS_CONFIG_FOO);
+
+        waitForHandlerThreadToFinish();
+        assertThat(taskQueue).hasSize(1);
+        assertThat(taskQueue.poll()).isEqualTo(taskWithMetricsConfigBar);
     }
 
     @Test
-    public void testAddMetricsConfiguration_addSameMetricsConfigs() {
-        mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
+    public void testRemoveMetricsConfiguration_whenMetricsConfigNonExistent_shouldDoNothing() {
+        mDataBroker.removeMetricsConfiguration(METRICS_CONFIG_BAR);
 
-        boolean status = mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
-
-        assertThat(status).isFalse();
+        waitForHandlerThreadToFinish();
+        assertThat(mDataBroker.getSubscriptionMap()).hasSize(0);
     }
 
-    @Test
-    public void testRemoveMetricsConfiguration_removeNonexistentMetricsConfig() {
-        boolean status = mDataBroker.removeMetricsConfiguration(METRICS_CONFIG_FOO);
-
-        assertThat(status).isFalse();
+    private void waitForHandlerThreadToFinish() {
+        assertWithMessage("handler not idle in %sms", TIMEOUT_MS)
+                .that(mHandler.runWithScissors(() -> {}, TIMEOUT_MS)).isTrue();
     }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
new file mode 100644
index 0000000..6e04768
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.android.car.telemetry.publisher;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.automotive.telemetry.internal.ICarDataListener;
+import android.automotive.telemetry.internal.ICarTelemetryInternal;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+import com.android.car.telemetry.TelemetryProto;
+import com.android.car.telemetry.databroker.DataSubscriber;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CarTelemetrydPublisherTest extends AbstractExtendedMockitoTestCase {
+    private static final String SERVICE_NAME = ICarTelemetryInternal.DESCRIPTOR + "/default";
+    private static final int CAR_DATA_ID_1 = 100;
+    private static final TelemetryProto.Publisher PUBLISHER_PARAMS_1 =
+            TelemetryProto.Publisher.newBuilder()
+                    .setCartelemetryd(TelemetryProto.CarTelemetrydPublisher.newBuilder()
+                            .setId(CAR_DATA_ID_1))
+                    .build();
+
+    @Mock private IBinder mMockBinder;
+    @Mock private ICarTelemetryInternal mMockCarTelemetryInternal;
+    @Mock private DataSubscriber mMockDataSubscriber;
+
+    private final CarTelemetrydPublisher mPublisher = new CarTelemetrydPublisher();
+
+    // ICarTelemetryInternal side of the listener.
+    @Captor private ArgumentCaptor<ICarDataListener> mCarDataListenerCaptor;
+
+    @Before
+    public void setUp() throws Exception {
+        when(mMockDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+        doNothing().when(mMockCarTelemetryInternal).setListener(mCarDataListenerCaptor.capture());
+    }
+
+    private void mockICarTelemetryInternalBinder() {
+        when(mMockBinder.queryLocalInterface(any())).thenReturn(mMockCarTelemetryInternal);
+        when(mMockCarTelemetryInternal.asBinder()).thenReturn(mMockBinder);
+        doReturn(mMockBinder).when(() -> ServiceManager.checkService(SERVICE_NAME));
+    }
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder.spyStatic(ServiceManager.class);
+    }
+
+    @Test
+    public void testAddDataSubscriber_registersNewListener() throws Exception {
+        mockICarTelemetryInternalBinder();
+
+        mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+        assertThat(mCarDataListenerCaptor.getAllValues()).hasSize(1);
+        assertThat(mPublisher.isConnectedToCarTelemetryd()).isTrue();
+        assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+    }
+
+    // TODO(b/189142577): add test cases when connecting to cartelemetryd fails
+
+
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
index bcd408a..8410d02 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -74,7 +75,7 @@
                             .setVehiclePropertyId(-200))
                     .build();
 
-    // mMockCarPropertyService supported car property list.
+    // CarPropertyConfigs for mMockCarPropertyService.
     private static final CarPropertyConfig<Integer> PROP_CONFIG_1 =
             CarPropertyConfig.newBuilder(Integer.class, PROP_ID_1, AREA_ID).setAccess(
                     CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
@@ -108,7 +109,21 @@
         mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
 
         verify(mMockCarPropertyService).registerListener(eq(PROP_ID_1), eq(PROP_READ_RATE), any());
-        assertThat(mVehiclePropertyPublisher.getDataSubscribers()).hasSize(1);
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+    }
+
+    @Test
+    public void testAddDataSubscriber_withSamePropertyId_registersSingleListener() {
+        DataSubscriber subscriber2 = mock(DataSubscriber.class);
+        when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+
+        mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
+        mVehiclePropertyPublisher.addDataSubscriber(subscriber2);
+
+        verify(mMockCarPropertyService, times(1))
+                .registerListener(eq(PROP_ID_1), eq(PROP_READ_RATE), any());
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(subscriber2)).isTrue();
     }
 
     @Test
@@ -125,7 +140,7 @@
                 () -> mVehiclePropertyPublisher.addDataSubscriber(invalidDataSubscriber));
 
         assertThat(error).hasMessageThat().contains("No access.");
-        assertThat(mVehiclePropertyPublisher.getDataSubscribers()).isEmpty();
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
     }
 
     @Test
@@ -137,7 +152,7 @@
                 () -> mVehiclePropertyPublisher.addDataSubscriber(invalidDataSubscriber));
 
         assertThat(error).hasMessageThat().contains("not found");
-        assertThat(mVehiclePropertyPublisher.getDataSubscribers()).isEmpty();
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
     }
 
     @Test
@@ -145,7 +160,9 @@
         mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
 
         mVehiclePropertyPublisher.removeDataSubscriber(mMockDataSubscriber);
-        // TODO(b/189143814): add proper verification
+
+        verify(mMockCarPropertyService, times(1)).unregisterListener(eq(PROP_ID_1), any());
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
     }
 
     @Test
@@ -153,13 +170,21 @@
         Throwable error = assertThrows(IllegalArgumentException.class,
                 () -> mVehiclePropertyPublisher.removeDataSubscriber(mMockDataSubscriber));
 
-        assertThat(error).hasMessageThat().contains("subscriber not found");
+        assertThat(error).hasMessageThat().contains("DataSubscriber was not found");
     }
 
     @Test
     public void testRemoveAllDataSubscribers_succeeds() {
+        DataSubscriber subscriber2 = mock(DataSubscriber.class);
+        when(subscriber2.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+        mVehiclePropertyPublisher.addDataSubscriber(mMockDataSubscriber);
+        mVehiclePropertyPublisher.addDataSubscriber(subscriber2);
+
         mVehiclePropertyPublisher.removeAllDataSubscribers();
-        // TODO(b/189143814): add tests
+
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+        assertThat(mVehiclePropertyPublisher.hasDataSubscriber(subscriber2)).isFalse();
+        verify(mMockCarPropertyService, times(1)).unregisterListener(eq(PROP_ID_1), any());
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index b12aa27..8140e79 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -31,6 +31,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyList;
@@ -1245,6 +1246,23 @@
         assertPackageInfoEquals(actualPackageInfos, expectedPackageInfos);
     }
 
+    @Test
+    public void testSetProcessHealthCheckEnabled() throws Exception {
+        mCarWatchdogService.controlProcessHealthCheck(true);
+
+        verify(mMockCarWatchdogDaemon).controlProcessHealthCheck(eq(true));
+    }
+
+    @Test
+    public void testSetProcessHealthCheckEnabledWithDisconnectedDaemon() throws Exception {
+        crashWatchdogDaemon();
+
+        assertThrows(IllegalStateException.class,
+                () -> mCarWatchdogService.controlProcessHealthCheck(false));
+
+        verify(mMockCarWatchdogDaemon, never()).controlProcessHealthCheck(anyBoolean());
+    }
+
     private void mockWatchdogDaemon() {
         when(mMockBinder.queryLocalInterface(anyString())).thenReturn(mMockCarWatchdogDaemon);
         when(mMockCarWatchdogDaemon.asBinder()).thenReturn(mMockBinder);