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)
)
}