Snap for 11566466 from 3a9f30891739141965879afc0e6bced26703042d to car-apps-aosp-release

Change-Id: Ia081ce518734acb09f3f0d91517e3beeaf111de1
diff --git a/aaos-apps-gradle-project/copy_gradle_output.sh b/aaos-apps-gradle-project/copy_gradle_output.sh
index e91d79a..5ab51db 100755
--- a/aaos-apps-gradle-project/copy_gradle_output.sh
+++ b/aaos-apps-gradle-project/copy_gradle_output.sh
@@ -59,6 +59,7 @@
 cp $OUTPUT_DIR/car-messenger-common/outputs/aar/car-messenger-common-release.aar $1/car-messenger-common.aar
 
 # Tests
+cp $OUTPUT_DIR/car-calendar-app/outputs/apk/androidTest/platform/debug/car-calendar-app-platform-debug-androidTest.apk $1/CarCalendarUnitTests.apk
 cp $OUTPUT_DIR/car-rotary-lib/outputs/apk/androidTest/debug/car-rotary-lib-debug-androidTest.apk $1/CarRotaryLibUnitTests.apk
 cp $OUTPUT_DIR/car-ui-lib/outputs/apk/androidTest/debug/car-ui-lib-debug-androidTest.apk $1/CarUILibUnitTests.apk
 cp $OUTPUT_DIR/car-dialer-app/outputs/apk/emulator/debug/car-dialer-app-emulator-debug.apk $1/CarDialerAppForTesting.apk
diff --git a/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.jar b/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.jar
index 62d4c05..249e583 100644
--- a/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.jar
+++ b/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.properties b/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.properties
index 8049c68..3994438 100644
--- a/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.properties
+++ b/aaos-apps-gradle-project/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/aaos-apps-gradle-project/gradlew b/aaos-apps-gradle-project/gradlew
index 4f906e0..a69d9cb 100755
--- a/aaos-apps-gradle-project/gradlew
+++ b/aaos-apps-gradle-project/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
 
 #
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
 #
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,101 @@
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=`expr $i + 1`
-    done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
 
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
 
 exec "$JAVACMD" "$@"
diff --git a/aaos-apps-gradle-project/gradlew.bat b/aaos-apps-gradle-project/gradlew.bat
index a9f778a..53a6b23 100644
--- a/aaos-apps-gradle-project/gradlew.bat
+++ b/aaos-apps-gradle-project/gradlew.bat
@@ -14,7 +14,7 @@
 @rem limitations under the License.

 @rem

 

-@if "%DEBUG%" == "" @echo off

+@if "%DEBUG%"=="" @echo off

 @rem ##########################################################################

 @rem

 @rem  Gradle startup script for Windows

@@ -25,7 +25,7 @@
 if "%OS%"=="Windows_NT" setlocal

 

 set DIRNAME=%~dp0

-if "%DIRNAME%" == "" set DIRNAME=.

+if "%DIRNAME%"=="" set DIRNAME=.

 set APP_BASE_NAME=%~n0

 set APP_HOME=%DIRNAME%

 

@@ -40,7 +40,7 @@
 

 set JAVA_EXE=java.exe

 %JAVA_EXE% -version >NUL 2>&1

-if "%ERRORLEVEL%" == "0" goto init

+if %ERRORLEVEL% equ 0 goto execute

 

 echo.

 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

@@ -54,7 +54,7 @@
 set JAVA_HOME=%JAVA_HOME:"=%

 set JAVA_EXE=%JAVA_HOME%/bin/java.exe

 

-if exist "%JAVA_EXE%" goto init

+if exist "%JAVA_EXE%" goto execute

 

 echo.

 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

@@ -64,21 +64,6 @@
 

 goto fail

 

-:init

-@rem Get command-line arguments, handling Windows variants

-

-if not "%OS%" == "Windows_NT" goto win9xME_args

-

-:win9xME_args

-@rem Slurp the command line arguments.

-set CMD_LINE_ARGS=

-set _SKIP=2

-

-:win9xME_args_slurp

-if "x%~1" == "x" goto execute

-

-set CMD_LINE_ARGS=%*

-

 :execute

 @rem Setup the command line

 

@@ -86,17 +71,19 @@
 

 

 @rem Execute Gradle

-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

 

 :end

 @rem End local scope for the variables with windows NT shell

-if "%ERRORLEVEL%"=="0" goto mainEnd

+if %ERRORLEVEL% equ 0 goto mainEnd

 

 :fail

 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

 rem the _cmd.exe /c_ return code!

-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

-exit /b 1

+set EXIT_CODE=%ERRORLEVEL%

+if %EXIT_CODE% equ 0 set EXIT_CODE=1

+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%

+exit /b %EXIT_CODE%

 

 :mainEnd

 if "%OS%"=="Windows_NT" endlocal

diff --git a/aaos-apps-gradle-project/settings.gradle b/aaos-apps-gradle-project/settings.gradle
index b27344c..e3ab3c6 100644
--- a/aaos-apps-gradle-project/settings.gradle
+++ b/aaos-apps-gradle-project/settings.gradle
@@ -22,6 +22,9 @@
 project(':PaintBooth').projectDir = new File('../car-ui-lib/paintbooth')
 include ':oem-apis'
 project(':oem-apis').projectDir = new File('../car-ui-lib/oem-apis')
+include ':proxy-plugin'
+project(':proxy-plugin').projectDir = new File('../car-ui-lib/proxy-plugin')
+
 include ':car-rotary-lib'
 project(':car-rotary-lib').projectDir = new File('../car-ui-lib/car-rotary-lib')
 include ':car-ui-lib-testing'
@@ -30,8 +33,7 @@
 project(':oem-token-shared-lib').projectDir = new File('../car-ui-lib/oem-tokens/shared-lib')
 include ':oem-token-lib'
 project(':oem-token-lib').projectDir = new File('../car-ui-lib/oem-tokens/lib')
-include ':oem-demo-rro'
-project(':oem-demo-rro').projectDir = new File('../car-ui-lib/oem-tokens/rro')
+
 include ':token-compose-compat'
 project(':token-compose-compat').projectDir = new File('../car-ui-lib/token-compose-compat')
 
diff --git a/car-apps-common/res/values/overlayable.xml b/car-apps-common/res/values/overlayable.xml
index 564e7ca..3e5c656 100644
--- a/car-apps-common/res/values/overlayable.xml
+++ b/car-apps-common/res/values/overlayable.xml
@@ -36,11 +36,14 @@
       <item type="id" name="minimized_control_bar_left_slot"/>
       <item type="id" name="minimized_control_bar_main_slot"/>
       <item type="id" name="minimized_control_bar_right_slot"/>
+      <item type="id" name="rows_container"/>
 
       <item type="integer" name="control_bar_columns"/>
 
+      <item type="layout" name="control_bar"/>
       <item type="layout" name="minimized_control_bar"/>
 
+      <item type="style" name="Widget.ActionButton"/>
       <item type="style" name="Widget.ActionButton.PlayPause"/>
       <item type="style" name="MinimizedControlBar"/>
       <item type="style" name="ControlBar"/>
diff --git a/car-apps-common/src/com/android/car/apps/common/BackgroundImageView.java b/car-apps-common/src/com/android/car/apps/common/BackgroundImageView.java
index b6555b4..7bffbc7 100644
--- a/car-apps-common/src/com/android/car/apps/common/BackgroundImageView.java
+++ b/car-apps-common/src/com/android/car/apps/common/BackgroundImageView.java
@@ -15,11 +15,15 @@
  */
 package com.android.car.apps.common;
 
+import static android.graphics.Shader.TileMode.MIRROR;
+
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.RenderEffect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Size;
 import android.view.View;
@@ -78,6 +82,18 @@
         setImageAdditionalScale(extraScale);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            int averageDim = (mImageView.getWidth() + mImageView.getHeight()) / 2;
+            float radius = mBitmapBlurPercent * averageDim;
+            RenderEffect blur = RenderEffect.createBlurEffect(radius, radius, MIRROR);
+            mImageView.setRenderEffect(blur);
+        }
+    }
+
     /**
      * @deprecated Use {@link #setBackgroundDrawable} instead, and make sure to only call when the
      * image is actually different! TODO(b/139387273).
@@ -87,8 +103,8 @@
      */
     @Deprecated
     public void setBackgroundImage(@Nullable Bitmap bitmap, boolean showAnimation) {
-        Drawable drawable = (bitmap != null) ? new BitmapDrawable(bitmap) : null;
-        updateBlur(drawable, showAnimation);
+        Drawable drawable = (bitmap != null) ? new BitmapDrawable(getResources(), bitmap) : null;
+        updateImage(drawable, showAnimation);
     }
 
     /** Sets the drawable that will be displayed blurred by this view. */
@@ -101,18 +117,18 @@
      * enabled.
      */
     public void setBackgroundDrawable(@Nullable Drawable drawable, boolean showAnimation) {
-        updateBlur(drawable, showAnimation);
+        updateImage(drawable, showAnimation);
     }
 
