diff options
author | Deepanshu Gupta <deepanshu@google.com> | 2014-07-31 11:32:25 -0700 |
---|---|---|
committer | Deepanshu Gupta <deepanshu@google.com> | 2014-08-04 22:58:39 +0000 |
commit | 86eb8b4e29b1ad889fc814bae723d4d6e491f53f (patch) | |
tree | 6288e70c680adaa54cfec66e00c8a3f8d988bcf2 /tools/layoutlib/bridge | |
parent | b99b18e78e8aa9a27596c13ea05a188ab43c7e12 (diff) | |
download | frameworks_base-86eb8b4e29b1ad889fc814bae723d4d6e491f53f.zip frameworks_base-86eb8b4e29b1ad889fc814bae723d4d6e491f53f.tar.gz frameworks_base-86eb8b4e29b1ad889fc814bae723d4d6e491f53f.tar.bz2 |
Add testing framework to LayoutLib.
This change adds an end to end test which loads the framework resources
and a test app and ensures that no exceptions or warnings are thrown.
The change also adds project configuration for intelliJ.
Change-Id: I7b67c0f1a2af2dac95df7f3231cab537b9826d7d
Diffstat (limited to 'tools/layoutlib/bridge')
39 files changed, 1463 insertions, 25 deletions
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath index aef3efa..9c4160c 100644 --- a/tools/layoutlib/bridge/.classpath +++ b/tools/layoutlib/bridge/.classpath @@ -10,5 +10,7 @@ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/> <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/icu4j/icu4j.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> + <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/sdk-common/sdk-common.jar"/> + <classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/javalib.jar"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/tools/layoutlib/bridge/bridge.iml b/tools/layoutlib/bridge/bridge.iml new file mode 100644 index 0000000..7553b59 --- /dev/null +++ b/tools/layoutlib/bridge/bridge.iml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" /> + <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> + <sourceFolder url="file://$MODULE_DIR$/tests/res" type="java-test-resource" /> + <sourceFolder url="file://$MODULE_DIR$/tests/src" isTestSource="true" /> + <excludeFolder url="file://$MODULE_DIR$/.settings" /> + <excludeFolder url="file://$MODULE_DIR$/bin" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/.gradle" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/.idea" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/generated" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/assets" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/dependency-cache" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/incremental" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/libs" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/manifests" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/res" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/rs" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/build/intermediates/symbols" /> + <excludeFolder url="file://$MODULE_DIR$/tests/res/testApp/MyApplication/gradle" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="library" name="icu4j" level="project" /> + <orderEntry type="library" name="kxml2-2.3.0" level="project" /> + <orderEntry type="library" name="layoutlib_api-prebuilt" level="project" /> + <orderEntry type="library" name="ninepatch-prebuilt" level="project" /> + <orderEntry type="library" name="tools-common-prebuilt" level="project" /> + <orderEntry type="library" name="framework.jar" level="project" /> + <orderEntry type="library" scope="TEST" name="guava" level="project" /> + <orderEntry type="module-library" scope="TEST"> + <library> + <CLASSES> + <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/sdk-common/sdk-common.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$ANDROID_BUILD_TOP$/prebuilts/misc/common/sdk-common/sdk-common-sources.jar!/" /> + </SOURCES> + </library> + </orderEntry> + <orderEntry type="library" scope="TEST" name="JUnit4" level="application" /> + </component> +</module> + diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index cc69af2..3d0e1e8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -290,7 +290,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { if (log != null) { log.error(LayoutLog.TAG_BROKEN, "Failed to load com.android.internal.R from the layout library jar", - throwable); + throwable, null); } return false; } @@ -418,8 +418,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { locale = ""; } ULocale uLocale = new ULocale(locale); - return uLocale.getCharacterOrientation().equals(ICU_LOCALE_DIRECTION_RTL) ? - true : false; + return uLocale.getCharacterOrientation().equals(ICU_LOCALE_DIRECTION_RTL); } /** diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk index 98cade9..7a9e067 100644 --- a/tools/layoutlib/bridge/tests/Android.mk +++ b/tools/layoutlib/bridge/tests/Android.mk @@ -24,7 +24,13 @@ LOCAL_JAVA_RESOURCE_DIRS := res LOCAL_MODULE := layoutlib-tests LOCAL_MODULE_TAGS := optional -LOCAL_JAVA_LIBRARIES := layoutlib kxml2-2.3.0 junit +LOCAL_JAVA_LIBRARIES := layoutlib \ + kxml2-2.3.0 \ + icu4j \ + layoutlib_api-prebuilt \ + tools-common-prebuilt \ + sdk-common \ + junit include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/.gitignore b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/.gitignore new file mode 100644 index 0000000..a2ce0dc --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/.gitignore @@ -0,0 +1,14 @@ +.gradle +local.properties +.idea +.DS_Store +*.iml +# We need the built .class files to load custom views and R class. +# The only way to negate an exclusion is by including every single parent +# and excluding all children of those parents. + +/build/* +!/build/intermediates/ + +/build/intermediates/* +!/build/intermediates/classes/ diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle new file mode 100644 index 0000000..80be12d --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle @@ -0,0 +1,43 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.12.+' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 20 + buildToolsVersion '20' + defaultConfig { + applicationId 'com.android.layoutlib.test.myapplication' + minSdkVersion 19 + targetSdkVersion 20 + versionCode 1 + versionName '1.0' + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + productFlavors { + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class Binary files differnew file mode 100644 index 0000000..2b4f7bf --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class Binary files differnew file mode 100644 index 0000000..d252462 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class Binary files differnew file mode 100644 index 0000000..9bab801 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class Binary files differnew file mode 100644 index 0000000..7ad8605 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class Binary files differnew file mode 100644 index 0000000..e9e0a33 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class Binary files differnew file mode 100644 index 0000000..d109302 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class Binary files differnew file mode 100644 index 0000000..816ecc8 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class Binary files differnew file mode 100644 index 0000000..b034b75 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class Binary files differnew file mode 100644 index 0000000..f86b1d3 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class Binary files differnew file mode 100644 index 0000000..8bbae90 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class Binary files differnew file mode 100644 index 0000000..8af745d --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle.properties b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle.properties new file mode 100644 index 0000000..5d08ba7 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Settings specified in this file will override any Gradle settings +# configured through the IDE. + +# 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. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# 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
\ No newline at end of file diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.jar b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 0000000..8c0fb64 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.jar diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..5de946b --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradlew b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# 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 +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# 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\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +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" ] ; 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, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # 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=$((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 + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradlew.bat b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradlew.bat @@ -0,0 +1,90 @@ +@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
+
+@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=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@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 init
+
+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 init
+
+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
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_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=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+: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 %CMD_LINE_ARGS%
+
+: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/tools/layoutlib/bridge/tests/res/testApp/MyApplication/proguard-rules.pro b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/proguard-rules.pro new file mode 100644 index 0000000..b0fcd2d --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/google/home/deepanshu/ssd/sdk_out/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/androidTest/java/com/android/layoulib/test/myapplication/ApplicationTest.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/androidTest/java/com/android/layoulib/test/myapplication/ApplicationTest.java new file mode 100644 index 0000000..7304af1 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/androidTest/java/com/android/layoulib/test/myapplication/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.android.layoulib.test.myapplication; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> + */ +public class ApplicationTest extends ApplicationTestCase<Application> { + public ApplicationTest() { + super(Application.class); + } +}
\ No newline at end of file diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/AndroidManifest.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2067474 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.layoutlib.test.myapplication" > +<!-- If changing package here, update LayoutLibCallBack in tests. --> + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name="com.android.layoutlib.test.myapplication.MyActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/MyActivity.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/MyActivity.java new file mode 100644 index 0000000..59de457 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/MyActivity.java @@ -0,0 +1,35 @@ +package com.android.layoutlib.test.myapplication; + +import android.app.Activity; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; + +public class MyActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.my, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/ic_launcher.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000..67481d4 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#ff0000" /> + <size + android:width="20dp" + android:height="20dp" /> +</shape>
\ No newline at end of file diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/activity.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/activity.xml new file mode 100644 index 0000000..97d1983 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/activity.xml @@ -0,0 +1,21 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingBottom="@dimen/activity_vertical_margin" + tools:context=".MyActivity"> + + <TextView + android:text="@string/hello_world" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/text1"/> + + <include layout="@layout/layout" + android:layout_below="@+id/text1" + android:layout_height="wrap_content" + android:layout_width="wrap_content" /> +</RelativeLayout> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml new file mode 100644 index 0000000..2704c07 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Some text"/> +</LinearLayout>
\ No newline at end of file diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/menu/my.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/menu/my.xml new file mode 100644 index 0000000..bea58cc --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/menu/my.xml @@ -0,0 +1,8 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:context=".MyActivity" > + <item android:id="@+id/action_settings" + android:title="@string/action_settings" + android:orderInCategory="100" + android:showAsAction="never" /> +</menu> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/dimens.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/dimens.xml new file mode 100644 index 0000000..47c8224 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ +<resources> + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> +</resources> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/strings.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/strings.xml new file mode 100644 index 0000000..2b7083b --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">My Application</string> + <string name="hello_world">Hello world!</string> + <string name="action_settings">Settings</string> + +</resources> diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml new file mode 100644 index 0000000..ff6c9d2 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ +<resources> + + <!-- Base application theme. --> + <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar"> + <!-- Customize your theme here. --> + </style> + +</resources> diff --git a/tools/layoutlib/bridge/tests/src/android/graphics/Matrix_DelegateTest.java b/tools/layoutlib/bridge/tests/src/android/graphics/Matrix_DelegateTest.java index ec4edac..d20fb14 100644 --- a/tools/layoutlib/bridge/tests/src/android/graphics/Matrix_DelegateTest.java +++ b/tools/layoutlib/bridge/tests/src/android/graphics/Matrix_DelegateTest.java @@ -23,16 +23,6 @@ import junit.framework.TestCase; */ public class Matrix_DelegateTest extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - public void testIdentity() { Matrix m1 = new Matrix(); diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java index 865a008..92fcf90 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java @@ -24,17 +24,6 @@ import org.xmlpull.v1.XmlPullParser; import junit.framework.TestCase; public class BridgeXmlBlockParserTest extends TestCase { - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - public void testXmlBlockParser() throws Exception { XmlPullParser parser = ParserFactory.create( diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java new file mode 100644 index 0000000..4af07dd --- /dev/null +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.layoutlib.bridge.intensive; + +import com.android.annotations.NonNull; +import com.android.ide.common.rendering.api.LayoutLog; +import com.android.ide.common.rendering.api.RenderSession; +import com.android.ide.common.rendering.api.Result; +import com.android.ide.common.rendering.api.SessionParams; +import com.android.ide.common.rendering.api.SessionParams.RenderingMode; +import com.android.ide.common.resources.FrameworkResources; +import com.android.ide.common.resources.ResourceItem; +import com.android.ide.common.resources.ResourceRepository; +import com.android.ide.common.resources.ResourceResolver; +import com.android.ide.common.resources.configuration.FolderConfiguration; +import com.android.io.FolderWrapper; +import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; +import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback; +import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; +import com.android.utils.ILogger; + +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.FileFilter; +import java.net.URL; +import java.util.Arrays; +import java.util.Comparator; + +import static org.junit.Assert.fail; + +/** + * This is a set of tests that loads all the framework resources and a project checked in this + * test's resources. The main dependencies + * are: + * 1. Fonts directory. + * 2. Framework Resources. + * 3. App resources. + * 4. build.prop file + * + * These are configured by two variables set in the system properties. + * + * 1. platform.dir: This is the directory for the current platform in the built SDK + * (.../sdk/platforms/android-<version>). + * + * The fonts are platform.dir/data/fonts. + * The Framework resources are platform.dir/data/res. + * build.prop is at platform.dir/build.prop. + * + * 2. test_res.dir: This is the directory for the resources of the test. If not specified, this + * falls back to getClass().getProtectionDomain().getCodeSource().getLocation() + * + * The app resources are at: test_res.dir/testApp/MyApplication/app/src/main/res + */ +public class Main { + + private static final String PLATFORM_DIR_PROPERTY = "platform.dir"; + private static final String RESOURCE_DIR_PROPERTY = "test_res.dir"; + + private static final String PLATFORM_DIR; + private static final String TEST_RES_DIR; + private static final String APP_TEST_RES = "/testApp/MyApplication/src/main/res"; + + private LayoutLog mLayoutLibLog; + private FrameworkResources mFrameworkRepo; + private ResourceRepository mProjectResources; + private ILogger mLogger; + private Bridge mBridge; + + static { + // Test that System Properties are properly set. + PLATFORM_DIR = getPlatformDir(); + if (PLATFORM_DIR == null) { + fail(String.format("System Property %1$s not properly set. The value is %2$s", + PLATFORM_DIR_PROPERTY, System.getProperty(PLATFORM_DIR_PROPERTY))); + } + + TEST_RES_DIR = getTestResDir(); + if (TEST_RES_DIR == null) { + fail(String.format("System property %1$s.dir not properly set. The value is %2$s", + RESOURCE_DIR_PROPERTY, System.getProperty(RESOURCE_DIR_PROPERTY))); + } + } + + private static String getPlatformDir() { + String platformDir = System.getProperty(PLATFORM_DIR_PROPERTY); + if (platformDir != null && !platformDir.isEmpty() && new File(platformDir).isDirectory()) { + return platformDir; + } + // System Property not set. Try to find the directory in the build directory. + String out = System.getenv("ANDROID_HOST_OUT"); + if (out == null || out.isEmpty() || !new File(out).isDirectory()) { + // Can't find the out directory. + return null; + } + File sdkDir = new File(out, "sdk" + File.separator + "sdk"); + if (!sdkDir.isDirectory()) { + // The directory we thought that should contain the sdk is not a directory. + return null; + } + File[] possibleSdks = sdkDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory() && pathname.getAbsolutePath().contains("android-sdk"); + } + }); + for (File possibleSdk : possibleSdks) { + File platformsDir = new File(possibleSdk, "platforms"); + File[] platforms = platformsDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory() + && pathname.toPath().getFileName().toString().startsWith("android-"); + } + }); + if (platforms == null || platforms.length == 0) { + continue; + } + Arrays.sort(platforms, new Comparator<File>() { + // Codenames before ints. Higher APIs precede lower. + @Override + public int compare(File o1, File o2) { + final int MAX_VALUE = 1000; + String suffix1 = o1.toPath().getFileName().toString() + .substring("android-".length()); + String suffix2 = o2.toPath().getFileName().toString() + .substring("android-".length()); + int suff1, suff2; + try { + suff1 = Integer.parseInt(suffix1); + } catch (NumberFormatException e) { + suff1 = MAX_VALUE; + } + try { + suff2 = Integer.parseInt(suffix2); + } catch (NumberFormatException e) { + suff2 = MAX_VALUE; + } + if (suff1 != MAX_VALUE || suff2 != MAX_VALUE) { + return suff2 - suff1; + } + return suffix2.compareTo(suffix1); + } + }); + return platforms[0].getAbsolutePath(); + } + return null; + } + + private static String getTestResDir() { + String resourceDir = System.getProperty(RESOURCE_DIR_PROPERTY); + if (resourceDir != null && !resourceDir.isEmpty() && new File(resourceDir).isDirectory()) { + return resourceDir; + } + // TEST_RES_DIR not explicitly set. Fallback to the class's source location. + try { + URL location = Main.class.getProtectionDomain().getCodeSource().getLocation(); + return new File(location.getPath()).exists() ? location.getPath() : null; + } catch (NullPointerException e) { + // Prevent a lot of null checks by just catching the exception. + return null; + } + } + /** + * Initialize the bridge and the resource maps. + */ + @Before + public void setUp() { + File data_dir = new File(PLATFORM_DIR, "data"); + File res = new File(data_dir, "res"); + mFrameworkRepo = new FrameworkResources(new FolderWrapper(res)); + mFrameworkRepo.loadResources(); + mFrameworkRepo.loadPublicResources(getLogger()); + + mProjectResources = + new ResourceRepository(new FolderWrapper(TEST_RES_DIR + APP_TEST_RES), false) { + @NonNull + @Override + protected ResourceItem createResourceItem(String name) { + return new ResourceItem(name); + } + }; + mProjectResources.loadResources(); + + File fontLocation = new File(data_dir, "fonts"); + File buildProp = new File(PLATFORM_DIR, "build.prop"); + File attrs = new File(res, "values" + File.separator + "attrs.xml"); + mBridge = new Bridge(); + mBridge.init(ConfigGenerator.loadProperties(buildProp), fontLocation, + ConfigGenerator.getEnumMap(attrs), getLayoutLog()); + } + + /** + * Create a new rendering session and test that rendering /layout/activity.xml on nexus 5 + * doesn't throw any exceptions. + */ + @Test + public void testRendering() throws ClassNotFoundException { + // Create the layout pull parser. + LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/activity.xml"); + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); + layoutLibCallback.initResources(); + // TODO: Set up action bar handler properly to test menu rendering. + // Create session params. + SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, layoutLibCallback); + RenderSession session = mBridge.createSession(params); + if (!session.getResult().isSuccess()) { + getLogger().error(session.getResult().getException(), + session.getResult().getErrorMessage()); + } + // Render the session with a timeout of 50s. + Result renderResult = session.render(50000); + if (!renderResult.isSuccess()) { + getLogger().error(session.getResult().getException(), + session.getResult().getErrorMessage()); + } + } + + /** + * Uses Theme.Material and Target sdk version as 21. + */ + private SessionParams getSessionParams(LayoutPullParser layoutParser, + ConfigGenerator configGenerator, LayoutLibTestCallback layoutLibCallback) { + FolderConfiguration config = configGenerator.getFolderConfig(); + ResourceResolver resourceResolver = + ResourceResolver.create(mProjectResources.getConfiguredResources(config), + mFrameworkRepo.getConfiguredResources(config), "Theme.Material", false); + + return new SessionParams( + layoutParser, + RenderingMode.NORMAL, + null /*used for caching*/, + configGenerator.getHardwareConfig(), + resourceResolver, + layoutLibCallback, + 0, + 21, // TODO: Make it more configurable to run tests for various versions. + getLayoutLog()); + } + + private LayoutLog getLayoutLog() { + if (mLayoutLibLog == null) { + mLayoutLibLog = new LayoutLog() { + @Override + public void warning(String tag, String message, Object data) { + System.out.println("Warning " + tag + ": " + message); + fail(message); + } + + @Override + public void fidelityWarning(String tag, String message, Throwable throwable, + Object data) { + System.out.println("FidelityWarning " + tag + ": " + message); + if (throwable != null) { + throwable.printStackTrace(); + } + fail(message); + } + + @Override + public void error(String tag, String message, Object data) { + System.out.println("Error " + tag + ": " + message); + fail(message); + } + + @Override + public void error(String tag, String message, Throwable throwable, Object data) { + System.out.println("Error " + tag + ": " + message); + if (throwable != null) { + throwable.printStackTrace(); + } + fail(message); + } + }; + } + return mLayoutLibLog; + } + + private ILogger getLogger() { + if (mLogger == null) { + mLogger = new ILogger() { + @Override + public void error(Throwable t, String msgFormat, Object... args) { + if (t != null) { + t.printStackTrace(); + } + fail(String.format(msgFormat, args)); + } + + @Override + public void warning(String msgFormat, Object... args) { + fail(String.format(msgFormat, args)); + } + + @Override + public void info(String msgFormat, Object... args) { + // pass. + } + + @Override + public void verbose(String msgFormat, Object... args) { + // pass. + } + }; + } + return mLogger; + } +} diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java new file mode 100644 index 0000000..a5c3202 --- /dev/null +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.layoutlib.bridge.intensive.setup; + +import com.android.ide.common.rendering.api.HardwareConfig; +import com.android.ide.common.resources.configuration.CountryCodeQualifier; +import com.android.ide.common.resources.configuration.DensityQualifier; +import com.android.ide.common.resources.configuration.FolderConfiguration; +import com.android.ide.common.resources.configuration.KeyboardStateQualifier; +import com.android.ide.common.resources.configuration.LanguageQualifier; +import com.android.ide.common.resources.configuration.LayoutDirectionQualifier; +import com.android.ide.common.resources.configuration.NavigationMethodQualifier; +import com.android.ide.common.resources.configuration.NetworkCodeQualifier; +import com.android.ide.common.resources.configuration.NightModeQualifier; +import com.android.ide.common.resources.configuration.RegionQualifier; +import com.android.ide.common.resources.configuration.ScreenDimensionQualifier; +import com.android.ide.common.resources.configuration.ScreenOrientationQualifier; +import com.android.ide.common.resources.configuration.ScreenRatioQualifier; +import com.android.ide.common.resources.configuration.ScreenSizeQualifier; +import com.android.ide.common.resources.configuration.TextInputMethodQualifier; +import com.android.ide.common.resources.configuration.TouchScreenQualifier; +import com.android.ide.common.resources.configuration.UiModeQualifier; +import com.android.ide.common.resources.configuration.VersionQualifier; +import com.android.resources.Density; +import com.android.resources.Keyboard; +import com.android.resources.KeyboardState; +import com.android.resources.Navigation; +import com.android.resources.NightMode; +import com.android.resources.ScreenOrientation; +import com.android.resources.ScreenRatio; +import com.android.resources.ScreenSize; +import com.android.resources.TouchScreen; +import com.android.resources.UiMode; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Map; +import java.util.Properties; + +import com.google.android.collect.Maps; + +/** + * Provides {@link FolderConfiguration} and {@link HardwareConfig} for various devices. Also + * provides utility methods to parse build.prop and attrs.xml to generate the appropriate maps. + */ +@SuppressWarnings("UnusedDeclaration") // For the pre-configured nexus generators. +public class ConfigGenerator { + + public static final ConfigGenerator NEXUS_4 = new ConfigGenerator(); + + public static final ConfigGenerator NEXUS_5 = new ConfigGenerator() + .setScreenHeight(1920) + .setScreenWidth(1080) + .setXdpi(445) + .setYdpi(445) + .setOrientation(ScreenOrientation.PORTRAIT) + .setDensity(Density.XXHIGH) + .setRatio(ScreenRatio.NOTLONG) + .setSize(ScreenSize.NORMAL) + .setKeyboard(Keyboard.NOKEY) + .setTouchScreen(TouchScreen.FINGER) + .setKeyboardState(KeyboardState.SOFT) + .setSoftButtons(true) + .setNavigation(Navigation.NONAV); + + public static final ConfigGenerator NEXUS_7 = new ConfigGenerator() + .setScreenHeight(1920) + .setScreenWidth(1200) + .setXdpi(323) + .setYdpi(323) + .setOrientation(ScreenOrientation.PORTRAIT) + .setDensity(Density.XHIGH) + .setRatio(ScreenRatio.NOTLONG) + .setSize(ScreenSize.LARGE) + .setKeyboard(Keyboard.NOKEY) + .setTouchScreen(TouchScreen.FINGER) + .setKeyboardState(KeyboardState.SOFT) + .setSoftButtons(true) + .setNavigation(Navigation.NONAV); + + public static final ConfigGenerator NEXUS_10 = new ConfigGenerator() + .setScreenHeight(1600) + .setScreenWidth(2560) + .setXdpi(300) + .setYdpi(300) + .setOrientation(ScreenOrientation.LANDSCAPE) + .setDensity(Density.XHIGH) + .setRatio(ScreenRatio.NOTLONG) + .setSize(ScreenSize.XLARGE) + .setKeyboard(Keyboard.NOKEY) + .setTouchScreen(TouchScreen.FINGER) + .setKeyboardState(KeyboardState.SOFT) + .setSoftButtons(true) + .setNavigation(Navigation.NONAV); + + private static final String TAG_ATTR = "attr"; + private static final String TAG_ENUM = "enum"; + private static final String TAG_FLAG = "flag"; + private static final String ATTR_NAME = "name"; + private static final String ATTR_VALUE = "value"; + + // Device Configuration. Defaults are for a Nexus 4 device. + private int mScreenHeight = 1280; + private int mScreenWidth = 768; + private int mXdpi = 320; + private int mYdpi = 320; + private ScreenOrientation mOrientation = ScreenOrientation.PORTRAIT; + private Density mDensity = Density.XHIGH; + private ScreenRatio mRatio = ScreenRatio.NOTLONG; + private ScreenSize mSize = ScreenSize.NORMAL; + private Keyboard mKeyboard = Keyboard.NOKEY; + private TouchScreen mTouchScreen = TouchScreen.FINGER; + private KeyboardState mKeyboardState = KeyboardState.SOFT; + private boolean mSoftButtons = true; + private Navigation mNavigation = Navigation.NONAV; + + public FolderConfiguration getFolderConfig() { + FolderConfiguration config = new FolderConfiguration(); + config.createDefault(); + config.setDensityQualifier(new DensityQualifier(mDensity)); + config.setNavigationMethodQualifier(new NavigationMethodQualifier(mNavigation)); + if (mScreenWidth > mScreenHeight) { + config.setScreenDimensionQualifier(new ScreenDimensionQualifier(mScreenWidth, + mScreenHeight)); + } else { + config.setScreenDimensionQualifier(new ScreenDimensionQualifier(mScreenHeight, + mScreenWidth)); + } + config.setScreenRatioQualifier(new ScreenRatioQualifier(mRatio)); + config.setScreenSizeQualifier(new ScreenSizeQualifier(mSize)); + config.setTextInputMethodQualifier(new TextInputMethodQualifier(mKeyboard)); + config.setTouchTypeQualifier(new TouchScreenQualifier(mTouchScreen)); + config.setKeyboardStateQualifier(new KeyboardStateQualifier(mKeyboardState)); + config.setScreenOrientationQualifier(new ScreenOrientationQualifier(mOrientation)); + + config.updateScreenWidthAndHeight(); + + // some default qualifiers. + config.setUiModeQualifier(new UiModeQualifier(UiMode.NORMAL)); + config.setNightModeQualifier(new NightModeQualifier(NightMode.NOTNIGHT)); + config.setCountryCodeQualifier(new CountryCodeQualifier()); + config.setLanguageQualifier(new LanguageQualifier()); + config.setLayoutDirectionQualifier(new LayoutDirectionQualifier()); + config.setNetworkCodeQualifier(new NetworkCodeQualifier()); + config.setRegionQualifier(new RegionQualifier()); + config.setVersionQualifier(new VersionQualifier()); + return config; + } + + public HardwareConfig getHardwareConfig() { + return new HardwareConfig(mScreenWidth, mScreenHeight, mDensity, mXdpi, mYdpi, mSize, + mOrientation, mSoftButtons); + } + + public static Map<String, String> loadProperties(File path) { + Properties p = new Properties(); + Map<String, String> map = Maps.newHashMap(); + try { + p.load(new FileInputStream(path)); + for (String key : p.stringPropertyNames()) { + map.put(key, p.getProperty(key)); + } + } catch (IOException e) { + e.printStackTrace(); + } + return map; + } + + public static Map<String, Map<String, Integer>> getEnumMap(File path) { + Map<String, Map<String, Integer>> map = Maps.newHashMap(); + try { + XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser(); + xmlPullParser.setInput(new FileInputStream(path), null); + int eventType = xmlPullParser.getEventType(); + String attr = null; + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + if (TAG_ATTR.equals(xmlPullParser.getName())) { + attr = xmlPullParser.getAttributeValue(null, ATTR_NAME); + } else if (TAG_ENUM.equals(xmlPullParser.getName()) + || TAG_FLAG.equals(xmlPullParser.getName())) { + String name = xmlPullParser.getAttributeValue(null, ATTR_NAME); + String value = xmlPullParser.getAttributeValue(null, ATTR_VALUE); + // Integer.decode cannot handle "ffffffff", see JDK issue 6624867 + int i = (int) (long) Long.decode(value); + assert attr != null; + Map<String, Integer> attributeMap = map.get(attr); + if (attributeMap == null) { + attributeMap = Maps.newHashMap(); + map.put(attr, attributeMap); + } + attributeMap.put(name, i); + } + } else if (eventType == XmlPullParser.END_TAG) { + if (TAG_ATTR.equals(xmlPullParser.getName())) { + attr = null; + } + } + eventType = xmlPullParser.next(); + } + } catch (XmlPullParserException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return map; + } + + // Methods to set the configuration values. + + public ConfigGenerator setScreenHeight(int height) { + mScreenHeight = height; + return this; + } + + public ConfigGenerator setScreenWidth(int width) { + mScreenWidth = width; + return this; + } + + public ConfigGenerator setXdpi(int xdpi) { + mXdpi = xdpi; + return this; + } + + public ConfigGenerator setYdpi(int ydpi) { + mYdpi = ydpi; + return this; + } + + public ConfigGenerator setOrientation(ScreenOrientation orientation) { + mOrientation = orientation; + return this; + } + + public ConfigGenerator setDensity(Density density) { + mDensity = density; + return this; + } + + public ConfigGenerator setRatio(ScreenRatio ratio) { + mRatio = ratio; + return this; + } + + public ConfigGenerator setSize(ScreenSize size) { + mSize = size; + return this; + } + + public ConfigGenerator setKeyboard(Keyboard keyboard) { + mKeyboard = keyboard; + return this; + } + + public ConfigGenerator setTouchScreen(TouchScreen touchScreen) { + mTouchScreen = touchScreen; + return this; + } + + public ConfigGenerator setKeyboardState(KeyboardState state) { + mKeyboardState = state; + return this; + } + + public ConfigGenerator setSoftButtons(boolean softButtons) { + mSoftButtons = softButtons; + return this; + } + + public ConfigGenerator setNavigation(Navigation navigation) { + mNavigation = navigation; + return this; + } +} diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java new file mode 100644 index 0000000..565e881 --- /dev/null +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.layoutlib.bridge.intensive.setup; + +import com.android.SdkConstants; +import com.android.ide.common.rendering.api.ActionBarCallback; +import com.android.ide.common.rendering.api.AdapterBinding; +import com.android.ide.common.rendering.api.ILayoutPullParser; +import com.android.ide.common.rendering.api.IProjectCallback; +import com.android.ide.common.rendering.api.ResourceReference; +import com.android.ide.common.rendering.api.ResourceValue; +import com.android.resources.ResourceType; +import com.android.ide.common.resources.IntArrayWrapper; +import com.android.util.Pair; +import com.android.utils.ILogger; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Map; + +import com.google.android.collect.Maps; + +@SuppressWarnings("deprecation") // For Pair +public class LayoutLibTestCallback extends ClassLoader implements IProjectCallback { + + private static final String PROJECT_CLASSES_LOCATION = "/testApp/MyApplication/build/intermediates/classes/debug/"; + private static final String PACKAGE_NAME = "com.android.layoutlib.test.myapplication"; + + private final Map<Integer, Pair<ResourceType, String>> mProjectResources = Maps.newHashMap(); + private final Map<IntArrayWrapper, String> mStyleableValueToNameMap = Maps.newHashMap(); + private final Map<ResourceType, Map<String, Integer>> mResources = Maps.newHashMap(); + private final Map<String, Class<?>> mClasses = Maps.newHashMap(); + private final ILogger mLog; + private final ActionBarCallback mActionBarCallback = new ActionBarCallback(); + + public LayoutLibTestCallback(ILogger logger) { + mLog = logger; + } + + public void initResources() throws ClassNotFoundException { + Class<?> rClass = loadClass(PACKAGE_NAME + ".R"); + Class<?>[] nestedClasses = rClass.getDeclaredClasses(); + for (Class<?> resClass : nestedClasses) { + final ResourceType resType = ResourceType.getEnum(resClass.getSimpleName()); + + if (resType != null) { + final Map<String, Integer> resName2Id = Maps.newHashMap(); + mResources.put(resType, resName2Id); + + for (Field field : resClass.getDeclaredFields()) { + final int modifiers = field.getModifiers(); + if (Modifier.isStatic(modifiers)) { // May not be final in library projects + final Class<?> type = field.getType(); + try { + if (type.isArray() && type.getComponentType() == int.class) { + mStyleableValueToNameMap.put( + new IntArrayWrapper((int[]) field.get(null)), + field.getName()); + } else if (type == int.class) { + final Integer value = (Integer) field.get(null); + mProjectResources.put(value, Pair.of(resType, field.getName())); + resName2Id.put(field.getName(), value); + } else { + mLog.error(null, "Unknown field type in R class: %1$s", type); + } + } catch (IllegalAccessException ignored) { + mLog.error(ignored, "Malformed R class: %1$s", PACKAGE_NAME + ".R"); + } + } + } + } + } + } + + @Override + protected Class<?> findClass(String name) throws ClassNotFoundException { + Class<?> aClass = mClasses.get(name); + if (aClass != null) { + return aClass; + } + String pathName = PROJECT_CLASSES_LOCATION.concat(name.replace('.', '/')).concat(".class"); + InputStream classInputStream = getClass().getResourceAsStream(pathName); + if (classInputStream == null) { + throw new ClassNotFoundException("Unable to find class " + name + " at " + pathName); + } + byte[] data; + try { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + data = new byte[16384]; + while ((nRead = classInputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + data = buffer.toByteArray(); + } catch (IOException e) { + // Wrap the exception with ClassNotFoundException so that caller can deal with it. + throw new ClassNotFoundException("Unable to load class " + name, e); + } + aClass = defineClass(name, data, 0, data.length); + mClasses.put(name, aClass); + return aClass; + } + + @Override + public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs) + throws Exception { + Class<?> viewClass = findClass(name); + Constructor<?> viewConstructor = viewClass.getConstructor(constructorSignature); + viewConstructor.setAccessible(true); + return viewConstructor.newInstance(constructorArgs); + } + + @Override + public String getNamespace() { + return String.format(SdkConstants.NS_CUSTOM_RESOURCES_S, + PACKAGE_NAME); + } + + @Override + public Pair<ResourceType, String> resolveResourceId(int id) { + return mProjectResources.get(id); + } + + @Override + public String resolveResourceId(int[] id) { + return mStyleableValueToNameMap.get(new IntArrayWrapper(id)); + } + + @Override + public Integer getResourceId(ResourceType type, String name) { + return mResources.get(type).get(name); + } + + @Override + public ILayoutPullParser getParser(String layoutName) { + org.junit.Assert.fail("This method shouldn't be called by this version of LayoutLib."); + return null; + } + + @Override + public ILayoutPullParser getParser(ResourceValue layoutResource) { + return new LayoutPullParser(new File(layoutResource.getValue())); + } + + @Override + public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie, + ResourceReference itemRef, int fullPosition, int positionPerType, + int fullParentPosition, int parentPositionPerType, ResourceReference viewRef, + ViewAttribute viewAttribute, Object defaultValue) { + return null; + } + + @Override + public AdapterBinding getAdapterBinding(ResourceReference adapterViewRef, Object adapterCookie, + Object viewObject) { + return null; + } + + @Override + public ActionBarCallback getActionBarCallback() { + return mActionBarCallback; + } +} diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java new file mode 100644 index 0000000..c79b662 --- /dev/null +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.layoutlib.bridge.intensive.setup; + +import com.android.ide.common.rendering.api.ILayoutPullParser; + +import org.kxml2.io.KXmlParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOError; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import static com.android.SdkConstants.ATTR_IGNORE; +import static com.android.SdkConstants.EXPANDABLE_LIST_VIEW; +import static com.android.SdkConstants.GRID_VIEW; +import static com.android.SdkConstants.LIST_VIEW; +import static com.android.SdkConstants.SPINNER; +import static com.android.SdkConstants.TOOLS_URI; + +public class LayoutPullParser extends KXmlParser implements ILayoutPullParser{ + + /** + * @param layoutPath Must start with '/' and be relative to test resources. + */ + public LayoutPullParser(String layoutPath) { + assert layoutPath.startsWith("/"); + try { + init(getClass().getResourceAsStream(layoutPath)); + } catch (XmlPullParserException e) { + throw new IOError(e); + } + } + + /** + * @param layoutFile Path of the layout xml file on disk. + */ + public LayoutPullParser(File layoutFile) { + try { + init(new FileInputStream(layoutFile)); + } catch (XmlPullParserException e) { + throw new IOError(e); + } catch (FileNotFoundException e) { + throw new IOError(e); + } + } + + private void init(InputStream stream) throws XmlPullParserException { + setFeature(FEATURE_PROCESS_NAMESPACES, true); + setInput(stream, null); + } + + @Override + public Object getViewCookie() { + // TODO: Implement this properly. + String name = super.getName(); + if (name == null) { + return null; + } + + // Store tools attributes if this looks like a layout we'll need adapter view + // bindings for in the LayoutlibCallback. + if (LIST_VIEW.equals(name) || EXPANDABLE_LIST_VIEW.equals(name) || GRID_VIEW.equals(name) || SPINNER.equals(name)) { + Map<String, String> map = null; + int count = getAttributeCount(); + for (int i = 0; i < count; i++) { + String namespace = getAttributeNamespace(i); + if (namespace != null && namespace.equals(TOOLS_URI)) { + String attribute = getAttributeName(i); + if (attribute.equals(ATTR_IGNORE)) { + continue; + } + if (map == null) { + map = new HashMap<String, String>(4); + } + map.put(attribute, getAttributeValue(i)); + } + } + + return map; + } + + return null; + } + + @Override + @Deprecated + public ILayoutPullParser getParser(String layoutName) { + // Studio returns null. + return null; + } + +} |