-    private void updateBlur(@Nullable Drawable drawable, boolean showAnimation) {
+    private void updateImage(@Nullable Drawable drawable, boolean showAnimation) {
         if (drawable == null) {
             mImageView.setImageBitmap(null, false);
             return;
         }
 
-        Bitmap src = BitmapUtils.fromDrawable(drawable, mBitmapTargetSize);
-        Bitmap blurred = ImageUtils.blur(getContext(), src, mBitmapTargetSize, mBitmapBlurPercent);
-        mImageView.setImageBitmap(blurred, showAnimation);
+        Bitmap bmp = BitmapUtils.fromDrawable(drawable, mBitmapTargetSize);
+        mImageView.setImageBitmap(bmp, showAnimation);
+
         invalidate();
         requestLayout();
     }
diff --git a/car-apps-common/src/com/android/car/apps/common/ImageUtils.java b/car-apps-common/src/com/android/car/apps/common/ImageUtils.java
index cfdbe57..f354d46 100644
--- a/car-apps-common/src/com/android/car/apps/common/ImageUtils.java
+++ b/car-apps-common/src/com/android/car/apps/common/ImageUtils.java
@@ -35,9 +35,10 @@
     private static final float MAX_BLUR = 25f;
 
     /**
-     * Blurs the given image by scaling it down by the given factor and applying the given
-     * blurring radius.
+     * @deprecated Scheduled to stop working with gradle 8... or 9. Replace with the following:
+     * https://developer.android.com/guide/topics/renderscript/migrate#image_blur_on_android_12_into_a_view
      */
+    @Deprecated
     @NonNull
     public static Bitmap blur(Context context, @NonNull Bitmap image, Size bitmapTargetSize,
             float bitmapBlurPercent) {
diff --git a/car-media-common/build.gradle b/car-media-common/build.gradle
index c76f94b..eba4d89 100644
--- a/car-media-common/build.gradle
+++ b/car-media-common/build.gradle
@@ -71,7 +71,7 @@
     implementation 'androidx.recyclerview:recyclerview:1.2.1'
 
     implementation "androidx.media:media:1.6.0"
-    implementation files(gradle.ext.lib_car_system_stubs)
+    compileOnly files(gradle.ext.lib_car_system_stubs)
 
     implementation project(":car-apps-common")
     implementation project(":car-media-extensions")
diff --git a/car-media-common/src/com/android/car/media/common/MediaConstants.java b/car-media-common/src/com/android/car/media/common/MediaConstants.java
index bbe5b3c..2e10e74 100644
--- a/car-media-common/src/com/android/car/media/common/MediaConstants.java
+++ b/car-media-common/src/com/android/car/media/common/MediaConstants.java
@@ -51,7 +51,7 @@
     public static final String BROWSE_CUSTOM_ACTIONS_ACTION_ICON =
             "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_ICON_URI";
     public static final String BROWSE_CUSTOM_ACTIONS_ACTION_LIMIT =
-            "androidx.media.MediaBrowserCompat.BROWSE_CUSTOM_ACTIONS_ACTION_LIMIT";
+            "androidx.media.utils.MediaBrowserCompat.extras.CUSTOM_BROWSER_ACTION_LIMIT";
     public static final String BROWSE_CUSTOM_ACTIONS_ACTION_EXTRAS =
             "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_EXTRAS";
     public static final String BROWSE_CUSTOM_ACTIONS_EXTRA_RESULT_BROWSE_NODE =
diff --git a/car-media-common/src/com/android/car/media/common/analytics/AnalyticsHelper.java b/car-media-common/src/com/android/car/media/common/analytics/AnalyticsHelper.java
index 6ede788..889b9ea 100644
--- a/car-media-common/src/com/android/car/media/common/analytics/AnalyticsHelper.java
+++ b/car-media-common/src/com/android/car/media/common/analytics/AnalyticsHelper.java
@@ -18,19 +18,15 @@
 
 import static com.android.car.media.common.analytics.AnalyticsFlags.ANALYTICS_ENABLED;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
-import android.text.TextUtils;
+import android.support.v4.media.MediaBrowserCompat;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.car.app.mediaextensions.analytics.Constants;
 import androidx.car.app.mediaextensions.analytics.host.AnalyticsManager;
 import androidx.car.app.mediaextensions.analytics.host.IAnalyticsManager;
 
-import com.android.car.media.common.source.MediaSource;
-
 /**
  * Analytics related helper methods.
  */
@@ -38,58 +34,34 @@
 
     static IAnalyticsManager sIAnalyticsManagerStub = new IAnalyticsManager() {};
 
+
     /**
      * Builds and returns analytics manager.
      * Returns stub if invalid component name or feature not enabled.
+     *
      * @param context
-     * @param rootExtras
-     * @return
+     * @param browser browser to send analytics
+     * @param rootExtras root extras returned by browser
+     * @return IAnalyticsManager implementation.
      */
     public static IAnalyticsManager makeAnalyticsManager(@NonNull Context context,
-            @NonNull MediaSource mediaSource, @NonNull Bundle rootExtras) {
+            @NonNull MediaBrowserCompat browser, @NonNull Bundle rootExtras) {
         int batchinterval  = context.getResources().getInteger(
                 com.android.car.media.common.R.integer.analytics_send_batch_interval);
         int batchSize = context.getResources().getInteger(
                 com.android.car.media.common.R.integer.analytics_send_batch_size);
-        String passkey = AnalyticsHelper.getPasskey(rootExtras);
-        int sessionId = AnalyticsHelper.getSessionId(rootExtras);
-        ComponentName receiverComponentName = AnalyticsHelper.getAnalyticsComponentName(rootExtras);
-        String sourcePackage = mediaSource.getPackageName();
+        boolean optIn = AnalyticsHelper.getOptIn(rootExtras);
 
         // We return unimplemented stub when analytics not enabled. This way we do not need this
         //  check at every capture point.
-        if (!ANALYTICS_ENABLED || receiverComponentName == null
-                || !receiverComponentName.getPackageName().equals(sourcePackage)) {
-            return sIAnalyticsManagerStub;
+        if (ANALYTICS_ENABLED && optIn) {
+            return new AnalyticsManager(context, browser, batchinterval, batchSize);
         } else {
-            return new AnalyticsManager(context, receiverComponentName.flattenToString(), passkey,
-                    sessionId, batchinterval, batchSize);
+            return sIAnalyticsManagerStub;
         }
     }
 
-    /**
-     * Empty string returned indicates no receiver package or invalid package.
-     */
-    @Nullable
-    private static ComponentName getAnalyticsComponentName(@NonNull Bundle rootExtras) {
-        String receiverComponentName =
-                rootExtras.getString(Constants.ANALYTICS_ROOT_KEY_BROADCAST_COMPONENT_NAME);
-
-        // Check null/empty
-        if (TextUtils.isEmpty(receiverComponentName)) {
-            return null;
-        }
-
-        return ComponentName.unflattenFromString(receiverComponentName);
-    }
-
-    @Nullable
-    private static String getPasskey(@NonNull Bundle rootExtras) {
-        return rootExtras.getString(Constants.ANALYTICS_ROOT_KEY_PASSKEY);
-    }
-
-    @Nullable
-    private static int getSessionId(@NonNull Bundle rootExtras) {
-        return rootExtras.getInt(Constants.ANALYTICS_ROOT_KEY_SESSION_ID);
+    private static boolean getOptIn(Bundle rootExtras) {
+        return rootExtras.getBoolean(Constants.ANALYTICS_ROOT_KEY_OPT_IN, false);
     }
 }
diff --git a/car-media-common/src/com/android/car/media/common/browse/MediaItemsRepository.java b/car-media-common/src/com/android/car/media/common/browse/MediaItemsRepository.java
index 96475b5..8901503 100644
--- a/car-media-common/src/com/android/car/media/common/browse/MediaItemsRepository.java
+++ b/car-media-common/src/com/android/car/media/common/browse/MediaItemsRepository.java
@@ -200,15 +200,17 @@
         }
 
         // Always refresh the subscription (to work around bugs in media apps).
-        mBrowsingState.mBrowser.unsubscribe(nodeId);
-        mBrowsingState.mBrowser.subscribe(nodeId, options, mBrowseCallback);
+        if (mBrowsingState.mBrowser != null) {
+            mBrowsingState.mBrowser.unsubscribe(nodeId);
+            mBrowsingState.mBrowser.subscribe(nodeId, options, mBrowseCallback);
+        }
 
         return items.mLiveData;
     }
 
     /** Retrieves a specific {@link MediaBrowserCompat.MediaItem} from the connected service. */
     public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
-        if (mBrowsingState.mConnectionStatus == CONNECTED) {
+        if (mBrowsingState.mConnectionStatus == CONNECTED && mBrowsingState.mBrowser != null) {
             mBrowsingState.mBrowser.getItem(mediaId, cb);
         } else {
             Log.e(TAG, "getItem called without a connection! "
@@ -222,7 +224,7 @@
         mSearchQuery = query;
         if (TextUtils.isEmpty(mSearchQuery)) {
             clearSearchResults();
-        } else {
+        } else if (mBrowsingState.mBrowser != null) {
             mSearchMediaItems.setLoading();
             mBrowsingState.mBrowser.search(mSearchQuery, options, mSearchCallback);
         }
@@ -248,7 +250,9 @@
                 mRootMediaItems.setLoading();
                 break;
             case CONNECTED:
-                getCache().mRootId = mBrowsingState.mBrowser.getRoot();
+            case NONEXISTENT:
+                getCache().mRootId = mBrowsingState.mBrowser == null ? null :
+                        mBrowsingState.mBrowser.getRoot();
                 mCustomBrowseActions.postValue(parseBrowseActions(mBrowsingState));
                 break;
             case DISCONNECTING:
@@ -275,6 +279,10 @@
 
     /** Does NOT clear the cache. */
     private void unsubscribeNodes() {
+        if (mBrowsingState.mBrowser == null) {
+            return;
+        }
+
         PerMediaSourceCache cache = getCache();
         for (String nodeId : cache.mChildrenByNodeId.keySet()) {
             mBrowsingState.mBrowser.unsubscribe(nodeId);
@@ -364,6 +372,7 @@
     private Map<String, CustomBrowseAction> parseBrowseActions(BrowsingState browsingState) {
         Map<String, CustomBrowseAction> customBrowseActions = new HashMap<>();
 
+        if (browsingState.mBrowser == null) return customBrowseActions;
         Bundle rootExtras = browsingState.mBrowser.getExtras();
         if (rootExtras == null) return customBrowseActions;
 
diff --git a/car-media-common/src/com/android/car/media/common/playback/PlaybackViewModel.java b/car-media-common/src/com/android/car/media/common/playback/PlaybackViewModel.java
index f0e4aab..3d0c0f8 100644
--- a/car-media-common/src/com/android/car/media/common/playback/PlaybackViewModel.java
+++ b/car-media-common/src/com/android/car/media/common/playback/PlaybackViewModel.java
@@ -288,6 +288,7 @@
                     case REJECTED:
                     case CONNECTING:
                     case CONNECTED:
+                    case NONEXISTENT:
                         mMediaController.unregisterCallback(this);
                         // Fall through
                     case SUSPENDED:
@@ -299,6 +300,8 @@
 
             if (mBrowsingState.mConnectionStatus == ConnectionStatus.CONNECTED) {
                 setMediaController(mInputFactory.getControllerForBrowser(mBrowsingState.mBrowser));
+            } else if (mBrowsingState.mConnectionStatus == ConnectionStatus.NONEXISTENT) {
+                setMediaController(mBrowsingState.mMediaSource.getMediaController());
             }
         }
 
diff --git a/car-media-common/src/com/android/car/media/common/source/MediaBrowserConnector.java b/car-media-common/src/com/android/car/media/common/source/MediaBrowserConnector.java
index 81ac331..868c6f5 100644
--- a/car-media-common/src/com/android/car/media/common/source/MediaBrowserConnector.java
+++ b/car-media-common/src/com/android/car/media/common/source/MediaBrowserConnector.java
@@ -86,7 +86,11 @@
          * from {@link #connectTo} just before calling {@link MediaBrowserCompat#disconnect} on the
          * old browser.
          */
-        DISCONNECTING
+        DISCONNECTING,
+        /**
+         * The browser does not exist an no connection can be made
+         */
+        NONEXISTENT
     }
 
     /**
@@ -96,22 +100,22 @@
     public static class BrowsingState {
         @NonNull final Context mContext;
         @NonNull public final MediaSource mMediaSource;
-        @NonNull public final MediaBrowserCompat mBrowser;
+        @Nullable public final MediaBrowserCompat mBrowser;
         @NonNull public final ConnectionStatus mConnectionStatus;
         @NonNull final Bundle mRootExtras = new Bundle();
         @NonNull IAnalyticsManager mAnalyticsManager;
 
         @VisibleForTesting
         public BrowsingState(Context context, @NonNull MediaSource mediaSource,
-                @NonNull MediaBrowserCompat browser, @NonNull ConnectionStatus status) {
+                @Nullable MediaBrowserCompat browser, @NonNull ConnectionStatus status) {
             mContext = context;
             mMediaSource = Preconditions.checkNotNull(mediaSource, "source can't be null");
-            mBrowser = Preconditions.checkNotNull(browser, "browser can't be null");
+            mBrowser = browser;
             mConnectionStatus = Preconditions.checkNotNull(status, "status can't be null");
-            if (browser.isConnected() && browser.getExtras() != null) {
+            if (browser != null && browser.isConnected() && browser.getExtras() != null) {
                 mRootExtras.putAll(browser.getExtras());
             }
-            mAnalyticsManager = AnalyticsHelper.makeAnalyticsManager(mContext, mMediaSource,
+            mAnalyticsManager = AnalyticsHelper.makeAnalyticsManager(mContext, browser,
                     mRootExtras);
         }
 
@@ -120,7 +124,7 @@
             mRootExtras.clear();
             mRootExtras.putAll(rootExtras);
             mAnalyticsManager.sendQueue();
-            mAnalyticsManager = AnalyticsHelper.makeAnalyticsManager(mContext, mMediaSource,
+            mAnalyticsManager = AnalyticsHelper.makeAnalyticsManager(mContext, mBrowser,
                     mRootExtras);
         }
 
@@ -176,7 +180,9 @@
     }
 
     private String getSourcePackage() {
-        if (mMediaSource == null) return null;
+        if (mMediaSource == null || mMediaSource.getBrowseServiceComponentName() == null) {
+            return null;
+        }
         return mMediaSource.getBrowseServiceComponentName().getPackageName();
     }
 
@@ -238,10 +244,6 @@
             Log.e(TAG, "sendNewState mMediaSource is null!");
             return;
         }
-        if (mBrowser == null) {
-            Log.e(TAG, "sendNewState mBrowser is null!");
-            return;
-        }
         mCallback.onBrowserConnectionChanged(
                 new BrowsingState(mContext, mMediaSource, mBrowser, cnx));
     }
@@ -253,6 +255,11 @@
                 Log.d(TAG, "Disconnecting: " + getSourcePackage()
                         + " mBrowser: " + idHash(mBrowser));
             }
+
+            // Send queued analytic events before we disconnect.
+            Bundle rootExtras =  mBrowser.getExtras() == null ? new Bundle() : mBrowser.getExtras();
+            AnalyticsHelper.makeAnalyticsManager(mContext, mBrowser, rootExtras).sendQueue();
+
             sendNewState(ConnectionStatus.DISCONNECTING);
             mBrowser.disconnect();
         }
@@ -269,7 +276,9 @@
         maybeDisconnect();
 
         mMediaSource = mediaSource;
-        if (mMediaSource != null) {
+        if (mMediaSource == null) {
+            mBrowser = null;
+        } else if (mMediaSource.getBrowseServiceComponentName() != null) {
             mBrowser = createMediaBrowser(mMediaSource, new BrowserConnectionCallback());
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "Connecting to: " + getSourcePackage()
@@ -287,7 +296,9 @@
                 sendNewState(ConnectionStatus.SUSPENDED);
             }
         } else {
+            // No browse service
             mBrowser = null;
+            sendNewState(ConnectionStatus.NONEXISTENT);
         }
     }
 
diff --git a/car-media-common/src/com/android/car/media/common/source/MediaModels.java b/car-media-common/src/com/android/car/media/common/source/MediaModels.java
index 35de01e..51338b0 100644
--- a/car-media-common/src/com/android/car/media/common/source/MediaModels.java
+++ b/car-media-common/src/com/android/car/media/common/source/MediaModels.java
@@ -57,6 +57,18 @@
         mPlaybackViewModel = new PlaybackViewModel(context, browseState);
     }
 
+    /**
+     * Creates models tied to {@link MediaSessionHelper#getMediaSource}
+     */
+    public MediaModels(Context context) {
+        MediaSessionHelper helper = MediaSessionHelper.getInstance(context);
+        LiveData<MediaSource> srcData = helper.getMediaSource();
+        mMediaSourceViewModel = new MediaSourceViewModel(context, srcData);
+        LiveData<BrowsingState> browseState = mMediaSourceViewModel.getBrowsingState();
+        mMediaItemsRepository = new MediaItemsRepository(browseState);
+        mPlaybackViewModel = new PlaybackViewModel(context, browseState);
+    }
+
     /** Returns the {@link MediaSourceViewModel}. */
     public MediaSourceViewModel getMediaSourceViewModel() {
         return mMediaSourceViewModel;
diff --git a/car-media-common/src/com/android/car/media/common/source/MediaSessionHelper.java b/car-media-common/src/com/android/car/media/common/source/MediaSessionHelper.java
new file mode 100644
index 0000000..c2b2670
--- /dev/null
+++ b/car-media-common/src/com/android/car/media/common/source/MediaSessionHelper.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2024 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.media.common.source;
+
+import android.content.Context;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Source of MediaSources that listens to {@link MediaSessionManager} media session changes.
+ * <p>
+ * When there are multiple media sessions, it prioritizes returning the following:
+ * 1. The most recent active MediaSession
+ * 2. The most recent MediaSession
+ * <p>
+ * For non-active MediaSessions, listeners are created to be notified if one of the others become
+ * active, since playback changes don't always trigger a session change.
+ */
+public class MediaSessionHelper extends MediaController.Callback {
+
+    private final MutableLiveData<MediaSource> mMediaSource = new MutableLiveData<>();
+    private final MediaSessionManager mMediaSessionManager;
+    private final InputFactory mInputFactory;
+    private final List<MediaController> mMediaControllersList = new ArrayList<>();
+
+    private final MediaSessionManager.OnActiveSessionsChangedListener mActiveSessionsListener =
+            this::onMediaControllersChange;
+    private static MediaSessionHelper sInstance;
+
+    /** Returns the singleton. */
+    public static MediaSessionHelper getInstance(@NonNull Context context) {
+        if (sInstance == null) {
+            sInstance = new MediaSessionHelper(context.getApplicationContext());
+        }
+        return sInstance;
+    }
+
+    /**
+     * Factory for creating dependencies. Can be swapped out for testing.
+     */
+    @VisibleForTesting
+    interface InputFactory {
+
+        MediaSessionManager getMediaSessionManager(Context appContext);
+
+        MediaSource getMediaSource(MediaController mediaController);
+    }
+
+    private static InputFactory createInputFactory(@NonNull Context appContext) {
+        return new InputFactory() {
+
+            @Override
+            public MediaSessionManager getMediaSessionManager(Context appContext) {
+                return appContext.getSystemService(MediaSessionManager.class);
+            }
+
+            @Override
+            public MediaSource getMediaSource(MediaController mediaController) {
+                if (mediaController == null) {
+                    return null;
+                }
+                MediaSessionCompat.Token token =
+                        MediaSessionCompat.Token.fromToken(mediaController.getSessionToken());
+                MediaControllerCompat newMediaController =
+                        new MediaControllerCompat(appContext, token);
+
+                return MediaSource.create(appContext, newMediaController);
+            }
+        };
+    }
+
+    private MediaSessionHelper(@NonNull Context appContext) {
+        this(appContext, createInputFactory(appContext));
+    }
+
+    private MediaSessionHelper(Context appContext, InputFactory inputFactory) {
+        mInputFactory = inputFactory;
+        // Register our listener to be notified of changes in the active media sessions.
+        mMediaSessionManager = mInputFactory.getMediaSessionManager(appContext);
+        mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveSessionsListener, null);
+
+        // Set initial value
+        onMediaControllersChange(mMediaSessionManager.getActiveSessions(null));
+    }
+
+    /** Returns a filtered live data of {@link MediaSource}. */
+    public LiveData<MediaSource> getMediaSource() {
+        return mMediaSource;
+    }
+
+    private void onMediaControllersChange(List<MediaController> controllers) {
+        unregisterSessionCallbacks();
+
+        MediaController activeMediaController = getActiveMediaController(controllers);
+        updateMediaSource(activeMediaController);
+    }
+
+    @Nullable
+    private MediaController getActiveMediaController(List<MediaController> controllers) {
+        if (controllers == null || controllers.isEmpty()) {
+            return null;
+        }
+
+        MediaController activeMediaController = null;
+        for (MediaController mediaController : controllers) {
+            if (mediaController.getPlaybackState() == null) {
+                continue;
+            }
+
+            if (activeMediaController == null
+                    && isActive(mediaController.getPlaybackState().getState())) {
+                activeMediaController = mediaController;
+            } else {
+                // Since playback state changes don't trigger an active media session change, we
+                // need to listen to the other media sessions in case another one becomes active.
+                registerForPlaybackChanges(mediaController);
+            }
+        }
+
+        // If no active sessions, return the most recent media session.
+        return activeMediaController == null ? controllers.get(0) : activeMediaController;
+    }
+
+    private void registerForPlaybackChanges(MediaController controller) {
+        if (mMediaControllersList.contains(controller)) {
+            return;
+        }
+
+        controller.registerCallback(this);
+        mMediaControllersList.add(controller);
+    }
+
+    private void unregisterSessionCallbacks() {
+        for (MediaController mediaController : mMediaControllersList) {
+            if (mediaController != null) {
+                mediaController.unregisterCallback(this);
+            }
+        }
+        mMediaControllersList.clear();
+    }
+
+    @Override
+    public void onPlaybackStateChanged(@Nullable PlaybackState state) {
+        if (state != null && isActive(state.getState())) {
+            onMediaControllersChange(
+                    mMediaSessionManager.getActiveSessions(/* notificationListener= */ null));
+        }
+    }
+
+    private void updateMediaSource(MediaController mediaController) {
+        mMediaSource.setValue(mInputFactory.getMediaSource(mediaController));
+    }
+
+    /* Copy of PlaybackState.isActive() which is only available for minsdk >=S  */
+    private boolean isActive(int playbackState) {
+        switch (playbackState) {
+            case PlaybackState.STATE_FAST_FORWARDING:
+            case PlaybackState.STATE_REWINDING:
+            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
+            case PlaybackState.STATE_SKIPPING_TO_NEXT:
+            case PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM:
+            case PlaybackState.STATE_BUFFERING:
+            case PlaybackState.STATE_CONNECTING:
+            case PlaybackState.STATE_PLAYING:
+                return true;
+        }
+        return false;
+    }
+}
diff --git a/car-media-common/src/com/android/car/media/common/source/MediaSource.java b/car-media-common/src/com/android/car/media/common/source/MediaSource.java
index 7522a78..d0067d2 100644
--- a/car-media-common/src/com/android/car/media/common/source/MediaSource.java
+++ b/car-media-common/src/com/android/car/media/common/source/MediaSource.java
@@ -16,16 +16,19 @@
 
 package com.android.car.media.common.source;
 
+import android.car.Car;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.service.media.MediaBrowserService;
+import android.support.v4.media.session.MediaControllerCompat;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -44,13 +47,16 @@
 
 /**
  * This represents a source of media content. It provides convenient methods to access media source
- * metadata, such as application name and icon.
+ * metadata, such as application name and icon. Media content can either be derived from a
+ * {@link MediaBrowserService} or a {@link MediaControllerCompat}.
  */
 public class MediaSource {
     private static final String TAG = "MediaSource";
 
-    @NonNull
+    @Nullable
     private final ComponentName mBrowseService;
+    @Nullable
+    private final MediaControllerCompat mMediaController;
     @NonNull
     private final CharSequence mDisplayName;
     @NonNull
@@ -62,33 +68,62 @@
      * Creates a {@link MediaSource} for the given {@link ComponentName}
      */
     @Nullable
-    public static MediaSource create(@NonNull Context context,
-            @NonNull ComponentName componentName) {
-        ServiceInfo serviceInfo = getBrowseServiceInfo(context, componentName);
+    public static MediaSource create(@NonNull Context ctx, @NonNull ComponentName componentName) {
+        ServiceInfo serviceInfo = getBrowseServiceInfo(ctx, componentName);
 
         String className = serviceInfo != null ? serviceInfo.name : null;
         if (TextUtils.isEmpty(className)) {
-            Log.w(TAG,
-                    "No MediaBrowserService found in component " + componentName.flattenToString());
+            Log.w(TAG, "No MediaBrowserService for component " + componentName.flattenToString());
             return null;
         }
 
         try {
             String packageName = componentName.getPackageName();
-            CharSequence displayName = extractDisplayName(context, serviceInfo, packageName);
-            Drawable icon = extractIcon(context, serviceInfo, packageName);
+            CharSequence displayName = extractDisplayName(ctx, serviceInfo, packageName);
+            Drawable icon = extractIcon(ctx, serviceInfo, packageName);
             ComponentName browseService = new ComponentName(packageName, className);
-            return new MediaSource(browseService, displayName, icon, new IconCropper(context));
+            return new MediaSource(browseService, null, displayName, icon, new IconCropper(ctx));
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "Component not found " + componentName.flattenToString());
             return null;
         }
     }
 
+    /**
+     * Creates a {@link MediaSource} for the given {@link MediaControllerCompat}
+     */
+    @Nullable
+    public static MediaSource create(@NonNull Context context,
+            @NonNull MediaControllerCompat mediaController) {
+        String packageName = mediaController.getPackageName();
+        try {
+            ServiceInfo serviceInfo = null;
+            ComponentName componentName = extractServiceComponentName(mediaController);
+            if (componentName != null) {
+                serviceInfo = getBrowseServiceInfo(context, componentName);
+                String className = serviceInfo != null ? serviceInfo.name : null;
+                if (TextUtils.isEmpty(className)) {
+                    serviceInfo = null;
+                }
+            }
+
+            CharSequence displayName = extractDisplayName(context, serviceInfo, packageName);
+            Drawable icon = extractIcon(context, serviceInfo, packageName);
+
+            return new MediaSource(/* componentName= */ null, mediaController, displayName, icon,
+                new IconCropper(context));
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "App not found " + packageName);
+            return null;
+        }
+    }
+
     @VisibleForTesting
-    public MediaSource(@NonNull ComponentName browseService, @NonNull CharSequence displayName,
+    public MediaSource(@Nullable ComponentName browseService,
+            @Nullable MediaControllerCompat mediaController, @NonNull CharSequence displayName,
             @NonNull Drawable icon, @NonNull IconCropper iconCropper) {
         mBrowseService = browseService;
+        mMediaController = mediaController;
         mDisplayName = displayName;
         mIcon = icon;
         mIconCropper = iconCropper;
@@ -156,14 +191,31 @@
     }
 
     /**
+     * @return the browse service associated with the media session if provided, null otherwise.
+     */
+    @Nullable
+    private static ComponentName extractServiceComponentName(MediaControllerCompat controller) {
+        if (controller.getExtras() == null || controller.getExtras()
+                .getString(Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION) == null) {
+            return null;
+        }
+        String serviceNameString =
+                controller.getExtras().getString(Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION);
+
+        return new ComponentName(controller.getPackageName(), serviceNameString);
+    }
+
+    /**
      * @return media source human readable name for display.
      */
     @NonNull
     public CharSequence getDisplayName(Context context) {
-        ServiceInfo serviceInfo = getBrowseServiceInfo(context, mBrowseService);
+        ServiceInfo serviceInfo = null;
+        if (mBrowseService != null) {
+            serviceInfo = getBrowseServiceInfo(context, mBrowseService);
+        }
         try {
-            String packageName = mBrowseService.getPackageName();
-            return extractDisplayName(context, serviceInfo, packageName);
+            return extractDisplayName(context, serviceInfo, getPackageName());
         } catch (PackageManager.NameNotFoundException e) {
             Log.e(TAG, "getDisplayName: " + e);
             return mDisplayName;
@@ -175,13 +227,19 @@
      */
     @NonNull
     public String getPackageName() {
-        return mBrowseService.getPackageName();
+        if (mBrowseService != null) {
+            return mBrowseService.getPackageName();
+        } else if (mMediaController != null) {
+            return mMediaController.getPackageName();
+        }
+        Log.e(TAG, "getPackageName() has null BrowseService and Controller");
+        return ""; // Should never happen
     }
 
     /**
      * @return a {@link ComponentName} referencing this media source's {@link MediaBrowserService}.
      */
-    @NonNull
+    @Nullable
     public ComponentName getBrowseServiceComponentName() {
         return mBrowseService;
     }
@@ -202,23 +260,46 @@
         return mIconCropper.crop(mIcon);
     }
 
+    /**
+     * @return {@link MediaControllerCompat} of this media source
+     */
+    @Nullable
+    public MediaControllerCompat getMediaController() {
+        return mMediaController;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         MediaSource that = (MediaSource) o;
-        return Objects.equals(mBrowseService, that.mBrowseService);
+        if (mBrowseService != null) {
+            return Objects.equals(mBrowseService, that.mBrowseService);
+        }
+        return Objects.equals(mMediaController, that.mMediaController);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mBrowseService);
+        if (mBrowseService != null) {
+            return Objects.hash(mBrowseService);
+        } else if (mMediaController != null) {
+            return Objects.hash(mMediaController);
+        }
+        Log.e(TAG, "hashCode() has null BrowseService and Controller");
+        return 0; // Should never happen
     }
 
     @Override
     @NonNull
     public String toString() {
-        return mBrowseService.flattenToString();
+        if (mBrowseService != null) {
+            mBrowseService.flattenToString();
+        } else if (mMediaController != null) {
+            return mMediaController.toString();
+        }
+        Log.e(TAG, "toString() has null BrowseService and Controller");
+        return ""; // Should never happen
     }
 
     /**
diff --git a/car-media-common/src/com/android/car/media/common/ui/MediaWidgetViewModel.java b/car-media-common/src/com/android/car/media/common/ui/MediaWidgetViewModel.java
new file mode 100644
index 0000000..abc2c87
--- /dev/null
+++ b/car-media-common/src/com/android/car/media/common/ui/MediaWidgetViewModel.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 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.media.common.ui;
+
+import android.app.Application;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+
+/** ViewModel used to track state of media widgets that use the {@link MediaWidgetController} */
+public class MediaWidgetViewModel extends AndroidViewModel {
+
+    private boolean mQueueVisible = false;
+    private boolean mHistoryVisible = false;
+    private boolean mOverflowExpanded = false;
+
+    public MediaWidgetViewModel(@NonNull Application application) {
+        super(application);
+    }
+
+    public void setQueueVisible(boolean visible) {
+        mQueueVisible = visible;
+    }
+
+    public boolean getQueueVisible() {
+        return mQueueVisible;
+    }
+
+    public void setHistoryVisible(boolean visible) {
+        mHistoryVisible = visible;
+    }
+
+    public boolean getHistoryVisible() {
+        return mHistoryVisible;
+    }
+
+    public void setOverflowExpanded(boolean expanded) {
+        mOverflowExpanded = expanded;
+    }
+
+    public boolean getOverflowExpanded() {
+        return mOverflowExpanded;
+    }
+}
diff --git a/car-media-common/tests/unittests/src/com/android/car/media/common/MediaTestUtils.java b/car-media-common/tests/unittests/src/com/android/car/media/common/MediaTestUtils.java
index 84643c4..972f1fa 100644
--- a/car-media-common/tests/unittests/src/com/android/car/media/common/MediaTestUtils.java
+++ b/car-media-common/tests/unittests/src/com/android/car/media/common/MediaTestUtils.java
@@ -20,8 +20,10 @@
 import android.graphics.Path;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.support.v4.media.session.MediaControllerCompat;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.car.apps.common.IconCropper;
 import com.android.car.media.common.source.MediaSource;
@@ -31,16 +33,22 @@
     private MediaTestUtils() {
     }
 
-    /** Creates a fake {@link MediaSource}. */
+    /** Creates a fake {@link MediaSource} with browse service. */
     public static MediaSource newFakeMediaSource(@NonNull String pkg, @NonNull String cls) {
-        return newFakeMediaSource(new ComponentName(pkg, cls));
+        return newFakeMediaSource(new ComponentName(pkg, cls), null);
+    }
+
+    /** Creates a fake {@link MediaSource} with media controller. */
+    public static MediaSource newFakeMediaSource(MediaControllerCompat mediaController) {
+        return newFakeMediaSource(null, mediaController);
     }
 
     /** Creates a fake {@link MediaSource}. */
-    public static MediaSource newFakeMediaSource(@NonNull ComponentName browseService) {
-        String displayName = browseService.getClassName();
+    public static MediaSource newFakeMediaSource(@Nullable ComponentName browseService,
+            @Nullable MediaControllerCompat mediaController) {
+        String displayName = browseService == null ? "" : browseService.getClassName();
         Drawable icon = new ColorDrawable();
         IconCropper iconCropper = new IconCropper(new Path());
-        return new MediaSource(browseService, displayName, icon, iconCropper);
+        return new MediaSource(browseService, mediaController, displayName, icon, iconCropper);
     }
 }
diff --git a/car-media-common/tests/unittests/src/com/android/car/media/common/playback/PlaybackViewModelTest.java b/car-media-common/tests/unittests/src/com/android/car/media/common/playback/PlaybackViewModelTest.java
index 626378d..9240c86 100644
--- a/car-media-common/tests/unittests/src/com/android/car/media/common/playback/PlaybackViewModelTest.java
+++ b/car-media-common/tests/unittests/src/com/android/car/media/common/playback/PlaybackViewModelTest.java
@@ -73,8 +73,6 @@
     @Rule
     public final TestLifecycleOwner mLifecycleOwner = new TestLifecycleOwner();
 
-    private final MediaSource mMediaSource = newFakeMediaSource("test", "test");
-
     @Mock
     public MediaBrowserCompat mMediaBrowser;
     @Mock
@@ -88,6 +86,9 @@
     @Captor
     private ArgumentCaptor<MediaControllerCompat.Callback> mCapturedCallback;
 
+    private final MediaSource mMediaSource = newFakeMediaSource("test", "test");
+    private final MediaSource mMediaSource2 = newFakeMediaSource(mMediaController);
+
     private PlaybackViewModel mPlaybackViewModel;
 
     private MutableLiveData<BrowsingState> mBrowsingStateLD;
@@ -249,6 +250,52 @@
         deliverValuesToCallbacks(newCallbackCaptor, newMetadata, newPlaybackState);
     }
 
+    @Test
+    public void testChangeMediaSource_noBrowseService_consistentController() {
+        when(mMediaController.getMediaController()).thenReturn(mMediaController);
+        deliverValuesToCallbacks(mCapturedCallback, mMediaMetadata, mPlaybackState);
+
+        // Create new MediaBrowser, new MediaController and associated callback captor
+        MediaBrowserCompat newMediaBrowser = mock(MediaBrowserCompat.class);
+        MediaControllerCompat newController = mock(MediaControllerCompat.class);
+        mBrowserToController.put(newMediaBrowser, newController);
+
+        ArgumentCaptor<MediaControllerCompat.Callback> newCallbackCaptor =
+                ArgumentCaptor.forClass(MediaControllerCompat.Callback.class);
+        doNothing().when(newController).registerCallback(newCallbackCaptor.capture());
+
+        // Wire up new data for new MediaController
+        MediaMetadataCompat newMetadata = mock(MediaMetadataCompat.class);
+        PlaybackStateCompat newPlaybackState = mock(PlaybackStateCompat.class);
+
+        // Ensure that all values are coming from the correct MediaController.
+        mPlaybackViewModel.getMetadata().observe(mLifecycleOwner, mediaItemMetadata -> {
+            if (mPlaybackViewModel.getMediaMetadata() == newMetadata) {
+                assertThat(mPlaybackViewModel.getMediaController()).isSameInstanceAs(newController);
+            }
+            if (mPlaybackViewModel.getMediaMetadata() == mMediaMetadata) {
+                assertThat(mPlaybackViewModel.getMediaController())
+                    .isSameInstanceAs(mMediaController);
+            }
+        });
+
+        mPlaybackViewModel.getPlaybackStateWrapper().observe(mLifecycleOwner, state -> {
+            if (state == null) return;
+
+            if (state.getStateCompat() == newPlaybackState) {
+                assertThat(mPlaybackViewModel.getMediaController()).isSameInstanceAs(newController);
+            }
+            if (state.getStateCompat() == mPlaybackState) {
+                assertThat(mPlaybackViewModel.getMediaController())
+                    .isSameInstanceAs(mMediaController);
+            }
+        });
+
+        mBrowsingStateLD.setValue(new BrowsingState(
+                mContext, mMediaSource2, null, ConnectionStatus.NONEXISTENT));
+        deliverValuesToCallbacks(newCallbackCaptor, newMetadata, newPlaybackState);
+    }
+
     private void deliverValuesToCallbacks(
             ArgumentCaptor<MediaControllerCompat.Callback> callbackCaptor,
             MediaMetadataCompat metadata,
diff --git a/car-media-common/tests/unittests/src/com/android/car/media/common/source/MediaBrowserConnectorTest.java b/car-media-common/tests/unittests/src/com/android/car/media/common/source/MediaBrowserConnectorTest.java
index 5b9be7d..99b250b 100644
--- a/car-media-common/tests/unittests/src/com/android/car/media/common/source/MediaBrowserConnectorTest.java
+++ b/car-media-common/tests/unittests/src/com/android/car/media/common/source/MediaBrowserConnectorTest.java
@@ -27,6 +27,7 @@
 
 import android.content.Context;
 import android.support.v4.media.MediaBrowserCompat;
+import android.support.v4.media.session.MediaControllerCompat;
 
 import androidx.annotation.NonNull;
 import androidx.test.core.app.ApplicationProvider;
@@ -65,9 +66,12 @@
     public MediaBrowserCompat mMediaBrowser1;
     @Mock
     public MediaBrowserCompat mMediaBrowser2;
+    @Mock
+    public MediaControllerCompat mMediaController;
 
     private final MediaSource mMediaSource1 = newFakeMediaSource("mediaService1", "className1");
     private final MediaSource mMediaSource2 = newFakeMediaSource("mediaService2", "className2");
+    private final MediaSource mMediaSource3 = newFakeMediaSource(mMediaController);
 
     private final Map<MediaSource, MediaBrowserCompat> mBrowsers = new HashMap<>(2);
 
@@ -177,6 +181,14 @@
         assertThat(mBrowsingStateCaptor.getValue().mBrowser).isEqualTo(mMediaBrowser2);
     }
 
+    @Test
+    public void testConnectionCallback_noBrowseTree_returnsNull() {
+        mBrowserConnector.connectTo(mMediaSource3);
+
+        assertThat(mBrowsingStateCaptor.getValue().mConnectionStatus)
+            .isEqualTo(ConnectionStatus.NONEXISTENT);
+    }
+
     private void setConnectionAction(@NonNull Runnable action) {
         doAnswer(invocation -> {
             action.run();
@@ -184,5 +196,4 @@
         }).when(mMediaBrowser1).connect();
     }
 
-
 }
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/Constants.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/Constants.java
index 51cadd2..b50b13d 100644
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/Constants.java
+++ b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/Constants.java
@@ -20,10 +20,9 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.os.Bundle;
-import android.service.media.MediaBrowserService;
 
 import androidx.annotation.RestrictTo;
-import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
+import androidx.media.MediaBrowserServiceCompat;
 
 /** Constants for Analytics Events. */
 public class Constants {
@@ -36,87 +35,60 @@
      * <p>Used by AnalyticsParser
      */
     @RestrictTo(LIBRARY_GROUP)
-    public static final int ANALYTICS_VERSION = 1;
+    public static final int ANALYTICS_VERSION = 2;
 
     /**
-     * Presence of this flag in {@link MediaBrowserService#onGetRoot(String, int, Bundle)} rootHints
-     * {@linkplain Bundle} with a string value indicates an op-in for analytics feature.
-     * <p>
-     * Value of this flag sets {@link android.content.ComponentName} for the analytics broadcast
-     * receiver.
-     * <p>
-     * Absence of flag indicates no opt-in.
-     * <p>
-     * Type: String - component name for analytics broadcast receiver
+     * Presence of this flag in {@link MediaBrowserServiceCompat#onGetRoot(String, int, Bundle)}
+     * rootHints with a value of true indicates opt-in to receive diagnostic analytics.
+     *
+     * <p>Absence of this flag will result in no analytics collected and sent to media application.
+     *
+     * <p>Type: Boolean - Boolean value of true opts-in to feature.
      *
      * @see Constants#ANALYTICS_SHARE_PLATFORM_DIAGNOSTICS
      * @see Constants#ANALYTICS_SHARE_OEM_DIAGNOSTICS
      */
     @RestrictTo(LIBRARY)
-    public static final String ANALYTICS_ROOT_KEY_BROADCAST_COMPONENT_NAME =
-            "androidx.car.app.mediaextension.analytics.broadcastcomponentname";
+    public static final String ANALYTICS_ROOT_KEY_OPT_IN =
+            "androidx.car.app.mediaextensions.analytics.optin";
 
     /**
-     * Passkey used to verify analytics broadcast is sent from an approved host. Handled by
-     * AnalyticsManager and
-     * {@link androidx.car.app.mediaextensions.analytics.client.RootHintsUtil}
-     *
-     * <p>Type: String - String value of passkey. E.g. a new UUID
-     */
-    @RestrictTo(LIBRARY)
-    public static final String ANALYTICS_ROOT_KEY_PASSKEY =
-            "androidx.car.app.mediaextensions.analytics.broadcastpasskey";
-
-    /**
-     * Session key used to identify which session generated the analytics event.
-     *
-     * <p>
-     *     Include this key in {@link MediaBrowserService#onGetRoot(String, int, Bundle)} rootHints.
-     *     Analytics broadcasts will include this key in {@link AnalyticsEvent#getSessionId()}.
-     *
-     * <p>Type: Integer - Integer value of session.
-     */
-    @RestrictTo(LIBRARY)
-    public static final String ANALYTICS_ROOT_KEY_SESSION_ID =
-            "androidx.car.app.mediaextensions.analytics.sessionid";
-
-    /**
-     * Presence of this flag in {@link MediaBrowserService#onGetRoot(String, int, Bundle)}
+     * Presence of this flag in {@link MediaBrowserServiceCompat#onGetRoot(String, int, Bundle)}
      * rootHints with a value of true indicates opt-in to share diagnostic analytics to platform.
      *
      * <p>Absence of this flag will result in no analytics collected and sent to platform.
      *
-     * @see Constants#ANALYTICS_ROOT_KEY_BROADCAST_COMPONENT_NAME
-     * @see Constants#ANALYTICS_SHARE_OEM_DIAGNOSTICS
-     *
      * <p>Type: Boolean - Boolean value of true opts-in to feature.
+     *
+     * @see Constants#ANALYTICS_SHARE_OEM_DIAGNOSTICS
+     * @see Constants#ANALYTICS_ROOT_KEY_OPT_IN
      */
     @RestrictTo(LIBRARY)
     public static final String ANALYTICS_SHARE_PLATFORM_DIAGNOSTICS =
             "androidx.car.app.mediaextensions.analytics.shareplatformdiagnostics";
 
     /**
-     * Presence of this flag in {@link MediaBrowserService#onGetRoot(String, int, Bundle)}
+     * Presence of this flag in {@link MediaBrowserServiceCompat#onGetRoot(String, int, Bundle)}
      * rootHints with a value of true indicates opt-in to share diagnostic analytics to OEM.
      *
      * <p>Absence of this flag will result in no analytics collected and sent to OEM.
      *
-     * <p>
+     * <p>Type: Boolean - Boolean value of true opts-in to feature.
      *
-     * @see Constants#ANALYTICS_ROOT_KEY_BROADCAST_COMPONENT_NAME
      * @see Constants#ANALYTICS_SHARE_PLATFORM_DIAGNOSTICS
-     *     <p>Type: Boolean - Boolean value of true opts-in to feature.
+     * @see Constants#ANALYTICS_ROOT_KEY_OPT_IN
      */
     @RestrictTo(LIBRARY)
     public static final String ANALYTICS_SHARE_OEM_DIAGNOSTICS =
             "androidx.car.app.mediaextensions.analytics.shareoemdiagnostics";
 
     /**
-     * Broadcast Receiver intent action for analytics broadcast receiver.
+     * Custom action for analytic events.
      *
-     * <p>Use the value of this string for the intent filter of analytics broadcast receivers.
+     * <p>Type: String - String value that indicates analytics event custom action.
      *
-     * <p>Type: String - String value that indicates analytics event action.
+     * @see
+     * MediaBrowserServiceCompat#onCustomAction(String, Bundle, MediaBrowserServiceCompat.Result)
      */
     public static final String ACTION_ANALYTICS =
             "androidx.car.app.mediaextensions.analytics.action.ANALYTICS";
@@ -125,9 +97,6 @@
     public static final String ANALYTICS_EVENT_BUNDLE_ARRAY_KEY =
             "androidx.car.app.mediaextensions.analytics.bundlearraykey";
     @RestrictTo(LIBRARY)
-    public static final String ANALYTICS_BUNDLE_KEY_PASSKEY =
-            "androidx.car.app.mediaextensions.analytics.passkey";
-    @RestrictTo(LIBRARY)
     public static final String ANALYTICS_EVENT_MEDIA_CLICKED =
             "androidx.car.app.mediaextensions.analytics.mediaClicked";
     @RestrictTo(LIBRARY)
@@ -152,9 +121,6 @@
     public static final String ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID =
             "androidx.car.app.mediaextensions.analytics.componentid";
     @RestrictTo(LIBRARY)
-    public static final String ANALYTICS_EVENT_DATA_KEY_SESSION_ID =
-            "androidx.car.app.mediaextensions.analytics.sessionID";
-    @RestrictTo(LIBRARY)
     public static final String ANALYTICS_EVENT_DATA_KEY_MEDIA_ID =
             "androidx.car.app.mediaextensions.analytics.mediaId";
     @RestrictTo(LIBRARY)
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/AnalyticsBroadcastReceiver.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/AnalyticsBroadcastReceiver.java
deleted file mode 100644
index 372cff2..0000000
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/AnalyticsBroadcastReceiver.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2023 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 androidx.car.app.mediaextensions.analytics.client;
-
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_BUNDLE_KEY_PASSKEY;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Looper;
-import android.util.Log;
-
-import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
-import androidx.car.app.annotations2.ExperimentalCarApi;
-import androidx.car.app.mediaextensions.analytics.Constants;
-import androidx.car.app.mediaextensions.analytics.ThreadUtils;
-import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
-
-import java.util.Objects;
-import java.util.UUID;
-import java.util.concurrent.Executor;
-
-/**
- * BroadcastReceiver that parses {@link AnalyticsEvent} from intent and hands off to
- * {@link AnalyticsCallback} .
- *
- * <p>
- *     Extend and add to manifest with {@link Constants#ACTION_ANALYTICS}.
- *
- * <p>
- *     Add analytics opt-in and sessionId to rootHints with
- *     {@link RootHintsUtil.RootHintsPopulator}
- */
-@ExperimentalCarApi
-public abstract class AnalyticsBroadcastReceiver extends BroadcastReceiver {
-    private static final String TAG = "AnalyticsBroadcastRcvr";
-    static final UUID sAuthKey = UUID.randomUUID();
-
-    private final AnalyticsCallback mAnalyticsCallback;
-    private final Executor mExecutor;
-
-    /**
-     * BroadcastReceiver used to receive analytic events.
-     * <p>
-     * Note that the callback will be executed on the main thread using
-     * {@link Looper#getMainLooper()}. To specify the execution thread, use
-     * {@link #AnalyticsBroadcastReceiver(Executor, AnalyticsCallback)}.
-     *
-     * @param analyticsCallback Callback for {@link AnalyticsEvent AnalyticEvents} handled on
-     *                          main thread.
-     */
-    @MainThread
-    public AnalyticsBroadcastReceiver(@NonNull AnalyticsCallback analyticsCallback) {
-        super();
-        this.mExecutor = ThreadUtils.getMainThreadExecutor();
-        this.mAnalyticsCallback = analyticsCallback;
-    }
-
-    /**
-     * BroadcastReceiver used to receive analytic events.
-     *
-     * @param executor executor used in calling callback.
-     * @param analyticsCallback Callback for {@link AnalyticsEvent AnalyticEvents} handled on
-     *                          main thread.
-     */
-    public AnalyticsBroadcastReceiver(@NonNull Executor executor,
-            @NonNull AnalyticsCallback analyticsCallback) {
-        super();
-        this.mExecutor = executor;
-        this.mAnalyticsCallback = analyticsCallback;
-    }
-
-    /**
-     * Receives intent with analytic events packed in arraylist of bundles.
-     * <p>
-     * Parses and sends to {@link AnalyticsCallback} with the result on main thread.
-     * <p>
-     * @param context The Context in which the receiver is running.
-     * @param intent The Intent being received.
-     */
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (intent.getExtras() != null && isValid(sAuthKey.toString(), intent.getExtras())) {
-            AnalyticsParser.parseAnalyticsIntent(intent, mExecutor, mAnalyticsCallback);
-        } else {
-            Log.w(TAG, "Invalid analytics auth key, ignoring analytics event!");
-        }
-    }
-
-    /**
-     * Checks if passkey in {@link AnalyticsEvent analyticsEvent} bundle is same passkey as
-     * {@link AnalyticsBroadcastReceiver#sAuthKey}.
-     */
-    private boolean isValid(@NonNull String receiverPassKey,
-            @NonNull Bundle bactchBundle) {
-        String bundlePassKey = bactchBundle.getString(ANALYTICS_BUNDLE_KEY_PASSKEY);
-        return bundlePassKey != null && Objects.equals(receiverPassKey, bundlePassKey);
-    }
-}
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/AnalyticsParser.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/AnalyticsParser.java
index fa09c55..8811fb4 100644
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/AnalyticsParser.java
+++ b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/AnalyticsParser.java
@@ -24,19 +24,23 @@
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_VIEW_CHANGE;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_VISIBLE_ITEMS;
 
-import android.content.Intent;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.car.app.annotations2.ExperimentalCarApi;
+import androidx.car.app.mediaextensions.analytics.Constants;
+import androidx.car.app.mediaextensions.analytics.ThreadUtils;
 import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
 import androidx.car.app.mediaextensions.analytics.event.BrowseChangeEvent;
 import androidx.car.app.mediaextensions.analytics.event.ErrorEvent;
 import androidx.car.app.mediaextensions.analytics.event.MediaClickedEvent;
 import androidx.car.app.mediaextensions.analytics.event.ViewChangeEvent;
 import androidx.car.app.mediaextensions.analytics.event.VisibleItemsEvent;
+import androidx.media.MediaBrowserServiceCompat;
 
 import java.util.ArrayList;
 import java.util.concurrent.Executor;
@@ -50,29 +54,79 @@
     private AnalyticsParser() {}
 
     /**
-     * Parses batch of {@link AnalyticsEvent}s from intent.
+     *
+     * Checks if supplied action is an Analytics action.
+     *
+     * @param action custom action
+     * @return boolean value whether the action is an analytics action.
+     */
+    public static boolean isAnalyticsAction(@NonNull String action) {
+        return Constants.ACTION_ANALYTICS.equalsIgnoreCase(action);
+    }
+
+    /**
+     * Parses a batch of {@link AnalyticsEvent}s from a custom action and extras.
      * <p>
-     *  Deserializes each event in batch and sends to analyticsCallback
+     *  Deserializes each event in batch and sends to analyticsCallback.
      * <p>
      *
-     * @param intent intent with batch of events in extras.
+     * <p>
+     *     Usage: Pass in action string and extras bundle to this method from
+     *     {@link androidx.media.MediaBrowserServiceCompat#onCustomAction(String, Bundle,
+     *     MediaBrowserServiceCompat.Result)}.
+     *     If present, the batch of analytic events will be parsed, deserialized and passed to the
+     *     supplied {@link AnalyticsCallback}.
+     * </p>
+     *
+     * @param action custom action
+     * @param extras custom action extras.
+     * @param analyticsCallback callback for deserialized events.
+     */
+    public static void parseAnalyticsAction(@NonNull String action, @Nullable Bundle extras,
+            @NonNull AnalyticsCallback analyticsCallback) {
+        parseAnalyticsAction(action, extras, ThreadUtils.getMainThreadExecutor(),
+                analyticsCallback);
+    }
+
+    /**
+     * Parses a batch of {@link AnalyticsEvent}s from a custom action and extras.
+     * <p>
+     *  Deserializes each event in batch and sends to analyticsCallback.
+     * <p>
+     *
+     * <p>
+     *     Usage: Pass in action string and extras bundle to this method from
+     *     {@link
+     *     androidx.media.MediaBrowserServiceCompat#onCustomAction(String, Bundle,
+     *     MediaBrowserServiceCompat.Result)}.
+     *     If present, the batch of analytic events will be parsed, deserialized and passed to the
+     *     supplied {@link AnalyticsCallback}.
+     * </p>
+     *
+     * @param action custom action
+     * @param extras custom action extras.
      * @param executor Valid Executor on which callback will be called.
      * @param analyticsCallback callback for deserialized events.
      */
     @SuppressWarnings("deprecation")
-    public static void parseAnalyticsIntent(@NonNull Intent intent, @NonNull Executor executor,
-            @NonNull AnalyticsCallback analyticsCallback) {
-        Bundle intentExtras = intent.getExtras();
+    public static void parseAnalyticsAction(@NonNull String action, @Nullable Bundle extras,
+            @NonNull Executor executor, @NonNull AnalyticsCallback analyticsCallback) {
 
-        if (intentExtras == null || intentExtras.isEmpty()) {
+        if (!action.equals(Constants.ACTION_ANALYTICS)) {
+            analyticsCallback.onErrorEvent(new ErrorEvent(new Bundle(),
+                    ErrorEvent.ERROR_CODE_INVALID_EVENT));
+            return;
+        }
+
+        if (extras == null || extras.isEmpty()) {
             Log.e(TAG, "Analytics event bundle is null or empty.");
             analyticsCallback.onErrorEvent(new ErrorEvent(new Bundle(),
-                    ErrorEvent.ERROR_CODE_INVALID_INTENT));
+                    ErrorEvent.ERROR_CODE_INVALID_EXTRAS));
             return;
         }
 
         ArrayList<Bundle> eventBundles =
-                intentExtras.getParcelableArrayList(ANALYTICS_EVENT_BUNDLE_ARRAY_KEY);
+                extras.getParcelableArrayList(ANALYTICS_EVENT_BUNDLE_ARRAY_KEY);
 
         if (eventBundles == null || eventBundles.isEmpty()) {
             Log.e(TAG, "Analytics event bundle list is empty.");
@@ -82,6 +136,7 @@
         }
 
         for (Bundle bundle : eventBundles) {
+            // TODO(b/322512398): Handle version mismatch
             AnalyticsParser.parseAnalyticsBundle(bundle, executor, analyticsCallback);
         }
     }
@@ -96,6 +151,12 @@
             @NonNull Executor executor, @NonNull AnalyticsCallback analyticsCallback) {
         String eventName = analyticsBundle.getString(ANALYTICS_EVENT_DATA_KEY_EVENT_NAME, "");
 
+        if (TextUtils.isEmpty(eventName)) {
+            executor.execute(() -> analyticsCallback.onErrorEvent(new ErrorEvent(analyticsBundle,
+                    ErrorEvent.ERROR_CODE_INVALID_EVENT)));
+            return;
+        }
+
         executor.execute(() -> createEvent(analyticsCallback, getEventType(eventName),
                 analyticsBundle));
     }
@@ -124,7 +185,8 @@
         }
     }
 
-    private static @AnalyticsEvent.EventType int getEventType(String eventName) {
+    @AnalyticsEvent.EventType
+    private static int getEventType(String eventName) {
         switch (eventName) {
             case ANALYTICS_EVENT_MEDIA_CLICKED:
                 return AnalyticsEvent.EVENT_TYPE_MEDIA_CLICKED_EVENT;
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/RootHintsPopulator.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/RootHintsPopulator.java
index c5f3b52..0d57fea 100644
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/RootHintsPopulator.java
+++ b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/client/RootHintsPopulator.java
@@ -16,20 +16,15 @@
 
 package androidx.car.app.mediaextensions.analytics.client;
 
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_SHARE_PLATFORM_DIAGNOSTICS;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_ROOT_KEY_OPT_IN;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_SHARE_OEM_DIAGNOSTICS;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_ROOT_KEY_BROADCAST_COMPONENT_NAME;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_ROOT_KEY_PASSKEY;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_ROOT_KEY_SESSION_ID;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_SHARE_PLATFORM_DIAGNOSTICS;
 
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.os.Bundle;
 import android.support.v4.media.session.MediaSessionCompat;
 
 import androidx.annotation.NonNull;
 import androidx.car.app.annotations2.ExperimentalCarApi;
-import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
 import androidx.media.MediaBrowserServiceCompat;
 
 /**
@@ -42,7 +37,6 @@
  * {@link MediaSessionCompat#setExtras(Bundle)}.
  *
  * @see MediaBrowserServiceCompat#onGetRoot(String, int, Bundle)
- * @see AnalyticsBroadcastReceiver
  * @see MediaSessionCompat#setExtras(Bundle)
  */
 @ExperimentalCarApi
@@ -54,26 +48,13 @@
     }
 
     /**
-     * Sets analytics opt in and {@link BroadcastReceiver} {@link ComponentName}.
+     * Sets analytics opt in state.
      *
      * @param analyticsOptIn boolean value indicating opt-in to receive analytics.
-     * @param receiverComponentName ComponentName of {@link BroadcastReceiver } that extends
-     * {@link AnalyticsBroadcastReceiver}. This is the receiver that will receive analytics
-     *                              event.
      */
     @NonNull
-    public RootHintsPopulator setAnalyticsOptIn(boolean analyticsOptIn,
-            @NonNull ComponentName receiverComponentName) {
-
-        if (analyticsOptIn) {
-            mRootHintsBundle.putString(ANALYTICS_ROOT_KEY_BROADCAST_COMPONENT_NAME,
-                    receiverComponentName.flattenToString());
-        } else {
-            mRootHintsBundle.putString(ANALYTICS_ROOT_KEY_BROADCAST_COMPONENT_NAME, "");
-        }
-
-        mRootHintsBundle.putString(ANALYTICS_ROOT_KEY_PASSKEY,
-                AnalyticsBroadcastReceiver.sAuthKey.toString());
+    public RootHintsPopulator setAnalyticsOptIn(boolean analyticsOptIn) {
+        mRootHintsBundle.putBoolean(ANALYTICS_ROOT_KEY_OPT_IN, analyticsOptIn);
         return this;
     }
 
@@ -82,7 +63,7 @@
      * @param shareOem boolean value indicating opt-in to share diagnostic analytics with OEM.
      */
     @NonNull
-    public RootHintsPopulator setOemShare(boolean shareOem) {
+    public RootHintsPopulator setShareOem(boolean shareOem) {
         mRootHintsBundle.putBoolean(ANALYTICS_SHARE_OEM_DIAGNOSTICS, shareOem);
         return this;
     }
@@ -93,21 +74,8 @@
      *                      the platform.
      */
     @NonNull
-    public RootHintsPopulator setPlatformShare(boolean sharePlatform) {
+    public RootHintsPopulator setSharePlatform(boolean sharePlatform) {
         mRootHintsBundle.putBoolean(ANALYTICS_SHARE_PLATFORM_DIAGNOSTICS, sharePlatform);
         return this;
     }
-
-    /**
-     * Sets sessionId. Session Id will set in each {@link AnalyticsEvent#getSessionId()}.
-     * <p>
-     *     Use this identify which session is generating {@link AnalyticsEvent events}.
-     * </p>
-     * @param sessionId Session Id used to identify which session generated event.
-     */
-    @NonNull
-    public RootHintsPopulator setSessionId(int sessionId) {
-        mRootHintsBundle.putInt(ANALYTICS_ROOT_KEY_SESSION_ID, sessionId);
-        return this;
-    }
 }
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/AnalyticsEvent.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/AnalyticsEvent.java
index 14fb61e..f00ac8b 100644
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/AnalyticsEvent.java
+++ b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/AnalyticsEvent.java
@@ -18,7 +18,6 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_SESSION_ID;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_TIMESTAMP;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VERSION;
 
@@ -29,7 +28,6 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
-import androidx.car.app.mediaextensions.analytics.client.RootHintsPopulator;
 
 import java.lang.annotation.Retention;
 
@@ -120,7 +118,6 @@
     public @interface EventType {}
 
     private final int mAnalyticsVersion;
-    private final int mSessionId;
     private final @EventType int mEventType;
     private final long mTimeStampMillis;
     private final String mComponent;
@@ -128,7 +125,6 @@
     @RestrictTo(LIBRARY)
     public AnalyticsEvent(@NonNull Bundle eventBundle, @EventType int eventType) {
         mAnalyticsVersion = eventBundle.getInt(ANALYTICS_EVENT_DATA_KEY_VERSION, -1);
-        mSessionId = eventBundle.getInt(ANALYTICS_EVENT_DATA_KEY_SESSION_ID, 0);
         mTimeStampMillis = eventBundle.getLong(ANALYTICS_EVENT_DATA_KEY_TIMESTAMP, -1);
         mComponent = eventBundle.getString(ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID, "");
         mEventType = eventType;
@@ -163,20 +159,11 @@
         return mComponent;
     }
 
-    /**
-     * Returns session Id set in
-     * {@link RootHintsPopulator#setSessionId(int)}
-     */
-    public int getSessionId() {
-        return mSessionId;
-    }
-
     @NonNull
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("AnalyticsEvent{");
         sb.append("mAnalyticsVersion=").append(mAnalyticsVersion);
-        sb.append(", mSessionId='").append(mSessionId).append('\'');
         sb.append(", mEventType=").append(mEventType);
         sb.append(", mTime=").append(mTimeStampMillis);
         sb.append(", mComponent='").append(mComponent).append('\'');
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/ErrorEvent.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/ErrorEvent.java
index e4640f4..eb6709a 100644
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/ErrorEvent.java
+++ b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/event/ErrorEvent.java
@@ -34,14 +34,16 @@
 public class ErrorEvent extends AnalyticsEvent{
 
     /** Indicates an invalid intent*/
-    public static final int ERROR_CODE_INVALID_INTENT = 0;
+    public static final int ERROR_CODE_INVALID_EXTRAS = 0;
     /** Indicates an invalid bundle*/
     public static final int ERROR_CODE_INVALID_BUNDLE = 1;
+    /** Indicates invalid event */
+    public static final int ERROR_CODE_INVALID_EVENT = 2;
 
     @Retention(SOURCE)
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @IntDef (
-            value = {ERROR_CODE_INVALID_INTENT, ERROR_CODE_INVALID_BUNDLE}
+            value = {ERROR_CODE_INVALID_EXTRAS, ERROR_CODE_INVALID_BUNDLE, ERROR_CODE_INVALID_EVENT}
     )
     public @interface ErrorCode {}
 
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsEventFactory.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsEventFactory.java
index 96dd53d..f75f570 100644
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsEventFactory.java
+++ b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsEventFactory.java
@@ -23,7 +23,6 @@
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_ITEM_IDS;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_MEDIA_ID;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_PARENT_NODE_ID;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_SESSION_ID;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_TIMESTAMP;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VERSION;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION;
@@ -40,7 +39,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
-
 import androidx.car.app.annotations2.ExperimentalCarApi;
 import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
 import androidx.car.app.mediaextensions.analytics.event.BrowseChangeEvent;
@@ -58,12 +56,11 @@
     @NonNull private final Bundle mBaseBundle;
     @NonNull private Bundle mBundle;
 
-    AnalyticsEventFactory(@NonNull Context context, int sessionId) {
+    AnalyticsEventFactory(@NonNull Context context) {
         mBaseBundle = new Bundle();
         mBundle = new Bundle();
         mBaseBundle.putString(ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID,
                 context.getApplicationContext().getPackageName());
-        mBaseBundle.putInt(ANALYTICS_EVENT_DATA_KEY_SESSION_ID, sessionId);
     }
     /**
      * Create BrowseChangeEvent
diff --git a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsManager.java b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsManager.java
index c39f8ec..ed1681e 100644
--- a/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsManager.java
+++ b/car-media-extensions/src/androidx/car/app/mediaextensions/analytics/host/AnalyticsManager.java
@@ -16,24 +16,22 @@
 package androidx.car.app.mediaextensions.analytics.host;
 
 import static androidx.car.app.mediaextensions.analytics.Constants.ACTION_ANALYTICS;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_BUNDLE_KEY_PASSKEY;
 import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_BUNDLE_ARRAY_KEY;
 
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.support.v4.media.MediaBrowserCompat;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-
 import androidx.car.app.annotations2.ExperimentalCarApi;
 import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
 import androidx.car.app.mediaextensions.analytics.event.BrowseChangeEvent;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -53,30 +51,24 @@
     /** We don't want to come to close to binder buffer limit, so we limit queue. */
     private final int mEventBufferSize;
     private final AnalyticsEventFactory mAnalyticsFactory;
-    private final String mReceiverComponent;
-    private final Context mContext;
-    private final String mPassKey;
+    private final WeakReference<MediaBrowserCompat> mBrowser;
+    private final String mBrowserComponentString;
 
     /**
      *
      * @param context Context used to send analytics broadcast intent
-     * @param receiverComponent BroadcastReceiver ComponentName flattened to string
-     * @param passKey Same key handed to {@link RootHintsUtil} to auth sent analytics,
-     * {@link androidx.car.app.mediaextensions.analytics.client.AnalyticsBroadcastReceiver#sAuthKey}
-     * @param sessionId Handed to {@link RootHintsUtil} to map sessions for 3P app.
      * @param batchInterval How long to listen for events before sending a batch of events
      * @param batchSize How many events to batch before sending a batch, interval or size,
      *                  whichever happens first.
      */
-    public AnalyticsManager(@NonNull Context context, @NonNull String receiverComponent,
-            @NonNull String passKey, int sessionId, int batchInterval, int batchSize) {
+    public AnalyticsManager(@NonNull Context context, @NonNull MediaBrowserCompat browser,
+            int batchInterval, int batchSize) {
         mHandler = new Handler(Looper.myLooper());
         mBatchInterval = batchInterval;
         mEventBufferSize = batchSize;
-        mReceiverComponent = receiverComponent;
-        mAnalyticsFactory =  new AnalyticsEventFactory(context, sessionId);
-        mContext = context;
-        mPassKey = passKey;
+        mBrowser = new WeakReference<>(browser);
+        mBrowserComponentString = browser.getServiceComponent().flattenToString();
+        mAnalyticsFactory =  new AnalyticsEventFactory(context);
     }
 
     /**
@@ -90,10 +82,10 @@
             mHandler.postDelayed(this::sendAllBatches, mBatchInterval);
         }
 
-        Queue<Bundle> queue = sPackageEventQueueMap.get(mReceiverComponent);
+        Queue<Bundle> queue = sPackageEventQueueMap.get(mBrowserComponentString);
         if (queue == null) {
             queue = new ArrayDeque<>(mEventBufferSize);
-            sPackageEventQueueMap.put(mReceiverComponent, queue);
+            sPackageEventQueueMap.put(mBrowserComponentString, queue);
         }
         queue.add(eventBundle);
 
@@ -123,25 +115,25 @@
     }
 
     private void sendBatch(@NonNull Queue<Bundle> eventQueue) {
-        Intent eventIntent = new Intent(ACTION_ANALYTICS);
-        eventIntent.setComponent(ComponentName.unflattenFromString(mReceiverComponent));
-
+        //Get the browser service with mMediaAppComponent
+        MediaBrowserCompat browser = mBrowser.get();
+        if (browser == null || !browser.isConnected()){
+            Log.w(TAG, "sendBatch failed, browser null or not connected.");
+            return;
+        }
         Bundle eventBatchBundle = createBatch(new ArrayList<>(eventQueue));
-
-        eventIntent.putExtras(eventBatchBundle);
-        mContext.sendBroadcast(eventIntent);
+        browser.sendCustomAction(ACTION_ANALYTICS, eventBatchBundle, null);
     }
 
     /**
      * Packs an arrayList of AnalyticsEvent into a bundle.
      *
-     * @param eventBundleList
+     * @param eventBundleList list of events each packed into a separate bundle.
      * @return bundle with list of events packed
      */
     private Bundle createBatch(@NonNull ArrayList<Bundle> eventBundleList) {
         Bundle batchBundle = new Bundle();
         batchBundle.putParcelableArrayList(ANALYTICS_EVENT_BUNDLE_ARRAY_KEY, eventBundleList);
-        batchBundle.putString(ANALYTICS_BUNDLE_KEY_PASSKEY, mPassKey);
         return batchBundle;
     }
 
diff --git a/car-media-extensions/tests/src/androidx/car/app/mediaextensions/analytics/AnalyticsParserTest.java b/car-media-extensions/tests/src/androidx/car/app/mediaextensions/analytics/AnalyticsParserTest.java
new file mode 100644
index 0000000..79b582f
--- /dev/null
+++ b/car-media-extensions/tests/src/androidx/car/app/mediaextensions/analytics/AnalyticsParserTest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2023 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 androidx.car.app.mediaextensions.analytics;
+
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_BROWSE_NODE_CHANGE;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_BUNDLE_ARRAY_KEY;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_EVENT_NAME;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_ITEM_IDS;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_MEDIA_ID;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_TIMESTAMP;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VERSION;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VIEW_COMPONENT;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_MEDIA_CLICKED;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_VIEW_CHANGE;
+import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_VISIBLE_ITEMS;
+import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.ComponentName;
+import android.os.Bundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import androidx.car.app.mediaextensions.analytics.client.AnalyticsCallback;
+import androidx.car.app.mediaextensions.analytics.client.AnalyticsParser;
+import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
+import androidx.car.app.mediaextensions.analytics.event.BrowseChangeEvent;
+import androidx.car.app.mediaextensions.analytics.event.ErrorEvent;
+import androidx.car.app.mediaextensions.analytics.event.MediaClickedEvent;
+import androidx.car.app.mediaextensions.analytics.event.ViewChangeEvent;
+import androidx.car.app.mediaextensions.analytics.event.VisibleItemsEvent;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class AnalyticsParserTest {
+    @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    AnalyticsCallback mAnalyticsCallback;
+
+    @Captor ArgumentCaptor<AnalyticsEvent> mEventArgCaptor;
+
+    private final Executor mExecutor = Runnable::run;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void isAnalyticsActionTest() {
+        String action = "incorrect";
+        boolean isAnalyticsAction = AnalyticsParser.isAnalyticsAction(action);
+        assertFalse(isAnalyticsAction);
+
+        action = Constants.ACTION_ANALYTICS;
+        isAnalyticsAction = AnalyticsParser.isAnalyticsAction(action);
+        assertTrue(isAnalyticsAction);
+    }
+
+
+    @Test
+    public void parserCallbackAction() throws InterruptedException {
+        Bundle bundle1 = createTestBundle(ANALYTICS_EVENT_MEDIA_CLICKED);
+        String mediaID = "test_media_id_1";
+        bundle1.putString(ANALYTICS_EVENT_DATA_KEY_MEDIA_ID, mediaID);
+
+        Bundle bundle2 = createTestBundle(ANALYTICS_EVENT_VIEW_CHANGE);
+        int viewID = VIEW_COMPONENT_BROWSE_LIST;
+        bundle2.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_COMPONENT, viewID);
+
+        Bundle list = new Bundle();
+        list.putParcelableArrayList(ANALYTICS_EVENT_BUNDLE_ARRAY_KEY,
+                Lists.newArrayList(bundle1, bundle2));
+
+        AnalyticsParser.parseAnalyticsAction(Constants.ACTION_ANALYTICS, list,
+                mExecutor, mAnalyticsCallback);
+
+        verify(mAnalyticsCallback).onMediaClickedEvent(
+                (MediaClickedEvent) mEventArgCaptor.capture());
+        verify(mAnalyticsCallback).onViewChangeEvent(
+                (ViewChangeEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+
+        List<AnalyticsEvent> events = mEventArgCaptor.getAllValues();
+
+        MediaClickedEvent clickEvent = (MediaClickedEvent) events.get(0);
+        ViewChangeEvent viewEvent = (ViewChangeEvent) events.get(1);
+
+        assertEquals(mediaID, clickEvent.getMediaId());
+        assertEquals(viewID, viewEvent.getViewComponent());
+    }
+
+    @Test
+    public void parserCallbackTimeComponentTest() throws InterruptedException {
+        Bundle bundle = createTestBundle(ANALYTICS_EVENT_MEDIA_CLICKED);
+        String mediaID = "test_media_id_1";
+        bundle.putString(ANALYTICS_EVENT_DATA_KEY_MEDIA_ID, mediaID);
+        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback).onMediaClickedEvent(
+                (MediaClickedEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertNotNull(mEventArgCaptor.getValue());
+        AnalyticsEvent event = mEventArgCaptor.getValue();
+        ComponentName componentName =
+                new ComponentName(
+                        AnalyticsParserTest.class.getPackage().toString(),
+                        AnalyticsParserTest.class.getName());
+        assertEquals(componentName.flattenToString(), event.getComponent());
+        assertTrue(event.getTimestampMillis() > 0);
+        assertTrue(event.getAnalyticsVersion() > 0);
+    }
+
+    @Test
+    public void parserCallbackMediaClickedTest() {
+        Bundle bundle = createTestBundle(ANALYTICS_EVENT_MEDIA_CLICKED);
+        String mediaID = "test_media_id_1";
+        bundle.putString(ANALYTICS_EVENT_DATA_KEY_MEDIA_ID, mediaID);
+        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onMediaClickedEvent((MediaClickedEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof MediaClickedEvent);
+        MediaClickedEvent event = (MediaClickedEvent) mEventArgCaptor.getValue();
+        String eventMediaId = event.getMediaId();
+        assertEquals(eventMediaId, mediaID);
+    }
+
+    @Test
+    public void parserCallbackVisibleItemsTest() {
+        Bundle bundle = createTestBundle(ANALYTICS_EVENT_VISIBLE_ITEMS);
+        List<String> visibleItems = Arrays.asList("test_media_id_1", "test_media_id_2",
+                "test_media_id_3");
+        bundle.putStringArrayList(ANALYTICS_EVENT_DATA_KEY_ITEM_IDS,
+                new ArrayList<>(visibleItems));
+        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onVisibleItemsEvent((VisibleItemsEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof VisibleItemsEvent);
+        VisibleItemsEvent event = (VisibleItemsEvent) mEventArgCaptor.getValue();
+        List<String> eventVisibleItems = event.getItemsIds();
+        assertArrayEquals(eventVisibleItems.toArray(), visibleItems.toArray());
+    }
+
+    @Test
+    public void parserCallbackBrowseNodeChangeTest() {
+        Bundle bundle = createTestBundle(ANALYTICS_EVENT_BROWSE_NODE_CHANGE);
+        String node = "test_media_id_1";
+        int action = 1;
+        bundle.putString(ANALYTICS_EVENT_DATA_KEY_MEDIA_ID, node);
+        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION, action);
+        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onBrowseNodeChangeEvent((BrowseChangeEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof BrowseChangeEvent);
+        BrowseChangeEvent event = (BrowseChangeEvent) mEventArgCaptor.getValue();
+        String eventBrowseNew = event.getBrowseNodeId();
+        int eventAction = event.getViewAction();
+        assertEquals(eventAction, action);
+        assertEquals(eventBrowseNew, node);
+    }
+
+    @Test
+    public void parserCallbackViewEntryTest() {
+        Bundle bundle = createTestBundle(ANALYTICS_EVENT_VIEW_CHANGE);
+        int viewComponent = VIEW_COMPONENT_BROWSE_LIST;
+        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_COMPONENT, viewComponent);
+        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION, ViewChangeEvent.VIEW_ACTION_SHOW);
+        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onViewChangeEvent((ViewChangeEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof ViewChangeEvent);
+        ViewChangeEvent event = (ViewChangeEvent) mEventArgCaptor.getValue();
+        int eventViewType = event.getViewComponent();
+        assertEquals(eventViewType, viewComponent);
+        int type = event.getViewAction();
+        assertEquals(type, ViewChangeEvent.VIEW_ACTION_SHOW);
+    }
+
+    @Test
+    public void parserCallbackViewExitTest() {
+        Bundle bundle = createTestBundle(ANALYTICS_EVENT_VIEW_CHANGE);
+        int viewComponent = VIEW_COMPONENT_BROWSE_LIST;
+        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_COMPONENT, viewComponent);
+        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION, ViewChangeEvent.VIEW_ACTION_HIDE);
+        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onViewChangeEvent((ViewChangeEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof ViewChangeEvent);
+        ViewChangeEvent event = (ViewChangeEvent) mEventArgCaptor.getValue();
+        int eventViewType = event.getViewComponent();
+        assertEquals(eventViewType, viewComponent);
+        int type = event.getViewAction();
+        assertEquals(type, ViewChangeEvent.VIEW_ACTION_HIDE);
+    }
+
+    @Test
+    public void parserCallbackErrorEmptyBundleTest() {
+        AnalyticsParser.parseAnalyticsBundle(new Bundle(), mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onErrorEvent((ErrorEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof ErrorEvent);
+        ErrorEvent event = (ErrorEvent) mEventArgCaptor.getValue();
+        int errorCode = event.getErrorCode();
+        assertEquals(errorCode, ErrorEvent.ERROR_CODE_INVALID_EVENT);
+        int type = event.getEventType();
+        assertEquals(type, AnalyticsEvent.EVENT_TYPE_ERROR_EVENT);
+    }
+
+    @Test
+    public void parserCallbackErrorInvalidActionTest() {
+        AnalyticsParser.parseAnalyticsAction("bad_action",
+                createTestBundle(ANALYTICS_EVENT_VIEW_CHANGE),
+                mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onErrorEvent((ErrorEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof ErrorEvent);
+        ErrorEvent event = (ErrorEvent) mEventArgCaptor.getValue();
+        int errorCode = event.getErrorCode();
+        assertEquals(errorCode, ErrorEvent.ERROR_CODE_INVALID_EVENT);
+        int type = event.getEventType();
+        assertEquals(type, AnalyticsEvent.EVENT_TYPE_ERROR_EVENT);
+    }
+
+    @Test
+    public void parserCallbackErrorInvalidExtrasTest() {
+        AnalyticsParser.parseAnalyticsAction(Constants.ACTION_ANALYTICS,
+                new Bundle(), mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onErrorEvent((ErrorEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof ErrorEvent);
+        ErrorEvent event = (ErrorEvent) mEventArgCaptor.getValue();
+        int errorCode = event.getErrorCode();
+        assertEquals(errorCode, ErrorEvent.ERROR_CODE_INVALID_EXTRAS);
+        int type = event.getEventType();
+        assertEquals(type, AnalyticsEvent.EVENT_TYPE_ERROR_EVENT);
+    }
+
+    @Test
+    public void parserCallbackErrorInvalidEventNameTest() {
+        Bundle eventBundle = createTestBundle("");
+        AnalyticsParser.parseAnalyticsBundle(eventBundle, mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onErrorEvent((ErrorEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof ErrorEvent);
+        ErrorEvent event = (ErrorEvent) mEventArgCaptor.getValue();
+        int errorCode = event.getErrorCode();
+        assertEquals(errorCode, ErrorEvent.ERROR_CODE_INVALID_EVENT);
+        int type = event.getEventType();
+        assertEquals(type, AnalyticsEvent.EVENT_TYPE_ERROR_EVENT);
+    }
+
+    @Test
+    public void parserCallbackErrorInvalidBundlesTest() {
+        AnalyticsParser.parseAnalyticsAction(Constants.ACTION_ANALYTICS,
+                createTestBundle(ANALYTICS_EVENT_VIEW_CHANGE), mExecutor, mAnalyticsCallback);
+        verify(mAnalyticsCallback)
+                .onErrorEvent((ErrorEvent) mEventArgCaptor.capture());
+        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
+        assertTrue(mEventArgCaptor.getValue() instanceof ErrorEvent);
+        ErrorEvent event = (ErrorEvent) mEventArgCaptor.getValue();
+        int errorCode = event.getErrorCode();
+        assertEquals(ErrorEvent.ERROR_CODE_INVALID_BUNDLE, errorCode);
+        int type = event.getEventType();
+        assertEquals(AnalyticsEvent.EVENT_TYPE_ERROR_EVENT, type);
+    }
+
+    private Bundle createTestBundle(String eventName) {
+        Bundle bundle = new Bundle();
+        bundle.putString(ANALYTICS_EVENT_DATA_KEY_EVENT_NAME, eventName);
+        bundle.putLong(ANALYTICS_EVENT_DATA_KEY_TIMESTAMP, System.currentTimeMillis());
+        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VERSION, 1);
+        ComponentName componentName =
+                new ComponentName(
+                        AnalyticsParserTest.class.getPackage().toString(),
+                        AnalyticsParserTest.class.getName());
+        bundle.putString(
+                ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID, componentName.flattenToString());
+        return bundle;
+    }
+}
diff --git a/car-media-extensions/tests/src/androidx/car/app/mediaextensions/analytics/AnalyticsParserTests.java b/car-media-extensions/tests/src/androidx/car/app/mediaextensions/analytics/AnalyticsParserTests.java
deleted file mode 100644
index 6b46485..0000000
--- a/car-media-extensions/tests/src/androidx/car/app/mediaextensions/analytics/AnalyticsParserTests.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2023 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  androidx.car.app.mediaextensions.analytics;
-
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_BROWSE_NODE_CHANGE;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_EVENT_NAME;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_ITEM_IDS;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_MEDIA_ID;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_TIMESTAMP;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VERSION;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_DATA_KEY_VIEW_COMPONENT;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_MEDIA_CLICKED;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_VIEW_CHANGE;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_EVENT_VISIBLE_ITEMS;
-import static androidx.car.app.mediaextensions.analytics.Constants.ANALYTICS_ROOT_KEY_PASSKEY;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.content.ComponentName;
-import android.os.Bundle;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import androidx.car.app.mediaextensions.analytics.client.AnalyticsCallback;
-import androidx.car.app.mediaextensions.analytics.client.AnalyticsParser;
-import androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent;
-import androidx.car.app.mediaextensions.analytics.event.BrowseChangeEvent;
-import androidx.car.app.mediaextensions.analytics.event.MediaClickedEvent;
-import androidx.car.app.mediaextensions.analytics.event.ViewChangeEvent;
-import androidx.car.app.mediaextensions.analytics.event.VisibleItemsEvent;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.Executor;
-
-@RunWith(AndroidJUnit4.class)
-public class AnalyticsParserTests {
-    @Rule public final MockitoRule mockito = MockitoJUnit.rule();
-
-    @Mock
-    AnalyticsCallback mAnalyticsCallback;
-
-    @Captor ArgumentCaptor<AnalyticsEvent> mEventArgCaptor;
-
-    @Captor ArgumentCaptor<Integer> mErrorArgCaptor;
-
-    private final UUID mPassKey = UUID.randomUUID();
-
-    private final Executor mExecutor = Runnable::run;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-    }
-
-    @Test
-    public void parserCallbackTimeComponentTest() {
-        Bundle bundle = createTestBundle(ANALYTICS_EVENT_MEDIA_CLICKED);
-        String mediaID = "test_media_id_1";
-        bundle.putString(ANALYTICS_EVENT_DATA_KEY_MEDIA_ID, mediaID);
-        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
-        verify(mAnalyticsCallback).onMediaClickedEvent(
-                (MediaClickedEvent) mEventArgCaptor.capture());
-        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
-        assertNotNull(mEventArgCaptor.getValue());
-        AnalyticsEvent event = mEventArgCaptor.getValue();
-        ComponentName componentName =
-                new ComponentName(
-                        AnalyticsParserTests.class.getPackage().toString(),
-                        AnalyticsParserTests.class.getName());
-        assertEquals(componentName.flattenToString(), event.getComponent());
-        assertTrue(event.getTimestampMillis() > 0);
-        assertTrue(event.getAnalyticsVersion() > 0);
-    }
-
-    @Test
-    public void parserCallbackMediaClickedTest() {
-        Bundle bundle = createTestBundle(ANALYTICS_EVENT_MEDIA_CLICKED);
-        String mediaID = "test_media_id_1";
-        bundle.putString(ANALYTICS_EVENT_DATA_KEY_MEDIA_ID, mediaID);
-        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
-        verify(mAnalyticsCallback)
-                .onMediaClickedEvent((MediaClickedEvent) mEventArgCaptor.capture());
-        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
-        assertTrue(mEventArgCaptor.getValue() instanceof MediaClickedEvent);
-        MediaClickedEvent event = (MediaClickedEvent) mEventArgCaptor.getValue();
-        String eventMediaId = event.getMediaId();
-        assertEquals(eventMediaId, mediaID);
-    }
-
-    @Test
-    public void parserCallbackVisibleItemsTest() {
-        Bundle bundle = createTestBundle(ANALYTICS_EVENT_VISIBLE_ITEMS);
-        List<String> visibleItems = Arrays.asList("test_media_id_1", "test_media_id_2",
-                "test_media_id_3");
-        bundle.putStringArrayList(ANALYTICS_EVENT_DATA_KEY_ITEM_IDS,
-                new ArrayList<>(visibleItems));
-        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
-        verify(mAnalyticsCallback)
-                .onVisibleItemsEvent((VisibleItemsEvent) mEventArgCaptor.capture());
-        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
-        assertTrue(mEventArgCaptor.getValue() instanceof VisibleItemsEvent);
-        VisibleItemsEvent event = (VisibleItemsEvent) mEventArgCaptor.getValue();
-        List<String> eventVisibleItems = event.getItemsIds();
-        assertArrayEquals(eventVisibleItems.toArray(), visibleItems.toArray());
-    }
-
-    @Test
-    public void parserCallbackBrowseNodeChangeTest() {
-        Bundle bundle = createTestBundle(ANALYTICS_EVENT_BROWSE_NODE_CHANGE);
-        String node = "test_media_id_1";
-        int action = 1;
-        bundle.putString(ANALYTICS_EVENT_DATA_KEY_MEDIA_ID, node);
-        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION, action);
-        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
-        verify(mAnalyticsCallback)
-                .onBrowseNodeChangeEvent((BrowseChangeEvent) mEventArgCaptor.capture());
-        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
-        assertTrue(mEventArgCaptor.getValue() instanceof BrowseChangeEvent);
-        BrowseChangeEvent event = (BrowseChangeEvent) mEventArgCaptor.getValue();
-        String eventBrowseNew = event.getBrowseNodeId();
-        int eventAction = event.getViewAction();
-        assertEquals(eventAction, action);
-        assertEquals(eventBrowseNew, node);
-    }
-
-    @Test
-    public void parserCallbackViewEntryTest() {
-        Bundle bundle = createTestBundle(ANALYTICS_EVENT_VIEW_CHANGE);
-        int viewComponent = AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST;
-        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_COMPONENT, viewComponent);
-        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION, AnalyticsEvent.VIEW_ACTION_SHOW);
-        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
-        verify(mAnalyticsCallback)
-                .onViewChangeEvent((ViewChangeEvent) mEventArgCaptor.capture());
-        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
-        assertTrue(mEventArgCaptor.getValue() instanceof ViewChangeEvent);
-        ViewChangeEvent event = (ViewChangeEvent) mEventArgCaptor.getValue();
-        int eventViewType = event.getViewComponent();
-        assertEquals(eventViewType, viewComponent);
-        int type = event.getViewAction();
-        assertEquals(type, AnalyticsEvent.VIEW_ACTION_SHOW);
-    }
-
-    @Test
-    public void parserCallbackViewExitTest() {
-        Bundle bundle = createTestBundle(ANALYTICS_EVENT_VIEW_CHANGE);
-        int viewComponent = AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST;
-        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_COMPONENT, viewComponent);
-        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VIEW_ACTION, AnalyticsEvent.VIEW_ACTION_HIDE);
-        AnalyticsParser.parseAnalyticsBundle(bundle, mExecutor, mAnalyticsCallback);
-        verify(mAnalyticsCallback)
-                .onViewChangeEvent((ViewChangeEvent) mEventArgCaptor.capture());
-        verifyNoMoreInteractions(mAnalyticsCallback); // Verify onError not called
-        assertTrue(mEventArgCaptor.getValue() instanceof ViewChangeEvent);
-        ViewChangeEvent event = (ViewChangeEvent) mEventArgCaptor.getValue();
-        int eventViewType = event.getViewComponent();
-        assertEquals(eventViewType, viewComponent);
-        int type = event.getViewAction();
-        assertEquals(type, AnalyticsEvent.VIEW_ACTION_HIDE);
-    }
-
-    private Bundle createTestBundle(String eventName) {
-        Bundle bundle = new Bundle();
-        bundle.putString(ANALYTICS_ROOT_KEY_PASSKEY, mPassKey.toString());
-        bundle.putString(ANALYTICS_EVENT_DATA_KEY_EVENT_NAME, eventName);
-        bundle.putLong(ANALYTICS_EVENT_DATA_KEY_TIMESTAMP, System.currentTimeMillis());
-        bundle.putInt(ANALYTICS_EVENT_DATA_KEY_VERSION, 1);
-        ComponentName componentName =
-                new ComponentName(
-                        AnalyticsParserTests.class.getPackage().toString(),
-                        AnalyticsParserTests.class.getName());
-        bundle.putString(
-                ANALYTICS_EVENT_DATA_KEY_HOST_COMPONENT_ID, componentName.flattenToString());
-        return bundle;
-    }
-}
diff --git a/car-ui-lib/Android.bp b/car-ui-lib/Android.bp
index 6b47626..51c2dca 100644
--- a/car-ui-lib/Android.bp
+++ b/car-ui-lib/Android.bp
@@ -35,6 +35,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "car-ui-lib/src/main/AndroidManifest-resourceOnly.xml",
     resource_dirs: [
@@ -61,6 +63,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "car-ui-lib/src/main/AndroidManifest-resourceOnly.xml",
     resource_dirs: [
@@ -82,6 +86,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "car-ui-lib/src/main/AndroidManifest.xml",
     srcs: ["car-ui-lib/src/main/java/**/*.java"],
@@ -134,6 +140,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "car-ui-lib/src/main/AndroidManifest.xml",
     srcs: ["car-ui-lib/src/main/java/**/*.java"],
@@ -201,6 +209,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "car-ui-lib/src/main/AndroidManifest.xml",
     srcs: [
@@ -243,6 +253,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "car-ui-lib-testing/src/main/AndroidManifest.xml",
     srcs: [
@@ -295,6 +307,7 @@
     ],
     required: ["car-ui-lib-proxyplugin"],
     platform_apis: true,
+    min_sdk_version: "28",
     test_suites: ["device-tests"],
 }
 
@@ -331,6 +344,7 @@
     ],
 
     platform_apis: true,
+    min_sdk_version: "28",
     certificate: CERTIFICATE,
     privileged: true,
 
diff --git a/car-ui-lib/build.gradle b/car-ui-lib/build.gradle
deleted file mode 100644
index ca984ef..0000000
--- a/car-ui-lib/build.gradle
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
-    repositories {
-        google()
-        mavenCentral()
-
-    }
-    dependencies {
-        // Before upgrading this version, make sure you can close android
-        // studio, run git clean -fxd, and then reopen this folder in android
-        // studio and have it work. Sometimes android studio's built in gradle
-        // wrapper seems to lag behind the version required by the android
-        // plugin.
-        classpath 'com.android.tools.build:gradle:8.0.2'
-        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22'
-
-        // NOTE: Do not place your application dependencies here; they belong
-        // in the individual module build.gradle files
-    }
-
-    gradle.ext.aaosLatestSDK = 33
-    gradle.ext.aaosTargetSDK = 33
-
-    gradle.ext.repoRootPath = rootDir.parentFile.parentFile.parentFile.parentFile.parent
-    gradle.ext.aaosCertPath = gradle.ext.repoRootPath + "/packages/apps/Car/libs/certs/com_android_car_apps_test.jks"
-    gradle.ext.chassisCertPath = gradle.ext.repoRootPath + "/vendor/auto/embedded/prebuilts/car-ui-lib/chassis_upload_key.jks"
-    def googleCertPath = gradle.ext.repoRootPath + "/vendor/google/certs/devkeys/platform.keystore"
-    if (file(googleCertPath).exists()) {
-        gradle.ext.platformCertPath = googleCertPath
-    } else {
-        gradle.ext.platformCertPath = gradle.ext.repoRootPath + "/packages/apps/Car/libs/certs/platform.keystore"
-    }
-    gradle.ext.soongBash = gradle.ext.repoRootPath + "/build/soong/soong_ui.bash"
-    gradle.ext.platformSdkVersion = "33" // Change this to the most recent android API level.
-    if (file(gradle.ext.soongBash).exists()) {
-        gradle.ext.platformSdkVersion = (gradle.ext.soongBash + " --dumpvar-mode PLATFORM_SDK_VERSION").execute().text.trim()
-    }
-
-    gradle.ext.getVersionCode = { ->
-        def code = project.hasProperty('versionCode') ? versionCode.toInteger() : gradle.ext.platformSdkVersion.toInteger()
-        println "VersionCode is set to $code"
-        return code
-    }
-
-    gradle.ext.getVersionName = { ->
-        def name = project.hasProperty('versionName') ? versionName : gradle.ext.platformSdkVersion
-        println "VersionName is set to $name"
-        return name
-    }
-}
-
-allprojects {
-    repositories {
-        google()
-        mavenCentral()
-    }
-    tasks.withType(JavaCompile) {
-        options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
-    }
-}
-
diff --git a/car-ui-lib/car-rotary-lib/Android.bp b/car-ui-lib/car-rotary-lib/Android.bp
index b329ee7..2c5dcfa 100644
--- a/car-ui-lib/car-rotary-lib/Android.bp
+++ b/car-ui-lib/car-rotary-lib/Android.bp
@@ -22,6 +22,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "src/main/AndroidManifest.xml",
     resource_dirs: [
@@ -42,6 +44,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "src/main/AndroidManifest.xml",
     resource_dirs: [
@@ -63,6 +67,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "src/main/AndroidManifest.xml",
     srcs: ["src/main/java/**/*.java"],
@@ -88,6 +94,8 @@
     sdk_version: "current",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     manifest: "src/main/AndroidManifest.xml",
     srcs: ["src/main/java/**/*.java"],
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java
index 3f2295a..4fb4c4d 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java
@@ -18,6 +18,7 @@
 
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.swipeRight;
 import static androidx.test.espresso.action.ViewActions.typeText;
 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
@@ -1044,24 +1045,21 @@
 
     @Test
     public void testTwoActionSwitchPreference_switchWidgetFocusableFalse() {
-        // Create mock activity to test when global switchWidgetFocusable bool is false
-        mActivityRule.getScenario().onActivity(activity -> {
-            Context testableContext = spy(activity);
-            Resources testableResources = spy(activity.getResources());
-            when(testableContext.getResources()).thenReturn(testableResources);
-            // Start by setting global bool to be false (focus should now wrap container)
-            doReturn(false).when(testableResources).getBoolean(
-                    R.bool.car_ui_preference_two_action_switch_widget_focusable);
+        Context testableContext = spy(mActivity);
+        Resources testableResources = spy(mActivity.getResources());
+        when(testableContext.getResources()).thenReturn(testableResources);
+        // Start by setting global bool to be false (focus should now wrap container)
+        doReturn(false).when(testableResources).getBoolean(
+                R.bool.car_ui_preference_two_action_switch_widget_focusable);
 
-            // Create CarUiTwoActionSwitchPreference preference and add it to screen.
-            CarUiTwoActionSwitchPreference preference =
-                    new CarUiTwoActionSwitchPreference(testableContext);
-            preference.setKey("twoaction");
-            preference.setOrder(0);
-            activity.addPreference(preference);
-            // Scroll to preference
-            activity.runOnUiThread(() -> activity.scrollToPreference("twoaction"));
-        });
+        // Create CarUiTwoActionSwitchPreference preference and add it to screen.
+        CarUiTwoActionSwitchPreference preference =
+                new CarUiTwoActionSwitchPreference(testableContext);
+        preference.setKey("twoaction");
+        preference.setOrder(0);
+        mActivity.addPreference(preference);
+        // Scroll to preference
+        mActivity.runOnUiThread(() -> mActivity.scrollToPreference("twoaction"));
         // verify focus wraps container when global bool is false
         onView(withIndex(withId(R.id.car_ui_secondary_action_concrete),
                 0)).check(matches(not(isFocusable())));
@@ -1071,24 +1069,21 @@
 
     @Test
     public void testTwoActionSwitchPreference_switchWidgetFocusableTrue() {
-        // Create mock activity to test when global switchWidgetFocusable bool is true
-        mActivityRule.getScenario().onActivity(activity -> {
-            Context testableContext = spy(activity);
-            Resources testableResources = spy(activity.getResources());
-            when(testableContext.getResources()).thenReturn(testableResources);
-            // Start by setting global bool to be true (focus should now wrap switch)
-            doReturn(true).when(testableResources).getBoolean(
-                    R.bool.car_ui_preference_two_action_switch_widget_focusable);
+        Context testableContext = spy(mActivity);
+        Resources testableResources = spy(mActivity.getResources());
+        when(testableContext.getResources()).thenReturn(testableResources);
+        // Start by setting global bool to be true (focus should now wrap switch)
+        doReturn(true).when(testableResources).getBoolean(
+                R.bool.car_ui_preference_two_action_switch_widget_focusable);
 
-            // Create CarUiTwoActionSwitchPreference preference and add it to screen.
-            CarUiTwoActionSwitchPreference preference =
-                    new CarUiTwoActionSwitchPreference(testableContext);
-            preference.setKey("twoaction");
-            preference.setOrder(0);
-            activity.addPreference(preference);
-            // Scroll to preference
-            activity.runOnUiThread(() -> activity.scrollToPreference("twoaction"));
-        });
+        // Create CarUiTwoActionSwitchPreference preference and add it to screen.
+        CarUiTwoActionSwitchPreference preference =
+                new CarUiTwoActionSwitchPreference(testableContext);
+        preference.setKey("twoaction");
+        preference.setOrder(0);
+        mActivity.addPreference(preference);
+        // Scroll to preference
+        mActivity.runOnUiThread(() -> mActivity.scrollToPreference("twoaction"));
         // verify focus wraps switch when global bool is true
         onView(withIndex(withId(R.id.car_ui_secondary_action_concrete),
                 0)).check(matches(isFocusable()));
@@ -1097,6 +1092,72 @@
     }
 
     @Test
+    public void testTwoActionSwitchPreference_switchNotToggleableWhenDisabled() {
+        Context testableContext = spy(mActivity);
+        Resources testableResources = spy(mActivity.getResources());
+        when(testableContext.getResources()).thenReturn(testableResources);
+        // Set switch widget to be focusable instead of secondary action
+        doReturn(true).when(testableResources).getBoolean(
+                R.bool.car_ui_preference_two_action_switch_widget_focusable);
+
+        // Create CarUiTwoActionSwitchPreference preference and add it to screen.
+        CarUiTwoActionSwitchPreference preference =
+                new CarUiTwoActionSwitchPreference(testableContext);
+        preference.setKey("twoaction");
+        preference.setOrder(0);
+        mActivity.addPreference(preference);
+        // Scroll to preference
+        mActivity.runOnUiThread(() -> mActivity.scrollToPreference("twoaction"));
+
+        // Set preference to be unchecked and clickable while disabled
+        preference.setSecondaryActionChecked(false);
+        preference.setSecondaryActionEnabled(false);
+        preference.setClickableWhileDisabled(true);
+        preference.setDisabledClickListener(mock(Consumer.class));
+
+        // Ensure switch stays unchecked when clicked
+        onView(withId(R.id.car_ui_secondary_action_concrete)).perform(click());
+        onView(withId(R.id.car_ui_secondary_action_concrete)).check(matches(not(isChecked())));
+
+        // Ensure switch stays unchecked when thumb is dragged
+        onView(withId(R.id.car_ui_secondary_action_concrete)).perform(swipeRight());
+        onView(withId(R.id.car_ui_secondary_action_concrete)).check(matches(not(isChecked())));
+    }
+
+    @Test
+    public void testTwoActionSwitchPreference_switchNotToggleableWhenUxRestricted() {
+        Context testableContext = spy(mActivity);
+        Resources testableResources = spy(mActivity.getResources());
+        when(testableContext.getResources()).thenReturn(testableResources);
+        // Set switch widget to be focusable instead of secondary action
+        doReturn(true).when(testableResources).getBoolean(
+                R.bool.car_ui_preference_two_action_switch_widget_focusable);
+
+        // Create CarUiTwoActionSwitchPreference preference and add it to screen.
+        CarUiTwoActionSwitchPreference preference =
+                new CarUiTwoActionSwitchPreference(testableContext);
+        preference.setKey("twoaction");
+        preference.setOrder(0);
+        mActivity.addPreference(preference);
+        // Scroll to preference
+        mActivity.runOnUiThread(() -> mActivity.scrollToPreference("twoaction"));
+
+        // Set preference to be unchecked and ux restricted
+        preference.setSecondaryActionChecked(false);
+        preference.setUxRestricted(true);
+        assertTrue(preference.isUxRestricted());
+        preference.setOnClickWhileRestrictedListener(mock(Consumer.class));
+
+        // Ensure switch stays unchecked when clicked
+        onView(withId(R.id.car_ui_secondary_action_concrete)).perform(click());
+        onView(withId(R.id.car_ui_secondary_action_concrete)).check(matches(not(isChecked())));
+
+        // Ensure switch stays unchecked when thumb is dragged
+        onView(withId(R.id.car_ui_secondary_action_concrete)).perform(swipeRight());
+        onView(withId(R.id.car_ui_secondary_action_concrete)).check(matches(not(isChecked())));
+    }
+
+    @Test
     public void testEditTextPreference() {
         // Create CarUiEditTextPreference preference and add it to screen.
         CarUiEditTextPreference preference = new CarUiEditTextPreference(mActivity);
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java
index fa9d755..104f872 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/AlertDialogBuilder.java
@@ -58,7 +58,9 @@
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.car.ui.core.CarUi;
 import com.android.car.ui.recyclerview.CarUiContentListItem;
+import com.android.car.ui.recyclerview.CarUiListItem;
 import com.android.car.ui.recyclerview.CarUiListItemAdapter;
 import com.android.car.ui.recyclerview.CarUiRadioButtonListItem;
 import com.android.car.ui.recyclerview.CarUiRadioButtonListItemAdapter;
@@ -236,8 +238,8 @@
      * Set the {@link Drawable} to be used in the title.
      * <p>
      * <strong>Note:</strong> To ensure consistent styling, the drawable
-     * should be inflated or constructed using the alert dialog's themed context obtained via {@link
-     * #getContext()}.
+     * should be inflated or constructed using the alert dialog's themed context obtained via
+     * {@link #getContext()}.
      *
      * @return this Builder object to allow for chaining of calls to set methods
      */
@@ -430,9 +432,21 @@
     }
 
     /**
+     * Set a list of items to be displayed in the dialog as the content, you will be notified of the
+     * selected item via the supplied listener.
+     *
+     * @return This Builder object to allow for chaining of calls to set methods
+     */
+    public AlertDialogBuilder setItems(List<? extends CarUiListItem> items) {
+        setCustomList(CarUi.createListItemAdapter(getContext(), items));
+        mHasSingleChoiceBodyButton = true;
+        return this;
+    }
+
+    /**
      * This was not supposed to be in the Chassis API because it allows custom views.
      *
-     * @deprecated Use {@link #setAdapter(CarUiListItemAdapter)} instead.
+     * @deprecated Use {@link #setItems(List)} instead.
      */
     @Deprecated
     public AlertDialogBuilder setAdapter(final ListAdapter adapter,
@@ -446,14 +460,19 @@
      * Display all the {@link com.android.car.ui.recyclerview.CarUiListItem CarUiListItems} in a
      * {@link CarUiListItemAdapter}. You should set click listeners on the CarUiListItems as opposed
      * to a callback in this function.
+     *
+     * @deprecated Use {@link #setItems(List)} instead. This method is incompatible with the
+     * Car UI plugin.
      */
+    @Deprecated
     public AlertDialogBuilder setAdapter(final CarUiListItemAdapter adapter) {
         setCustomList(adapter);
         mHasSingleChoiceBodyButton = true;
         return this;
     }
 
-    private void setCustomList(@NonNull CarUiListItemAdapter adapter) {
+    private void setCustomList(
+            @NonNull RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter) {
         View customList = LayoutInflater.from(mContext).inflate(
                 R.layout.car_ui_alert_dialog_list, null);
         RecyclerView list = CarUiUtils.requireViewByRefId(customList, R.id.list);
@@ -744,8 +763,8 @@
      * @param textChangedListener textWatcher whose methods are called whenever this TextView's text
      *                            changes {@code null} otherwise.
      * @param inputFilters        list of input filters, {@code null} if no filter is needed
-     * @param inputType           See {@link EditText#setInputType(int)}, except {@link
-     *                            android.text.InputType#TYPE_NULL} will not be set.
+     * @param inputType           See {@link EditText#setInputType(int)}, except
+     *                            {@link android.text.InputType#TYPE_NULL} will not be set.
      * @return this Builder object to allow for chaining of calls to set methods
      */
     public AlertDialogBuilder setEditBox(String prompt, TextWatcher textChangedListener,
@@ -819,9 +838,9 @@
     /**
      * By default, the AlertDialogBuilder may add a "Dismiss" button if you don't provide a
      * positive/negative/neutral button. This is so that the dialog is still dismissible using the
-     * rotary controller. If however, you add buttons that can close the dialog via {@link
-     * #setAdapter(CarUiListItemAdapter)} or a similar method, then you may wish to suppress the
-     * addition of the dismiss button, which this method allows for.
+     * rotary controller. If however, you add buttons that can close the dialog via
+     * {@link #setAdapter(CarUiListItemAdapter)} or a similar method, then you may wish to suppress
+     * the addition of the dismiss button, which this method allows for.
      *
      * @param allowDismissButton If true, a "Dismiss" button may be added to the dialog. If false,
      *                           it will never be added.
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialog.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialog.java
index 78c7fa0..c05b260 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialog.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialog.java
@@ -20,11 +20,11 @@
 import android.app.Activity;
 import android.app.Dialog;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Build;
 import android.os.Bundle;
+import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -63,18 +63,18 @@
  * Apps should not use this directly. Apps should use {@link AppStyledDialogController}.
  */
 
-class AppStyledDialog extends Dialog implements DialogInterface.OnDismissListener, LifecycleOwner,
-        SavedStateRegistryOwner, OnBackPressedDispatcherOwner {
+class AppStyledDialog extends Dialog implements LifecycleOwner, SavedStateRegistryOwner,
+        OnBackPressedDispatcherOwner {
 
     private static final int IME_OVERLAP_DP = 32;
     private final AppStyledViewController mController;
-    private Runnable mOnDismissListener;
     private View mContent;
     private View mAppStyledView;
     private final Context mContext;
     private final LifecycleRegistry mLifecycleRegistry;
     private final SavedStateRegistryController mSavedStateRegistryController;
     private final OnBackPressedDispatcher mOnBackPressedDispatcher;
+    private WindowManager.LayoutParams mBaseLayoutParams;
 
     AppStyledDialog(@NonNull Activity context, @NonNull AppStyledViewController controller) {
         super(context);
@@ -85,7 +85,6 @@
         // need in order to get call getWindow()
         mContext = context;
         mController = controller;
-        setOnDismissListener(this);
         requestWindowFeature(Window.FEATURE_NO_TITLE);
     }
 
@@ -106,13 +105,27 @@
             return;
         }
 
-        window.setAttributes(mController.getDialogWindowLayoutParam(getWindow().getAttributes()));
         window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        mBaseLayoutParams = new WindowManager.LayoutParams();
+        mBaseLayoutParams.copyFrom(window.getAttributes());
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            mBaseLayoutParams.setFitInsetsTypes(0);
+        }
+        updateAttributes();
         configureImeInsetFit();
 
         mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
     }
 
+    private void updateAttributes() {
+        Window window = getWindow();
+        if (window == null) {
+            return;
+        }
+
+        window.setAttributes(mController.getDialogWindowLayoutParam(mBaseLayoutParams));
+    }
+
     private void configureImeInsetFit() {
         // Required inset API is unsupported. Fallback to default IME behavior.
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
@@ -125,26 +138,33 @@
         }
 
         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
-        WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
+        WindowCompat.setDecorFitsSystemWindows(window, false);
         ViewCompat.setWindowInsetsAnimationCallback(window.getDecorView().getRootView(),
                 new WindowInsetsAnimationCompat.Callback(
                         WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP) {
 
                     int mEndHeight;
+                    int mStartHeight;
                     WindowManager.LayoutParams mAnimationLayoutParams;
-                    WindowManager.LayoutParams mStartLayoutParams;
                     int mAppStyledViewBottomPadding;
                     boolean mIsImeShown;
                     final int mImeOverlapPx =
                             (int) CarUiUtils.dpToPixel(mContext.getResources(), IME_OVERLAP_DP);
 
+                    private boolean isImeAnimation(WindowInsetsAnimationCompat animation) {
+                        return (animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0;
+                    }
+
                     @Override
                     @SuppressLint({"NewApi", "RtlHardcoded"})
                     public void onPrepare(@NonNull WindowInsetsAnimationCompat animation) {
+                        if (!isImeAnimation(animation)) {
+                            return;
+                        }
+
                         mAnimationLayoutParams = new WindowManager.LayoutParams();
-                        mStartLayoutParams = mController.getDialogWindowLayoutParam(
-                                window.getAttributes());
-                        mAnimationLayoutParams.copyFrom(mStartLayoutParams);
+                        mAnimationLayoutParams.copyFrom(window.getAttributes());
+                        mStartHeight = mAnimationLayoutParams.height;
 
                         int[] location = new int[2];
                         window.getDecorView().getRootView().getLocationOnScreen(location);
@@ -165,24 +185,30 @@
                     public WindowInsetsAnimationCompat.BoundsCompat onStart(
                             @NonNull WindowInsetsAnimationCompat animation,
                             @NonNull WindowInsetsAnimationCompat.BoundsCompat bounds) {
+                        if (!isImeAnimation(animation)) {
+                            return bounds;
+                        }
                         WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(
                                 window.getDecorView().getRootView());
+                        WindowManager.LayoutParams layoutParams =
+                                mController.getDialogWindowLayoutParam(window.getAttributes());
                         int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
                         mIsImeShown = imeHeight > 0;
-                        int imeOverlap = mIsImeShown ? imeHeight - mImeOverlapPx : 0;
-                        mEndHeight = mController.getDialogWindowLayoutParam(
-                                window.getAttributes()).height - imeOverlap;
+                        int bottom = layoutParams.y + layoutParams.height;
 
+                        DisplayMetrics displayMetrics =
+                                CarUiUtils.getDeviceDisplayMetrics(mContext);
+
+                        int imeTop = displayMetrics.heightPixels - imeHeight;
+                        int resize = 0;
+                        if (imeTop < bottom) {
+                            resize = bottom - imeTop;
+                        }
+
+                        mEndHeight = layoutParams.height - resize;
                         return bounds;
                     }
 
-                    @Override
-                    public void onEnd(@NonNull WindowInsetsAnimationCompat animation) {
-                        mStartLayoutParams.height = mEndHeight;
-                        window.setAttributes(mStartLayoutParams);
-                        super.onEnd(animation);
-                    }
-
                     @NonNull
                     @Override
                     public WindowInsetsCompat onProgress(@NonNull WindowInsetsCompat insets,
@@ -190,7 +216,7 @@
                         // Find an IME animation.
                         WindowInsetsAnimationCompat imeAnimation = null;
                         for (WindowInsetsAnimationCompat animation : runningAnimations) {
-                            if ((animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) {
+                            if (isImeAnimation(animation)) {
                                 imeAnimation = animation;
                                 break;
                             }
@@ -198,7 +224,6 @@
                         if (imeAnimation != null) {
                             // Offset the view based on the interpolated fraction of the IME
                             // animation.
-                            int mStartHeight = mStartLayoutParams.height;
                             mAnimationLayoutParams.height =
                                     (int) (mStartHeight - ((mStartHeight - mEndHeight)
                                             * imeAnimation.getInterpolatedFraction()));
@@ -214,6 +239,16 @@
 
                         return insets;
                     }
+
+                    @Override
+                    public void onEnd(@NonNull WindowInsetsAnimationCompat animation) {
+                        if (!mIsImeShown) {
+                            updateAttributes();
+                            copyWindowInsets();
+                        }
+
+                        super.onEnd(animation);
+                    }
                 });
     }
 
@@ -221,6 +256,7 @@
     protected void onStart() {
         mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
         mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
+
         super.onStart();
     }
 
@@ -231,17 +267,11 @@
     }
 
     @Override
-    public void onDismiss(DialogInterface dialog) {
-        if (mOnDismissListener != null) {
-            mOnDismissListener.run();
-        }
-    }
-
-    @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         copyWindowInsets();
         copySystemUiVisibility();
+        updateAttributes();
     }
 
     /**
@@ -249,6 +279,10 @@
      * activity is in Immersive mode the dialog will be in Immersive mode too and vice versa.
      */
     private void copySystemUiVisibility() {
+        if (getWindow() == null) {
+            return;
+        }
+
         getWindow().getDecorView().setSystemUiVisibility(
                 ((Activity) mContext).getWindow().getDecorView().getSystemUiVisibility());
         getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
@@ -261,36 +295,43 @@
      * mirror activity state but nav bar requires the following workaround.
      */
     private void copyWindowInsets() {
-        // WindowInsetsController corresponding to activity that requested the dialog
-        WindowInsetsControllerCompat activityWindowInsetsController =
-                ViewCompat.getWindowInsetsController(
-                        ((Activity) mContext).getWindow().getDecorView());
+        Window window = getWindow();
+        if (window == null) {
+            return;
+        }
 
         // WindowInsetsController corresponding to the dialog
         WindowInsetsControllerCompat dialogWindowInsetsController =
-                ViewCompat.getWindowInsetsController(getWindow().getDecorView());
+                WindowCompat.getInsetsController(window, getWindow().getDecorView());
 
-        if (dialogWindowInsetsController == null || activityWindowInsetsController == null) {
-            return;
-        }
+        Activity activity = ((Activity) mContext);
+
+        // WindowInsetsController corresponding to activity that requested the dialog
+        WindowInsetsControllerCompat activityWindowInsetsController =
+                WindowCompat.getInsetsController(activity.getWindow(),
+                        activity.getWindow().getDecorView());
+
 
         int activitySystemBarBehavior = activityWindowInsetsController.getSystemBarsBehavior();
         // Only set system bar behavior when non-default settings are required. Setting default may
         // overwrite flags set by deprecated methods with different defaults.
         if (activitySystemBarBehavior != 0) {
             // Configure the behavior of the hidden system bars to match requesting activity
-            dialogWindowInsetsController.setSystemBarsBehavior(
-                    activityWindowInsetsController.getSystemBarsBehavior());
+            dialogWindowInsetsController.setSystemBarsBehavior(activitySystemBarBehavior);
         }
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
             // Configure nav bar visibility to match requesting activity
-            WindowInsets windowInsets =
-                    ((Activity) mContext).getWindow().getDecorView().getRootWindowInsets();
+            WindowInsets windowInsets = activity.getWindow().getDecorView().getRootWindowInsets();
             if (windowInsets == null) {
                 return;
             }
 
+            boolean isStatusBarVisible = windowInsets.isVisible(WindowInsets.Type.statusBars());
+            if (!isStatusBarVisible) {
+                dialogWindowInsetsController.hide(WindowInsetsCompat.Type.statusBars());
+            }
+
             boolean isNavBarVisible = windowInsets.isVisible(WindowInsets.Type.navigationBars());
             if (!isNavBarVisible) {
                 dialogWindowInsetsController.hide(WindowInsetsCompat.Type.navigationBars());
@@ -300,22 +341,26 @@
 
     @Override
     public void show() {
-        if (getWindow() != null) {
-            getWindow().setAttributes(
-                    mController.getDialogWindowLayoutParam(getWindow().getAttributes()));
+        if (isShowing()) {
+            return;
         }
+
+        updateContent();
         super.show();
         mContent.clearFocus();
     }
 
     void setContent(View contentView) {
-        if (contentView.getParent() != null) {
-            ((ViewGroup) contentView.getParent()).removeView(contentView);
+        mContent = contentView;
+
+    }
+
+    private void updateContent() {
+        if (mContent.getParent() != null) {
+            ((ViewGroup) mContent.getParent()).removeView(mContent);
         }
 
-        mContent = contentView;
         mAppStyledView = mController.getAppStyledView(mContent);
-        configureImeInsetFit();
         setContentView(mAppStyledView);
     }
 
@@ -347,10 +392,6 @@
         return mContent;
     }
 
-    void setOnDismissListener(Runnable listener) {
-        mOnDismissListener = listener;
-    }
-
     @Nullable
     WindowManager.LayoutParams getWindowLayoutParams() {
         if (getWindow() == null) {
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialogController.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialogController.java
index aea8f54..f023f59 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialogController.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledDialogController.java
@@ -223,8 +223,13 @@
     /**
      * Sets a runnable that will be invoked when a dialog is dismissed.
      */
-    public void setOnDismissListener(@NonNull Runnable listener) {
-        mDialog.setOnDismissListener(listener);
+    public void setOnDismissListener(@Nullable Runnable listener) {
+        if (listener == null) {
+            mDialog.setOnDismissListener(null);
+            return;
+        }
+
+        mDialog.setOnDismissListener(dialog -> listener.run());
     }
 
     /**
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java
index 5d9d203..5f1b749 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java
@@ -110,9 +110,7 @@
 
     @Override
     public LayoutParams getDialogWindowLayoutParam(LayoutParams params) {
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        WindowManager wm = mContext.getSystemService(WindowManager.class);
-        wm.getDefaultDisplay().getRealMetrics(displayMetrics);
+        DisplayMetrics displayMetrics = CarUiUtils.getDeviceDisplayMetrics(mContext);
 
         int maxWidth = mContext.getResources().getDimensionPixelSize(
                 R.dimen.car_ui_app_styled_dialog_width_max);
@@ -167,6 +165,9 @@
             params.y = posY;
 
             return params;
+        } else {
+            params.x = 0;
+            params.y = 0;
         }
 
         int minPaddingPx = (int) CarUiUtils.dpToPixel(mContext.getResources(),
@@ -185,14 +186,16 @@
 
         int startMarginThresholdPx = (int) CarUiUtils.dpToPixel(mContext.getResources(),
                 DIALOG_START_MARGIN_THRESHOLD);
-        if (mContext.getResources().getConfiguration().orientation
-                == Configuration.ORIENTATION_LANDSCAPE) {
-            int startMargin = (displayWidth - mWidth) / 2;
-            if (startMargin >= startMarginThresholdPx) {
+        boolean isLandscape = mContext.getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_LANDSCAPE;
+        int startMargin = (displayWidth - mWidth) / 2;
+
+        if (isLandscape && startMargin >= startMarginThresholdPx) {
                 params.gravity = Gravity.TOP | Gravity.START;
                 params.x = startMarginThresholdPx;
                 params.y = (displayHeight - mHeight) / 2;
-            }
+        } else {
+            params.gravity = Gravity.CENTER;
         }
 
         return params;
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenController.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenController.java
index 3612a6d..799c233 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenController.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/imewidescreen/CarUiImeWideScreenController.java
@@ -857,7 +857,6 @@
     private void resetAutomotiveWideScreenViews() {
         mWideScreenDescriptionTitle.setVisibility(View.GONE);
         mContentAreaSurfaceView.setVisibility(View.GONE);
-        mContentAreaSurfaceView.setChildSurfacePackage(null);
         mWideScreenErrorMessage.setVisibility(View.GONE);
         mRecyclerView.setVisibility(View.GONE);
         mWideScreenDescription.setVisibility(View.GONE);
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/preference/CarUiTwoActionSwitchPreference.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/preference/CarUiTwoActionSwitchPreference.java
index 8878ce1..cff8864 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/preference/CarUiTwoActionSwitchPreference.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/preference/CarUiTwoActionSwitchPreference.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.Switch;
 
@@ -102,32 +103,47 @@
                 R.id.car_ui_secondary_action);
         mSwitchWidget = requireViewByRefId(holder.itemView,
                 R.id.car_ui_secondary_action_concrete);
+        boolean firstActionEnabledViewState = isEnabled() || isUxRestricted()
+                || isClickableWhileDisabled();
+        boolean secondaryActionEnabledViewState = isSecondaryActionEnabled() || isUxRestricted()
+                || isClickableWhileDisabled();
 
         holder.itemView.setFocusable(false);
         holder.itemView.setClickable(false);
         firstActionContainer.setOnClickListener(this::performClickUnrestricted);
-        firstActionContainer.setEnabled(
-                isEnabled() || isUxRestricted() || isClickableWhileDisabled());
-        firstActionContainer.setFocusable(
-                isEnabled() || isUxRestricted() || isClickableWhileDisabled());
+        firstActionContainer.setEnabled(firstActionEnabledViewState);
+        firstActionContainer.setFocusable(firstActionEnabledViewState);
 
         secondActionContainer.setVisibility(mSecondaryActionVisible ? View.VISIBLE : View.GONE);
         mSwitchWidget.setChecked(mSecondaryActionChecked);
 
-        secondaryAction.setEnabled(
-                isSecondaryActionEnabled() || isUxRestricted() || isClickableWhileDisabled());
-        mSwitchWidget.setEnabled(
-                isSecondaryActionEnabled() || isUxRestricted() || isClickableWhileDisabled());
+        secondaryAction.setEnabled(secondaryActionEnabledViewState);
+        mSwitchWidget.setEnabled(secondaryActionEnabledViewState);
         secondaryAction.setOnClickListener(v -> performSecondaryActionClick());
         mSwitchWidget.setOnClickListener(v -> performSecondaryActionClick());
+        // When a switch is enabled, its onTouchEvent listens for drag events so that the switch can
+        // be toggled when the thumb is dragged. When this preference's secondary action is ux
+        // restricted or is disabled and clickable, the thumb shouldn't be draggable. So, intercept
+        // touch events and return true (which eats the event). Return false when the secondary
+        // action is enabled and not ux restricted (which will flow into normal touch behavior).
+        mSwitchWidget.setOnTouchListener((view, event) -> {
+            if ((!isSecondaryActionEnabled() && isClickableWhileDisabled()) || isUxRestricted()) {
+                // When handling touch events, the touch listener is responsible for performing a
+                // click if applicable. Only perform click when click is finished (i.e., ACTION_UP).
+                if (event.getAction() == MotionEvent.ACTION_UP) {
+                    view.performClick();
+                }
+                return true;
+            }
+            // Don't handle the touch event, fallback to default behavior
+            return false;
+        });
         if (mSwitchWidgetFocusable) {
             secondaryAction.setFocusable(false);
-            mSwitchWidget.setFocusable(
-                    isSecondaryActionEnabled() || isUxRestricted() || isClickableWhileDisabled());
+            mSwitchWidget.setFocusable(secondaryActionEnabledViewState);
         } else {
             mSwitchWidget.setFocusable(false);
-            secondaryAction.setFocusable(
-                    isSecondaryActionEnabled() || isUxRestricted() || isClickableWhileDisabled());
+            secondaryAction.setFocusable(secondaryActionEnabledViewState);
         }
 
         CarUiUtils.makeAllViewsEnabledAndUxRestricted(secondaryAction, isSecondaryActionEnabled(),
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/MenuItemAdapterV1.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/MenuItemAdapterV1.java
index bb248cb..2e821ee 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/MenuItemAdapterV1.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/MenuItemAdapterV1.java
@@ -84,6 +84,7 @@
                 .setIcon(mClientMenuItem.getIcon())
                 .setEnabled(mClientMenuItem.isEnabled())
                 .setPrimary(mClientMenuItem.isPrimary())
+                .setTinted(mClientMenuItem.isTinted())
                 .setRestricted(mClientMenuItem.isRestricted())
                 .setShowIconAndTitle(mClientMenuItem.isShowingIconAndTitle())
                 .setDisplayBehavior(convertDisplayBehavior(mClientMenuItem.getDisplayBehavior()));
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java
index 6d2bf85..115d226 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/CarUiUtils.java
@@ -28,11 +28,13 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 
 import androidx.annotation.DimenRes;
 import androidx.annotation.IdRes;
@@ -475,4 +477,25 @@
 
         return context;
     }
+
+    /**
+     * Return {@link DisplayMetrics} for the current display if {@link Context} is associated with a
+     * {@link android.view.Display}. If the {@link Context} is not associated with a
+     * {@link android.view.Display}, reference the default {@link android.view.Display}.
+     */
+    public static DisplayMetrics getDeviceDisplayMetrics(@NonNull Context context) {
+        DisplayMetrics displayMetrics = new DisplayMetrics();
+        try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && context.getDisplay() != null) {
+                context.getDisplay().getRealMetrics(displayMetrics);
+                return displayMetrics;
+            }
+        } catch (UnsupportedOperationException e) {
+            // Fall through to default display implementation
+        }
+
+        WindowManager wm = context.getSystemService(WindowManager.class);
+        wm.getDefaultDisplay().getRealMetrics(displayMetrics);
+        return displayMetrics;
+    }
 }
diff --git a/car-ui-lib/gradle.properties b/car-ui-lib/gradle.properties
deleted file mode 100644
index b8dfa7f..0000000
--- a/car-ui-lib/gradle.properties
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Copyright (C) 2019 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.
-
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-# AndroidX package structure to make it clearer which packages are bundled with the
-# Android operating system, and which are packaged with your app's APK
-# https://developer.android.com/topic/libraries/support-library/androidx-rn
-android.useAndroidX=true
-# Automatically convert third-party libraries to use AndroidX
-android.enableJetifier=true
-android.defaults.buildfeatures.buildconfig=true
-android.nonTransitiveRClass=false
-android.nonFinalResIds=false
\ No newline at end of file
diff --git a/car-ui-lib/gradle/wrapper/gradle-wrapper.jar b/car-ui-lib/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index e708b1c..0000000
--- a/car-ui-lib/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/car-ui-lib/gradle/wrapper/gradle-wrapper.properties b/car-ui-lib/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index da1db5f..0000000
--- a/car-ui-lib/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/car-ui-lib/gradlew b/car-ui-lib/gradlew
deleted file mode 100755
index 4f906e0..0000000
--- a/car-ui-lib/gradlew
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/usr/bin/env sh
-
-#
-# Copyright 2015 the original author or authors.
-#
-# 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
-#
-#      https://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.
-#
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
-    echo "$*"
-}
-
-die () {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=`expr $i + 1`
-    done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=`save "$@"`
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-exec "$JAVACMD" "$@"
diff --git a/car-ui-lib/gradlew.bat b/car-ui-lib/gradlew.bat
deleted file mode 100644
index ac1b06f..0000000
--- a/car-ui-lib/gradlew.bat
+++ /dev/null
@@ -1,89 +0,0 @@
-@rem

-@rem Copyright 2015 the original author or authors.

-@rem

-@rem Licensed under the Apache License, Version 2.0 (the "License");

-@rem you may not use this file except in compliance with the License.

-@rem You may obtain a copy of the License at

-@rem

-@rem      https://www.apache.org/licenses/LICENSE-2.0

-@rem

-@rem Unless required by applicable law or agreed to in writing, software

-@rem distributed under the License is distributed on an "AS IS" BASIS,

-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-@rem See the License for the specific language governing permissions and

-@rem limitations under the License.

-@rem

-

-@if "%DEBUG%" == "" @echo off

-@rem ##########################################################################

-@rem

-@rem  Gradle startup script for Windows

-@rem

-@rem ##########################################################################

-

-@rem Set local scope for the variables with windows NT shell

-if "%OS%"=="Windows_NT" setlocal

-

-set DIRNAME=%~dp0

-if "%DIRNAME%" == "" set DIRNAME=.

-set APP_BASE_NAME=%~n0

-set APP_HOME=%DIRNAME%

-

-@rem Resolve any "." and ".." in APP_HOME to make it shorter.

-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

-

-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

-

-@rem Find java.exe

-if defined JAVA_HOME goto findJavaFromJavaHome

-

-set JAVA_EXE=java.exe

-%JAVA_EXE% -version >NUL 2>&1

-if "%ERRORLEVEL%" == "0" goto execute

-

-echo.

-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

-echo.

-echo Please set the JAVA_HOME variable in your environment to match the

-echo location of your Java installation.

-

-goto fail

-

-:findJavaFromJavaHome

-set JAVA_HOME=%JAVA_HOME:"=%

-set JAVA_EXE=%JAVA_HOME%/bin/java.exe

-

-if exist "%JAVA_EXE%" goto execute

-

-echo.

-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

-echo.

-echo Please set the JAVA_HOME variable in your environment to match the

-echo location of your Java installation.

-

-goto fail

-

-:execute

-@rem Setup the command line

-

-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

-

-

-@rem Execute Gradle

-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

-

-:end

-@rem End local scope for the variables with windows NT shell

-if "%ERRORLEVEL%"=="0" goto mainEnd

-

-:fail

-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

-rem the _cmd.exe /c_ return code!

-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

-exit /b 1

-

-:mainEnd

-if "%OS%"=="Windows_NT" endlocal

-

-:omega

diff --git a/car-ui-lib/oem-apis/Android.bp b/car-ui-lib/oem-apis/Android.bp
index ff67f1f..af09178 100644
--- a/car-ui-lib/oem-apis/Android.bp
+++ b/car-ui-lib/oem-apis/Android.bp
@@ -22,6 +22,8 @@
     min_sdk_version: "28",
     target_sdk_version: "30",
     sdk_version: "current",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
 
     srcs: ["src/main/java/**/*.java"],
 
diff --git a/car-ui-lib/oem-tokens/android-rro/Android.bp b/car-ui-lib/oem-tokens/android-rro/Android.bp
new file mode 100644
index 0000000..47b2c67
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 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"],
+}
+
+runtime_resource_overlay {
+    name: "token-android-rro",
+    resource_dirs: ["res"],
+    certificate: "platform",
+    manifest: "AndroidManifest.xml",
+    system_ext_specific: true,
+    static_libs: [
+        "token-customization-base"
+    ],
+}
diff --git a/car-ui-lib/oem-tokens/android-rro/AndroidManifest.xml b/car-ui-lib/oem-tokens/android-rro/AndroidManifest.xml
new file mode 100644
index 0000000..bc7fd4e
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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="oem.brand.model.android.rro">
+    <application android:hasCode="false" />
+    <overlay
+        android:targetPackage="android"
+        android:isStatic="false"
+        android:priority="20"/>
+</manifest>
diff --git a/car-ui-lib/oem-tokens/android-rro/res/color/car_switch_thumb_selector.xml b/car-ui-lib/oem-tokens/android-rro/res/color/car_switch_thumb_selector.xml
new file mode 100644
index 0000000..57b9179
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/color/car_switch_thumb_selector.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2024 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_checked="true" android:state_enabled="false"
+        android:alpha="?android:attr/disabledAlpha"
+        android:color="@color/color_on_primary" />
+    <item
+        android:state_enabled="false"
+        android:alpha="?android:attr/disabledAlpha"
+        android:color="@color/color_secondary" />
+    <item
+        android:state_checked="true" android:color="@color/color_on_primary" />
+    <item android:color="@color/color_secondary" />
+</selector>
diff --git a/car-ui-lib/oem-tokens/android-rro/res/color/car_switch_track_background_selector.xml b/car-ui-lib/oem-tokens/android-rro/res/color/car_switch_track_background_selector.xml
new file mode 100644
index 0000000..c7cfd8b
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/color/car_switch_track_background_selector.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2024 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_checked="true" android:state_enabled="false"
+        android:alpha="?android:attr/disabledAlpha"
+        android:color="@color/car_switch_track_background_checked" />
+    <item
+        android:state_enabled="false"
+        android:alpha="?android:attr/disabledAlpha"
+        android:color="@color/car_switch_track_background_unchecked" />
+    <item
+        android:state_checked="true" android:color="@color/car_switch_track_background_checked" />
+    <item android:color="@color/car_switch_track_background_unchecked" />
+</selector>
diff --git a/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_thumb.xml b/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_thumb.xml
new file mode 100644
index 0000000..0f44a53
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_thumb.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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"
+    android:paddingLeft="@dimen/car_switch_thumb_stroke_width"
+    android:paddingRight="@dimen/car_switch_thumb_stroke_width">
+    <item
+        android:gravity="center"
+        android:bottom="@dimen/car_switch_thumb_stroke_width"
+        android:left="@dimen/car_switch_thumb_stroke_width"
+        android:right="@dimen/car_switch_thumb_stroke_width"
+        android:top="@dimen/car_switch_thumb_stroke_width">
+        <shape android:shape="oval">
+            <size
+                android:width="@dimen/car_switch_thumb_size"
+                android:height="@dimen/car_switch_thumb_size" />
+            <solid android:color="@color/car_switch_thumb_selector"/>
+        </shape>
+    </item>
+</layer-list>
+
diff --git a/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_track.xml b/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_track.xml
new file mode 100644
index 0000000..bd32de9
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_track.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2024 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:bottom="@dimen/car_switch_track_margin_vertical"
+        android:gravity="center"
+        android:top="@dimen/car_switch_track_margin_vertical">
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/car_switch_thumb_outer_radius" />
+            <padding
+                android:left="@dimen/car_switch_thumb_stroke_width"
+                android:right="@dimen/car_switch_thumb_stroke_width" />
+            <size
+                android:height="@dimen/car_switch_track_height"
+                android:width="@dimen/car_switch_track_width" />
+            <solid android:color="@color/car_switch_track_background_selector" />
+        </shape>
+    </item>
+    <item
+        android:bottom="@dimen/car_switch_track_margin_vertical"
+        android:drawable="@drawable/car_switch_track_focus_highlight"
+        android:gravity="center"
+        android:top="@dimen/car_switch_track_margin_vertical" />
+</layer-list>
diff --git a/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_track_focus_highlight.xml b/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_track_focus_highlight.xml
new file mode 100644
index 0000000..cd0a40c
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/drawable/car_switch_track_focus_highlight.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 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_focused="true" android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/car_switch_track_focus_ring_outer_radius" />
+            <solid android:color="@color/focus_pressed_fill_color" />
+            <padding
+                android:left="@dimen/car_switch_track_focus_ring_padding"
+                android:right="@dimen/car_switch_track_focus_ring_padding" />
+            <size
+                android:height="@dimen/car_switch_track_focus_ring_height"
+                android:width="@dimen/car_switch_track_focus_ring_width" />
+            <stroke
+                android:width="@dimen/focus_pressed_stroke_width"
+                android:color="@color/focus_pressed_stroke_color" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/car_switch_track_focus_ring_outer_radius" />
+            <solid android:color="@color/focus_fill_color" />
+            <padding
+                android:left="@dimen/car_switch_track_focus_ring_padding"
+                android:right="@dimen/car_switch_track_focus_ring_padding" />
+            <size
+                android:height="@dimen/car_switch_track_focus_ring_height"
+                android:width="@dimen/car_switch_track_focus_ring_width" />
+            <stroke
+                android:width="@dimen/focus_stroke_width"
+                android:color="@color/focus_stroke_color" />
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="?android:attr/colorControlHighlight" />
+    </item>
+</selector>
diff --git a/car-ui-lib/oem-tokens/android-rro/res/values/colors.xml b/car-ui-lib/oem-tokens/android-rro/res/values/colors.xml
new file mode 100644
index 0000000..e133f4a
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/values/colors.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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">
+    <!-- Focus colors -->
+    <color name="focus_stroke_color">#94CBFF</color>
+    <color name="focus_fill_color">#3D94CBFF</color>
+    <color name="focus_pressed_stroke_color">#94CBFF</color>
+    <color name="focus_pressed_fill_color">#8A94CBFF</color>
+
+
+    <!-- The Switch track background color when checked. -->
+    <color name="car_switch_track_background_checked">@color/color_primary</color>
+    <!-- The Switch track background color when unchecked. -->
+    <color name="car_switch_track_background_unchecked">@color/color_secondary_container</color>
+</resources>
diff --git a/car-ui-lib/oem-tokens/android-rro/res/values/dimens.xml b/car-ui-lib/oem-tokens/android-rro/res/values/dimens.xml
new file mode 100644
index 0000000..b181607
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/values/dimens.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2024, 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.
+*/
+-->
+<!-- Consider other dimension overrides in values-xxx when adding/changing the value here! -->
+<resources>
+    <!-- Focus dimensions -->
+    <dimen name="focus_stroke_width">8dp</dimen>
+    <dimen name="focus_pressed_stroke_width">4dp</dimen>
+
+    <!-- Switch dimensions -->
+    <dimen name="car_switch_track_height">48dp</dimen>
+    <dimen name="car_switch_track_width">88dp</dimen>
+    <!-- Increases the vertical touch target size. -->
+    <dimen name="car_switch_track_margin_vertical">14dp</dimen>
+    <!-- Switch focus ring height. -->
+    <dimen name="car_switch_track_focus_ring_height">72dp</dimen>
+    <!-- Switch focus ring width. -->
+    <dimen name="car_switch_track_focus_ring_width">112dp</dimen>
+    <!-- Switch focus ring padding. -->
+    <dimen name="car_switch_track_focus_ring_padding">12dp</dimen>
+    <!-- Should be the half of car_switch_track_focus_ring_height. -->
+    <dimen name="car_switch_track_focus_ring_outer_radius">36dp</dimen>
+    <!-- Should be the half of car_switch_track_height. -->
+    <dimen name="car_switch_thumb_outer_radius">24dp</dimen>
+    <!--  The difference between the track size and the thumb size. -->
+    <dimen name="car_switch_thumb_stroke_width">4dp</dimen>
+    <!-- car_switch_thumb_size + car_switch_thumb_stroke_width == car_switch_track_height -->
+    <dimen name="car_switch_thumb_size">40dp</dimen>
+</resources>
diff --git a/car-ui-lib/oem-tokens/android-rro/res/values/styles_device_default.xml b/car-ui-lib/oem-tokens/android-rro/res/values/styles_device_default.xml
new file mode 100644
index 0000000..9276c0f
--- /dev/null
+++ b/car-ui-lib/oem-tokens/android-rro/res/values/styles_device_default.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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 an override of frameworks/base/core/res/res/values/styles_device_default.xml
+    It is how the device default is changed to match the desired look for a car theme.
+-->
+<resources>
+    <style name="Widget.DeviceDefault.CompoundButton.Switch"
+        parent="android:Widget.Material.CompoundButton.Switch">
+        <item name="android:thumb">@drawable/car_switch_thumb</item>
+        <item name="android:track">@drawable/car_switch_track</item>
+    </style>
+
+    <style name="Widget.DeviceDefault.Light.CompoundButton.Switch"
+        parent="android:Widget.Material.Light.CompoundButton.Switch">
+        <item name="android:thumb">@drawable/car_switch_thumb</item>
+        <item name="android:track">@drawable/car_switch_track</item>
+    </style>
+</resources>
diff --git a/car-ui-lib/oem-tokens/customization-base/Android.bp b/car-ui-lib/oem-tokens/customization-base/Android.bp
new file mode 100644
index 0000000..92b4872
--- /dev/null
+++ b/car-ui-lib/oem-tokens/customization-base/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 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: "token-customization-base",
+    resource_dirs: ["src/main/res"],
+    manifest: "src/main/AndroidManifest.xml",
+    sdk_version: "current",
+}
+
diff --git a/car-ui-lib/oem-tokens/customization-base/src/main/AndroidManifest.xml b/car-ui-lib/oem-tokens/customization-base/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b433451
--- /dev/null
+++ b/car-ui-lib/oem-tokens/customization-base/src/main/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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="oem.brand.model.base">
+</manifest>
diff --git a/car-ui-lib/oem-tokens/customization-base/src/main/res/values-night/colors.xml b/car-ui-lib/oem-tokens/customization-base/src/main/res/values-night/colors.xml
new file mode 100644
index 0000000..71ac334
--- /dev/null
+++ b/car-ui-lib/oem-tokens/customization-base/src/main/res/values-night/colors.xml
@@ -0,0 +1,46 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Copyright (C) 2024 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="color_primary">#Df8C93</color>
+    <color name="color_on_primary">#35040E</color>
+    <color name="color_primary_container">#72333A</color>
+    <color name="color_on_primary_container">#Ffdadb</color>
+    <color name="color_secondary">#C0999C</color>
+    <color name="color_on_secondary">#271113</color>
+    <color name="color_secondary_container">#5C3F41</color>
+    <color name="color_on_secondary_container">#Ffdadb</color>
+    <color name="color_tertiary">#C19D6D</color>
+    <color name="color_on_tertiary">#241400</color>
+    <color name="color_tertiary_container">#5D421B</color>
+    <color name="color_on_tertiary_container">#Ffddb5</color>
+    <color name="color_error">#Ffb4Ab</color>
+    <color name="color_on_error">#690005</color>
+    <color name="color_error_container">#93000A</color>
+    <color name="color_on_error_container">#Ffdad6</color>
+    <color name="color_outline">#9F8C8D</color>
+    <color name="color_background">#1A1112</color>
+    <color name="color_on_background">#F0Dedf</color>
+    <color name="color_surface">#1A1112</color>
+    <color name="color_on_surface">#F0Dedf</color>
+    <color name="color_surface_variant">#524344</color>
+    <color name="color_on_surface_variant">#D7C1C2</color>
+    <color name="color_surface_inverse">#F0Dedf</color>
+    <color name="color_on_surface_inverse">#382E2E</color>
+    <color name="color_primary_inverse">#8F4A51</color>
+    <color name="color_surface_tint">#Ffb2B8</color>
+    <color name="color_outline_variant">#524344</color>
+    <color name="color_scrim">#000000</color>
+</resources>
diff --git a/car-ui-lib/oem-tokens/customization-base/src/main/res/values/colors.xml b/car-ui-lib/oem-tokens/customization-base/src/main/res/values/colors.xml
new file mode 100644
index 0000000..d62cc98
--- /dev/null
+++ b/car-ui-lib/oem-tokens/customization-base/src/main/res/values/colors.xml
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+    <color name="color_primary">#48121B</color>
+    <color name="color_on_primary">#Ffffff</color>
+    <color name="color_primary_container">#72333A</color>
+    <color name="color_on_primary_container">#Ffd6D8</color>
+    <color name="color_secondary">#381F21</color>
+    <color name="color_on_secondary">#Ffffff</color>
+    <color name="color_secondary_container">#5C3F41</color>
+    <color name="color_on_secondary_container">#Ffd6D8</color>
+    <color name="color_tertiary">#372100</color>
+    <color name="color_on_tertiary">#Ffffff</color>
+    <color name="color_tertiary_container">#5D421B</color>
+    <color name="color_on_tertiary_container">#Ffdaae</color>
+    <color name="color_error">#Ba1A1A</color>
+    <color name="color_on_error">#Ffffff</color>
+    <color name="color_error_container">#Ffdad6</color>
+    <color name="color_on_error_container">#410002</color>
+    <color name="color_outline">#857374</color>
+    <color name="color_background">#Fff8F7</color>
+    <color name="color_on_background">#22191A</color>
+    <color name="color_surface">#Fff8F7</color>
+    <color name="color_on_surface">#22191A</color>
+    <color name="color_surface_variant">#F4Ddde</color>
+    <color name="color_on_surface_variant">#524344</color>
+    <color name="color_surface_inverse">#382E2E</color>
+    <color name="color_on_surface_inverse">#Ffeded</color>
+    <color name="color_primary_inverse">#Ffb2B8</color>
+    <color name="color_surface_tint">#8F4A51</color>
+    <color name="color_outline_variant">#D7C1C2</color>
+    <color name="color_scrim">#000000</color>
+
+    <color name="color_primary_palette_0">#000000</color>
+    <color name="color_primary_palette_10">#3B0711</color>
+    <color name="color_primary_palette_20">#561D25</color>
+    <color name="color_primary_palette_30">#72333A</color>
+    <color name="color_primary_palette_40">#8F4A51</color>
+    <color name="color_primary_palette_50">#AC6169</color>
+    <color name="color_primary_palette_60">#CA7A81</color>
+    <color name="color_primary_palette_70">#E8949B</color>
+    <color name="color_primary_palette_80">#FFB2B8</color>
+    <color name="color_primary_palette_90">#FFDADB</color>
+    <color name="color_primary_palette_95">#FFECED</color>
+    <color name="color_primary_palette_99">#FFFBFF</color>
+    <color name="color_primary_palette_100">#FFFFFF</color>
+
+    <color name="color_secondary_palette_0">#000000</color>
+    <color name="color_secondary_palette_10">#2C1517</color>
+    <color name="color_secondary_palette_20">#44292B</color>
+    <color name="color_secondary_palette_30">#5C3F41</color>
+    <color name="color_secondary_palette_40">#765658</color>
+    <color name="color_secondary_palette_50">#916E71</color>
+    <color name="color_secondary_palette_60">#AC888A</color>
+    <color name="color_secondary_palette_70">#C9A2A4</color>
+    <color name="color_secondary_palette_80">#E5BDBF</color>
+    <color name="color_secondary_palette_90">#FFDADB</color>
+    <color name="color_secondary_palette_95">#FFECED</color>
+    <color name="color_secondary_palette_99">#FFFBFF</color>
+    <color name="color_secondary_palette_100">#FFFFFF</color>
+
+    <color name="color_tertiary_palette_0">#000000</color>
+    <color name="color_tertiary_palette_10">#2A1800</color>
+    <color name="color_tertiary_palette_20">#442C06</color>
+    <color name="color_tertiary_palette_30">#5D421B</color>
+    <color name="color_tertiary_palette_40">#775930</color>
+    <color name="color_tertiary_palette_50">#927146</color>
+    <color name="color_tertiary_palette_60">#AE8B5D</color>
+    <color name="color_tertiary_palette_70">#CAA575</color>
+    <color name="color_tertiary_palette_80">#E8C08E</color>
+    <color name="color_tertiary_palette_90">#FFDDB5</color>
+    <color name="color_tertiary_palette_95">#FFEEDD</color>
+    <color name="color_tertiary_palette_99">#FFFBFF</color>
+    <color name="color_tertiary_palette_100">#FFFFFF</color>
+
+    <color name="color_neutral_palette_0">#000000</color>
+    <color name="color_neutral_palette_10">#22191A</color>
+    <color name="color_neutral_palette_20">#382E2E</color>
+    <color name="color_neutral_palette_30">#4F4444</color>
+    <color name="color_neutral_palette_40">#685B5C</color>
+    <color name="color_neutral_palette_50">#817474</color>
+    <color name="color_neutral_palette_60">#9C8D8E</color>
+    <color name="color_neutral_palette_70">#B7A8A8</color>
+    <color name="color_neutral_palette_80">#D3C3C3</color>
+    <color name="color_neutral_palette_90">#F0DEDF</color>
+    <color name="color_neutral_palette_95">#FFEDED</color>
+    <color name="color_neutral_palette_99">#FFFBFF</color>
+    <color name="color_neutral_palette_100">#FFFFFF</color>
+
+    <color name="color_neutral_variant_palette_0">#000000</color>
+    <color name="color_neutral_variant_palette_10">#241819</color>
+    <color name="color_neutral_variant_palette_20">#3B2D2E</color>
+    <color name="color_neutral_variant_palette_30">#524344</color>
+    <color name="color_neutral_variant_palette_40">#6B5A5B</color>
+    <color name="color_neutral_variant_palette_50">#857374</color>
+    <color name="color_neutral_variant_palette_60">#9F8C8D</color>
+    <color name="color_neutral_variant_palette_70">#BBA6A7</color>
+    <color name="color_neutral_variant_palette_80">#D7C1C2</color>
+    <color name="color_neutral_variant_palette_90">#F4DDDE</color>
+    <color name="color_neutral_variant_palette_95">#FFECED</color>
+    <color name="color_neutral_variant_palette_99">#FFFBFF</color>
+    <color name="color_neutral_variant_palette_100">#FFFFFF</color>
+</resources>
diff --git a/car-ui-lib/oem-tokens/lib/Android.bp b/car-ui-lib/oem-tokens/lib/Android.bp
index c071019..ec79910 100644
--- a/car-ui-lib/oem-tokens/lib/Android.bp
+++ b/car-ui-lib/oem-tokens/lib/Android.bp
@@ -15,9 +15,13 @@
 // MUST be a resource only library
 android_library {
     name: "oem-token-lib-source",
+
     min_sdk_version: "28",
     target_sdk_version: "33",
     sdk_version: "current",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
+
     manifest: "src/main/AndroidManifest.xml",
     srcs: ["src/main/java/**/*.java"],
     resource_dirs: [
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_background_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_background_token.xml
deleted file mode 100644
index 10b5ccc..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_background_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorBackground" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_error_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_error_container_token.xml
deleted file mode 100644
index 7e754a5..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_error_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorErrorContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_error_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_error_token.xml
deleted file mode 100644
index 63c576b..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_error_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorError" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_background_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_background_token.xml
deleted file mode 100644
index 788420a..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_background_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnBackground" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_error_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_error_container_token.xml
deleted file mode 100644
index f72ce9d..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_error_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnErrorContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_error_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_error_token.xml
deleted file mode 100644
index a2d1a77..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_error_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnError" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_primary_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_primary_container_token.xml
deleted file mode 100644
index 028d39d..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_primary_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnPrimaryContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_primary_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_primary_token.xml
deleted file mode 100644
index c998e98..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_primary_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnPrimary" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_secondary_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_secondary_container_token.xml
deleted file mode 100644
index 65bd1b8..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_secondary_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnSecondaryContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_secondary_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_secondary_token.xml
deleted file mode 100644
index b263a21..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_secondary_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnSecondary" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_surface_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_surface_token.xml
deleted file mode 100644
index a6ebe35..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_surface_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnSurface" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_surface_variant_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_surface_variant_token.xml
deleted file mode 100644
index 5ef5378..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_surface_variant_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnSurfaceVariant" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_tertiary_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_tertiary_container_token.xml
deleted file mode 100644
index 35d454c..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_tertiary_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnTertiaryContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_tertiary_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_tertiary_token.xml
deleted file mode 100644
index c0b6ea7..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_on_tertiary_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorOnTertiary" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_primary_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_primary_container_token.xml
deleted file mode 100644
index bf8b640..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_primary_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorPrimaryContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_primary_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_primary_token.xml
deleted file mode 100644
index 083aac1..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_primary_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorPrimary" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_secondary_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_secondary_container_token.xml
deleted file mode 100644
index da64772..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_secondary_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorSecondaryContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_secondary_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_secondary_token.xml
deleted file mode 100644
index 4c6bc4c..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_secondary_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorSecondary" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_surface_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_surface_token.xml
deleted file mode 100644
index b455e33..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_surface_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorSurface" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_surface_variant_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_surface_variant_token.xml
deleted file mode 100644
index 31e9f8d..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_surface_variant_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorSurfaceVariant" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_tertiary_container_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_tertiary_container_token.xml
deleted file mode 100644
index d65587b..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_tertiary_container_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorTertiaryContainer" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_tertiary_token.xml b/car-ui-lib/oem-tokens/lib/src/main/res/color/color_tertiary_token.xml
deleted file mode 100644
index 19908b7..0000000
--- a/car-ui-lib/oem-tokens/lib/src/main/res/color/color_tertiary_token.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/oemColorTertiary" />
-</selector>
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/values/attrs.xml b/car-ui-lib/oem-tokens/lib/src/main/res/values/attrs.xml
index 4ca823d..d8ffced 100644
--- a/car-ui-lib/oem-tokens/lib/src/main/res/values/attrs.xml
+++ b/car-ui-lib/oem-tokens/lib/src/main/res/values/attrs.xml
@@ -23,6 +23,7 @@
         <attr name="oemColorOnPrimary" format="color" />
         <attr name="oemColorPrimaryContainer" format="color" />
         <attr name="oemColorOnPrimaryContainer" format="color" />
+        <attr name="oemColorPrimaryInverse" format="color" />
 
         <attr name="oemColorSecondary" format="color" />
         <attr name="oemColorOnSecondary" format="color" />
@@ -45,7 +46,12 @@
         <attr name="oemColorOnSurface" format="color" />
         <attr name="oemColorSurfaceVariant" format="color" />
         <attr name="oemColorOnSurfaceVariant" format="color" />
+        <attr name="oemColorSurfaceInverse" format="color" />
+        <attr name="oemColorOnSurfaceInverse" format="color" />
         <attr name="oemColorOutline" format="color" />
+        <attr name="oemColorScrim" format="color" />
+        <attr name="oemColorOutlineVariant" format="color" />
+        <attr name="oemColorSurfaceTint" format="color" />
 
         <attr name="oemColorPrimaryPalette100" format="color" />
         <attr name="oemColorPrimaryPalette99" format="color" />
diff --git a/car-ui-lib/oem-tokens/lib/src/main/res/values/styles.xml b/car-ui-lib/oem-tokens/lib/src/main/res/values/styles.xml
index 664234a..f1baa18 100644
--- a/car-ui-lib/oem-tokens/lib/src/main/res/values/styles.xml
+++ b/car-ui-lib/oem-tokens/lib/src/main/res/values/styles.xml
@@ -40,7 +40,13 @@
         <item name="oemColorOnSurface">?attr/oemColorNeutralPalette80</item>
         <item name="oemColorSurfaceVariant">?attr/oemColorNeutralVariantPalette30</item>
         <item name="oemColorOnSurfaceVariant">?attr/oemColorNeutralVariantPalette80</item>
+        <item name="oemColorSurfaceInverse">?attr/oemColorNeutralVariantPalette80</item>
+        <item name="oemColorOnSurfaceInverse">?attr/oemColorNeutralVariantPalette10</item>
+        <item name="oemColorPrimaryInverse">?attr/oemColorPrimaryPalette40</item>
         <item name="oemColorOutline">?attr/oemColorNeutralVariantPalette60</item>
+        <item name="oemColorScrim">?attr/oemColorNeutralPalette80</item>
+        <item name="oemColorOutlineVariant">?attr/oemColorNeutralVariantPalette30</item>
+        <item name="oemColorSurfaceTint">?attr/oemColorPrimaryPalette80</item>
 
         <item name="oemColorPrimaryPalette100">@color/oem_default_color_primary_palette_100</item>
         <item name="oemColorPrimaryPalette99">@color/oem_default_color_primary_palette_99</item>
@@ -175,6 +181,12 @@
         <item name="oemColorSurfaceVariant">?com.android.oem.tokens:attr/colorSurfaceVariant</item>
         <item name="oemColorOnSurfaceVariant">?com.android.oem.tokens:attr/colorOnSurfaceVariant</item>
         <item name="oemColorOutline">?com.android.oem.tokens:attr/colorOutline</item>
+        <item name="oemColorSurfaceInverse">?com.android.oem.tokens:attr/colorSurfaceInverse</item>
+        <item name="oemColorOnSurfaceInverse">?com.android.oem.tokens:attr/colorOnSurfaceInverse</item>
+        <item name="oemColorPrimaryInverse">?com.android.oem.tokens:attr/colorPrimaryInverse</item>
+        <item name="oemColorScrim">?com.android.oem.tokens:attr/colorScrim</item>
+        <item name="oemColorOutlineVariant">?com.android.oem.tokens:attr/colorOutlineVariant</item>
+        <item name="oemColorSurfaceTint">?com.android.oem.tokens:attr/colorSurfaceTint</item>
 
         <item name="oemColorPrimaryPalette100">?com.android.oem.tokens:attr/colorPrimaryPalette100</item>
         <item name="oemColorPrimaryPalette99">?com.android.oem.tokens:attr/colorPrimaryPalette99</item>
@@ -283,6 +295,12 @@
         <item name="com.android.oem.tokens:colorSurfaceVariant">?attr/oemColorNeutralVariantPalette30</item>
         <item name="com.android.oem.tokens:colorOnSurfaceVariant">?attr/oemColorNeutralVariantPalette80</item>
         <item name="com.android.oem.tokens:colorOutline">?attr/oemColorNeutralVariantPalette60</item>
+        <item name="com.android.oem.tokens:colorSurfaceInverse">?attr/oemColorNeutralPalette80</item>
+        <item name="com.android.oem.tokens:colorOnSurfaceInverse">?attr/oemColorNeutralPalette10</item>
+        <item name="com.android.oem.tokens:colorPrimaryInverse">?attr/oemColorPrimaryPalette40</item>
+        <item name="com.android.oem.tokens:colorScrim">?attr/oemColorNeutralPalette80</item>
+        <item name="com.android.oem.tokens:colorOutlineVariant">?attr/oemColorNeutralVariantPalette30</item>
+        <item name="com.android.oem.tokens:colorSurfaceTint">?attr/oemColorPrimaryPalette80</item>
 
         <item name="com.android.oem.tokens:colorPrimaryPalette100">@color/oem_default_color_primary_palette_100</item>
         <item name="com.android.oem.tokens:colorPrimaryPalette99">@color/oem_default_color_primary_palette_99</item>
diff --git a/car-ui-lib/oem-tokens/rro/Android.bp b/car-ui-lib/oem-tokens/rro/Android.bp
index b1b5f98..7161676 100644
--- a/car-ui-lib/oem-tokens/rro/Android.bp
+++ b/car-ui-lib/oem-tokens/rro/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 The Android Open Source Project
+// Copyright (C) 2024 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.
@@ -25,6 +25,9 @@
        "token-shared-lib",
     ],
     enforce_uses_libs:false,
+    static_libs: [
+       "token-customization-base",
+    ],
     dex_preopt: {
         enabled: false,
     },
diff --git a/car-ui-lib/oem-tokens/rro/build.gradle b/car-ui-lib/oem-tokens/rro/build.gradle
index ac22cbd..2beefc6 100644
--- a/car-ui-lib/oem-tokens/rro/build.gradle
+++ b/car-ui-lib/oem-tokens/rro/build.gradle
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 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.
diff --git a/car-ui-lib/oem-tokens/rro/src/main/AndroidManifest.xml b/car-ui-lib/oem-tokens/rro/src/main/AndroidManifest.xml
index 7e64c94..5fa267b 100644
--- a/car-ui-lib/oem-tokens/rro/src/main/AndroidManifest.xml
+++ b/car-ui-lib/oem-tokens/rro/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2022 The Android Open Source Project
+  ~ Copyright (C) 2024 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.
diff --git a/car-ui-lib/oem-tokens/rro/src/main/res/values-night/styles.xml b/car-ui-lib/oem-tokens/rro/src/main/res/values-night/styles.xml
deleted file mode 100644
index b48b6c1..0000000
--- a/car-ui-lib/oem-tokens/rro/src/main/res/values-night/styles.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <style name="OemStyle">
-        <item name="com.android.oem.tokens:colorPrimary">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorOnPrimary">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorPrimaryContainer">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorOnPrimaryContainer">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorSecondary">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorOnSecondary">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorSecondaryContainer">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorOnSecondaryContainer">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorTertiary">@android:color/holo_orange_dark</item>
-        <item name="com.android.oem.tokens:colorOnTertiary">@android:color/holo_orange_dark</item>
-    </style>
-</resources>
diff --git a/car-ui-lib/oem-tokens/rro/src/main/res/values/bools.xml b/car-ui-lib/oem-tokens/rro/src/main/res/values/bools.xml
index 2ac5c00..c126c3d 100644
--- a/car-ui-lib/oem-tokens/rro/src/main/res/values/bools.xml
+++ b/car-ui-lib/oem-tokens/rro/src/main/res/values/bools.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
diff --git a/car-ui-lib/oem-tokens/rro/src/main/res/values/styles.xml b/car-ui-lib/oem-tokens/rro/src/main/res/values/styles.xml
index 58bc1b5..fb7d1a1 100644
--- a/car-ui-lib/oem-tokens/rro/src/main/res/values/styles.xml
+++ b/car-ui-lib/oem-tokens/rro/src/main/res/values/styles.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
@@ -13,17 +13,106 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
+<resources>
     <style name="OemStyle">
-        <item name="com.android.oem.tokens:colorPrimary">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorOnPrimary">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorPrimaryContainer">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorOnPrimaryContainer">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorSecondary">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorOnSecondary">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorSecondaryContainer">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorOnSecondaryContainer">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorTertiary">@android:color/holo_green_dark</item>
-        <item name="com.android.oem.tokens:colorOnTertiary">@android:color/holo_green_dark</item>
+        <item name="com.android.oem.tokens:colorPrimary">@color/color_primary</item>
+        <item name="com.android.oem.tokens:colorOnPrimary">@color/color_on_primary</item>
+        <item name="com.android.oem.tokens:colorPrimaryContainer">@color/color_primary_container</item>
+        <item name="com.android.oem.tokens:colorOnPrimaryContainer">@color/color_on_primary_container</item>
+        <item name="com.android.oem.tokens:colorSecondary">@color/color_secondary</item>
+        <item name="com.android.oem.tokens:colorOnSecondary">@color/color_on_secondary</item>
+        <item name="com.android.oem.tokens:colorSecondaryContainer">@color/color_secondary_container</item>
+        <item name="com.android.oem.tokens:colorOnSecondaryContainer">@color/color_on_secondary_container</item>
+        <item name="com.android.oem.tokens:colorTertiary">@color/color_tertiary</item>
+        <item name="com.android.oem.tokens:colorOnTertiary">@color/color_on_tertiary</item>
+        <item name="com.android.oem.tokens:colorTertiaryContainer">@color/color_tertiary_container</item>
+        <item name="com.android.oem.tokens:colorOnTertiaryContainer">@color/color_on_tertiary_container</item>
+        <item name="com.android.oem.tokens:colorError">@color/color_error</item>
+        <item name="com.android.oem.tokens:colorOnError">@color/color_on_error</item>
+        <item name="com.android.oem.tokens:colorErrorContainer">@color/color_error_container</item>
+        <item name="com.android.oem.tokens:colorOnErrorContainer">@color/color_on_error_container</item>
+        <item name="com.android.oem.tokens:colorOutline">@color/color_outline</item>
+        <item name="com.android.oem.tokens:colorBackground">@color/color_background</item>
+        <item name="com.android.oem.tokens:colorOnBackground">@color/color_on_background</item>
+        <item name="com.android.oem.tokens:colorSurface">@color/color_surface</item>
+        <item name="com.android.oem.tokens:colorOnSurface">@color/color_on_surface</item>
+        <item name="com.android.oem.tokens:colorSurfaceVariant">@color/color_surface_variant</item>
+        <item name="com.android.oem.tokens:colorOnSurfaceVariant">@color/color_on_surface_variant</item>
+        <item name="com.android.oem.tokens:colorSurfaceInverse">@color/color_surface_inverse</item>
+        <item name="com.android.oem.tokens:colorOnSurfaceInverse">@color/color_on_surface_inverse</item>
+        <item name="com.android.oem.tokens:colorPrimaryInverse">@color/color_primary_inverse</item>
+        <item name="com.android.oem.tokens:colorSurfaceTint">@color/color_surface_tint</item>
+        <item name="com.android.oem.tokens:colorOutlineVariant">@color/color_outline_variant</item>
+        <item name="com.android.oem.tokens:colorScrim">@color/color_scrim</item>
+
+        <item name="com.android.oem.tokens:colorPrimaryPalette0">@color/color_primary_palette_0</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette10">@color/color_primary_palette_10</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette20">@color/color_primary_palette_20</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette30">@color/color_primary_palette_30</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette40">@color/color_primary_palette_40</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette50">@color/color_primary_palette_50</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette60">@color/color_primary_palette_60</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette70">@color/color_primary_palette_70</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette80">@color/color_primary_palette_80</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette90">@color/color_primary_palette_90</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette95">@color/color_primary_palette_95</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette99">@color/color_primary_palette_99</item>
+        <item name="com.android.oem.tokens:colorPrimaryPalette100">@color/color_primary_palette_100</item>
+
+        <item name="com.android.oem.tokens:colorSecondaryPalette0">@color/color_secondary_palette_0</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette10">@color/color_secondary_palette_10</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette20">@color/color_secondary_palette_20</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette30">@color/color_secondary_palette_30</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette40">@color/color_secondary_palette_40</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette50">@color/color_secondary_palette_50</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette60">@color/color_secondary_palette_60</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette70">@color/color_secondary_palette_70</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette80">@color/color_secondary_palette_80</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette90">@color/color_secondary_palette_90</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette95">@color/color_secondary_palette_95</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette99">@color/color_secondary_palette_99</item>
+        <item name="com.android.oem.tokens:colorSecondaryPalette100">@color/color_secondary_palette_100</item>
+
+        <item name="com.android.oem.tokens:colorTertiaryPalette0">@color/color_tertiary_palette_0</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette10">@color/color_tertiary_palette_10</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette20">@color/color_tertiary_palette_20</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette30">@color/color_tertiary_palette_30</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette40">@color/color_tertiary_palette_40</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette50">@color/color_tertiary_palette_50</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette60">@color/color_tertiary_palette_60</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette70">@color/color_tertiary_palette_70</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette80">@color/color_tertiary_palette_80</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette90">@color/color_tertiary_palette_90</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette95">@color/color_tertiary_palette_95</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette99">@color/color_tertiary_palette_99</item>
+        <item name="com.android.oem.tokens:colorTertiaryPalette100">@color/color_tertiary_palette_100</item>
+
+        <item name="com.android.oem.tokens:colorNeutralPalette0">@color/color_neutral_palette_0</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette10">@color/color_neutral_palette_10</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette20">@color/color_neutral_palette_20</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette30">@color/color_neutral_palette_30</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette40">@color/color_neutral_palette_40</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette50">@color/color_neutral_palette_50</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette60">@color/color_neutral_palette_60</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette70">@color/color_neutral_palette_70</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette80">@color/color_neutral_palette_80</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette90">@color/color_neutral_palette_90</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette95">@color/color_neutral_palette_95</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette99">@color/color_neutral_palette_99</item>
+        <item name="com.android.oem.tokens:colorNeutralPalette100">@color/color_neutral_palette_100</item>
+
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette0">@color/color_neutral_variant_palette_0</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette10">@color/color_neutral_variant_palette_10</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette20">@color/color_neutral_variant_palette_20</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette30">@color/color_neutral_variant_palette_30</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette40">@color/color_neutral_variant_palette_40</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette50">@color/color_neutral_variant_palette_50</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette60">@color/color_neutral_variant_palette_60</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette70">@color/color_neutral_variant_palette_70</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette80">@color/color_neutral_variant_palette_80</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette90">@color/color_neutral_variant_palette_90</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette95">@color/color_neutral_variant_palette_95</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette99">@color/color_neutral_variant_palette_99</item>
+        <item name="com.android.oem.tokens:colorNeutralVariantPalette100">@color/color_neutral_variant_palette_100</item>
     </style>
 </resources>
diff --git a/car-ui-lib/oem-tokens/rro/src/main/res/xml/overlays.xml b/car-ui-lib/oem-tokens/rro/src/main/res/xml/overlays.xml
index 556c715..15dbba5 100644
--- a/car-ui-lib/oem-tokens/rro/src/main/res/xml/overlays.xml
+++ b/car-ui-lib/oem-tokens/rro/src/main/res/xml/overlays.xml
@@ -1,5 +1,5 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
diff --git a/car-ui-lib/oem-tokens/shared-lib/Android.bp b/car-ui-lib/oem-tokens/shared-lib/Android.bp
index 6a3ca07..70e8ed9 100644
--- a/car-ui-lib/oem-tokens/shared-lib/Android.bp
+++ b/car-ui-lib/oem-tokens/shared-lib/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 The Android Open Source Project
+// Copyright (C) 2024 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.
@@ -15,9 +15,13 @@
 // MUST be a resource only library
 android_app {
     name: "token-shared-lib",
+
     min_sdk_version: "28",
     target_sdk_version: "33",
     sdk_version: "current",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
+
     aaptflags: ["--shared-lib"],
     manifest: "src/main/AndroidManifest.xml",
     resource_dirs: [
@@ -49,9 +53,13 @@
 
 android_library {
     name: "token-sharedlibrary-base",
+
     min_sdk_version: "28",
     target_sdk_version: "33",
     sdk_version: "current",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
+
     manifest: "src/main/AndroidManifest.xml",
 }
 
@@ -71,4 +79,3 @@
         targets: ["token-sharedlibrary-aar",]
     },
 }
-
diff --git a/car-ui-lib/oem-tokens/shared-lib/build.gradle b/car-ui-lib/oem-tokens/shared-lib/build.gradle
index 2faaf85..7e2313f 100644
--- a/car-ui-lib/oem-tokens/shared-lib/build.gradle
+++ b/car-ui-lib/oem-tokens/shared-lib/build.gradle
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 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.
diff --git a/car-ui-lib/oem-tokens/shared-lib/prebuilt/token-shared-lib.apk b/car-ui-lib/oem-tokens/shared-lib/prebuilt/token-shared-lib.apk
index e4d93c0..bf72a95 100644
--- a/car-ui-lib/oem-tokens/shared-lib/prebuilt/token-shared-lib.apk
+++ b/car-ui-lib/oem-tokens/shared-lib/prebuilt/token-shared-lib.apk
Binary files differ
diff --git a/car-ui-lib/oem-tokens/shared-lib/src/main/AndroidManifest.xml b/car-ui-lib/oem-tokens/shared-lib/src/main/AndroidManifest.xml
index c1c7367..e76c82c 100644
--- a/car-ui-lib/oem-tokens/shared-lib/src/main/AndroidManifest.xml
+++ b/car-ui-lib/oem-tokens/shared-lib/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2022 The Android Open Source Project
+  ~ Copyright (C) 2024 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.
@@ -16,7 +16,8 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.oem.tokens">
+    package="com.android.oem.tokens"
+    android:versionCode="2">
     <application>
         <library android:name="com.android.oem.tokens" />
     </application>
diff --git a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/attrs.xml b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/attrs.xml
index 6a52469..d27eb55 100644
--- a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/attrs.xml
+++ b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/attrs.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
@@ -19,10 +19,9 @@
     <!-- Primary color palette -->
     <attr name="colorPrimary" format="color" />
     <attr name="colorOnPrimary" format="color" />
+    <attr name="colorPrimaryInverse" format="color" />
     <attr name="colorPrimaryContainer" format="color" />
     <attr name="colorOnPrimaryContainer" format="color" />
-    <!-- TODO: Determine usage of inverse colors. -->
-    <!--  <attr name="colorPrimaryInverse" format="color" />-->
 
     <!-- Secondary color palette -->
     <attr name="colorSecondary" format="color" />
@@ -49,10 +48,12 @@
     <attr name="colorOnSurface" format="color" />
     <attr name="colorSurfaceVariant" format="color" />
     <attr name="colorOnSurfaceVariant" format="color" />
+    <attr name="colorSurfaceInverse" format="color" />
+    <attr name="colorOnSurfaceInverse" format="color" />
+    <attr name="colorSurfaceTint" format="color" />
     <attr name="colorOutline" format="color" />
-    <!-- TODO: Determine usage of inverse colors. -->
-    <!--  <attr name="colorSurfaceInverse" format="color" />-->
-    <!--  <attr name="colorOnSurfaceInverse" format="color" />-->
+    <attr name="colorOutlineVariant" format="color" />
+    <attr name="colorScrim" format="color" />
 
     <!-- Primary tonal palette -->
     <attr name="colorPrimaryPalette100" format="color" />
@@ -114,7 +115,6 @@
     <attr name="colorErrorPalette10" format="color" />
     <attr name="colorErrorPalette0" format="color" />
 
-    <!-- Neutral tonal palette -->
     <attr name="colorNeutralPalette100" format="color" />
     <attr name="colorNeutralPalette99" format="color" />
     <attr name="colorNeutralPalette95" format="color" />
diff --git a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/bools.xml b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/bools.xml
index 2ac5c00..c126c3d 100644
--- a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/bools.xml
+++ b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/bools.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
diff --git a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/public.xml b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/public.xml
index e0a598f..b4f0d6e 100644
--- a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/public.xml
+++ b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/public.xml
@@ -14,6 +14,7 @@
  limitations under the License.
 -->
 <resources>
+    <!-- Color tokens -->
     <public name="colorOemSeed" id="0x00770000" type="attr" />
     <public name="colorPrimary" id="0x00770001" type="attr" />
     <public name="colorOnPrimary" id="0x00770002" type="attr" />
@@ -38,104 +39,126 @@
     <public name="colorSurfaceVariant" id="0x00770015" type="attr" />
     <public name="colorOnSurfaceVariant" id="0x00770016" type="attr" />
     <public name="colorOutline" id="0x00770017" type="attr" />
-    <public name="colorPrimaryPalette100" id="0x00770018" type="attr" />
-    <public name="colorPrimaryPalette99" id="0x00770019" type="attr" />
-    <public name="colorPrimaryPalette95" id="0x0077001A" type="attr" />
-    <public name="colorPrimaryPalette90" id="0x0077001B" type="attr" />
-    <public name="colorPrimaryPalette80" id="0x0077001C" type="attr" />
-    <public name="colorPrimaryPalette70" id="0x0077001D" type="attr" />
-    <public name="colorPrimaryPalette60" id="0x0077001E" type="attr" />
-    <public name="colorPrimaryPalette50" id="0x0077001F" type="attr" />
-    <public name="colorPrimaryPalette40" id="0x00770020" type="attr" />
-    <public name="colorPrimaryPalette30" id="0x00770021" type="attr" />
-    <public name="colorPrimaryPalette20" id="0x00770022" type="attr" />
-    <public name="colorPrimaryPalette10" id="0x00770023" type="attr" />
-    <public name="colorPrimaryPalette0" id="0x00770024" type="attr" />
-    <public name="colorSecondaryPalette100" id="0x00770025" type="attr" />
-    <public name="colorSecondaryPalette99" id="0x00770026" type="attr" />
-    <public name="colorSecondaryPalette95" id="0x00770027" type="attr" />
-    <public name="colorSecondaryPalette90" id="0x00770028" type="attr" />
-    <public name="colorSecondaryPalette80" id="0x00770029" type="attr" />
-    <public name="colorSecondaryPalette70" id="0x0077002A" type="attr" />
-    <public name="colorSecondaryPalette60" id="0x0077002B" type="attr" />
-    <public name="colorSecondaryPalette50" id="0x0077002C" type="attr" />
-    <public name="colorSecondaryPalette40" id="0x0077002D" type="attr" />
-    <public name="colorSecondaryPalette30" id="0x0077002E" type="attr" />
-    <public name="colorSecondaryPalette20" id="0x0077002F" type="attr" />
-    <public name="colorSecondaryPalette10" id="0x00770030" type="attr" />
-    <public name="colorSecondaryPalette0" id="0x00770031" type="attr" />
-    <public name="colorTertiaryPalette100" id="0x00770032" type="attr" />
-    <public name="colorTertiaryPalette99" id="0x00770033" type="attr" />
-    <public name="colorTertiaryPalette95" id="0x00770034" type="attr" />
-    <public name="colorTertiaryPalette90" id="0x00770035" type="attr" />
-    <public name="colorTertiaryPalette80" id="0x00770036" type="attr" />
-    <public name="colorTertiaryPalette70" id="0x00770037" type="attr" />
-    <public name="colorTertiaryPalette60" id="0x00770038" type="attr" />
-    <public name="colorTertiaryPalette50" id="0x00770039" type="attr" />
-    <public name="colorTertiaryPalette40" id="0x0077003A" type="attr" />
-    <public name="colorTertiaryPalette30" id="0x0077003B" type="attr" />
-    <public name="colorTertiaryPalette20" id="0x0077003C" type="attr" />
-    <public name="colorTertiaryPalette10" id="0x0077003D" type="attr" />
-    <public name="colorTertiaryPalette0" id="0x0077003E" type="attr" />
-    <public name="colorErrorPalette100" id="0x0077003F" type="attr" />
-    <public name="colorErrorPalette99" id="0x00770040" type="attr" />
-    <public name="colorErrorPalette95" id="0x00770041" type="attr" />
-    <public name="colorErrorPalette90" id="0x00770042" type="attr" />
-    <public name="colorErrorPalette80" id="0x00770043" type="attr" />
-    <public name="colorErrorPalette70" id="0x00770044" type="attr" />
-    <public name="colorErrorPalette60" id="0x00770045" type="attr" />
-    <public name="colorErrorPalette50" id="0x00770046" type="attr" />
-    <public name="colorErrorPalette40" id="0x00770047" type="attr" />
-    <public name="colorErrorPalette30" id="0x00770048" type="attr" />
-    <public name="colorErrorPalette20" id="0x00770049" type="attr" />
-    <public name="colorErrorPalette10" id="0x0077004A" type="attr" />
-    <public name="colorErrorPalette0" id="0x0077004B" type="attr" />
-    <public name="colorNeutralPalette100" id="0x0077004C" type="attr" />
-    <public name="colorNeutralPalette99" id="0x0077004D" type="attr" />
-    <public name="colorNeutralPalette95" id="0x0077004E" type="attr" />
-    <public name="colorNeutralPalette90" id="0x0077004F" type="attr" />
-    <public name="colorNeutralPalette80" id="0x00770050" type="attr" />
-    <public name="colorNeutralPalette70" id="0x00770051" type="attr" />
-    <public name="colorNeutralPalette60" id="0x00770052" type="attr" />
-    <public name="colorNeutralPalette50" id="0x00770053" type="attr" />
-    <public name="colorNeutralPalette40" id="0x00770054" type="attr" />
-    <public name="colorNeutralPalette30" id="0x00770055" type="attr" />
-    <public name="colorNeutralPalette20" id="0x00770056" type="attr" />
-    <public name="colorNeutralPalette10" id="0x00770057" type="attr" />
-    <public name="colorNeutralPalette0" id="0x00770058" type="attr" />
-    <public name="colorNeutralVariantPalette100" id="0x00770059" type="attr" />
-    <public name="colorNeutralVariantPalette99" id="0x0077005A" type="attr" />
-    <public name="colorNeutralVariantPalette95" id="0x0077005B" type="attr" />
-    <public name="colorNeutralVariantPalette90" id="0x0077005C" type="attr" />
-    <public name="colorNeutralVariantPalette80" id="0x0077005D" type="attr" />
-    <public name="colorNeutralVariantPalette70" id="0x0077005E" type="attr" />
-    <public name="colorNeutralVariantPalette60" id="0x0077005F" type="attr" />
-    <public name="colorNeutralVariantPalette50" id="0x00770060" type="attr" />
-    <public name="colorNeutralVariantPalette40" id="0x00770061" type="attr" />
-    <public name="colorNeutralVariantPalette30" id="0x00770062" type="attr" />
-    <public name="colorNeutralVariantPalette20" id="0x00770063" type="attr" />
-    <public name="colorNeutralVariantPalette10" id="0x00770064" type="attr" />
-    <public name="colorNeutralVariantPalette0" id="0x00770065" type="attr" />
-    <public name="textAppearanceDisplayLarge" id="0x00770066" type="attr" />
-    <public name="textAppearanceDisplayMedium" id="0x00770067" type="attr" />
-    <public name="textAppearanceDisplaySmall" id="0x00770068" type="attr" />
-    <public name="textAppearanceHeadlineLarge" id="0x00770069" type="attr" />
-    <public name="textAppearanceHeadlineMedium" id="0x0077006A" type="attr" />
-    <public name="textAppearanceHeadlineSmall" id="0x0077006B" type="attr" />
-    <public name="textAppearanceTitleLarge" id="0x0077006C" type="attr" />
-    <public name="textAppearanceTitleMedium" id="0x0077006D" type="attr" />
-    <public name="textAppearanceTitleSmall" id="0x0077006E" type="attr" />
-    <public name="textAppearanceLabelLarge" id="0x0077006F" type="attr" />
-    <public name="textAppearanceLabelMedium" id="0x00770070" type="attr" />
-    <public name="textAppearanceLabelSmall" id="0x00770071" type="attr" />
-    <public name="textAppearanceBodyLarge" id="0x00770072" type="attr" />
-    <public name="textAppearanceBodyMedium" id="0x00770073" type="attr" />
-    <public name="textAppearanceBodySmall" id="0x00770074" type="attr" />
-    <public name="shapeCornerNone" id="0x00770075" type="attr" />
-    <public name="shapeCornerExtraSmall" id="0x00770076" type="attr" />
-    <public name="shapeCornerSmall" id="0x00770077" type="attr" />
-    <public name="shapeCornerMedium" id="0x00770078" type="attr" />
-    <public name="shapeCornerLarge" id="0x00770079" type="attr" />
-    <public name="shapeCornerExtraLarge" id="0x0077007A" type="attr" />
-    <public name="shapeCornerFull" id="0x0077007B" type="attr" />
+    <public name="colorPrimaryInverse" id="0x00770018" type="attr" />
+    <public name="colorSurfaceInverse" id="0x00770019" type="attr" />
+    <public name="colorOnSurfaceInverse" id="0x0077001A" type="attr" />
+    <public name="colorScrim" id="0x0077001B" type="attr" />
+    <public name="colorOutlineVariant" id="0x0077001C" type="attr" />
+    <public name="colorSurfaceTint" id="0x0077001D" type="attr" />
+
+    <!-- Primary tonal palette -->
+    <public name="colorPrimaryPalette0" id="0x00771000" type="attr" />
+    <public name="colorPrimaryPalette10" id="0x0077100A" type="attr" />
+    <public name="colorPrimaryPalette20" id="0x00771014" type="attr" />
+    <public name="colorPrimaryPalette30" id="0x0077101E" type="attr" />
+    <public name="colorPrimaryPalette40" id="0x00771028" type="attr" />
+    <public name="colorPrimaryPalette50" id="0x00771032" type="attr" />
+    <public name="colorPrimaryPalette60" id="0x0077103C" type="attr" />
+    <public name="colorPrimaryPalette70" id="0x00771046" type="attr" />
+    <public name="colorPrimaryPalette80" id="0x00771050" type="attr" />
+    <public name="colorPrimaryPalette90" id="0x0077105A" type="attr" />
+    <public name="colorPrimaryPalette95" id="0x0077105F" type="attr" />
+    <public name="colorPrimaryPalette99" id="0x00771063" type="attr" />
+    <public name="colorPrimaryPalette100" id="0x00771064" type="attr" />
+
+    <!-- Secondary tonal palette -->
+    <public name="colorSecondaryPalette0" id="0x00772000" type="attr" />
+    <public name="colorSecondaryPalette10" id="0x0077200A" type="attr" />
+    <public name="colorSecondaryPalette20" id="0x00772014" type="attr" />
+    <public name="colorSecondaryPalette30" id="0x0077201E" type="attr" />
+    <public name="colorSecondaryPalette40" id="0x00772028" type="attr" />
+    <public name="colorSecondaryPalette50" id="0x00772032" type="attr" />
+    <public name="colorSecondaryPalette60" id="0x0077203C" type="attr" />
+    <public name="colorSecondaryPalette70" id="0x00772046" type="attr" />
+    <public name="colorSecondaryPalette80" id="0x00772050" type="attr" />
+    <public name="colorSecondaryPalette90" id="0x0077205A" type="attr" />
+    <public name="colorSecondaryPalette95" id="0x0077205F" type="attr" />
+    <public name="colorSecondaryPalette99" id="0x00772063" type="attr" />
+    <public name="colorSecondaryPalette100" id="0x00772064" type="attr" />
+
+    <!-- Tertiary tonal palette -->
+    <public name="colorTertiaryPalette0" id="0x00773000" type="attr" />
+    <public name="colorTertiaryPalette10" id="0x0077300A" type="attr" />
+    <public name="colorTertiaryPalette20" id="0x00773014" type="attr" />
+    <public name="colorTertiaryPalette30" id="0x0077301E" type="attr" />
+    <public name="colorTertiaryPalette40" id="0x00773028" type="attr" />
+    <public name="colorTertiaryPalette50" id="0x00773032" type="attr" />
+    <public name="colorTertiaryPalette60" id="0x0077303C" type="attr" />
+    <public name="colorTertiaryPalette70" id="0x00773046" type="attr" />
+    <public name="colorTertiaryPalette80" id="0x00773050" type="attr" />
+    <public name="colorTertiaryPalette90" id="0x0077305A" type="attr" />
+    <public name="colorTertiaryPalette95" id="0x0077305F" type="attr" />
+    <public name="colorTertiaryPalette99" id="0x00773063" type="attr" />
+    <public name="colorTertiaryPalette100" id="0x00773064" type="attr" />
+
+    <!-- Error tonal palette -->
+    <public name="colorErrorPalette0" id="0x00774000" type="attr" />
+    <public name="colorErrorPalette10" id="0x0077400A" type="attr" />
+    <public name="colorErrorPalette20" id="0x00774014" type="attr" />
+    <public name="colorErrorPalette30" id="0x0077401E" type="attr" />
+    <public name="colorErrorPalette40" id="0x00774028" type="attr" />
+    <public name="colorErrorPalette50" id="0x00774032" type="attr" />
+    <public name="colorErrorPalette60" id="0x0077403C" type="attr" />
+    <public name="colorErrorPalette70" id="0x00774046" type="attr" />
+    <public name="colorErrorPalette80" id="0x00774050" type="attr" />
+    <public name="colorErrorPalette90" id="0x0077405A" type="attr" />
+    <public name="colorErrorPalette95" id="0x0077405F" type="attr" />
+    <public name="colorErrorPalette99" id="0x00774063" type="attr" />
+    <public name="colorErrorPalette100" id="0x00774064" type="attr" />
+
+    <!-- Neutral tonal palette -->
+    <public name="colorNeutralPalette0" id="0x00775000" type="attr" />
+    <public name="colorNeutralPalette10" id="0x0077500A" type="attr" />
+    <public name="colorNeutralPalette20" id="0x00775014" type="attr" />
+    <public name="colorNeutralPalette30" id="0x0077501E" type="attr" />
+    <public name="colorNeutralPalette40" id="0x00775028" type="attr" />
+    <public name="colorNeutralPalette50" id="0x00775032" type="attr" />
+    <public name="colorNeutralPalette60" id="0x0077503C" type="attr" />
+    <public name="colorNeutralPalette70" id="0x00775046" type="attr" />
+    <public name="colorNeutralPalette80" id="0x00775050" type="attr" />
+    <public name="colorNeutralPalette90" id="0x0077505A" type="attr" />
+    <public name="colorNeutralPalette95" id="0x0077505F" type="attr" />
+    <public name="colorNeutralPalette99" id="0x00775063" type="attr" />
+    <public name="colorNeutralPalette100" id="0x00775064" type="attr" />
+
+    <!-- Neutral variant tonal palette -->
+    <public name="colorNeutralVariantPalette0" id="0x00776000" type="attr" />
+    <public name="colorNeutralVariantPalette10" id="0x0077600A" type="attr" />
+    <public name="colorNeutralVariantPalette20" id="0x00776014" type="attr" />
+    <public name="colorNeutralVariantPalette30" id="0x0077601E" type="attr" />
+    <public name="colorNeutralVariantPalette40" id="0x00776028" type="attr" />
+    <public name="colorNeutralVariantPalette50" id="0x00776032" type="attr" />
+    <public name="colorNeutralVariantPalette60" id="0x0077603C" type="attr" />
+    <public name="colorNeutralVariantPalette70" id="0x00776046" type="attr" />
+    <public name="colorNeutralVariantPalette80" id="0x00776050" type="attr" />
+    <public name="colorNeutralVariantPalette90" id="0x0077605A" type="attr" />
+    <public name="colorNeutralVariantPalette95" id="0x0077605F" type="attr" />
+    <public name="colorNeutralVariantPalette99" id="0x00776063" type="attr" />
+    <public name="colorNeutralVariantPalette100" id="0x00776064" type="attr" />
+
+    <!-- Typeface tokens -->
+    <public name="textAppearanceDisplayLarge" id="0x00777000" type="attr" />
+    <public name="textAppearanceDisplayMedium" id="0x00777001" type="attr" />
+    <public name="textAppearanceDisplaySmall" id="0x00777002" type="attr" />
+    <public name="textAppearanceHeadlineLarge" id="0x00777003" type="attr" />
+    <public name="textAppearanceHeadlineMedium" id="0x00777004" type="attr" />
+    <public name="textAppearanceHeadlineSmall" id="0x00777005" type="attr" />
+    <public name="textAppearanceTitleLarge" id="0x00777006" type="attr" />
+    <public name="textAppearanceTitleMedium" id="0x00777007" type="attr" />
+    <public name="textAppearanceTitleSmall" id="0x00777008" type="attr" />
+    <public name="textAppearanceLabelLarge" id="0x00777009" type="attr" />
+    <public name="textAppearanceLabelMedium" id="0x0077700A" type="attr" />
+    <public name="textAppearanceLabelSmall" id="0x0077700B" type="attr" />
+    <public name="textAppearanceBodyLarge" id="0x0077700C" type="attr" />
+    <public name="textAppearanceBodyMedium" id="0x0077700D" type="attr" />
+    <public name="textAppearanceBodySmall" id="0x0077700E" type="attr" />
+
+    <!-- Shape tokens -->
+    <public name="shapeCornerNone" id="0x00778000" type="attr" />
+    <public name="shapeCornerExtraSmall" id="0x00778001" type="attr" />
+    <public name="shapeCornerSmall" id="0x00778002" type="attr" />
+    <public name="shapeCornerMedium" id="0x00778003" type="attr" />
+    <public name="shapeCornerLarge" id="0x00778004" type="attr" />
+    <public name="shapeCornerExtraLarge" id="0x00778005" type="attr" />
+    <public name="shapeCornerFull" id="0x00778006" type="attr" />
 </resources>
diff --git a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/styles.xml b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/styles.xml
index a831ea5..dfd5523 100644
--- a/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/styles.xml
+++ b/car-ui-lib/oem-tokens/shared-lib/src/main/res/values/styles.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<!-- Copyright (C) 2024 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.
diff --git a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/appstyledview/AppStyledViewSampleActivity.java b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/appstyledview/AppStyledViewSampleActivity.java
index 87f941c..0b55072 100644
--- a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/appstyledview/AppStyledViewSampleActivity.java
+++ b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/appstyledview/AppStyledViewSampleActivity.java
@@ -22,7 +22,7 @@
 import android.widget.Button;
 
 import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowCompat;
 import androidx.core.view.WindowInsetsCompat;
 import androidx.core.view.WindowInsetsControllerCompat;
 
@@ -59,23 +59,28 @@
 
         mAppStyledDialogController.setOnNavIconClickListener(
                 () -> mAppStyledDialogController.dismiss());
-        mAppStyledDialogController.setOnDismissListener(() -> showSystemBars());
 
-        Button btn = findViewById(R.id.show_app_styled_fragment);
+        Button btn = requireViewById(R.id.show_app_styled_fragment);
+        Button btnWithBars = requireViewById(R.id.show_app_styled_fragment_with_system_bars);
+
+        mAppStyledDialogController.setContentView(appStyledTestView);
+        mAppStyledDialogController.setNavIconType(NavIcon.CLOSE);
+
         btn.setOnClickListener(v -> {
-            mAppStyledDialogController.setContentView(appStyledTestView);
-            mAppStyledDialogController.setNavIconType(NavIcon.CLOSE);
+            mAppStyledDialogController.setOnDismissListener(this::showSystemBars);
             hideSystemBars();
             mAppStyledDialogController.show();
         });
+
+        btnWithBars.setOnClickListener(v -> {
+            mAppStyledDialogController.setOnDismissListener(null);
+            mAppStyledDialogController.show();
+        });
     }
 
     private void hideSystemBars() {
         WindowInsetsControllerCompat windowInsetsController =
-                ViewCompat.getWindowInsetsController(getWindow().getDecorView());
-        if (windowInsetsController == null) {
-            return;
-        }
+                WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView());
 
         // Configure the behavior of the hidden system bars
         windowInsetsController.setSystemBarsBehavior(
@@ -88,10 +93,7 @@
 
     private void showSystemBars() {
         WindowInsetsControllerCompat windowInsetsController =
-                ViewCompat.getWindowInsetsController(getWindow().getDecorView());
-        if (windowInsetsController == null) {
-            return;
-        }
+                WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView());
 
         // Show the system bars
         windowInsetsController.show(WindowInsetsCompat.Type.systemBars());
diff --git a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
index 5a13a0f..a5de065 100644
--- a/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
+++ b/car-ui-lib/paintbooth/src/main/java/com/android/car/ui/paintbooth/dialogs/DialogsActivity.java
@@ -35,7 +35,6 @@
 import com.android.car.ui.core.CarUi;
 import com.android.car.ui.paintbooth.R;
 import com.android.car.ui.recyclerview.CarUiContentListItem;
-import com.android.car.ui.recyclerview.CarUiListItemAdapter;
 import com.android.car.ui.recyclerview.CarUiRecyclerView;
 import com.android.car.ui.toolbar.NavButtonMode;
 import com.android.car.ui.toolbar.ToolbarController;
@@ -218,7 +217,7 @@
         dialog[0] = new AlertDialogBuilder(this)
                 .setTitle("Select one option.")
                 .setSubtitle("Ony one option may be selected at a time")
-                .setAdapter(new CarUiListItemAdapter(data))
+                .setItems(data)
                 .setAllowDismissButton(false)
                 .show();
     }
@@ -256,14 +255,14 @@
 
         new AlertDialogBuilder(this)
                 .setTitle("Unfocusable items")
-                .setAdapter(new CarUiListItemAdapter(data))
+                .setItems(data)
                 .show();
     }
 
     private void showDialogWithEmptyList() {
         new AlertDialogBuilder(this)
                 .setTitle("Empty list")
-                .setAdapter(new CarUiListItemAdapter(new ArrayList<CarUiContentListItem>()))
+                .setItems(new ArrayList<CarUiContentListItem>())
                 .show();
     }
 
diff --git a/car-ui-lib/paintbooth/src/main/res/layout/app_styled_view_sample_activity.xml b/car-ui-lib/paintbooth/src/main/res/layout/app_styled_view_sample_activity.xml
index 1344921..64c679a 100644
--- a/car-ui-lib/paintbooth/src/main/res/layout/app_styled_view_sample_activity.xml
+++ b/car-ui-lib/paintbooth/src/main/res/layout/app_styled_view_sample_activity.xml
@@ -16,17 +16,21 @@
   -->
 <com.android.car.ui.FocusArea
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:gravity="center"
+    android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-
-  <FrameLayout
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">
     <Button
         android:id="@+id/show_app_styled_fragment"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
+        android:layout_margin="16dp"
         android:text="Show App Styled View"/>
-  </FrameLayout>
+
+    <Button
+        android:id="@+id/show_app_styled_fragment_with_system_bars"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="16dp"
+        android:text="Show App Styled View With System Bars"/>
 </com.android.car.ui.FocusArea>
diff --git a/car-ui-lib/proxy-plugin/Android.bp b/car-ui-lib/proxy-plugin/Android.bp
index e35d814..b88de48 100644
--- a/car-ui-lib/proxy-plugin/Android.bp
+++ b/car-ui-lib/proxy-plugin/Android.bp
@@ -20,6 +20,9 @@
     name: "car-ui-lib-proxyplugin",
     min_sdk_version: "28",
     target_sdk_version: "30",
+    // sc-car only supports up to java 8.
+    java_version: "1.8",
+
     aaptflags: ["--shared-lib"],
     sdk_version: "current",
 
diff --git a/car-ui-lib/proxy-plugin/build.gradle b/car-ui-lib/proxy-plugin/build.gradle
new file mode 100644
index 0000000..ef56c06
--- /dev/null
+++ b/car-ui-lib/proxy-plugin/build.gradle
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+
+apply plugin: 'com.android.application'
+
+android {
+    namespace = "com.chassis.car.ui.plugin"
+    compileSdkVersion gradle.ext.aaosLatestSDK
+
+    defaultConfig {
+        minSdkVersion 28
+        targetSdkVersion gradle.ext.aaosTargetSDK
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+    buildFeatures {
+        buildConfig = false
+    }
+
+    sourceSets {
+        main {
+            manifest.srcFile 'plugin/src/main/AndroidManifest.xml'
+            java.srcDirs = ['plugin/src/main/java']
+        }
+    }
+
+    // This is the gradle equivalent of the libs: ["android.car"] in the Android.bp
+    useLibrary 'android.car'
+}
+
+dependencies {
+    implementation 'androidx.annotation:annotation:1.3.0'
+    implementation project(':car-ui-lib')
+    implementation project(':oem-apis')
+}
+
+// TODO (b/258676672): Cannot build shared libraries with APG with dependencies that contain
+// any resources. AS will fail to parse the R.txt generated by AGP.
+// android.aaptOptions.additionalParameters "--shared-lib"
diff --git a/car-ui-lib/settings.gradle b/car-ui-lib/settings.gradle
deleted file mode 100644
index 1d42e5f..0000000
--- a/car-ui-lib/settings.gradle
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 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 ':car-ui-lib'
-project(':car-ui-lib').projectDir = new File('./car-ui-lib')
-include ':PaintBooth'
-project(':PaintBooth').projectDir = new File('./paintbooth')
-include ':oem-apis'
-project(':oem-apis').projectDir = new File('./oem-apis')
-include ':oem-token-shared-lib'
-project(':oem-token-shared-lib').projectDir = new File('./oem-tokens/shared-lib')
-include ':oem-token-lib'
-project(':oem-token-lib').projectDir = new File('./oem-tokens/lib')
-include ':oem-demo-rro'
-project(':oem-demo-rro').projectDir = new File('./oem-tokens/rro')
-include ':token-compose-compat'
-project(':token-compose-compat').projectDir = new File('./token-compose-compat')
-
-rootProject.name='Chassis'
-include ':car-rotary-lib'
-include ':car-ui-lib-testing'
diff --git a/car-ui-lib/token-compose-compat/src/main/java/com/android/car/oem/tokens/compose/compat/ui/theme/OemTokenTheme.kt b/car-ui-lib/token-compose-compat/src/main/java/com/android/car/oem/tokens/compose/compat/ui/theme/OemTokenTheme.kt
index c73dbf0..4274818 100644
--- a/car-ui-lib/token-compose-compat/src/main/java/com/android/car/oem/tokens/compose/compat/ui/theme/OemTokenTheme.kt
+++ b/car-ui-lib/token-compose-compat/src/main/java/com/android/car/oem/tokens/compose/compat/ui/theme/OemTokenTheme.kt
@@ -61,6 +61,12 @@
     val oemColorSurfaceVariant = Token.getColor(oemContext, R.attr.oemColorSurfaceVariant)
     val oemColorOnSurfaceVariant = Token.getColor(oemContext, R.attr.oemColorOnSurfaceVariant)
     val oemColorOutline = Token.getColor(oemContext, R.attr.oemColorOutline)
+    val oemColorSurfaceInverse = Token.getColor(oemContext, R.attr.oemColorSurfaceInverse)
+    val oemColorOnSurfaceInverse = Token.getColor(oemContext, R.attr.oemColorOnSurfaceInverse)
+    val oemColorPrimaryInverse = Token.getColor(oemContext, R.attr.oemColorPrimaryInverse)
+    val oemColorOutlineVariant = Token.getColor(oemContext, R.attr.oemColorOutlineVariant)
+    val oemColorScrim = Token.getColor(oemContext, R.attr.oemColorScrim)
+    val oemColorSurfaceTint = Token.getColor(oemContext, R.attr.oemColorSurfaceTint)
 
     return ColorScheme(
         primary = Color(oemColorPrimary),
@@ -86,13 +92,12 @@
         surfaceVariant = Color(oemColorSurfaceVariant),
         onSurfaceVariant = Color(oemColorOnSurfaceVariant),
         outline = Color(oemColorOutline),
-        // TODO (b/318753781): Update token OEM definitions for consistency
-        inverseSurface = Color(0xFF000080),
-        inverseOnSurface = Color(0xFF000080),
-        inversePrimary = Color(0xFF000080),
-        outlineVariant = Color(0xFF000080),
-        scrim = Color(0xFF000080),
-        surfaceTint = Color(0xFF000080)
+        inverseSurface = Color(oemColorSurfaceInverse),
+        inverseOnSurface = Color(oemColorOnSurfaceInverse),
+        inversePrimary = Color(oemColorPrimaryInverse),
+        outlineVariant = Color(oemColorOutlineVariant),
+        scrim = Color(oemColorScrim),
+        surfaceTint = Color(oemColorSurfaceTint)
     )
 }