Merge "Proguard information in readme file was outdated"
diff --git a/.gitignore b/.gitignore
index 17e4ab3..233369b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,14 +15,18 @@
tests/dependencies/jarProject/build
tests/flavorlib/*/build
tests/flavorlibWithFailedTests/*/build
+tests/libProguardJarDep/*/build
+tests/libProguardLibDep/*/build
tests/libsTest/*/build
tests/multiproject/*/build
tests/localJars/*/build
+tests/ndkJniLib/*/build
tests/proguardLib/*/build
tests/renderscriptInLib/*/build
tests/repo/*/build
tests/sameNamedLibs/*/build
tests/sameNamedLibs/*/*/build
tests/tictactoe/*/build
+lint-results
/repo
/out
diff --git a/build.gradle b/build.gradle
index 145db7b..b440c7f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -22,6 +22,8 @@
// rootProject.buildDir is specific to this gradle build.
buildDir = new File(file(ext.androidHostOut), "tools/build/build")
+ext.localRepo = project.hasProperty('localRepo') ? localRepo : "$ext.androidHostOut/repo"
+
subprojects {
// Change buildDir first so that all plugins pick up the new value.
project.buildDir = project.file("$project.parent.buildDir/../$project.name")
@@ -44,7 +46,7 @@
}
project.ext {
- baseVersion = '0.5.0'
+ baseVersion = '0.7.0'
}
task disableTestFailures << {
diff --git a/builder-model/build.gradle b/builder-model/build.gradle
index 10032d6..3e780df 100644
--- a/builder-model/build.gradle
+++ b/builder-model/build.gradle
@@ -1,110 +1,16 @@
apply plugin: 'java'
apply plugin: 'maven'
-apply plugin: 'signing'
apply plugin: 'clone-artifacts'
dependencies {
compile "com.android.tools:common:$project.ext.baseAndroidVersion"
}
-def getVersion() {
- if (project.has("release")) {
- return project.ext.baseVersion
- }
-
- return project.ext.baseVersion + '-SNAPSHOT'
-}
-
-version = getVersion()
archivesBaseName = 'builder-model'
+project.ext.pomName = 'Android Builder Model library'
+project.ext.pomDesc = 'Model for the Builder library.'
+
+apply from: '../publish.gradle'
+apply from: '../javadoc.gradle'
jar.manifest.attributes("Model-Version": "$version")
-
-task publishLocal(type: Upload) {
- configuration = configurations.archives
- repositories {
- mavenDeployer {
- repository(url: uri("$rootProject.ext.androidHostOut/repo"))
- }
- }
-}
-
-project.ext.sonatypeUsername = hasProperty('sonatypeUsername') ? sonatypeUsername : ""
-project.ext.sonatypePassword = hasProperty('sonatypePassword') ? sonatypePassword : ""
-
-uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment ->
- if (!project.has("release")) {
- throw new StopExecutionException("uploadArchives must be called with the release.gradle init script")
- }
-
- if (project.ext.sonatypeUsername.length() == 0 || project.ext.sonatypePassword.length() == 0) {
- throw new StopExecutionException("uploadArchives cannot be called without sonatype username and password")
- }
-
- signing.signPom(deployment)
- }
-
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: project.ext.sonatypeUsername, password: project.ext.sonatypePassword)
- }
-
- pom.project {
- name 'Android Builder Model library'
- description 'Model for the Builder library.'
- url 'http://tools.android.com'
- inceptionYear '2007'
-
- licenses {
- license {
- name 'The Apache Software License, Version 2.0'
- url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
- distribution 'repo'
- }
- }
-
- scm {
- url "https://android.googlesource.com/platform/tools/build"
- connection "git://android.googlesource.com/platform/tools/build.git"
- }
- developers {
- developer {
- name 'The Android Open Source Project'
- }
- }
- }
- }
- }
-}
-
-// custom tasks for creating source/javadoc jars
-task sourcesJar(type: Jar, dependsOn:classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
-}
-
-javadoc {
- exclude "**/internal/**"
- options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
-
- title "Android Model"
-}
-
-task javadocJar(type: Jar, dependsOn:javadoc) {
- classifier 'javadoc'
- from javadoc.destinationDir
-}
-
-// add javadoc/source jar tasks as artifacts
-artifacts {
- archives jar
- archives sourcesJar
- archives javadocJar
-}
-
-signing {
- required { project.has("release") && gradle.taskGraph.hasTask("uploadArchives") }
- sign configurations.archives
-}
diff --git a/builder-model/src/main/java/com/android/builder/model/AaptOptions.java b/builder-model/src/main/java/com/android/builder/model/AaptOptions.java
index 86192e0..4cb9b36 100644
--- a/builder-model/src/main/java/com/android/builder/model/AaptOptions.java
+++ b/builder-model/src/main/java/com/android/builder/model/AaptOptions.java
@@ -16,7 +16,7 @@
package com.android.builder.model;
-import java.util.List;
+import java.util.Collection;
/**
* Options for aapt.
@@ -30,5 +30,5 @@
/**
* Returns the list of values for the -0 (disabled compression) option, or null
*/
- List<String> getNoCompress();
+ Collection<String> getNoCompress();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/ArtifactInfo.java b/builder-model/src/main/java/com/android/builder/model/AndroidArtifact.java
similarity index 75%
rename from builder-model/src/main/java/com/android/builder/model/ArtifactInfo.java
rename to builder-model/src/main/java/com/android/builder/model/AndroidArtifact.java
index 4a68755..3cfd2f2 100644
--- a/builder-model/src/main/java/com/android/builder/model/ArtifactInfo.java
+++ b/builder-model/src/main/java/com/android/builder/model/AndroidArtifact.java
@@ -20,12 +20,12 @@
import com.android.annotations.Nullable;
import java.io.File;
-import java.util.List;
+import java.util.Collection;
/**
- * The information for a generated artifact.
+ * The information for a generated Android artifact.
*/
-public interface ArtifactInfo {
+public interface AndroidArtifact extends BaseArtifact {
/**
* Returns the output file for this artifact. Depending on whether the project is an app
@@ -73,12 +73,10 @@
String getSourceGenTaskName();
/**
- * Returns the name of the task used to generate the artifact.
- *
- * @return the name of the task.
+ * The generated manifest for this variant's artifact.
*/
@NonNull
- String getAssembleTaskName();
+ File getGeneratedManifest();
/**
* Returns all the source folders that are generated. This is typically folders for the R,
@@ -87,7 +85,7 @@
* @return a list of folders.
*/
@NonNull
- List<File> getGeneratedSourceFolders();
+ Collection<File> getGeneratedSourceFolders();
/**
* Returns all the resource folders that are generated. This is typically the renderscript
@@ -96,22 +94,5 @@
* @return a list of folder.
*/
@NonNull
- List<File> getGeneratedResourceFolders();
-
- /**
- * Returns the folder containing the class files. This is the output of the java compilation.
- *
- * @return a folder.
- */
- @NonNull
- File getClassesFolder();
-
- /**
- * Returns the resolved dependencies for this artifact. This is a composite of all the
- * dependencies for that artifact: default config + build type + flavor(s).s
- *
- * @return The dependencies.
- */
- @NonNull
- Dependencies getDependencies();
+ Collection<File> getGeneratedResourceFolders();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/AndroidLibrary.java b/builder-model/src/main/java/com/android/builder/model/AndroidLibrary.java
index 64ac011..a46cb7e 100644
--- a/builder-model/src/main/java/com/android/builder/model/AndroidLibrary.java
+++ b/builder-model/src/main/java/com/android/builder/model/AndroidLibrary.java
@@ -20,6 +20,7 @@
import com.android.annotations.Nullable;
import java.io.File;
+import java.util.Collection;
import java.util.List;
/**
@@ -49,12 +50,18 @@
File getFolder();
/**
- * Returns the direct dependency of this dependency.
+ * Returns the direct dependency of this dependency. The order is important.
*/
@NonNull
List<? extends AndroidLibrary> getLibraryDependencies();
/**
+ * Returns the location of the manifest.
+ */
+ @NonNull
+ File getManifest();
+
+ /**
* Returns the location of the jar file to use for packaging.
*
* @return a File for the jar file. The file may not point to an existing file.
@@ -68,7 +75,7 @@
* @return a list of File. May be empty but not null.
*/
@NonNull
- List<File> getLocalJars();
+ Collection<File> getLocalJars();
/**
* Returns the location of the res folder.
diff --git a/builder-model/src/main/java/com/android/builder/model/AndroidProject.java b/builder-model/src/main/java/com/android/builder/model/AndroidProject.java
index f3929e1..f1118f4 100644
--- a/builder-model/src/main/java/com/android/builder/model/AndroidProject.java
+++ b/builder-model/src/main/java/com/android/builder/model/AndroidProject.java
@@ -18,14 +18,18 @@
import com.android.annotations.NonNull;
-import java.util.List;
-import java.util.Map;
+import java.io.File;
+import java.util.Collection;
/**
* Entry point for the model of the Android Projects. This models a single module, whether
* the module is an app project or a library project.
*/
public interface AndroidProject {
+ String BUILD_MODEL_ONLY_SYSTEM_PROPERTY = "android.build.model.only";
+
+ public static final String ARTIFACT_MAIN = "_main_";
+ public static final String ARTIFACT_INSTRUMENT_TEST = "_instrument_test_";
/**
* Returns the model version. This is a string in the format X.Y.Z
@@ -58,34 +62,39 @@
ProductFlavorContainer getDefaultConfig();
/**
- * Returns a map of all the {@link BuildType} in their container. The key is the build type
- * name as returned by {@link BuildType#getName()}
+ * Returns a list of all the {@link BuildType} in their container.
*
- * @return a map of build type containers.
+ * @return a list of build type containers.
*/
@NonNull
- Map<String, BuildTypeContainer> getBuildTypes();
+ Collection<BuildTypeContainer> getBuildTypes();
/**
- * Returns a map of all the {@link ProductFlavor} in their container. The key is the product
- * flavor name as returned by {@link ProductFlavor#getName()}
+ * Returns a list of all the {@link ProductFlavor} in their container.
*
- * @return a map of product flavor containers.
+ * @return a list of product flavor containers.
*/
@NonNull
- Map<String, ProductFlavorContainer> getProductFlavors();
+ Collection<ProductFlavorContainer> getProductFlavors();
/**
- * Returns a map of all the variants. The key is the variant name as returned by
- * {@link Variant#getName()}.
+ * Returns a list of all the variants.
*
- * This does not include test variant. Instead the variant and its component each contribute
- * their test part.
+ * This does not include test variant. Test variants are additional artifacts in their
+ * respective variant info.
*
- * @return a map of the variants.
+ * @return a list of the variants.
*/
@NonNull
- Map<String, Variant> getVariants();
+ Collection<Variant> getVariants();
+
+ /**
+ * Returns a list of extra artifacts meta data. This does not include the main artifact.
+ *
+ * @return a list of extra artifacts
+ */
+ @NonNull
+ Collection<ArtifactMetaData> getExtraArtifacts();
/**
* Returns the compilation target as a string. This is the full extended target hash string.
@@ -103,16 +112,22 @@
* @return a list of jar files.
*/
@NonNull
- List<String> getBootClasspath();
+ Collection<String> getBootClasspath();
/**
- * Returns a map of {@link SigningConfig}. The key is the signing config name as returned by
- * {@link SigningConfig#getName()}
+ * Returns a list of folders or jar files that contains the framework source code.
+ * @return a list of folders or jar files that contains the framework source code.
+ */
+ @NonNull
+ Collection<File> getFrameworkSources();
+
+ /**
+ * Returns a list of {@link SigningConfig}.
*
* @return a map of signing config
*/
@NonNull
- Map<String, SigningConfig> getSigningConfigs();
+ Collection<SigningConfig> getSigningConfigs();
/**
* Returns the aapt options.
@@ -121,4 +136,23 @@
*/
@NonNull
AaptOptions getAaptOptions();
+
+ /**
+ * Returns the dependencies that were not successfully resolved. The returned list gets
+ * populated only if the system property {@link #BUILD_MODEL_ONLY_SYSTEM_PROPERTY} has been
+ * set to {@code true}.
+ * <p>
+ * Each value of the collection has the format group:name:version, for example:
+ * com.google.guava:guava:15.0.2
+ *
+ * @return the dependencies that were not successfully resolved.
+ */
+ @NonNull
+ Collection<String> getUnresolvedDependencies();
+
+ /**
+ * @return the compile options for Java code.
+ */
+ @NonNull
+ JavaCompileOptions getJavaCompileOptions();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/ArtifactMetaData.java b/builder-model/src/main/java/com/android/builder/model/ArtifactMetaData.java
new file mode 100644
index 0000000..f1af029
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/ArtifactMetaData.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.model;
+
+import com.android.annotations.NonNull;
+
+/**
+ * Meta Data for an Artifact.
+ */
+public interface ArtifactMetaData {
+
+ public final static int TYPE_ANDROID = 1;
+ public final static int TYPE_JAVA = 2;
+
+ @NonNull
+ String getName();
+
+ boolean isTest();
+
+ int getType();
+}
diff --git a/builder-model/src/main/java/com/android/builder/model/BaseArtifact.java b/builder-model/src/main/java/com/android/builder/model/BaseArtifact.java
new file mode 100644
index 0000000..fd1a7b7
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/BaseArtifact.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.model;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+
+import java.io.File;
+
+/**
+ * The base information for all generated artifacts
+ */
+public interface BaseArtifact {
+
+ /**
+ * Name of the artifact. This should match {@link ArtifactMetaData#getName()}.
+ */
+ @NonNull
+ String getName();
+
+ /**
+ * @return the name of the task used to compile Java code.
+ */
+ @NonNull
+ String getJavaCompileTaskName();
+
+ /**
+ * Returns the name of the task used to generate the artifact.
+ *
+ * @return the name of the task.
+ */
+ @NonNull
+ String getAssembleTaskName();
+
+ /**
+ * Returns the folder containing the class files. This is the output of the java compilation.
+ *
+ * @return a folder.
+ */
+ @NonNull
+ File getClassesFolder();
+
+ /**
+ * Returns the resolved dependencies for this artifact. This is a composite of all the
+ * dependencies for that artifact: default config + build type + flavor(s).s
+ *
+ * @return The dependencies.
+ */
+ @NonNull
+ Dependencies getDependencies();
+
+ /**
+ * A SourceProvider specific to the variant. This can be null if there is no flavors as
+ * the "variant" is equal to the build type.
+ *
+ * @return the variant specific source provider
+ */
+ @Nullable
+ SourceProvider getVariantSourceProvider();
+
+ /**
+ * A SourceProvider specific to the flavor combination.
+ *
+ * For instance if there are 2 dimensions, then this would be Flavor1Flavor2, and would be
+ * common to all variant using these two flavors and any of the build type.
+ *
+ * This can be null if there is less than 2 flavors.
+ *
+ * @return the multi flavor specific source provider
+ */
+ @Nullable
+ SourceProvider getMultiFlavorSourceProvider();
+}
diff --git a/builder-model/src/main/java/com/android/builder/model/BaseConfig.java b/builder-model/src/main/java/com/android/builder/model/BaseConfig.java
index ff3efcc..d4e22c1 100644
--- a/builder-model/src/main/java/com/android/builder/model/BaseConfig.java
+++ b/builder-model/src/main/java/com/android/builder/model/BaseConfig.java
@@ -19,7 +19,7 @@
import com.android.annotations.NonNull;
import java.io.File;
-import java.util.List;
+import java.util.Collection;
/**
* Base config object for Build Type and Product flavor.
@@ -27,11 +27,11 @@
public interface BaseConfig {
/**
- * List of Build Config lines.
- * @return a non-null list of lines (possibly empty)
+ * List of Build Config Fields
+ * @return a non-null list of class fields (possibly empty)
*/
@NonNull
- List<String> getBuildConfig();
+ Collection<ClassField> getBuildConfigFields();
/**
* Returns the list of proguard rule files.
@@ -39,5 +39,13 @@
* @return a non-null list of files.
*/
@NonNull
- List<File> getProguardFiles();
+ Collection<File> getProguardFiles();
+
+ /**
+ * Returns the list of proguard rule files for consumers of the library to use.
+ *
+ * @return a non-null list of files.
+ */
+ @NonNull
+ Collection<File> getConsumerProguardFiles();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/BuildType.java b/builder-model/src/main/java/com/android/builder/model/BuildType.java
index 33d9ada..c8cf61e 100644
--- a/builder-model/src/main/java/com/android/builder/model/BuildType.java
+++ b/builder-model/src/main/java/com/android/builder/model/BuildType.java
@@ -26,7 +26,7 @@
* or in the artifact info.
*
* @see BuildTypeContainer
- * @see ArtifactInfo#getDependencies()
+ * @see AndroidArtifact#getDependencies()
*/
public interface BuildType extends BaseConfig {
@@ -69,7 +69,7 @@
/**
* Returns the package name suffix applied to this build type.
- * To get the final package name, use {@link ArtifactInfo#getPackageName()}.
+ * To get the final package name, use {@link AndroidArtifact#getPackageName()}.
*
* @return the package name suffix.
*/
@@ -97,4 +97,11 @@
* @return true if zipalign is enabled.
*/
boolean isZipAlign();
+
+ /**
+ * Returns the NDK configuration.
+ * @return the ndk config.
+ */
+ @Nullable
+ NdkConfig getNdkConfig();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/BuildTypeContainer.java b/builder-model/src/main/java/com/android/builder/model/BuildTypeContainer.java
index 4a0170d..87765f1 100644
--- a/builder-model/src/main/java/com/android/builder/model/BuildTypeContainer.java
+++ b/builder-model/src/main/java/com/android/builder/model/BuildTypeContainer.java
@@ -18,6 +18,8 @@
import com.android.annotations.NonNull;
+import java.util.Collection;
+
/**
* A Container of all the data related to {@link BuildType}.
*/
@@ -38,4 +40,12 @@
*/
@NonNull
SourceProvider getSourceProvider();
+
+ /**
+ * Returns a list of ArtifactMetaData/SourceProvider association.
+ *
+ * @return a list of ArtifactMetaData/SourceProvider association.
+ */
+ @NonNull
+ Collection<SourceProviderContainer> getExtraSourceProviders();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/ClassField.java b/builder-model/src/main/java/com/android/builder/model/ClassField.java
new file mode 100644
index 0000000..d6b6a26
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/ClassField.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.model;
+
+import com.android.annotations.NonNull;
+
+/**
+ * A Simple class field with name, type and value, all as strings.
+ */
+public interface ClassField {
+ @NonNull
+ String getType();
+
+ @NonNull
+ String getName();
+
+ @NonNull
+ String getValue();
+}
diff --git a/builder-model/src/main/java/com/android/builder/model/Dependencies.java b/builder-model/src/main/java/com/android/builder/model/Dependencies.java
index b5a27d1..f28b648 100644
--- a/builder-model/src/main/java/com/android/builder/model/Dependencies.java
+++ b/builder-model/src/main/java/com/android/builder/model/Dependencies.java
@@ -19,10 +19,11 @@
import com.android.annotations.NonNull;
import java.io.File;
+import java.util.Collection;
import java.util.List;
/**
- * A set of dependencies for an {@link ArtifactInfo}.
+ * A set of dependencies for an {@link AndroidArtifact}.
*/
public interface Dependencies {
@@ -41,7 +42,7 @@
* @return the list of jar files.
*/
@NonNull
- List<File> getJars();
+ Collection<File> getJars();
/**
* The list of project dependencies. This is only for non Android module dependencies (which
@@ -50,5 +51,5 @@
* @return the list of projects.
*/
@NonNull
- List<String> getProjects();
+ Collection<String> getProjects();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/JavaArtifact.java b/builder-model/src/main/java/com/android/builder/model/JavaArtifact.java
new file mode 100644
index 0000000..02cba55
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/JavaArtifact.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.model;
+
+/**
+ * The information for a generated Java artifact.
+ */
+public interface JavaArtifact extends BaseArtifact {
+
+}
diff --git a/builder-model/src/main/java/com/android/builder/model/JavaCompileOptions.java b/builder-model/src/main/java/com/android/builder/model/JavaCompileOptions.java
new file mode 100644
index 0000000..dafe83a
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/JavaCompileOptions.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.model;
+
+import com.android.annotations.NonNull;
+
+/**
+ * Java compile options.
+ */
+public interface JavaCompileOptions {
+ /**
+ * @return the level of compliance Java source code has.
+ */
+ @NonNull
+ String getSourceCompatibility();
+
+ /**
+ * @return the Java version to be able to run classes on.
+ */
+ @NonNull
+ String getTargetCompatibility();
+}
diff --git a/builder-model/src/main/java/com/android/builder/model/NdkConfig.java b/builder-model/src/main/java/com/android/builder/model/NdkConfig.java
new file mode 100644
index 0000000..25056c7
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/NdkConfig.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.model;
+
+import com.android.annotations.Nullable;
+
+import java.util.Collection;
+
+/**
+ * Base class for NDK config file.
+ */
+public interface NdkConfig {
+
+ /**
+ * The module name
+ */
+ @Nullable
+ public String getModuleName();
+
+ /**
+ * The C Flags
+ */
+ @Nullable
+ public String getcFlags();
+
+ /**
+ * The LD Libs
+ */
+ @Nullable
+ public Collection<String> getLdLibs();
+
+ /**
+ * The ABI Filters
+ */
+ @Nullable
+ public Collection<String> getAbiFilters();
+
+ /**
+ * The APP_STL value
+ */
+ @Nullable
+ public String getStl();
+}
diff --git a/builder-model/src/main/java/com/android/builder/model/ProductFlavor.java b/builder-model/src/main/java/com/android/builder/model/ProductFlavor.java
index f1a6d16..2e5eb81 100644
--- a/builder-model/src/main/java/com/android/builder/model/ProductFlavor.java
+++ b/builder-model/src/main/java/com/android/builder/model/ProductFlavor.java
@@ -19,6 +19,8 @@
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import java.util.Collection;
+
/**
* a Product Flavor. This is only the configuration of the flavor.
*
@@ -26,7 +28,7 @@
* or in the artifact info.
*
* @see ProductFlavorContainer
- * @see ArtifactInfo#getDependencies()
+ * @see BaseArtifact#getDependencies()
*/
public interface ProductFlavor extends BaseConfig {
@@ -40,7 +42,7 @@
/**
* Returns the name of the product flavor. This is only the value set on this product flavor.
- * To get the final package name, use {@link ArtifactInfo#getPackageName()}.
+ * To get the final package name, use {@link AndroidArtifact#getPackageName()}.
*
* @return the package name.
*/
@@ -90,9 +92,23 @@
int getRenderscriptTargetApi();
/**
+ * Returns whether the renderscript code should be compiled in support mode to
+ * make it compatible with older versions of Android.
+ *
+ * @return true if support mode is enabled.
+ */
+ boolean getRenderscriptSupportMode();
+
+ /**
+ * Returns whether the renderscript code should be compiled to generate C/C++ bindings.
+ * @return true for C/C++ generation, false for Java
+ */
+ boolean getRenderscriptNdkMode();
+
+ /**
* Returns the test package name. This is only the value set on this product flavor.
* To get the final value, use {@link Variant#getTestArtifactInfo()} and
- * {@link ArtifactInfo#getPackageName()}
+ * {@link AndroidArtifact#getPackageName()}
*
* @return the test package name.
*/
@@ -107,4 +123,38 @@
*/
@Nullable
String getTestInstrumentationRunner();
+
+ /**
+ * Returns the handlingProfile value. This is only the value set on this product flavor.
+ *
+ * @return the handlingProfile value.
+ */
+ @Nullable
+ Boolean getTestHandleProfiling();
+
+ /**
+ * Returns the functionalTest value. This is only the value set on this product flavor.
+ *
+ * @return the functionalTest value.
+ */
+ @Nullable
+ Boolean getTestFunctionalTest();
+
+ /**
+ * Returns the NDK configuration.
+ * @return the ndk config.
+ */
+ @Nullable
+ NdkConfig getNdkConfig();
+
+ /**
+ * Returns the resource configuration for this variant.
+ * TODO implement this.
+ *
+ * This is the list of -c parameters for aapt.
+ *
+ * @return the resource configuration options.
+ */
+ @NonNull
+ Collection<String> getResourceConfigurations();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/ProductFlavorContainer.java b/builder-model/src/main/java/com/android/builder/model/ProductFlavorContainer.java
index f8cc7ed..8643f9d 100644
--- a/builder-model/src/main/java/com/android/builder/model/ProductFlavorContainer.java
+++ b/builder-model/src/main/java/com/android/builder/model/ProductFlavorContainer.java
@@ -18,6 +18,8 @@
import com.android.annotations.NonNull;
+import java.util.Collection;
+
/**
* A Container of all the data related to {@link ProductFlavor}.
*/
@@ -40,10 +42,10 @@
SourceProvider getSourceProvider();
/**
- * The associated test sources of the product flavor
+ * Returns a list of ArtifactMetaData/SourceProvider association.
*
- * @return the test source provider.
+ * @return a list of ArtifactMetaData/SourceProvider association.
*/
@NonNull
- SourceProvider getTestSourceProvider();
+ Collection<SourceProviderContainer> getExtraSourceProviders();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/SourceProvider.java b/builder-model/src/main/java/com/android/builder/model/SourceProvider.java
index 7ed06ef..6d58e64 100644
--- a/builder-model/src/main/java/com/android/builder/model/SourceProvider.java
+++ b/builder-model/src/main/java/com/android/builder/model/SourceProvider.java
@@ -18,7 +18,7 @@
import com.android.annotations.NonNull;
import java.io.File;
-import java.util.Set;
+import java.util.Collection;
/**
* Represent a SourceProvider for a given configuration.
@@ -41,7 +41,7 @@
* @return a list of folders. They may not all exist.
*/
@NonNull
- Set<File> getJavaDirectories();
+ Collection<File> getJavaDirectories();
/**
* Returns the java resources folders.
@@ -49,7 +49,7 @@
* @return a list of folders. They may not all exist.
*/
@NonNull
- Set<File> getResourcesDirectories();
+ Collection<File> getResourcesDirectories();
/**
* Returns the aidl source folders.
@@ -57,7 +57,7 @@
* @return a list of folders. They may not all exist.
*/
@NonNull
- Set<File> getAidlDirectories();
+ Collection<File> getAidlDirectories();
/**
* Returns the renderscript source folders.
@@ -65,7 +65,7 @@
* @return a list of folders. They may not all exist.
*/
@NonNull
- Set<File> getRenderscriptDirectories();
+ Collection<File> getRenderscriptDirectories();
/**
* Returns the jni source folders.
@@ -73,7 +73,7 @@
* @return a list of folders. They may not all exist.
*/
@NonNull
- Set<File> getJniDirectories();
+ Collection<File> getJniDirectories();
/**
* Returns the android resources folders.
@@ -81,7 +81,7 @@
* @return a list of folders. They may not all exist.
*/
@NonNull
- Set<File> getResDirectories();
+ Collection<File> getResDirectories();
/**
* Returns the android assets folders.
@@ -89,5 +89,5 @@
* @return a list of folders. They may not all exist.
*/
@NonNull
- Set<File> getAssetsDirectories();
+ Collection<File> getAssetsDirectories();
}
diff --git a/builder-model/src/main/java/com/android/builder/model/SourceProviderContainer.java b/builder-model/src/main/java/com/android/builder/model/SourceProviderContainer.java
new file mode 100644
index 0000000..0ac8387
--- /dev/null
+++ b/builder-model/src/main/java/com/android/builder/model/SourceProviderContainer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.model;
+
+import com.android.annotations.NonNull;
+
+/**
+ * An association of an {@link ArtifactMetaData}'s name and a {@link SourceProvider}.
+ */
+public interface SourceProviderContainer {
+
+ /**
+ * Returns the name matching {@link ArtifactMetaData#getName()}
+ */
+ @NonNull
+ String getArtifactName();
+
+ /**
+ * Returns the source provider
+ */
+ @NonNull
+ SourceProvider getSourceProvider();
+}
diff --git a/builder-model/src/main/java/com/android/builder/model/Variant.java b/builder-model/src/main/java/com/android/builder/model/Variant.java
index 21ef33e..67813ae 100644
--- a/builder-model/src/main/java/com/android/builder/model/Variant.java
+++ b/builder-model/src/main/java/com/android/builder/model/Variant.java
@@ -17,8 +17,8 @@
package com.android.builder.model;
import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
+import java.util.Collection;
import java.util.List;
/**
@@ -49,16 +49,13 @@
* @return the artifact.
*/
@NonNull
- ArtifactInfo getMainArtifactInfo();
+ AndroidArtifact getMainArtifact();
- /**
- * Returns the test artifact for this variant. This may be null if this particular variant
- * is not configured to be tested.
- *
- * @return the test artifact.
- */
- @Nullable
- ArtifactInfo getTestArtifactInfo();
+ @NonNull
+ Collection<AndroidArtifact> getExtraAndroidArtifacts();
+
+ @NonNull
+ Collection<JavaArtifact> getExtraJavaArtifacts();
/**
* Returns the build type. All variants have a build type, so this is never null.
@@ -89,15 +86,4 @@
*/
@NonNull
ProductFlavor getMergedFlavor();
-
- /**
- * Returns the resource configuration for this variant.
- * TODO implement this.
- *
- * This is the list of -c parameters for aapt.
- *
- * @return the resource configuration options.
- */
- @NonNull
- List<String> getResourceConfigurations();
}
diff --git a/builder-test-api/build.gradle b/builder-test-api/build.gradle
index 579f4f7..4ba5312 100644
--- a/builder-test-api/build.gradle
+++ b/builder-test-api/build.gradle
@@ -7,102 +7,9 @@
compile "com.android.tools.ddms:ddmlib:$project.ext.baseAndroidVersion"
}
-def getVersion() {
- if (project.has("release")) {
- return project.ext.baseVersion
- }
-
- return project.ext.baseVersion + '-SNAPSHOT'
-}
-
-version = getVersion()
archivesBaseName = 'builder-test-api'
+project.ext.pomName = 'Android Builder Test API library'
+project.ext.pomDesc = 'API for the Test extension point in the Builder library.'
-task publishLocal(type: Upload) {
- configuration = configurations.archives
- repositories {
- mavenDeployer {
- repository(url: uri("$rootProject.ext.androidHostOut/repo"))
- }
- }
-}
-
-project.ext.sonatypeUsername = hasProperty('sonatypeUsername') ? sonatypeUsername : ""
-project.ext.sonatypePassword = hasProperty('sonatypePassword') ? sonatypePassword : ""
-
-uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment ->
- if (!project.has("release")) {
- throw new StopExecutionException("uploadArchives must be called with the release.gradle init script")
- }
-
- if (project.ext.sonatypeUsername.length() == 0 || project.ext.sonatypePassword.length() == 0) {
- throw new StopExecutionException("uploadArchives cannot be called without sonatype username and password")
- }
-
- signing.signPom(deployment)
- }
-
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: project.ext.sonatypeUsername, password: project.ext.sonatypePassword)
- }
-
- pom.project {
- name 'Android Builder Test API library'
- description 'API for the Test extension point in the Builder library.'
- url 'http://tools.android.com'
- inceptionYear '2007'
-
- licenses {
- license {
- name 'The Apache Software License, Version 2.0'
- url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
- distribution 'repo'
- }
- }
-
- scm {
- url "https://android.googlesource.com/platform/tools/build"
- connection "git://android.googlesource.com/platform/tools/build.git"
- }
- developers {
- developer {
- name 'The Android Open Source Project'
- }
- }
- }
- }
- }
-}
-
-// custom tasks for creating source/javadoc jars
-task sourcesJar(type: Jar, dependsOn:classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
-}
-
-javadoc {
- exclude "**/internal/**"
- options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
-
- title "Android Model"
-}
-
-task javadocJar(type: Jar, dependsOn:javadoc) {
- classifier 'javadoc'
- from javadoc.destinationDir
-}
-
-// add javadoc/source jar tasks as artifacts
-artifacts {
- archives jar
- archives sourcesJar
- archives javadocJar
-}
-
-signing {
- required { project.has("release") && gradle.taskGraph.hasTask("uploadArchives") }
- sign configurations.archives
-}
+apply from: '../publish.gradle'
+apply from: '../javadoc.gradle'
diff --git a/builder-test-api/src/main/java/com/android/builder/testing/api/DeviceConnector.java b/builder-test-api/src/main/java/com/android/builder/testing/api/DeviceConnector.java
index 243bdc2..48208e8 100644
--- a/builder-test-api/src/main/java/com/android/builder/testing/api/DeviceConnector.java
+++ b/builder-test-api/src/main/java/com/android/builder/testing/api/DeviceConnector.java
@@ -23,6 +23,7 @@
import com.google.common.annotations.Beta;
import java.io.File;
+import java.util.List;
/**
* A connector to a device to install/uninstall APKs, and run shell command.
@@ -60,10 +61,18 @@
*/
public abstract void uninstallPackage(@NonNull String packageName, int timeout, ILogger logger) throws DeviceException;
+ /**
+ * Returns the API level of the device, or 0 if it could not be queried.
+ * @return the api level
+ */
public abstract int getApiLevel();
+ /**
+ * The device supported ABIs. This is in preferred order.
+ * @return the list of supported ABIs
+ */
@NonNull
- public abstract String getAbi();
+ public abstract List<String> getAbis();
public abstract int getDensity();
diff --git a/builder/build.gradle b/builder/build.gradle
index f73a991..6b5fb9b 100644
--- a/builder/build.gradle
+++ b/builder/build.gradle
@@ -11,114 +11,24 @@
compile project(':builder-test-api')
compile "com.android.tools:sdklib:$project.ext.baseAndroidVersion"
compile "com.android.tools:sdk-common:$project.ext.baseAndroidVersion"
+ compile "com.android.tools:common:$project.ext.baseAndroidVersion"
compile "com.android.tools.build:manifest-merger:$project.ext.baseAndroidVersion"
compile "com.android.tools.ddms:ddmlib:$project.ext.baseAndroidVersion"
+ compile 'com.squareup:javawriter:2.2.1'
compile 'org.bouncycastle:bcpkix-jdk15on:1.48'
testCompile 'junit:junit:3.8.1'
testCompile "com.android.tools:testutils:$project.ext.baseAndroidVersion"
}
-def getVersion() {
- if (project.has("release")) {
- return project.ext.baseVersion
- }
-
- return project.ext.baseVersion + '-SNAPSHOT'
-}
-
-version = getVersion()
archivesBaseName = 'builder'
-jar.manifest.attributes("Builder-Version": version)
+project.ext.pomName = 'Android Builder library'
+project.ext.pomDesc = 'Library to build Android applications.'
-task publishLocal(type: Upload) {
- configuration = configurations.archives
- repositories {
- mavenDeployer {
- repository(url: uri("$rootProject.ext.androidHostOut/repo"))
- }
- }
-}
+apply from: '../publish.gradle'
+apply from: '../javadoc.gradle'
+
+jar.manifest.attributes("Builder-Version": version)
publishLocal.dependsOn ':builder-model:publishLocal', ':builder-test-api:publishLocal'
-project.ext.sonatypeUsername = hasProperty('sonatypeUsername') ? sonatypeUsername : ""
-project.ext.sonatypePassword = hasProperty('sonatypePassword') ? sonatypePassword : ""
-
-uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment ->
- if (!project.has("release")) {
- throw new StopExecutionException("uploadArchives must be called with the release.gradle init script")
- }
-
- if (project.ext.sonatypeUsername.length() == 0 || project.ext.sonatypePassword.length() == 0) {
- throw new StopExecutionException("uploadArchives cannot be called without sonatype username and password")
- }
-
- signing.signPom(deployment)
- }
-
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: project.ext.sonatypeUsername, password: project.ext.sonatypePassword)
- }
-
- pom.project {
- name 'Android Builder library'
- description 'library to build Android applications.'
- url 'http://tools.android.com'
- inceptionYear '2007'
-
- licenses {
- license {
- name 'The Apache Software License, Version 2.0'
- url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
- distribution 'repo'
- }
- }
-
- scm {
- url "https://android.googlesource.com/platform/tools/build"
- connection "git://android.googlesource.com/platform/tools/build.git"
- }
- developers {
- developer {
- name 'The Android Open Source Project'
- }
- }
- }
- }
- }
-}
-
-
-// custom tasks for creating source/javadoc jars
-task sourcesJar(type: Jar, dependsOn:classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
-}
-
-javadoc {
- exclude "**/internal/**"
- options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
-
- title "Android Builder"
-}
-
-task javadocJar(type: Jar, dependsOn:javadoc) {
- classifier 'javadoc'
- from javadoc.destinationDir
-}
-
-// add javadoc/source jar tasks as artifacts
-artifacts {
- archives jar
- archives sourcesJar
- archives javadocJar
-}
-
-signing {
- required { project.has("release") && gradle.taskGraph.hasTask("uploadArchives") }
- sign configurations.archives
-}
diff --git a/builder/src/main/java/com/android/builder/AndroidBuilder.java b/builder/src/main/java/com/android/builder/AndroidBuilder.java
index 9442f4d..0e12242 100644
--- a/builder/src/main/java/com/android/builder/AndroidBuilder.java
+++ b/builder/src/main/java/com/android/builder/AndroidBuilder.java
@@ -16,24 +16,25 @@
package com.android.builder;
-import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.annotations.VisibleForTesting;
import com.android.builder.compiling.DependencyFileProcessor;
import com.android.builder.dependency.ManifestDependency;
import com.android.builder.dependency.SymbolFileProvider;
-import com.android.builder.internal.BuildConfigGenerator;
+import com.android.builder.internal.ClassFieldImpl;
import com.android.builder.internal.SymbolLoader;
import com.android.builder.internal.SymbolWriter;
import com.android.builder.internal.TestManifestGenerator;
import com.android.builder.internal.compiler.AidlProcessor;
-import com.android.builder.internal.compiler.FileGatherer;
import com.android.builder.internal.compiler.LeafFolderGatherer;
+import com.android.builder.internal.compiler.RenderScriptProcessor;
import com.android.builder.internal.compiler.SourceSearcher;
import com.android.builder.internal.packaging.JavaResourceProcessor;
import com.android.builder.internal.packaging.Packager;
import com.android.builder.model.AaptOptions;
+import com.android.builder.model.ClassField;
+import com.android.builder.model.ProductFlavor;
import com.android.builder.model.SigningConfig;
import com.android.builder.packaging.DuplicateFileException;
import com.android.builder.packaging.PackagerException;
@@ -51,11 +52,13 @@
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.repository.FullRevision;
import com.android.utils.ILogger;
+import com.android.utils.SdkUtils;
+import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
-import com.google.common.io.Files;
+import com.google.common.collect.Sets;
import java.io.File;
import java.io.FileNotFoundException;
@@ -65,6 +68,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -78,13 +82,12 @@
* create a builder with {@link #AndroidBuilder(SdkParser, String, ILogger, boolean)}
*
* then build steps can be done with
- * {@link #generateBuildConfig(String, boolean, java.util.List, String)}
* {@link #processManifest(java.io.File, java.util.List, java.util.List, String, int, String, int, int, String)}
- * {@link #processTestManifest(String, int, int, String, String, java.util.List, String)}
+ * {@link #processTestManifest(String, int, int, String, String, Boolean, Boolean, java.util.List, String)}
* {@link #processResources(java.io.File, java.io.File, java.io.File, java.util.List, String, String, String, String, String, com.android.builder.VariantConfiguration.Type, boolean, com.android.builder.model.AaptOptions)}
* {@link #compileAllAidlFiles(java.util.List, java.io.File, java.util.List, com.android.builder.compiling.DependencyFileProcessor)}
- * {@link #convertByteCode(Iterable, Iterable, File, String, DexOptions, boolean)}
- * {@link #packageApk(String, String, java.util.List, String, String, boolean, SigningConfig, String)}
+ * {@link #convertByteCode(Iterable, Iterable, File, DexOptions, boolean)}
+ * {@link #packageApk(String, String, java.util.List, String, java.util.Collection, java.util.Set, boolean, com.android.builder.model.SigningConfig, String)}
*
* Java compilation is not handled but the builder provides the bootclasspath with
* {@link #getBootClasspath(SdkParser)}.
@@ -104,6 +107,7 @@
private final ILogger mLogger;
private final CommandLineRunner mCmdLineRunner;
private final boolean mVerboseExec;
+ private boolean mLibrary;
@NonNull
private final IAndroidTarget mTarget;
@@ -166,6 +170,7 @@
/**
* Helper method to get the boot classpath to be used during compilation.
*/
+ @NonNull
public static List<String> getBootClasspath(@NonNull SdkParser sdkParser) {
List<String> classpath = Lists.newArrayList();
@@ -190,35 +195,92 @@
return classpath;
}
+ /** Sets whether this builder is currently used to build a library. Defaults to false. */
+ public AndroidBuilder setBuildingLibrary(boolean library) {
+ mLibrary = library;
+ return this;
+ }
+
+ /** Sets whether this builder is currently used to build a library */
+ public boolean isBuildingLibrary() {
+ return mLibrary;
+ }
+
+ /**
+ * Returns the compile classpath for this config. If the config tests a library, this
+ * will include the classpath of the tested config
+ *
+ * @return a non null, but possibly empty set.
+ */
+ @NonNull
+ public Set<File> getCompileClasspath(@NonNull VariantConfiguration variantConfiguration) {
+ Set<File> compileClasspath = variantConfiguration.getCompileClasspath();
+
+ ProductFlavor mergedFlavor = variantConfiguration.getMergedFlavor();
+
+ if (mergedFlavor.getRenderscriptSupportMode()) {
+ File renderScriptSupportJar = RenderScriptProcessor.getSupportJar(
+ mBuildTools.getLocation().getAbsolutePath());
+
+ Set<File> fullJars = Sets.newHashSetWithExpectedSize(compileClasspath.size() + 1);
+ fullJars.addAll(compileClasspath);
+ fullJars.add(renderScriptSupportJar);
+ compileClasspath = fullJars;
+ }
+
+ return compileClasspath;
+ }
+
+ /**
+ * Returns the list of packaged jars for this config. If the config tests a library, this
+ * will include the jars of the tested config
+ *
+ * @return a non null, but possibly empty list.
+ */
+ @NonNull
+ public List<File> getPackagedJars(@NonNull VariantConfiguration variantConfiguration) {
+ List<File> packagedJars = variantConfiguration.getPackagedJars();
+
+ ProductFlavor mergedFlavor = variantConfiguration.getMergedFlavor();
+
+ if (mergedFlavor.getRenderscriptSupportMode()) {
+ File renderScriptSupportJar = RenderScriptProcessor.getSupportJar(
+ mBuildTools.getLocation().getAbsolutePath());
+
+ List<File> fullJars = Lists.newArrayListWithCapacity(packagedJars.size() + 1);
+ fullJars.addAll(packagedJars);
+ fullJars.add(renderScriptSupportJar);
+ packagedJars = fullJars;
+ }
+
+ return packagedJars;
+ }
+
+ @NonNull
+ public File getSupportNativeLibFolder() {
+ return RenderScriptProcessor.getSupportNativeLibFolder(
+ mBuildTools.getLocation().getAbsolutePath());
+ }
/**
* Returns an {@link AaptRunner} able to run aapt commands.
* @return an AaptRunner object
*/
+ @NonNull
public AaptRunner getAaptRunner() {
return new AaptRunner(
mBuildTools.getPath(BuildToolInfo.PathId.AAPT),
mCmdLineRunner);
}
- /**
- * Generate the BuildConfig class for the project.
- * @param packageName the package in which to generate the class
- * @param debuggable whether the app is considered debuggable
- * @param javaLines additional java lines to put in the class. These must be valid Java lines.
- * @param sourceOutputDir directory where to put this. This is the source folder, not the
- * package folder.
- * @throws IOException
- */
- public void generateBuildConfig(
- @NonNull String packageName,
- boolean debuggable,
- @NonNull List<String> javaLines,
- @NonNull String sourceOutputDir) throws IOException {
+ @NonNull
+ public CommandLineRunner getCommandLineRunner() {
+ return mCmdLineRunner;
+ }
- BuildConfigGenerator generator = new BuildConfigGenerator(
- sourceOutputDir, packageName, debuggable);
- generator.generate(javaLines);
+ @NonNull
+ public static ClassField createClassField(@NonNull String type, @NonNull String name, @NonNull String value) {
+ return new ClassFieldImpl(type, name, value);
}
/**
@@ -266,9 +328,11 @@
// if no manifest to merge, just copy to location, unless we have to inject
// attributes
if (attributeInjection.isEmpty() && packageOverride == null) {
- Files.copy(mainManifest, new File(outManifestLocation));
+ SdkUtils.copyXmlWithSourceReference(mainManifest,
+ new File(outManifestLocation));
} else {
ManifestMerger merger = new ManifestMerger(MergerLog.wrapSdkLog(mLogger), null);
+ merger.setInsertSourceMarkers(isInsertSourceMarkers());
doMerge(merger, new File(outManifestLocation), mainManifest,
attributeInjection, packageOverride);
}
@@ -287,6 +351,7 @@
}
ManifestMerger merger = new ManifestMerger(MergerLog.wrapSdkLog(mLogger), null);
+ merger.setInsertSourceMarkers(isInsertSourceMarkers());
doMerge(merger, mainManifestOut, mainManifest, manifestOverlays,
attributeInjection, packageOverride);
@@ -316,6 +381,8 @@
* @param targetSdkVersion the targetSdkVersion of the test application
* @param testedPackageName the package name of the tested application
* @param instrumentationRunner the name of the instrumentation runner
+ * @param handleProfiling whether or not the Instrumentation object will turn profiling on and off
+ * @param functionalTest whether or not the Instrumentation class should run as a functional test
* @param libraries the library dependency graph
* @param outManifestLocation the output location for the merged manifest
*
@@ -324,6 +391,8 @@
* @see com.android.builder.VariantConfiguration#getMinSdkVersion()
* @see com.android.builder.VariantConfiguration#getTestedPackageName()
* @see com.android.builder.VariantConfiguration#getInstrumentationRunner()
+ * @see com.android.builder.VariantConfiguration#getHandleProfiling()
+ * @see com.android.builder.VariantConfiguration#getFunctionalTest()
* @see com.android.builder.VariantConfiguration#getDirectLibraries()
*/
public void processTestManifest(
@@ -332,11 +401,15 @@
int targetSdkVersion,
@NonNull String testedPackageName,
@NonNull String instrumentationRunner,
+ @NonNull Boolean handleProfiling,
+ @NonNull Boolean functionalTest,
@NonNull List<? extends ManifestDependency> libraries,
@NonNull String outManifestLocation) {
checkNotNull(testPackageName, "testPackageName cannot be null.");
checkNotNull(testedPackageName, "testedPackageName cannot be null.");
checkNotNull(instrumentationRunner, "instrumentationRunner cannot be null.");
+ checkNotNull(handleProfiling, "handleProfiling cannot be null.");
+ checkNotNull(functionalTest, "functionalTest cannot be null.");
checkNotNull(libraries, "libraries cannot be null.");
checkNotNull(outManifestLocation, "outManifestLocation cannot be null.");
@@ -351,6 +424,8 @@
targetSdkVersion,
testedPackageName,
instrumentationRunner,
+ handleProfiling,
+ functionalTest,
generatedTestManifest.getAbsolutePath());
mergeLibraryManifests(
@@ -368,6 +443,8 @@
targetSdkVersion,
testedPackageName,
instrumentationRunner,
+ handleProfiling,
+ functionalTest,
outManifestLocation);
}
}
@@ -378,6 +455,8 @@
int targetSdkVersion,
String testedPackageName,
String instrumentationRunner,
+ Boolean handleProfiling,
+ Boolean functionalTest,
String outManifestLocation) {
TestManifestGenerator generator = new TestManifestGenerator(
outManifestLocation,
@@ -385,7 +464,9 @@
minSdkVersion,
targetSdkVersion,
testedPackageName,
- instrumentationRunner);
+ instrumentationRunner,
+ handleProfiling,
+ functionalTest);
try {
generator.generate();
} catch (IOException e) {
@@ -443,7 +524,7 @@
List<File> manifests = Lists.newArrayList();
for (ManifestDependency library : directLibraries) {
- List<? extends ManifestDependency> subLibraries = library.getManifestDependencies();
+ Collection<? extends ManifestDependency> subLibraries = library.getManifestDependencies();
if (subLibraries.isEmpty()) {
manifests.add(library.getManifest());
} else {
@@ -459,9 +540,27 @@
}
ManifestMerger merger = new ManifestMerger(MergerLog.wrapSdkLog(mLogger), null);
+ merger.setInsertSourceMarkers(isInsertSourceMarkers());
doMerge(merger, outManifest, mainManifest, manifests, attributeInjection, packageOverride);
}
+ /**
+ * Returns whether we should insert source markers in generated files (such as
+ * XML resources and merged manifest files)
+ *
+ * @return true to generate source comments
+ */
+ public boolean isInsertSourceMarkers() {
+ // In release library builds (generating AAR's) we don't want source comments.
+ // In other scenarios (e.g. during development) we do.
+
+ // TODO: Find out whether we're building in a release build type
+ boolean isRelease = false;
+
+ //noinspection ConstantConditions
+ return !(mLibrary && isRelease);
+ }
+
private void doMerge(ManifestMerger merger, File output, File input,
Map<String, String> injectionMap, String packageOverride) {
List<File> list = Collections.emptyList();
@@ -509,7 +608,8 @@
@Nullable String proguardOutput,
VariantConfiguration.Type type,
boolean debuggable,
- @NonNull AaptOptions options)
+ @NonNull AaptOptions options,
+ @NonNull Collection<String> resourceConfigs)
throws IOException, InterruptedException, LoggedErrorException {
checkNotNull(manifestFile, "manifestFile cannot be null.");
@@ -564,14 +664,14 @@
command.add(sourceOutputDir);
}
- if (type != VariantConfiguration.Type.LIBRARY && resPackageOutput != null) {
+ if (resPackageOutput != null) {
command.add("-F");
command.add(resPackageOutput);
+ }
- if (proguardOutput != null) {
- command.add("-G");
- command.add(proguardOutput);
- }
+ if (proguardOutput != null) {
+ command.add("-G");
+ command.add(proguardOutput);
}
// options controlled by build variants
@@ -600,7 +700,7 @@
command.add(ignoreAssets);
}
- List<String> noCompressList = options.getNoCompress();
+ Collection<String> noCompressList = options.getNoCompress();
if (noCompressList != null) {
for (String noCompress : noCompressList) {
command.add("-0");
@@ -608,6 +708,13 @@
}
}
+ if (!resourceConfigs.isEmpty()) {
+ command.add("-c");
+
+ Joiner joiner = Joiner.on(',');
+ command.add(joiner.join(resourceConfigs));
+ }
+
if (symbolOutputDir != null &&
(type == VariantConfiguration.Type.LIBRARY || !libraries.isEmpty())) {
command.add("--output-text-symbols");
@@ -782,9 +889,14 @@
@NonNull List<File> importFolders,
@NonNull File sourceOutputDir,
@NonNull File resOutputDir,
+ @NonNull File objOutputDir,
+ @NonNull File libOutputDir,
int targetApi,
boolean debugBuild,
- int optimLevel)
+ int optimLevel,
+ boolean ndkMode,
+ boolean supportMode,
+ @Nullable Set<String> abiFilters)
throws IOException, InterruptedException, LoggedErrorException {
checkNotNull(sourceFolders, "sourceFolders cannot be null.");
checkNotNull(importFolders, "importFolders cannot be null.");
@@ -796,76 +908,26 @@
throw new IllegalStateException("llvm-rs-cc is missing");
}
- // gather the files to compile
- FileGatherer fileGatherer = new FileGatherer();
- SourceSearcher searcher = new SourceSearcher(sourceFolders, "rs", "fs");
- searcher.setUseExecutor(false);
- searcher.search(fileGatherer);
-
- List<File> renderscriptFiles = fileGatherer.getFiles();
-
- if (renderscriptFiles.isEmpty()) {
- return;
+ if (supportMode && mBuildTools.getRevision().compareTo(new FullRevision(18,1, 0)) == -1) {
+ throw new IllegalStateException(
+ "RenderScript Support Mode requires buildToolsVersion >= 18.1");
}
- String rsPath = mBuildTools.getPath(BuildToolInfo.PathId.ANDROID_RS);
- String rsClangPath = mBuildTools.getPath(BuildToolInfo.PathId.ANDROID_RS_CLANG);
-
- // the renderscript compiler doesn't expect the top res folder,
- // but the raw folder directly.
- File rawFolder = new File(resOutputDir, SdkConstants.FD_RES_RAW);
-
- // compile all the files in a single pass
- ArrayList<String> command = Lists.newArrayList();
-
- command.add(renderscript);
-
- if (debugBuild) {
- command.add("-g");
- }
-
- command.add("-O");
- command.add(Integer.toString(optimLevel));
-
- // add all import paths
- command.add("-I");
- command.add(rsPath);
- command.add("-I");
- command.add(rsClangPath);
-
- for (File importPath : importFolders) {
- if (importPath.isDirectory()) {
- command.add("-I");
- command.add(importPath.getAbsolutePath());
- }
- }
-
- // source output
- command.add("-p");
- command.add(sourceOutputDir.getAbsolutePath());
-
- // res output
- command.add("-o");
- command.add(rawFolder.getAbsolutePath());
-
- command.add("-target-api");
- command.add(Integer.toString(targetApi < 11 ? 11 : targetApi));
-
- // input files
- for (File sourceFile : renderscriptFiles) {
- command.add(sourceFile.getAbsolutePath());
- }
-
- Map<String, String> env = null;
- if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN) {
- env = Maps.newHashMap();
- env.put("DYLD_LIBRARY_PATH", mBuildTools.getLocation().getAbsolutePath());
- } else if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_LINUX) {
- env = Maps.newHashMap();
- env.put("LD_LIBRARY_PATH", mBuildTools.getLocation().getAbsolutePath());
- }
-
- mCmdLineRunner.runCmdLine(command, env);
+ RenderScriptProcessor processor = new RenderScriptProcessor(
+ sourceFolders,
+ importFolders,
+ sourceOutputDir,
+ resOutputDir,
+ objOutputDir,
+ libOutputDir,
+ mBuildTools,
+ targetApi,
+ debugBuild,
+ optimLevel,
+ ndkMode,
+ supportMode,
+ abiFilters);
+ processor.build(mCmdLineRunner);
}
/**
@@ -910,8 +972,8 @@
/**
* Converts the bytecode to Dalvik format
- * @param classesLocation the location of the compiler output
- * @param libraries the list of libraries
+ * @param inputs the input files
+ * @param preDexedLibraries the list of pre-dexed libraries
* @param outDexFile the location of the output classes.dex file
* @param dexOptions dex options
* @param incremental true if it should attempt incremental dex if applicable
@@ -921,14 +983,13 @@
* @throws LoggedErrorException
*/
public void convertByteCode(
- @NonNull Iterable<File> classesLocation,
- @NonNull Iterable<File> libraries,
- @Nullable File proguardFile,
- @NonNull String outDexFile,
+ @NonNull Iterable<File> inputs,
+ @NonNull Iterable<File> preDexedLibraries,
+ @NonNull File outDexFile,
@NonNull DexOptions dexOptions,
boolean incremental) throws IOException, InterruptedException, LoggedErrorException {
- checkNotNull(classesLocation, "classesLocation cannot be null.");
- checkNotNull(libraries, "libraries cannot be null.");
+ checkNotNull(inputs, "inputs cannot be null.");
+ checkNotNull(preDexedLibraries, "preDexedLibraries cannot be null.");
checkNotNull(outDexFile, "outDexFile cannot be null.");
checkNotNull(dexOptions, "dexOptions cannot be null.");
@@ -956,45 +1017,99 @@
command.add("--core-library");
}
+ if (dexOptions.getJumboMode()) {
+ command.add("--force-jumbo");
+ }
+
if (incremental) {
command.add("--incremental");
command.add("--no-strict");
}
command.add("--output");
- command.add(outDexFile);
+ command.add(outDexFile.getAbsolutePath());
- // clean up and add class inputs
- List<String> classesList = Lists.newArrayList();
- for (File f : classesLocation) {
+ // clean up input list
+ List<String> inputList = Lists.newArrayList();
+ for (File f : inputs) {
if (f != null && f.exists()) {
- classesList.add(f.getAbsolutePath());
+ inputList.add(f.getAbsolutePath());
}
}
- if (!classesList.isEmpty()) {
- mLogger.verbose("Dex class inputs: " + classesList);
- command.addAll(classesList);
+ if (!inputList.isEmpty()) {
+ mLogger.verbose("Dex inputs: " + inputList);
+ command.addAll(inputList);
}
// clean up and add library inputs.
List<String> libraryList = Lists.newArrayList();
- for (File f : libraries) {
+ for (File f : preDexedLibraries) {
if (f != null && f.exists()) {
libraryList.add(f.getAbsolutePath());
}
}
if (!libraryList.isEmpty()) {
- mLogger.verbose("Dex library inputs: " + libraryList);
+ mLogger.verbose("Dex pre-dexed inputs: " + libraryList);
command.addAll(libraryList);
}
- if (proguardFile != null && proguardFile.exists()) {
- mLogger.verbose("ProGuarded inputs " + proguardFile);
- command.add(proguardFile.getAbsolutePath());
+ mCmdLineRunner.runCmdLine(command, null);
+ }
+
+ /**
+ * Converts the bytecode to Dalvik format
+ * @param inputFile the input file
+ * @param outFile the location of the output classes.dex file
+ * @param dexOptions dex options
+ *
+ * @throws IOException
+ * @throws InterruptedException
+ * @throws LoggedErrorException
+ */
+ public void preDexLibrary(
+ @NonNull File inputFile,
+ @NonNull File outFile,
+ @NonNull DexOptions dexOptions)
+ throws IOException, InterruptedException, LoggedErrorException {
+ checkNotNull(inputFile, "inputFile cannot be null.");
+ checkNotNull(outFile, "outFile cannot be null.");
+ checkNotNull(dexOptions, "dexOptions cannot be null.");
+
+ // launch dx: create the command line
+ ArrayList<String> command = Lists.newArrayList();
+
+ String dx = mBuildTools.getPath(BuildToolInfo.PathId.DX);
+ if (dx == null || !new File(dx).isFile()) {
+ throw new IllegalStateException("dx is missing");
}
+ command.add(dx);
+
+ if (dexOptions.getJavaMaxHeapSize() != null) {
+ command.add("-JXmx" + dexOptions.getJavaMaxHeapSize());
+ }
+
+ command.add("--dex");
+
+ if (mVerboseExec) {
+ command.add("--verbose");
+ }
+
+ if (dexOptions.isCoreLibrary()) {
+ command.add("--core-library");
+ }
+
+ if (dexOptions.getJumboMode()) {
+ command.add("--force-jumbo");
+ }
+
+ command.add("--output");
+ command.add(outFile.getAbsolutePath());
+
+ command.add(inputFile.getAbsolutePath());
+
mCmdLineRunner.runCmdLine(command, null);
}
@@ -1005,7 +1120,8 @@
* @param classesDexLocation the location of the classes.dex file
* @param packagedJars the jars that are packaged (libraries + jar dependencies)
* @param javaResourcesLocation the processed Java resource folder
- * @param jniLibsLocation the location of the compiled JNI libraries
+ * @param jniLibsFolders the folders containing jni shared libraries
+ * @param abiFilters optional ABI filter
* @param jniDebugBuild whether the app should include jni debug data
* @param signingConfig the signing configuration
* @param outApkLocation location of the APK.
@@ -1022,7 +1138,8 @@
@NonNull String classesDexLocation,
@NonNull List<File> packagedJars,
@Nullable String javaResourcesLocation,
- @Nullable String jniLibsLocation,
+ @Nullable Collection<File> jniLibsFolders,
+ @Nullable Set<String> abiFilters,
boolean jniDebugBuild,
@Nullable SigningConfig signingConfig,
@NonNull String outApkLocation) throws DuplicateFileException, FileNotFoundException,
@@ -1059,8 +1176,10 @@
}
// also add resources from library projects and jars
- if (jniLibsLocation != null) {
- packager.addNativeLibraries(jniLibsLocation);
+ if (jniLibsFolders != null) {
+ for (File jniFolder : jniLibsFolders) {
+ packager.addNativeLibraries(jniFolder, abiFilters);
+ }
}
packager.sealApk();
diff --git a/builder/src/main/java/com/android/builder/DefaultBuildType.java b/builder/src/main/java/com/android/builder/DefaultBuildType.java
index ea82e12..63abf00 100644
--- a/builder/src/main/java/com/android/builder/DefaultBuildType.java
+++ b/builder/src/main/java/com/android/builder/DefaultBuildType.java
@@ -20,6 +20,7 @@
import com.android.annotations.Nullable;
import com.android.builder.internal.BaseConfigImpl;
import com.android.builder.model.BuildType;
+import com.android.builder.model.NdkConfig;
import com.android.builder.model.SigningConfig;
import com.google.common.base.Objects;
@@ -111,7 +112,8 @@
}
@Override
- @Nullable public String getPackageNameSuffix() {
+ @Nullable
+ public String getPackageNameSuffix() {
return mPackageNameSuffix;
}
@@ -122,7 +124,8 @@
}
@Override
- @Nullable public String getVersionNameSuffix() {
+ @Nullable
+ public String getVersionNameSuffix() {
return mVersionNameSuffix;
}
@@ -160,6 +163,12 @@
}
@Override
+ @Nullable
+ public NdkConfig getNdkConfig() {
+ return null;
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
diff --git a/builder/src/main/java/com/android/builder/DefaultManifestParser.java b/builder/src/main/java/com/android/builder/DefaultManifestParser.java
index 97d8533..e8d70d6 100644
--- a/builder/src/main/java/com/android/builder/DefaultManifestParser.java
+++ b/builder/src/main/java/com/android/builder/DefaultManifestParser.java
@@ -67,6 +67,27 @@
}
@Override
+ public int getVersionCode(@NonNull File manifestFile) {
+ XPath xpath = AndroidXPathFactory.newXPath();
+
+ try {
+ String value= xpath.evaluate("/manifest/@android:versionCode",
+ new InputSource(new FileInputStream(manifestFile)));
+ if (value != null) {
+ return Integer.parseInt(value);
+ }
+ } catch (XPathExpressionException e) {
+ // won't happen.
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (NumberFormatException e) {
+ // return -1 below.
+ }
+
+ return -1;
+ }
+
+ @Override
public int getMinSdkVersion(@NonNull File manifestFile) {
try {
Object value = AndroidManifest.getMinSdkVersion(new FileWrapper(manifestFile));
diff --git a/builder/src/main/java/com/android/builder/DefaultProductFlavor.java b/builder/src/main/java/com/android/builder/DefaultProductFlavor.java
index 6541dde..2dbdd81 100644
--- a/builder/src/main/java/com/android/builder/DefaultProductFlavor.java
+++ b/builder/src/main/java/com/android/builder/DefaultProductFlavor.java
@@ -19,9 +19,15 @@
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.builder.internal.BaseConfigImpl;
+import com.android.builder.model.NdkConfig;
import com.android.builder.model.ProductFlavor;
import com.android.builder.model.SigningConfig;
import com.google.common.base.Objects;
+import com.google.common.collect.Sets;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
/**
* The configuration of a product flavor.
@@ -36,12 +42,17 @@
private int mMinSdkVersion = -1;
private int mTargetSdkVersion = -1;
private int mRenderscriptTargetApi = -1;
+ private Boolean mRenderscriptSupportMode;
+ private Boolean mRenderscriptNdkMode;
private int mVersionCode = -1;
private String mVersionName = null;
private String mPackageName = null;
private String mTestPackageName = null;
private String mTestInstrumentationRunner = null;
+ private Boolean mTestHandleProfiling = null;
+ private Boolean mTestFunctionalTest = null;
private SigningConfig mSigningConfig = null;
+ private Set<String> mResourceConfiguration = null;
/**
* Creates a ProductFlavor with a given name.
@@ -145,6 +156,26 @@
mRenderscriptTargetApi = renderscriptTargetApi;
}
+ @Override
+ public boolean getRenderscriptSupportMode() {
+ // default is false
+ return mRenderscriptSupportMode != null && mRenderscriptSupportMode.booleanValue();
+ }
+
+ public void setRenderscriptSupportMode(boolean renderscriptSupportMode) {
+ mRenderscriptSupportMode = renderscriptSupportMode;
+ }
+
+ @Override
+ public boolean getRenderscriptNdkMode() {
+ // default is false
+ return mRenderscriptNdkMode != null && mRenderscriptNdkMode.booleanValue();
+ }
+
+ public void setRenderscriptNdkMode(boolean renderscriptNdkMode) {
+ mRenderscriptNdkMode = renderscriptNdkMode;
+ }
+
@NonNull
public ProductFlavor setTestPackageName(String testPackageName) {
mTestPackageName = testPackageName;
@@ -169,6 +200,30 @@
return mTestInstrumentationRunner;
}
+ @Override
+ @Nullable
+ public Boolean getTestHandleProfiling() {
+ return mTestHandleProfiling;
+ }
+
+ @NonNull
+ public ProductFlavor setTestHandleProfiling(boolean handleProfiling) {
+ mTestHandleProfiling = handleProfiling;
+ return this;
+ }
+
+ @Override
+ @Nullable
+ public Boolean getTestFunctionalTest() {
+ return mTestFunctionalTest;
+ }
+
+ @NonNull
+ public ProductFlavor setTestFunctionalTest(boolean functionalTest) {
+ mTestFunctionalTest = functionalTest;
+ return this;
+ }
+
@Nullable
public SigningConfig getSigningConfig() {
return mSigningConfig;
@@ -180,6 +235,46 @@
return this;
}
+ @Override
+ @Nullable
+ public NdkConfig getNdkConfig() {
+ return null;
+ }
+
+ public void addResourceConfiguration(@NonNull String configuration) {
+ if (mResourceConfiguration == null) {
+ mResourceConfiguration = Sets.newHashSet();
+ }
+
+ mResourceConfiguration.add(configuration);
+ }
+
+ public void addResourceConfigurations(@NonNull String... configurations) {
+ if (mResourceConfiguration == null) {
+ mResourceConfiguration = Sets.newHashSet();
+ }
+
+ mResourceConfiguration.addAll(Arrays.asList(configurations));
+ }
+
+ public void addResourceConfigurations(@NonNull Collection<String> configurations) {
+ if (mResourceConfiguration == null) {
+ mResourceConfiguration = Sets.newHashSet();
+ }
+
+ mResourceConfiguration.addAll(configurations);
+ }
+
+ @NonNull
+ @Override
+ public Collection<String> getResourceConfigurations() {
+ if (mResourceConfiguration == null) {
+ mResourceConfiguration = Sets.newHashSet();
+ }
+
+ return mResourceConfiguration;
+ }
+
/**
* Merges the flavor on top of a base platform and returns a new object with the result.
* @param base the flavor to merge on top of
@@ -193,6 +288,10 @@
flavor.mTargetSdkVersion = chooseInt(mTargetSdkVersion, base.mTargetSdkVersion);
flavor.mRenderscriptTargetApi = chooseInt(mRenderscriptTargetApi,
base.mRenderscriptTargetApi);
+ flavor.mRenderscriptSupportMode = chooseBoolean(mRenderscriptSupportMode,
+ base.mRenderscriptSupportMode);
+ flavor.mRenderscriptNdkMode = chooseBoolean(mRenderscriptNdkMode,
+ base.mRenderscriptNdkMode);
flavor.mVersionCode = chooseInt(mVersionCode, base.mVersionCode);
flavor.mVersionName = chooseString(mVersionName, base.mVersionName);
@@ -203,9 +302,17 @@
flavor.mTestInstrumentationRunner = chooseString(mTestInstrumentationRunner,
base.mTestInstrumentationRunner);
+ flavor.mTestHandleProfiling = chooseBoolean(mTestHandleProfiling,
+ base.mTestHandleProfiling);
+
+ flavor.mTestFunctionalTest = chooseBoolean(mTestFunctionalTest,
+ base.mTestFunctionalTest);
+
flavor.mSigningConfig =
mSigningConfig != null ? mSigningConfig : base.mSigningConfig;
+ flavor.addResourceConfigurations(base.getResourceConfigurations());
+
return flavor;
}
@@ -218,6 +325,10 @@
return overlay != null ? overlay : base;
}
+ private Boolean chooseBoolean(Boolean overlay, Boolean base) {
+ return overlay != null ? overlay : base;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -226,27 +337,30 @@
DefaultProductFlavor that = (DefaultProductFlavor) o;
- if (!mName.equals(that.mName)) return false;
if (mMinSdkVersion != that.mMinSdkVersion) return false;
- if (mTargetSdkVersion != that.mTargetSdkVersion) return false;
if (mRenderscriptTargetApi != that.mRenderscriptTargetApi) return false;
+ if (mTargetSdkVersion != that.mTargetSdkVersion) return false;
if (mVersionCode != that.mVersionCode) return false;
- if (mPackageName != null ?
- !mPackageName.equals(that.mPackageName) :
- that.mPackageName != null)
+ if (!mName.equals(that.mName)) return false;
+ if (mPackageName != null ? !mPackageName.equals(that.mPackageName) : that.mPackageName != null)
return false;
- if (mTestInstrumentationRunner != null ?
- !mTestInstrumentationRunner.equals(that.mTestInstrumentationRunner) :
- that.mTestInstrumentationRunner != null)
+ if (mRenderscriptNdkMode != null ? !mRenderscriptNdkMode.equals(that.mRenderscriptNdkMode) : that.mRenderscriptNdkMode != null)
return false;
- if (mTestPackageName != null ?
- !mTestPackageName.equals(that.mTestPackageName) : that.mTestPackageName != null)
+ if (mRenderscriptSupportMode != null ? !mRenderscriptSupportMode.equals(that.mRenderscriptSupportMode) : that.mRenderscriptSupportMode != null)
return false;
- if (mVersionName != null ?
- !mVersionName.equals(that.mVersionName) : that.mVersionName != null)
+ if (mResourceConfiguration != null ? !mResourceConfiguration.equals(that.mResourceConfiguration) : that.mResourceConfiguration != null)
return false;
- if (mSigningConfig != null ?
- !mSigningConfig.equals(that.mSigningConfig) : that.mSigningConfig != null)
+ if (mSigningConfig != null ? !mSigningConfig.equals(that.mSigningConfig) : that.mSigningConfig != null)
+ return false;
+ if (mTestFunctionalTest != null ? !mTestFunctionalTest.equals(that.mTestFunctionalTest) : that.mTestFunctionalTest != null)
+ return false;
+ if (mTestHandleProfiling != null ? !mTestHandleProfiling.equals(that.mTestHandleProfiling) : that.mTestHandleProfiling != null)
+ return false;
+ if (mTestInstrumentationRunner != null ? !mTestInstrumentationRunner.equals(that.mTestInstrumentationRunner) : that.mTestInstrumentationRunner != null)
+ return false;
+ if (mTestPackageName != null ? !mTestPackageName.equals(that.mTestPackageName) : that.mTestPackageName != null)
+ return false;
+ if (mVersionName != null ? !mVersionName.equals(that.mVersionName) : that.mVersionName != null)
return false;
return true;
@@ -259,13 +373,17 @@
result = 31 * result + mMinSdkVersion;
result = 31 * result + mTargetSdkVersion;
result = 31 * result + mRenderscriptTargetApi;
+ result = 31 * result + (mRenderscriptSupportMode != null ? mRenderscriptSupportMode.hashCode() : 0);
+ result = 31 * result + (mRenderscriptNdkMode != null ? mRenderscriptNdkMode.hashCode() : 0);
result = 31 * result + mVersionCode;
result = 31 * result + (mVersionName != null ? mVersionName.hashCode() : 0);
result = 31 * result + (mPackageName != null ? mPackageName.hashCode() : 0);
result = 31 * result + (mTestPackageName != null ? mTestPackageName.hashCode() : 0);
- result = 31 * result + (mTestInstrumentationRunner != null ?
- mTestInstrumentationRunner.hashCode() : 0);
+ result = 31 * result + (mTestInstrumentationRunner != null ? mTestInstrumentationRunner.hashCode() : 0);
+ result = 31 * result + (mTestHandleProfiling != null ? mTestHandleProfiling.hashCode() : 0);
+ result = 31 * result + (mTestFunctionalTest != null ? mTestFunctionalTest.hashCode() : 0);
result = 31 * result + (mSigningConfig != null ? mSigningConfig.hashCode() : 0);
+ result = 31 * result + (mResourceConfiguration != null ? mResourceConfiguration.hashCode() : 0);
return result;
}
@@ -277,18 +395,17 @@
.add("minSdkVersion", mMinSdkVersion)
.add("targetSdkVersion", mTargetSdkVersion)
.add("renderscriptTargetApi", mRenderscriptTargetApi)
+ .add("renderscriptSupportMode", mRenderscriptSupportMode)
+ .add("renderscriptNdkMode", mRenderscriptNdkMode)
.add("versionCode", mVersionCode)
.add("versionName", mVersionName)
.add("packageName", mPackageName)
.add("testPackageName", mTestPackageName)
.add("testInstrumentationRunner", mTestInstrumentationRunner)
+ .add("testHandleProfiling", mTestHandleProfiling)
+ .add("testFunctionalTest", mTestFunctionalTest)
.add("signingConfig", mSigningConfig)
+ .add("resConfig", mResourceConfiguration)
.toString();
}
-
- /*
- release signing info (keystore, key alias, passwords,...).
- native abi filter
- */
-
}
diff --git a/builder/src/main/java/com/android/builder/DefaultSdkParser.java b/builder/src/main/java/com/android/builder/DefaultSdkParser.java
index 3f52971..6244fb9 100644
--- a/builder/src/main/java/com/android/builder/DefaultSdkParser.java
+++ b/builder/src/main/java/com/android/builder/DefaultSdkParser.java
@@ -50,6 +50,7 @@
public class DefaultSdkParser implements SdkParser {
private final String mSdkLocation;
+ private final File mNdkLocation;
private SdkManager mManager;
private IAndroidTarget mTarget;
@@ -60,12 +61,13 @@
private File mAdb;
private File mZipAlign;
- public DefaultSdkParser(@NonNull String sdkLocation) {
+ public DefaultSdkParser(@NonNull String sdkLocation, @Nullable File ndkLocation) {
if (!sdkLocation.endsWith(File.separator)) {
mSdkLocation = sdkLocation + File.separator;
} else {
mSdkLocation = sdkLocation;
}
+ mNdkLocation = ndkLocation;
}
@Override
@@ -211,4 +213,10 @@
return mTools;
}
+
+ @Nullable
+ @Override
+ public File getNdkLocation() {
+ return mNdkLocation;
+ }
}
diff --git a/builder/src/main/java/com/android/builder/DexOptions.java b/builder/src/main/java/com/android/builder/DexOptions.java
index 966d081..1db13be 100644
--- a/builder/src/main/java/com/android/builder/DexOptions.java
+++ b/builder/src/main/java/com/android/builder/DexOptions.java
@@ -20,5 +20,7 @@
boolean isCoreLibrary();
boolean getIncremental();
+ boolean getPreDexLibraries();
+ boolean getJumboMode();
String getJavaMaxHeapSize();
}
diff --git a/builder/src/main/java/com/android/builder/ManifestParser.java b/builder/src/main/java/com/android/builder/ManifestParser.java
index 5b6411c..3b8e4a3 100644
--- a/builder/src/main/java/com/android/builder/ManifestParser.java
+++ b/builder/src/main/java/com/android/builder/ManifestParser.java
@@ -21,14 +21,56 @@
import java.io.File;
+/**
+ * A Manifest parser
+ */
public interface ManifestParser {
+ /**
+ * Returns the package name parsed from the given manifest file.
+ *
+ * @param manifestFile the manifest file to parse
+ *
+ * @return the package name or null if not found.
+ */
@Nullable
String getPackage(@NonNull File manifestFile);
+ /**
+ * Returns the minSdkVersion parsed from the given manifest file.
+ *
+ * @param manifestFile the manifest file to parse
+ *
+ * @return the minSdkVersion or 1 if not found.
+ */
int getMinSdkVersion(@NonNull File manifestFile);
+
+ /**
+ * Returns the targetSdkVersion parsed from the given manifest file.
+ *
+ * @param manifestFile the manifest file to parse
+ *
+ * @return the targetSdkVersion or -1 if not found.
+ */
int getTargetSdkVersion(@NonNull File manifestFile);
+ /**
+ * Returns the version name parsed from the given manifest file.
+ *
+ * @param manifestFile the manifest file to parse
+ *
+ * @return the version name or null if not found.
+ */
@Nullable
String getVersionName(@NonNull File manifestFile);
+
+ /**
+ * Returns the version code parsed from the given manifest file.
+ *
+ * @param manifestFile the manifest file to parse
+ *
+ * @return the version code or -1 if not found.
+ */
+ int getVersionCode(@NonNull File manifestFile);
+
}
diff --git a/builder/src/main/java/com/android/builder/PlatformSdkParser.java b/builder/src/main/java/com/android/builder/PlatformSdkParser.java
index 3325ea0..d0e1828 100644
--- a/builder/src/main/java/com/android/builder/PlatformSdkParser.java
+++ b/builder/src/main/java/com/android/builder/PlatformSdkParser.java
@@ -165,4 +165,10 @@
}
return mHostTools;
}
+
+ @Nullable
+ @Override
+ public File getNdkLocation() {
+ return null;
+ }
}
diff --git a/builder/src/main/java/com/android/builder/SdkParser.java b/builder/src/main/java/com/android/builder/SdkParser.java
index 7c4e0c2..c247694 100644
--- a/builder/src/main/java/com/android/builder/SdkParser.java
+++ b/builder/src/main/java/com/android/builder/SdkParser.java
@@ -94,6 +94,13 @@
@NonNull
File getAdb();
+ /**
+ * Returns the location of artifact repositories built-in the SDK.
+ * @return a non null list of repository folders.
+ */
@NonNull
List<File> getRepositories();
+
+ @Nullable
+ File getNdkLocation();
}
\ No newline at end of file
diff --git a/builder/src/main/java/com/android/builder/VariantConfiguration.java b/builder/src/main/java/com/android/builder/VariantConfiguration.java
index 614d467..80df454 100644
--- a/builder/src/main/java/com/android/builder/VariantConfiguration.java
+++ b/builder/src/main/java/com/android/builder/VariantConfiguration.java
@@ -22,6 +22,11 @@
import com.android.builder.dependency.DependencyContainer;
import com.android.builder.dependency.JarDependency;
import com.android.builder.dependency.LibraryDependency;
+import com.android.builder.internal.MergedNdkConfig;
+import com.android.builder.internal.StringHelper;
+import com.android.builder.model.ClassField;
+import com.android.builder.model.NdkConfig;
+import com.android.builder.model.ProductFlavor;
import com.android.builder.model.SigningConfig;
import com.android.builder.model.SourceProvider;
import com.android.builder.testing.TestData;
@@ -32,6 +37,7 @@
import java.io.File;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -45,25 +51,61 @@
private static final ManifestParser sManifestParser = new DefaultManifestParser();
+ /**
+ * Full, unique name of the variant in camel case, including BuildType and Flavors (and Test)
+ */
+ private String mFullName;
+ /**
+ * Flavor Name of the variant, including all flavors in camel case (starting with a lower
+ * case).
+ */
+ private String mFlavorName;
+ /**
+ * Full, unique name of the variant, including BuildType, flavors and test, dash separated.
+ * (similar to full name but with dashes)
+ */
+ private String mBaseName;
+ /**
+ * Unique directory name (can include multiple folders) for the variant, based on build type,
+ * flavor and test.
+ * This always uses forward slashes ('/') as separator on all platform.
+ *
+ */
+ private String mDirName;
+
+ @NonNull
private final DefaultProductFlavor mDefaultConfig;
+ @NonNull
private final SourceProvider mDefaultSourceProvider;
+ @NonNull
private final DefaultBuildType mBuildType;
/** SourceProvider for the BuildType. Can be null */
+ @Nullable
private final SourceProvider mBuildTypeSourceProvider;
+ private final List<String> mFlavorDimensionNames = Lists.newArrayList();
private final List<DefaultProductFlavor> mFlavorConfigs = Lists.newArrayList();
private final List<SourceProvider> mFlavorSourceProviders = Lists.newArrayList();
+ /** Variant specific source provider, may be null */
+ @Nullable
+ private SourceProvider mVariantSourceProvider;
+
+ /** MultiFlavors specific source provider, may be null */
+ @Nullable
+ private SourceProvider mMultiFlavorSourceProvider;
+
+ @NonNull
private final Type mType;
/** Optional tested config in case type is Type#TEST */
private final VariantConfiguration mTestedConfig;
- private final String mDebugName;
/** An optional output that is only valid if the type is Type#LIBRARY so that the test
* for the library can use the library as if it was a normal dependency. */
private LibraryDependency mOutput;
private DefaultProductFlavor mMergedFlavor;
+ private final MergedNdkConfig mMergedNdkConfig = new MergedNdkConfig();
private final Set<JarDependency> mJars = Sets.newHashSet();
@@ -98,18 +140,16 @@
* @param defaultSourceProvider the default source provider. Required
* @param buildType the build type for this variant. Required.
* @param buildTypeSourceProvider the source provider for the build type. Required.
- * @param debugName an optional debug name
*/
public VariantConfiguration(
@NonNull DefaultProductFlavor defaultConfig,
@NonNull SourceProvider defaultSourceProvider,
@NonNull DefaultBuildType buildType,
- @NonNull SourceProvider buildTypeSourceProvider,
- @Nullable String debugName) {
- this(defaultConfig, defaultSourceProvider,
+ @Nullable SourceProvider buildTypeSourceProvider) {
+ this(
+ defaultConfig, defaultSourceProvider,
buildType, buildTypeSourceProvider,
- Type.DEFAULT, null /*testedConfig*/,
- debugName);
+ Type.DEFAULT, null /*testedConfig*/);
}
/**
@@ -120,19 +160,17 @@
* @param buildType the build type for this variant. Required.
* @param buildTypeSourceProvider the source provider for the build type.
* @param type the type of the project.
- * @param debugName an optional debug name
*/
public VariantConfiguration(
@NonNull DefaultProductFlavor defaultConfig,
@NonNull SourceProvider defaultSourceProvider,
@NonNull DefaultBuildType buildType,
@Nullable SourceProvider buildTypeSourceProvider,
- @NonNull Type type,
- @Nullable String debugName) {
- this(defaultConfig, defaultSourceProvider,
+ @NonNull Type type) {
+ this(
+ defaultConfig, defaultSourceProvider,
buildType, buildTypeSourceProvider,
- type, null /*testedConfig*/,
- debugName);
+ type, null /*testedConfig*/);
}
/**
@@ -144,7 +182,6 @@
* @param buildTypeSourceProvider the source provider for the build type.
* @param type the type of the project.
* @param testedConfig the reference to the tested project. Required if type is Type.TEST
- * @param debugName an optional debug name
*/
public VariantConfiguration(
@NonNull DefaultProductFlavor defaultConfig,
@@ -152,18 +189,17 @@
@NonNull DefaultBuildType buildType,
@Nullable SourceProvider buildTypeSourceProvider,
@NonNull Type type,
- @Nullable VariantConfiguration testedConfig,
- @Nullable String debugName) {
+ @Nullable VariantConfiguration testedConfig) {
mDefaultConfig = checkNotNull(defaultConfig);
mDefaultSourceProvider = checkNotNull(defaultSourceProvider);
mBuildType = checkNotNull(buildType);
mBuildTypeSourceProvider = buildTypeSourceProvider;
mType = checkNotNull(type);
mTestedConfig = testedConfig;
- mDebugName = debugName;
checkState(mType != Type.TEST || mTestedConfig != null);
mMergedFlavor = mDefaultConfig;
+ computeNdkConfig();
if (testedConfig != null &&
testedConfig.mType == Type.LIBRARY &&
@@ -175,26 +211,240 @@
}
/**
+ * Returns the full, unique name of the variant in camel case (starting with a lower case),
+ * including BuildType, Flavors and Test (if applicable).
+ *
+ * @return the name of the variant
+ */
+ @NonNull
+ public String getFullName() {
+ if (mFullName == null) {
+ StringBuilder sb = new StringBuilder();
+ String flavorName = getFlavorName();
+ if (!flavorName.isEmpty()) {
+ sb.append(flavorName);
+ sb.append(StringHelper.capitalize(mBuildType.getName()));
+ } else {
+ sb.append(mBuildType.getName());
+ }
+
+ if (mType == Type.TEST) {
+ sb.append("Test");
+ }
+
+ mFullName = sb.toString();
+ }
+
+ return mFullName;
+ }
+
+
+ /**
+ * Returns the flavor name of the variant, including all flavors in camel case (starting
+ * with a lower case). If the variant has no flavor, then an empty string is returned.
+ *
+ * @return the flavor name or an empty string.
+ */
+ @NonNull
+ public String getFlavorName() {
+ if (mFlavorName == null) {
+ if (mFlavorConfigs.isEmpty()) {
+ mFlavorName = "";
+ } else {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (DefaultProductFlavor flavor : mFlavorConfigs) {
+ sb.append(first ? flavor.getName() : StringHelper.capitalize(flavor.getName()));
+ first = false;
+ }
+
+ mFlavorName = sb.toString();
+ }
+ }
+
+ return mFlavorName;
+ }
+
+ /**
+ * Returns the full, unique name of the variant, including BuildType, flavors and test,
+ * dash separated. (similar to full name but with dashes)
+ *
+ * @return the name of the variant
+ */
+ @NonNull
+ public String getBaseName() {
+ if (mBaseName == null) {
+ StringBuilder sb = new StringBuilder();
+
+ if (!mFlavorConfigs.isEmpty()) {
+ for (ProductFlavor pf : mFlavorConfigs) {
+ sb.append(pf.getName()).append('-');
+ }
+ }
+
+ sb.append(mBuildType.getName());
+
+ if (mType == Type.TEST) {
+ sb.append('-').append("test");
+ }
+
+ mBaseName = sb.toString();
+ }
+
+ return mBaseName;
+ }
+
+ /**
+ * Returns a unique directory name (can include multiple folders) for the variant,
+ * based on build type, flavor and test.
+ * This always uses forward slashes ('/') as separator on all platform.
+ *
+ * @return the directory name for the variant
+ */
+ @NonNull
+ public String getDirName() {
+ if (mDirName == null) {
+ StringBuilder sb = new StringBuilder();
+
+ if (mType == Type.TEST) {
+ sb.append("test/");
+ }
+
+ if (!mFlavorConfigs.isEmpty()) {
+ for (DefaultProductFlavor flavor : mFlavorConfigs) {
+ sb.append(flavor.getName());
+ }
+
+ sb.append('/').append(mBuildType.getName());
+
+ } else {
+ sb.append(mBuildType.getName());
+ }
+
+ mDirName = sb.toString();
+
+ }
+
+ return mDirName;
+ }
+
+ /**
+ * Return the names of the applied flavors.
+ *
+ * The list contains the dimension names as well.
+ *
+ * @return the list, possibly empty if there are no flavors.
+ */
+ @NonNull
+ public List<String> getFlavorNamesWithDimensionNames() {
+ if (mFlavorConfigs.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ List<String> names;
+ int count = mFlavorConfigs.size();
+
+ if (count > 1) {
+ names = Lists.newArrayListWithCapacity(count * 2);
+
+ for (int i = 0 ; i < count ; i++) {
+ names.add(mFlavorConfigs.get(i).getName());
+ names.add(mFlavorDimensionNames.get(i));
+ }
+
+ } else {
+ names = Collections.singletonList(mFlavorConfigs.get(0).getName());
+ }
+
+ return names;
+ }
+
+
+ /**
* Add a new configured ProductFlavor.
*
* If multiple flavors are added, the priority follows the order they are added when it
* comes to resolving Android resources overlays (ie earlier added flavors supersedes
* latter added ones).
*
- * @param sourceProvider the configured product flavor
+ * @param productFlavor the configured product flavor
+ * @param sourceProvider the source provider for the product flavor
+ * @param dimensionName the name of the dimension associated with the flavor
+ *
* @return the config object
*/
@NonNull
- public VariantConfiguration addProductFlavor(@NonNull DefaultProductFlavor productFlavor,
- @NonNull SourceProvider sourceProvider) {
+ public VariantConfiguration addProductFlavor(
+ @NonNull DefaultProductFlavor productFlavor,
+ @NonNull SourceProvider sourceProvider,
+ @NonNull String dimensionName) {
+
mFlavorConfigs.add(productFlavor);
mFlavorSourceProviders.add(sourceProvider);
+ mFlavorDimensionNames.add(dimensionName);
+
mMergedFlavor = productFlavor.mergeOver(mMergedFlavor);
+ computeNdkConfig();
return this;
}
/**
+ * Sets the variant-specific source provider.
+ * @param sourceProvider the source provider for the product flavor
+ *
+ * @return the config object
+ */
+ public VariantConfiguration setVariantSourceProvider(@Nullable SourceProvider sourceProvider) {
+ mVariantSourceProvider = sourceProvider;
+ return this;
+ }
+
+ /**
+ * Sets the variant-specific source provider.
+ * @param sourceProvider the source provider for the product flavor
+ *
+ * @return the config object
+ */
+ public VariantConfiguration setMultiFlavorSourceProvider(@Nullable SourceProvider sourceProvider) {
+ mMultiFlavorSourceProvider = sourceProvider;
+ return this;
+ }
+
+ /**
+ * Returns the variant specific source provider
+ * @return the source provider or null if none has been provided.
+ */
+ @Nullable
+ public SourceProvider getVariantSourceProvider() {
+ return mVariantSourceProvider;
+ }
+
+ @Nullable
+ public SourceProvider getMultiFlavorSourceProvider() {
+ return mMultiFlavorSourceProvider;
+ }
+
+ private void computeNdkConfig() {
+ mMergedNdkConfig.reset();
+
+ if (mDefaultConfig.getNdkConfig() != null) {
+ mMergedNdkConfig.append(mDefaultConfig.getNdkConfig());
+ }
+
+ for (int i = mFlavorConfigs.size() - 1 ; i >= 0 ; i--) {
+ NdkConfig ndkConfig = mFlavorConfigs.get(i).getNdkConfig();
+ if (ndkConfig != null) {
+ mMergedNdkConfig.append(ndkConfig);
+ }
+ }
+
+ if (mBuildType.getNdkConfig() != null && mType != Type.TEST) {
+ mMergedNdkConfig.append(mBuildType.getNdkConfig());
+ }
+ }
+
+ /**
* Sets the dependencies
*
* @param container a DependencyContainer.
@@ -276,8 +526,15 @@
return mFlavorConfigs;
}
+ /**
+ * Returns the list of SourceProviders for the flavors.
+ *
+ * The list is ordered from higher priority to lower priority.
+ *
+ * @return the list of Source Providers for the flavors. Never null.
+ */
@NonNull
- public Iterable<SourceProvider> getFlavorSourceSets() {
+ public List<SourceProvider> getFlavorSourceProviders() {
return mFlavorSourceProviders;
}
@@ -330,10 +587,11 @@
LibraryDependency library = directDependencies.get(i);
// get its libraries
- List<LibraryDependency> dependencies = library.getDependencies();
+ Collection<LibraryDependency> dependencies = library.getDependencies();
+ List<LibraryDependency> depList = Lists.newArrayList(dependencies);
// resolve the dependencies for those libraries
- resolveIndirectLibraryDependencies(dependencies, outFlatDependencies);
+ resolveIndirectLibraryDependencies(depList, outFlatDependencies);
// and add the current one (if needed) in front (higher priority)
if (!outFlatDependencies.contains(library)) {
@@ -386,7 +644,7 @@
}
if (packageName == null) {
- throw new RuntimeException("Failed get query package name for " + mDebugName);
+ throw new RuntimeException("Failed get query package name for " + getFullName());
}
return packageName;
@@ -447,7 +705,11 @@
if (versionSuffix != null && versionSuffix.length() > 0) {
if (versionName == null) {
- versionName = getVersionNameFromManifest();
+ if (mType != Type.TEST) {
+ versionName = getVersionNameFromManifest();
+ } else {
+ versionName = "";
+ }
}
versionName = versionName + versionSuffix;
@@ -456,7 +718,27 @@
return versionName;
}
+ /**
+ * Returns the version code for this variant. This could be coming from the manifest or
+ * could be overridden through the product flavors, and can have a suffix specified by
+ * the build type.
+ *
+ * @return the version code or -1 if there was non defined.
+ */
+ public int getVersionCode() {
+ int versionCode = mMergedFlavor.getVersionCode();
+
+ if (versionCode == -1 && mType != Type.TEST) {
+
+ versionCode = getVersionCodeFromManifest();
+ }
+
+ return versionCode;
+ }
+
private final static String DEFAULT_TEST_RUNNER = "android.test.InstrumentationTestRunner";
+ private final static Boolean DEFAULT_HANDLE_PROFILING = false;
+ private final static Boolean DEFAULT_FUNCTIONAL_TEST = false;
/**
* Returns the instrumentationRunner to use to test this variant, or if the
@@ -475,6 +757,38 @@
}
/**
+ * Returns handleProfiling value to use to test this variant, or if the
+ * variant is a test, the one to use to test the tested variant.
+ * @return the handleProfiling value
+ */
+ @Override
+ @NonNull
+ public Boolean getHandleProfiling() {
+ VariantConfiguration config = this;
+ if (mType == Type.TEST) {
+ config = getTestedConfig();
+ }
+ Boolean handleProfiling = config.mMergedFlavor.getTestHandleProfiling();
+ return handleProfiling != null ? handleProfiling : DEFAULT_HANDLE_PROFILING;
+ }
+
+ /**
+ * Returns functionalTest value to use to test this variant, or if the
+ * variant is a test, the one to use to test the tested variant.
+ * @return the functionalTest value
+ */
+ @Override
+ @NonNull
+ public Boolean getFunctionalTest() {
+ VariantConfiguration config = this;
+ if (mType == Type.TEST) {
+ config = getTestedConfig();
+ }
+ Boolean functionalTest = config.mMergedFlavor.getTestFunctionalTest();
+ return functionalTest != null ? functionalTest : DEFAULT_FUNCTIONAL_TEST;
+ }
+
+ /**
* Reads the package name from the manifest. This is unmodified by the build type.
*/
@Nullable
@@ -494,6 +808,14 @@
}
/**
+ * Reads the version code from the manifest.
+ */
+ public int getVersionCodeFromManifest() {
+ File manifestLocation = mDefaultSourceProvider.getManifestFile();
+ return sManifestParser.getVersionCode(manifestLocation);
+ }
+
+ /**
* Return the minSdkVersion for this variant.
*
* This uses both the value from the manifest (if present), and the override coming
@@ -552,6 +874,13 @@
public List<File> getManifestOverlays() {
List<File> inputs = Lists.newArrayList();
+ if (mVariantSourceProvider != null) {
+ File variantLocation = mVariantSourceProvider.getManifestFile();
+ if (variantLocation.isFile()) {
+ inputs.add(variantLocation);
+ }
+ }
+
if (mBuildTypeSourceProvider != null) {
File typeLocation = mBuildTypeSourceProvider.getManifestFile();
if (typeLocation.isFile()) {
@@ -559,6 +888,13 @@
}
}
+ if (mMultiFlavorSourceProvider != null) {
+ File variantLocation = mMultiFlavorSourceProvider.getManifestFile();
+ if (variantLocation.isFile()) {
+ inputs.add(variantLocation);
+ }
+ }
+
for (SourceProvider sourceProvider : mFlavorSourceProviders) {
File f = sourceProvider.getManifestFile();
if (f.isFile()) {
@@ -601,7 +937,7 @@
}
}
- Set<File> mainResDirs = mDefaultSourceProvider.getResDirectories();
+ Collection<File> mainResDirs = mDefaultSourceProvider.getResDirectories();
ResourceSet resourceSet = new ResourceSet(BuilderConstants.MAIN);
resourceSet.addSources(mainResDirs);
@@ -614,7 +950,7 @@
for (int n = mFlavorSourceProviders.size() - 1; n >= 0 ; n--) {
SourceProvider sourceProvider = mFlavorSourceProviders.get(n);
- Set<File> flavorResDirs = sourceProvider.getResDirectories();
+ Collection<File> flavorResDirs = sourceProvider.getResDirectories();
// we need the same of the flavor config, but it's in a different list.
// This is fine as both list are parallel collections with the same number of items.
resourceSet = new ResourceSet(mFlavorConfigs.get(n).getName());
@@ -622,13 +958,30 @@
resourceSets.add(resourceSet);
}
+ // multiflavor specific overrides flavor
+ if (mMultiFlavorSourceProvider != null) {
+ Collection<File> variantResDirs = mMultiFlavorSourceProvider.getResDirectories();
+ resourceSet = new ResourceSet(getFlavorName());
+ resourceSet.addSources(variantResDirs);
+ resourceSets.add(resourceSet);
+ }
+
+ // build type overrides the flavors
if (mBuildTypeSourceProvider != null) {
- Set<File> typeResDirs = mBuildTypeSourceProvider.getResDirectories();
+ Collection<File> typeResDirs = mBuildTypeSourceProvider.getResDirectories();
resourceSet = new ResourceSet(mBuildType.getName());
resourceSet.addSources(typeResDirs);
resourceSets.add(resourceSet);
}
+ // variant specific overrides all
+ if (mVariantSourceProvider != null) {
+ Collection<File> variantResDirs = mVariantSourceProvider.getResDirectories();
+ resourceSet = new ResourceSet(getFullName());
+ resourceSet.addSources(variantResDirs);
+ resourceSets.add(resourceSet);
+ }
+
return resourceSets;
}
@@ -659,7 +1012,7 @@
}
}
- Set<File> mainResDirs = mDefaultSourceProvider.getAssetsDirectories();
+ Collection<File> mainResDirs = mDefaultSourceProvider.getAssetsDirectories();
AssetSet assetSet = new AssetSet(BuilderConstants.MAIN);
assetSet.addSources(mainResDirs);
@@ -669,7 +1022,7 @@
for (int n = mFlavorSourceProviders.size() - 1; n >= 0 ; n--) {
SourceProvider sourceProvider = mFlavorSourceProviders.get(n);
- Set<File> flavorResDirs = sourceProvider.getAssetsDirectories();
+ Collection<File> flavorResDirs = sourceProvider.getAssetsDirectories();
// we need the same of the flavor config, but it's in a different list.
// This is fine as both list are parallel collections with the same number of items.
assetSet = new AssetSet(mFlavorConfigs.get(n).getName());
@@ -677,16 +1030,48 @@
assetSets.add(assetSet);
}
+ // multiflavor specific overrides flavor
+ if (mMultiFlavorSourceProvider != null) {
+ Collection<File> variantResDirs = mMultiFlavorSourceProvider.getAssetsDirectories();
+ assetSet = new AssetSet(getFlavorName());
+ assetSet.addSources(variantResDirs);
+ assetSets.add(assetSet);
+ }
+
+ // build type overrides flavors
if (mBuildTypeSourceProvider != null) {
- Set<File> typeResDirs = mBuildTypeSourceProvider.getAssetsDirectories();
+ Collection<File> typeResDirs = mBuildTypeSourceProvider.getAssetsDirectories();
assetSet = new AssetSet(mBuildType.getName());
assetSet.addSources(typeResDirs);
assetSets.add(assetSet);
}
+ // variant specific overrides all
+ if (mVariantSourceProvider != null) {
+ Collection<File> variantResDirs = mVariantSourceProvider.getAssetsDirectories();
+ assetSet = new AssetSet(getFullName());
+ assetSet.addSources(variantResDirs);
+ assetSets.add(assetSet);
+ }
+
return assetSets;
}
+ @NonNull
+ public List<File> getLibraryJniFolders() {
+ List<File> list = Lists.newArrayListWithExpectedSize(mFlatLibraries.size());
+
+ for (int n = mFlatLibraries.size() - 1 ; n >= 0 ; n--) {
+ LibraryDependency dependency = mFlatLibraries.get(n);
+ File jniFolder = dependency.getJniFolder();
+ if (jniFolder.isDirectory()) {
+ list.add(jniFolder);
+ }
+ }
+
+ return list;
+ }
+
/**
* Returns all the renderscript import folder that are outside of the current project.
*/
@@ -724,6 +1109,14 @@
}
}
+ if (mMultiFlavorSourceProvider != null) {
+ sourceList.addAll(mMultiFlavorSourceProvider.getRenderscriptDirectories());
+ }
+
+ if (mVariantSourceProvider != null) {
+ sourceList.addAll(mVariantSourceProvider.getRenderscriptDirectories());
+ }
+
return sourceList;
}
@@ -758,6 +1151,39 @@
}
}
+ if (mMultiFlavorSourceProvider != null) {
+ sourceList.addAll(mMultiFlavorSourceProvider.getAidlDirectories());
+ }
+
+ if (mVariantSourceProvider != null) {
+ sourceList.addAll(mVariantSourceProvider.getAidlDirectories());
+ }
+
+ return sourceList;
+ }
+
+ @NonNull
+ public List<File> getJniSourceList() {
+ List<File> sourceList = Lists.newArrayList();
+ sourceList.addAll(mDefaultSourceProvider.getJniDirectories());
+ if (mType != Type.TEST && mBuildTypeSourceProvider != null) {
+ sourceList.addAll(mBuildTypeSourceProvider.getJniDirectories());
+ }
+
+ if (hasFlavors()) {
+ for (SourceProvider flavorSourceSet : mFlavorSourceProviders) {
+ sourceList.addAll(flavorSourceSet.getJniDirectories());
+ }
+ }
+
+ if (mMultiFlavorSourceProvider != null) {
+ sourceList.addAll(mMultiFlavorSourceProvider.getJniDirectories());
+ }
+
+ if (mVariantSourceProvider != null) {
+ sourceList.addAll(mVariantSourceProvider.getJniDirectories());
+ }
+
return sourceList;
}
@@ -819,27 +1245,52 @@
return Lists.newArrayList(jars);
}
+ /**
+ * Returns a list of items for the BuildConfig class.
+ *
+ * Items can be either fields (instance of {@link com.android.builder.model.ClassField})
+ * or comments (instance of String).
+ *
+ * @return a list of items.
+ */
@NonNull
- public List<String> getBuildConfigLines() {
- List<String> fullList = Lists.newArrayList();
+ public List<Object> getBuildConfigItems() {
+ List<Object> fullList = Lists.newArrayList();
- List<String> list = mDefaultConfig.getBuildConfig();
- if (!list.isEmpty()) {
- fullList.add("// lines from default config.");
- fullList.addAll(list);
- }
+ Set<String> usedFieldNames = Sets.newHashSet();
- list = mBuildType.getBuildConfig();
+ List<ClassField> list = mBuildType.getBuildConfigFields();
if (!list.isEmpty()) {
- fullList.add("// lines from build type: " + mBuildType.getName());
- fullList.addAll(list);
+ fullList.add("Fields from build type: " + mBuildType.getName());
+ for (ClassField f : list) {
+ usedFieldNames.add(f.getName());
+ fullList.add(f);
+ }
}
for (DefaultProductFlavor flavor : mFlavorConfigs) {
- list = flavor.getBuildConfig();
+ list = flavor.getBuildConfigFields();
if (!list.isEmpty()) {
- fullList.add("// lines from product flavor: " + flavor.getName());
- fullList.addAll(list);
+ fullList.add("Fields from product flavor: " + flavor.getName());
+ for (ClassField f : list) {
+ String name = f.getName();
+ if (!usedFieldNames.contains(name)) {
+ usedFieldNames.add(f.getName());
+ fullList.add(f);
+ }
+ }
+ }
+ }
+
+ list = mDefaultConfig.getBuildConfigFields();
+ if (!list.isEmpty()) {
+ fullList.add("Fields from default config.");
+ for (ClassField f : list) {
+ String name = f.getName();
+ if (!usedFieldNames.contains(name)) {
+ usedFieldNames.add(f.getName());
+ fullList.add(f);
+ }
}
}
@@ -885,6 +1336,21 @@
return fullList;
}
+ @NonNull
+ public List<Object> getConsumerProguardFiles() {
+ List<Object> fullList = Lists.newArrayList();
+
+ // add the config files from the build type, main config and flavors
+ fullList.addAll(mDefaultConfig.getConsumerProguardFiles());
+ fullList.addAll(mBuildType.getConsumerProguardFiles());
+
+ for (DefaultProductFlavor flavor : mFlavorConfigs) {
+ fullList.addAll(flavor.getConsumerProguardFiles());
+ }
+
+ return fullList;
+ }
+
protected void validate() {
if (mType != Type.TEST) {
File manifest = mDefaultSourceProvider.getManifestFile();
@@ -895,11 +1361,18 @@
}
}
+ @NonNull
+ public NdkConfig getNdkConfig() {
+ return mMergedNdkConfig;
+ }
@Nullable
@Override
public Set<String> getSupportedAbis() {
- // no ndk support yet, so return null
+ if (mMergedNdkConfig != null) {
+ return mMergedNdkConfig.getAbiFilters();
+ }
+
return null;
}
}
diff --git a/builder/src/main/java/com/android/builder/compiling/BuildConfigGenerator.java b/builder/src/main/java/com/android/builder/compiling/BuildConfigGenerator.java
new file mode 100644
index 0000000..1e298b4
--- /dev/null
+++ b/builder/src/main/java/com/android/builder/compiling/BuildConfigGenerator.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.compiling;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.AndroidBuilder;
+import com.android.builder.model.ClassField;
+import com.google.common.collect.Lists;
+import com.squareup.javawriter.JavaWriter;
+
+import javax.lang.model.element.Modifier;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Class able to generate a BuildConfig class in Android project.
+ * The BuildConfig class contains constants related to the build target.
+ */
+public class BuildConfigGenerator {
+
+ public final static String BUILD_CONFIG_NAME = "BuildConfig.java";
+
+ private final String mGenFolder;
+ private final String mBuildConfigPackageName;
+
+ private final List<ClassField> mFields = Lists.newArrayList();
+ private List<Object> mItems = Lists.newArrayList();
+
+ /**
+ * Creates a generator
+ * @param genFolder the gen folder of the project
+ * @param buildConfigPackageName the package in which to create the class.
+ */
+ public BuildConfigGenerator(@NonNull String genFolder, @NonNull String buildConfigPackageName) {
+ mGenFolder = checkNotNull(genFolder);
+ mBuildConfigPackageName = checkNotNull(buildConfigPackageName);
+ }
+
+ public BuildConfigGenerator addField(
+ @NonNull String type, @NonNull String name, @NonNull String value) {
+ mFields.add(AndroidBuilder.createClassField(type, name, value));
+ return this;
+ }
+
+ public BuildConfigGenerator addItems(@Nullable Collection<Object> items) {
+ if (items != null) {
+ mItems.addAll(items);
+ }
+ return this;
+ }
+
+ /**
+ * Returns a File representing where the BuildConfig class will be.
+ */
+ public File getFolderPath() {
+ File genFolder = new File(mGenFolder);
+ return new File(genFolder, mBuildConfigPackageName.replace('.', File.separatorChar));
+ }
+
+ public File getBuildConfigFile() {
+ File folder = getFolderPath();
+ return new File(folder, BUILD_CONFIG_NAME);
+ }
+
+ /**
+ * Generates the BuildConfig class.
+ */
+ public void generate() throws IOException {
+ File pkgFolder = getFolderPath();
+ if (!pkgFolder.isDirectory()) {
+ if (!pkgFolder.mkdirs()) {
+ throw new RuntimeException("Failed to create " + pkgFolder.getAbsolutePath());
+ }
+ }
+
+ File buildConfigJava = new File(pkgFolder, BUILD_CONFIG_NAME);
+ FileWriter out = new FileWriter(buildConfigJava);
+
+ JavaWriter writer = new JavaWriter(out);
+
+ Set<Modifier> publicFinal = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL);
+ Set<Modifier> publicFinalStatic = EnumSet.of(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC);
+
+ writer.emitJavadoc("Automatically generated file. DO NOT MODIFY")
+ .emitPackage(mBuildConfigPackageName)
+ .beginType("BuildConfig", "class", publicFinal);
+
+ for (ClassField field : mFields) {
+ writer.emitField(
+ field.getType(),
+ field.getName(),
+ publicFinalStatic,
+ field.getValue());
+ }
+
+ for (Object item : mItems) {
+ if (item instanceof ClassField) {
+ ClassField field = (ClassField)item;
+ writer.emitField(
+ field.getType(),
+ field.getName(),
+ publicFinalStatic,
+ field.getValue());
+
+ } else if (item instanceof String) {
+ writer.emitSingleLineComment((String) item);
+ }
+ }
+
+ writer.endType();
+
+ out.close();
+ }
+}
diff --git a/builder/src/main/java/com/android/builder/dependency/LibraryDependency.java b/builder/src/main/java/com/android/builder/dependency/LibraryDependency.java
index c143276..3649588 100644
--- a/builder/src/main/java/com/android/builder/dependency/LibraryDependency.java
+++ b/builder/src/main/java/com/android/builder/dependency/LibraryDependency.java
@@ -19,6 +19,7 @@
import com.android.annotations.NonNull;
import com.android.builder.model.AndroidLibrary;
+import java.util.Collection;
import java.util.List;
/**
@@ -27,15 +28,15 @@
public interface LibraryDependency extends AndroidLibrary, ManifestDependency, SymbolFileProvider {
/**
- * Returns the direct dependency of this dependency.
+ * Returns the direct dependency of this dependency. The order is important
*/
@NonNull
List<LibraryDependency> getDependencies();
/**
- * Returns the list of local Jar files that are included in the dependency.
+ * Returns the collection of local Jar files that are included in the dependency.
* @return a list of JarDependency. May be empty but not null.
*/
@NonNull
- List<JarDependency> getLocalDependencies();
+ Collection<JarDependency> getLocalDependencies();
}
diff --git a/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java b/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java
index e2517c5..62653d3 100644
--- a/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java
+++ b/builder/src/main/java/com/android/builder/internal/BaseConfigImpl.java
@@ -18,11 +18,13 @@
import com.android.annotations.NonNull;
import com.android.builder.model.BaseConfig;
+import com.android.builder.model.ClassField;
import com.google.common.collect.Lists;
import java.io.File;
import java.io.Serializable;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
/**
@@ -31,23 +33,28 @@
public class BaseConfigImpl implements Serializable, BaseConfig {
private static final long serialVersionUID = 1L;
- private final List<String> mBuildConfigLines = Lists.newArrayList();
+ private final List<ClassField> mBuildConfigFields = Lists.newArrayList();
private final List<File> mProguardFiles = Lists.newArrayList();
+ private final List<File> mConsumerProguardFiles = Lists.newArrayList();
- public void setBuildConfig(String... lines) {
- mBuildConfigLines.clear();
- mBuildConfigLines.addAll(Arrays.asList(lines));
+ public void setBuildConfigFields(@NonNull ClassField... fields) {
+ mBuildConfigFields.clear();
+ mBuildConfigFields.addAll(Arrays.asList(fields));
}
- public void setBuildConfig(String line) {
- mBuildConfigLines.clear();
- mBuildConfigLines.add(line);
+ public void setBuildConfigFields(@NonNull Collection<ClassField> fields) {
+ mBuildConfigFields.clear();
+ mBuildConfigFields.addAll(fields);
+ }
+
+ public void addBuildConfigField(@NonNull ClassField field) {
+ mBuildConfigFields.add(field);
}
@Override
@NonNull
- public List<String> getBuildConfig() {
- return mBuildConfigLines;
+ public List<ClassField> getBuildConfigFields() {
+ return mBuildConfigFields;
}
@Override
@@ -56,12 +63,20 @@
return mProguardFiles;
}
+ @Override
+ @NonNull
+ public List<File> getConsumerProguardFiles() {
+ return mConsumerProguardFiles;
+ }
+
protected void _initWith(BaseConfig that) {
- mBuildConfigLines.clear();
- mBuildConfigLines.addAll(that.getBuildConfig());
+ setBuildConfigFields(that.getBuildConfigFields());
mProguardFiles.clear();
mProguardFiles.addAll(that.getProguardFiles());
+
+ mConsumerProguardFiles.clear();
+ mConsumerProguardFiles.addAll(that.getConsumerProguardFiles());
}
@Override
@@ -71,16 +86,18 @@
BaseConfigImpl that = (BaseConfigImpl) o;
- if (!mBuildConfigLines.equals(that.mBuildConfigLines)) return false;
+ if (!mBuildConfigFields.equals(that.mBuildConfigFields)) return false;
if (!mProguardFiles.equals(that.mProguardFiles)) return false;
+ if (!mConsumerProguardFiles.equals(that.mConsumerProguardFiles)) return false;
return true;
}
@Override
public int hashCode() {
- int result = mBuildConfigLines.hashCode();
+ int result = mBuildConfigFields.hashCode();
result = 31 * result + mProguardFiles.hashCode();
+ result = 31 * result + mConsumerProguardFiles.hashCode();
return result;
}
}
diff --git a/builder/src/main/java/com/android/builder/internal/BuildConfigGenerator.java b/builder/src/main/java/com/android/builder/internal/BuildConfigGenerator.java
deleted file mode 100644
index b41ed5d..0000000
--- a/builder/src/main/java/com/android/builder/internal/BuildConfigGenerator.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.builder.internal;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.collect.Maps;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Class able to generate a BuildConfig class in Android project.
- * The BuildConfig class contains constants related to the build target.
- */
-public class BuildConfigGenerator {
-
- private final static String TEMPLATE = "BuildConfig.template";
- private final static String PH_PACKAGE = "#PACKAGE#";
- private final static String PH_DEBUG = "#DEBUG#";
- private final static String PH_LINES = "#ADDITIONAL_LINES#";
-
- private final String mGenFolder;
- private final String mAppPackage;
- private final boolean mDebug;
-
- public final static String BUILD_CONFIG_NAME = "BuildConfig.java";
-
- /**
- * Creates a generator
- * @param genFolder the gen folder of the project
- * @param appPackage the application package
- * @param debug whether it's a debug build
- */
- public BuildConfigGenerator(@NonNull String genFolder, @NonNull String appPackage,
- boolean debug) {
- mGenFolder = checkNotNull(genFolder);
- mAppPackage = checkNotNull(appPackage);
- mDebug = debug;
- }
-
- /**
- * Returns a File representing where the BuildConfig class will be.
- */
- public File getFolderPath() {
- File genFolder = new File(mGenFolder);
- return new File(genFolder, mAppPackage.replace('.', File.separatorChar));
- }
-
- public File getBuildConfigFile() {
- File folder = getFolderPath();
- return new File(folder, BUILD_CONFIG_NAME);
- }
-
- /**
- * Generates the BuildConfig class.
- * @param additionalLines a list of additional lines to be added to the class.
- */
- public void generate(@Nullable List<String> additionalLines) throws IOException {
- Map<String, String> map = Maps.newHashMap();
- map.put(PH_PACKAGE, mAppPackage);
- map.put(PH_DEBUG, Boolean.toString(mDebug));
-
- if (additionalLines != null) {
- StringBuilder sb = new StringBuilder();
- for (String line : additionalLines) {
- sb.append(" ").append(line).append('\n');
- }
- map.put(PH_LINES, sb.toString());
-
- } else {
- map.put(PH_LINES, "");
- }
-
- File pkgFolder = getFolderPath();
- if (!pkgFolder.isDirectory()) {
- pkgFolder.mkdirs();
- }
-
- File buildConfigJava = new File(pkgFolder, BUILD_CONFIG_NAME);
-
- TemplateProcessor processor = new TemplateProcessor(
- BuildConfigGenerator.class.getResourceAsStream(TEMPLATE), map);
- processor.generate(buildConfigJava);
- }
-}
diff --git a/builder/src/main/java/com/android/builder/internal/ClassFieldImpl.java b/builder/src/main/java/com/android/builder/internal/ClassFieldImpl.java
new file mode 100644
index 0000000..44824b4
--- /dev/null
+++ b/builder/src/main/java/com/android/builder/internal/ClassFieldImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.internal;
+
+import com.android.annotations.NonNull;
+import com.android.builder.model.ClassField;
+
+import java.io.Serializable;
+
+/**
+ */
+public final class ClassFieldImpl implements ClassField, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @NonNull
+ private final String type;
+ @NonNull
+ private final String name;
+ @NonNull
+ private final String value;
+
+ public ClassFieldImpl(@NonNull String type, @NonNull String name, @NonNull String value) {
+ //noinspection ConstantConditions
+ if (type == null || name == null || value == null) {
+ throw new NullPointerException("Build Config field cannot have a null parameter");
+ }
+ this.type = type;
+ this.name = name;
+ this.value = value;
+ }
+
+ @Override
+ @NonNull
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ @NonNull
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ @NonNull
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ClassFieldImpl that = (ClassFieldImpl) o;
+
+ if (!name.equals(that.name)) return false;
+ if (!type.equals(that.type)) return false;
+ if (!value.equals(that.value)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type.hashCode();
+ result = 31 * result + name.hashCode();
+ result = 31 * result + value.hashCode();
+ return result;
+ }
+}
diff --git a/builder/src/main/java/com/android/builder/internal/MergedNdkConfig.java b/builder/src/main/java/com/android/builder/internal/MergedNdkConfig.java
new file mode 100644
index 0000000..bd83e99
--- /dev/null
+++ b/builder/src/main/java/com/android/builder/internal/MergedNdkConfig.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.internal;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.model.NdkConfig;
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+/**
+ * Implementation of NdkConfig used to merge multiple configs together.
+ */
+public class MergedNdkConfig implements NdkConfig {
+
+ private String moduleName;
+ private String cFlags;
+ private Set<String> ldLibs;
+ private Set<String> abiFilters;
+ private String stl;
+
+ public void reset() {
+ moduleName = null;
+ cFlags = null;
+ ldLibs = null;
+ abiFilters = null;
+ }
+
+ @Override
+ @Nullable
+ public String getModuleName() {
+ return moduleName;
+ }
+
+ @Override
+ @Nullable
+ public String getcFlags() {
+ return cFlags;
+ }
+
+ @Override
+ @Nullable
+ public Set<String> getLdLibs() {
+ return ldLibs;
+ }
+
+ @Override
+ @Nullable
+ public Set<String> getAbiFilters() {
+ return abiFilters;
+ }
+
+ @Override
+ @Nullable
+ public String getStl() {
+ return stl;
+ }
+
+ public void append(@NonNull NdkConfig ndkConfig) {
+ // override
+ if (ndkConfig.getModuleName() != null) {
+ moduleName = ndkConfig.getModuleName();
+ }
+
+ if (ndkConfig.getStl() != null) {
+ stl = ndkConfig.getStl();
+ }
+
+ // append
+ if (ndkConfig.getAbiFilters() != null) {
+ if (abiFilters == null) {
+ abiFilters = Sets.newHashSetWithExpectedSize(ndkConfig.getAbiFilters().size());
+ } else {
+ abiFilters.clear();
+ }
+ abiFilters.addAll(ndkConfig.getAbiFilters());
+ }
+
+ if (cFlags == null) {
+ cFlags = ndkConfig.getcFlags();
+ } else if (ndkConfig.getcFlags() != null) {
+ cFlags = cFlags + " " + ndkConfig.getcFlags();
+ }
+
+ if (ndkConfig.getLdLibs() != null) {
+ if (ldLibs == null) {
+ ldLibs = Sets.newHashSetWithExpectedSize(ndkConfig.getLdLibs().size());
+ } else {
+ ldLibs.clear();
+ }
+ ldLibs.addAll(ndkConfig.getLdLibs());
+ }
+ }
+}
diff --git a/builder/src/main/java/com/android/builder/internal/StringHelper.java b/builder/src/main/java/com/android/builder/internal/StringHelper.java
new file mode 100644
index 0000000..4a59a82
--- /dev/null
+++ b/builder/src/main/java/com/android/builder/internal/StringHelper.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.internal;
+
+import com.android.annotations.NonNull;
+
+import java.util.Locale;
+
+/**
+ */
+public class StringHelper {
+
+ @NonNull
+ public static String capitalize(@NonNull String string) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(string.substring(0, 1).toUpperCase(Locale.US)).append(string.substring(1));
+
+ return sb.toString();
+ }
+}
diff --git a/builder/src/main/java/com/android/builder/internal/TestManifestGenerator.java b/builder/src/main/java/com/android/builder/internal/TestManifestGenerator.java
index 69fa7b5..9e443a7 100644
--- a/builder/src/main/java/com/android/builder/internal/TestManifestGenerator.java
+++ b/builder/src/main/java/com/android/builder/internal/TestManifestGenerator.java
@@ -33,6 +33,8 @@
private final static String PH_TARGET_SDK_VERSION = "#TARGETSDKVERSION#";
private final static String PH_TESTED_PACKAGE = "#TESTEDPACKAGE#";
private final static String PH_TEST_RUNNER = "#TESTRUNNER#";
+ private final static String PH_HANDLE_PROFILING = "#HANDLEPROFILING#";
+ private final static String PH_FUNCTIONAL_TEST = "#FUNCTIONALTEST#";
private final String mOutputFile;
private final String mPackageName;
@@ -40,19 +42,25 @@
private final int mTargetSdkVersion;
private final String mTestedPackageName;
private final String mTestRunnerName;
+ private final boolean mHandleProfiling;
+ private final boolean mFunctionalTest;
public TestManifestGenerator(@NonNull String outputFile,
@NonNull String packageName,
int minSdkVersion,
int targetSdkVersion,
@NonNull String testedPackageName,
- @NonNull String testRunnerName) {
+ @NonNull String testRunnerName,
+ @NonNull Boolean handleProfiling,
+ @NonNull Boolean functionalTest) {
mOutputFile = outputFile;
mPackageName = packageName;
mMinSdkVersion = minSdkVersion;
mTargetSdkVersion = targetSdkVersion != -1 ? targetSdkVersion : minSdkVersion;
mTestedPackageName = testedPackageName;
mTestRunnerName = testRunnerName;
+ mHandleProfiling = handleProfiling;
+ mFunctionalTest = functionalTest;
}
public void generate() throws IOException {
@@ -62,6 +70,8 @@
map.put(PH_TARGET_SDK_VERSION, Integer.toString(mTargetSdkVersion));
map.put(PH_TESTED_PACKAGE, mTestedPackageName);
map.put(PH_TEST_RUNNER, mTestRunnerName);
+ map.put(PH_HANDLE_PROFILING, Boolean.toString(mHandleProfiling));
+ map.put(PH_FUNCTIONAL_TEST, Boolean.toString(mFunctionalTest));
TemplateProcessor processor = new TemplateProcessor(
TestManifestGenerator.class.getResourceAsStream(TEMPLATE),
diff --git a/builder/src/main/java/com/android/builder/internal/compiler/RenderScriptProcessor.java b/builder/src/main/java/com/android/builder/internal/compiler/RenderScriptProcessor.java
new file mode 100644
index 0000000..9b28743
--- /dev/null
+++ b/builder/src/main/java/com/android/builder/internal/compiler/RenderScriptProcessor.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.internal.compiler;
+
+import com.android.SdkConstants;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.internal.CommandLineRunner;
+import com.android.ide.common.internal.LoggedErrorException;
+import com.android.ide.common.internal.WaitableExecutor;
+import com.android.sdklib.BuildToolInfo;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import static com.android.SdkConstants.EXT_BC;
+import static com.android.SdkConstants.FN_RENDERSCRIPT_V8_JAR;
+
+/**
+ * Compiles Renderscript files.
+ */
+public class RenderScriptProcessor {
+
+ // ABI list, as pairs of (android-ABI, toolchain-ABI)
+ private static final class Abi {
+
+ @NonNull
+ private final String mDevice;
+ @NonNull
+ private final String mToolchain;
+ @NonNull
+ private final BuildToolInfo.PathId mLinker;
+ @NonNull
+ private final String[] mLinkerArgs;
+
+ Abi(@NonNull String device,
+ @NonNull String toolchain,
+ @NonNull BuildToolInfo.PathId linker,
+ @NonNull String... linkerArgs) {
+
+ mDevice = device;
+ mToolchain = toolchain;
+ mLinker = linker;
+ mLinkerArgs = linkerArgs;
+ }
+ }
+
+ private static final Abi[] ABIS = {
+ new Abi("armeabi-v7a", "armv7-none-linux-gnueabi", BuildToolInfo.PathId.LD_ARM,
+ "-dynamic-linker", "/system/bin/linker", "-X", "-m", "armelf_linux_eabi"),
+ new Abi("mips", "mipsel-unknown-linux", BuildToolInfo.PathId.LD_MIPS, "-EL"),
+ new Abi("x86", "i686-unknown-linux", BuildToolInfo.PathId.LD_X86, "-m", "elf_i386") };
+
+ public static final String RS_DEPS = "rsDeps";
+
+ @NonNull
+ private final List<File> mSourceFolders;
+
+ @NonNull
+ private final List<File> mImportFolders;
+
+ @NonNull
+ private final File mSourceOutputDir;
+
+ @NonNull
+ private final File mResOutputDir;
+
+ @NonNull
+ private final File mObjOutputDir;
+
+ @NonNull
+ private final File mLibOutputDir;
+
+ @NonNull
+ private final BuildToolInfo mBuildToolInfo;
+
+ private final int mTargetApi;
+
+ private final boolean mDebugBuild;
+
+ private final int mOptimLevel;
+
+ private final boolean mNdkMode;
+
+ private final boolean mSupportMode;
+ private final Set<String> mAbiFilters;
+
+ private final File mRsLib;
+ private final File mLibClCore;
+
+ public RenderScriptProcessor(
+ @NonNull List<File> sourceFolders,
+ @NonNull List<File> importFolders,
+ @NonNull File sourceOutputDir,
+ @NonNull File resOutputDir,
+ @NonNull File objOutputDir,
+ @NonNull File libOutputDir,
+ @NonNull BuildToolInfo buildToolInfo,
+ int targetApi,
+ boolean debugBuild,
+ int optimLevel,
+ boolean ndkMode,
+ boolean supportMode,
+ @Nullable Set<String> abiFilters) {
+ mSourceFolders = sourceFolders;
+ mImportFolders = importFolders;
+ mSourceOutputDir = sourceOutputDir;
+ mResOutputDir = resOutputDir;
+ mObjOutputDir = objOutputDir;
+ mLibOutputDir = libOutputDir;
+ mBuildToolInfo = buildToolInfo;
+ mTargetApi = targetApi;
+ mDebugBuild = debugBuild;
+ mOptimLevel = optimLevel;
+ mNdkMode = ndkMode;
+ mSupportMode = supportMode;
+ mAbiFilters = abiFilters;
+
+ if (supportMode) {
+ File rs = new File(mBuildToolInfo.getLocation(), "renderscript");
+ mRsLib = new File(rs, "lib");
+ mLibClCore = new File(mRsLib, "libclcore.bc");
+ } else {
+ mLibClCore = null;
+ mRsLib = null;
+ }
+ }
+
+ public static File getSupportJar(String buildToolsFolder) {
+ return new File(buildToolsFolder, "renderscript/lib/" + FN_RENDERSCRIPT_V8_JAR);
+ }
+
+ public static File getSupportNativeLibFolder(String buildToolsFolder) {
+ File rs = new File(buildToolsFolder, "renderscript");
+ File lib = new File(rs, "lib");
+ return new File(lib, "packaged");
+ }
+
+ public void build(@NonNull CommandLineRunner launcher)
+ throws IOException, InterruptedException, LoggedErrorException {
+
+ // gather the files to compile
+ FileGatherer fileGatherer = new FileGatherer();
+ SourceSearcher searcher = new SourceSearcher(mSourceFolders, "rs", "fs");
+ searcher.setUseExecutor(false);
+ searcher.search(fileGatherer);
+
+ List<File> renderscriptFiles = fileGatherer.getFiles();
+
+ if (renderscriptFiles.isEmpty()) {
+ return;
+ }
+
+ // get the env var
+ Map<String, String> env = Maps.newHashMap();
+ if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN) {
+ env.put("DYLD_LIBRARY_PATH", mBuildToolInfo.getLocation().getAbsolutePath());
+ } else if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_LINUX) {
+ env.put("LD_LIBRARY_PATH", mBuildToolInfo.getLocation().getAbsolutePath());
+ }
+
+ doMainCompilation(renderscriptFiles, launcher, env);
+
+ if (mSupportMode) {
+ createSupportFiles(launcher, env);
+ }
+ }
+
+ private void doMainCompilation(
+ @NonNull List<File> inputFiles,
+ @NonNull CommandLineRunner launcher,
+ @NonNull Map<String, String> env)
+ throws IOException, InterruptedException, LoggedErrorException {
+
+ String renderscript = mBuildToolInfo.getPath(BuildToolInfo.PathId.LLVM_RS_CC);
+ if (renderscript == null || !new File(renderscript).isFile()) {
+ throw new IllegalStateException(BuildToolInfo.PathId.LLVM_RS_CC + " is missing");
+ }
+
+ String rsPath = mBuildToolInfo.getPath(BuildToolInfo.PathId.ANDROID_RS);
+ String rsClangPath = mBuildToolInfo.getPath(BuildToolInfo.PathId.ANDROID_RS_CLANG);
+
+ // the renderscript compiler doesn't expect the top res folder,
+ // but the raw folder directly.
+ File rawFolder = new File(mResOutputDir, SdkConstants.FD_RES_RAW);
+
+ // compile all the files in a single pass
+ ArrayList<String> command = Lists.newArrayListWithExpectedSize(26);
+
+ command.add(renderscript);
+
+ // Due to a device side bug, let's not enable this at this time.
+// if (mDebugBuild) {
+// command.add("-g");
+// }
+
+ command.add("-O");
+ command.add(Integer.toString(mOptimLevel));
+
+ // add all import paths
+ command.add("-I");
+ command.add(rsPath);
+ command.add("-I");
+ command.add(rsClangPath);
+
+ for (File importPath : mImportFolders) {
+ if (importPath.isDirectory()) {
+ command.add("-I");
+ command.add(importPath.getAbsolutePath());
+ }
+ }
+
+ if (mSupportMode) {
+ command.add("-rs-package-name=android.support.v8.renderscript");
+ }
+
+ // source output
+ command.add("-p");
+ command.add(mSourceOutputDir.getAbsolutePath());
+
+ if (mNdkMode) {
+ command.add("-reflect-c++");
+ }
+
+ // res output
+ command.add("-o");
+ command.add(rawFolder.getAbsolutePath());
+
+ command.add("-target-api");
+ int targetApi = mTargetApi < 11 ? 11 : mTargetApi;
+ targetApi = (mSupportMode && targetApi < 18) ? 18 : targetApi;
+ command.add(Integer.toString(targetApi));
+
+ // input files
+ for (File sourceFile : inputFiles) {
+ command.add(sourceFile.getAbsolutePath());
+ }
+
+ launcher.runCmdLine(command, env);
+ }
+
+ private void createSupportFiles(@NonNull final CommandLineRunner launcher,
+ @NonNull final Map<String, String> env)
+ throws IOException, InterruptedException, LoggedErrorException {
+ // get the generated BC files.
+ File rawFolder = new File(mResOutputDir, SdkConstants.FD_RES_RAW);
+
+ SourceSearcher searcher = new SourceSearcher(
+ Collections.singletonList(rawFolder), EXT_BC);
+ FileGatherer fileGatherer = new FileGatherer();
+ searcher.search(fileGatherer);
+
+ WaitableExecutor<Void> mExecutor = new WaitableExecutor<Void>();
+
+ for (final File bcFile : fileGatherer.getFiles()) {
+ String name = bcFile.getName();
+ final String objName = name.replaceAll("\\.bc", ".o");
+ final String soName = "librs." + name.replaceAll("\\.bc", ".so");
+
+ for (final Abi abi : ABIS) {
+ if (mAbiFilters != null && !mAbiFilters.contains(abi.mDevice)) {
+ continue;
+ }
+
+ // make sure the dest folders exist
+ final File objAbiFolder = new File(mObjOutputDir, abi.mDevice);
+ if (!objAbiFolder.isDirectory() && !objAbiFolder.mkdirs()) {
+ throw new IOException("Unable to create dir " + objAbiFolder.getAbsolutePath());
+ }
+
+ final File libAbiFolder = new File(mLibOutputDir, abi.mDevice);
+ if (!libAbiFolder.isDirectory() && !libAbiFolder.mkdirs()) {
+ throw new IOException("Unable to create dir " + libAbiFolder.getAbsolutePath());
+ }
+
+ mExecutor.execute(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ File objFile = createSupportObjFile(bcFile, abi, objName, objAbiFolder,
+ launcher, env);
+ createSupportLibFile(objFile, abi, soName, libAbiFolder, launcher, env);
+ return null;
+ }
+ });
+ }
+ }
+
+ mExecutor.waitForTasksWithQuickFail(true /*cancelRemaining*/);
+ }
+
+ private File createSupportObjFile(
+ @NonNull File bcFile,
+ @NonNull Abi abi,
+ @NonNull String objName,
+ @NonNull File objAbiFolder,
+ @NonNull CommandLineRunner launcher,
+ @NonNull Map<String, String> env)
+ throws IOException, InterruptedException, LoggedErrorException {
+
+ List<String> args = Lists.newArrayListWithExpectedSize(10);
+
+ args.add(mBuildToolInfo.getPath(BuildToolInfo.PathId.BCC_COMPAT));
+
+ args.add("-O" + Integer.toString(mOptimLevel));
+
+ File outFile = new File(objAbiFolder, objName);
+ args.add("-o");
+ args.add(outFile.getAbsolutePath());
+
+ args.add("-fPIC");
+ args.add("-shared");
+
+ args.add("-rt-path");
+ args.add(mLibClCore.getAbsolutePath());
+
+ args.add("-mtriple");
+ args.add(abi.mToolchain);
+
+ args.add(bcFile.getAbsolutePath());
+
+ launcher.runCmdLine(args, env);
+
+ return outFile;
+ }
+
+ private void createSupportLibFile(
+ @NonNull File objFile,
+ @NonNull Abi abi,
+ @NonNull String soName,
+ @NonNull File libAbiFolder,
+ @NonNull CommandLineRunner launcher,
+ @NonNull Map<String, String> env)
+ throws IOException, InterruptedException, LoggedErrorException {
+
+ File intermediatesFolder = new File(mRsLib, "intermediates");
+ File intermediatesAbiFolder = new File(intermediatesFolder, abi.mDevice);
+ File packagedFolder = new File(mRsLib, "packaged");
+ File packagedAbiFolder = new File(packagedFolder, abi.mDevice);
+
+ List<String> args = Lists.newArrayListWithExpectedSize(26);
+
+ args.add(mBuildToolInfo.getPath(abi.mLinker));
+
+ args.add("--eh-frame-hdr");
+ Collections.addAll(args, abi.mLinkerArgs);
+ args.add("-shared");
+ args.add("-Bsymbolic");
+ args.add("-z");
+ args.add("noexecstack");
+ args.add("-z");
+ args.add("relro");
+ args.add("-z");
+ args.add("now");
+
+ File outFile = new File(libAbiFolder, soName);
+ args.add("-o");
+ args.add(outFile.getAbsolutePath());
+
+ args.add("-L" + intermediatesAbiFolder.getAbsolutePath());
+ args.add("-L" + packagedAbiFolder.getAbsolutePath());
+
+ args.add("-soname");
+ args.add(soName);
+
+ args.add(objFile.getAbsolutePath());
+ args.add(new File(intermediatesAbiFolder, "libcompiler_rt.a").getAbsolutePath());
+
+ args.add("-lRSSupport");
+ args.add("-lm");
+ args.add("-lc");
+
+ launcher.runCmdLine(args, env);
+ }
+}
diff --git a/builder/src/main/java/com/android/builder/internal/incremental/ChangeManager.java b/builder/src/main/java/com/android/builder/internal/incremental/ChangeManager.java
deleted file mode 100644
index 62395fe..0000000
--- a/builder/src/main/java/com/android/builder/internal/incremental/ChangeManager.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.builder.internal.incremental;
-
-import com.android.annotations.NonNull;
-import com.android.ide.common.res2.FileStatus;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Class handling changes in input and output.
- *
- * The class stores the state of inputs/outputs after a task is run, and on subsequent runs can
- * compare this to the current state of detect exact file changes in the inputs or outputs.
- *
- * Gradle already does this to figure out if a task needs to be run, but does not offer this
- * information to the task.
- * This should become available in the Gradle plugin in the future, but in the meantime this
- * provides the same information, allowing us to build truly incremental tasks.
- *
- */
-public class ChangeManager {
-
- private static final String FN_INPUTS_DATA = "inputs.data";
- private static final String FN_OUTPUTS_DATA = "outputs.data";
-
- private FileManager mInputs = new FileManager();
- private FileManager mOutputs = new FileManager();
-
- public ChangeManager() {
- }
-
- /**
- * Loads the known state.
- *
- * @param incrementalFolder the folder in which to store the incremental data
- * @return false if the loading failed.
- */
- public boolean load(File incrementalFolder) {
- File inputs = new File(incrementalFolder, FN_INPUTS_DATA);
- File outputs = new File(incrementalFolder, FN_OUTPUTS_DATA);
- return inputs.exists() && outputs.exists() &&
- mInputs.load(inputs) && mOutputs.load(outputs);
- }
-
- /**
- * Writes the incremental data to a given folder.
- * @param incrementalFolder the name of the folder to write to.
- *
- * @throws IOException
- */
- public void write(File incrementalFolder) throws IOException {
- if (!incrementalFolder.isDirectory() && !incrementalFolder.mkdirs()) {
- throw new IOException("Failed to create directory " + incrementalFolder);
- }
-
- mInputs.write(new File(incrementalFolder, FN_INPUTS_DATA));
- mOutputs.write(new File(incrementalFolder, FN_OUTPUTS_DATA));
- }
-
- /**
- * Delete the incremental data from the given folder.
- * @param incrementalFolder the folder to delete the incremental data from.
- */
- public static void delete(File incrementalFolder) {
- File file = new File(incrementalFolder, FN_INPUTS_DATA);
- //noinspection ResultOfMethodCallIgnored
- file.delete();
- file = new File(incrementalFolder, FN_OUTPUTS_DATA);
- //noinspection ResultOfMethodCallIgnored
- file.delete();
- }
-
- /**
- * Add an input file or folder.
- * @param file the file.
- */
- public void addInput(File file) {
- mInputs.addFile(file);
- }
-
- /**
- * Adds a new output file or folder
- * @param file the file.
- */
- public void addOutput(File file) {
- mOutputs.addFile(file);
- }
-
- /**
- * Get the list of changed inputs. Empty list means no input changes.
- *
- * @return a map of (File, FileStatus) for all changed input.
- */
- @NonNull
- public Map<File, FileStatus> getChangedInputs() {
- return mInputs.getChangedFiles();
- }
-
- /**
- * Returns a list of changed output. Empty list means no output changes.
- *
- * @return a map of (file, status) for all changed output files.
- */
- @NonNull
- public Map<File, FileStatus> getChangedOutputs() {
- return mOutputs.getChangedFiles();
- }
-
- /**
- * Update the outputs before writing the file states
- */
- public void updateOutputs(Collection<File> outputs) {
- mOutputs.update(outputs);
- }
-}
diff --git a/builder/src/main/java/com/android/builder/internal/incremental/DependencyData.java b/builder/src/main/java/com/android/builder/internal/incremental/DependencyData.java
index 22035fd..575e50c 100644
--- a/builder/src/main/java/com/android/builder/internal/incremental/DependencyData.java
+++ b/builder/src/main/java/com/android/builder/internal/incremental/DependencyData.java
@@ -17,6 +17,7 @@
package com.android.builder.internal.incremental;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
@@ -74,6 +75,7 @@
*
* @param dependencyFile the dependency file
*/
+ @Nullable
public static DependencyData parseDependencyFile(@NonNull File dependencyFile)
throws IOException {
// first check if the dependency file is here.
@@ -91,6 +93,7 @@
}
@VisibleForTesting
+ @Nullable
static DependencyData processDependencyData(@NonNull List<String> content) {
// The format is technically:
// output1 output2 [...]: dep1 dep2 [...]
@@ -142,6 +145,10 @@
parseMode = nextMode;
}
+ if (data.getMainFile() == null) {
+ return null;
+ }
+
return data;
}
diff --git a/builder/src/main/java/com/android/builder/internal/incremental/FileEntity.java b/builder/src/main/java/com/android/builder/internal/incremental/FileEntity.java
deleted file mode 100644
index a981d8e..0000000
--- a/builder/src/main/java/com/android/builder/internal/incremental/FileEntity.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.builder.internal.incremental;
-
-import com.google.common.hash.HashCode;
-import com.google.common.hash.Hashing;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.Files;
-
-import java.io.File;
-
-/**
- * A {@link File} and its associated data needed to figure out if a file changed or not.
- */
-class FileEntity {
-
- private static final byte[] sBuffer = new byte[4096];
-
- private final File mFile;
- private final long mLastModified;
- private long mLength;
- private String mSha1;
-
- /**
- * Exception to indicate a failure to check a jar file's content.
- */
- private static final class Sha1Exception extends Exception {
- private static final long serialVersionUID = 1L;
- private final File file;
-
- public Sha1Exception(File jarFile, Throwable cause) {
- super(cause);
- file = jarFile;
- }
-
- public File getJarFile() {
- return file;
- }
- }
-
- /**
- * Creates an entity from cached data.
- *
- * @param file the file
- * @param lastModified when it was last modified
- * @param length its length
- * @param sha1 its sha1
- */
- FileEntity(File file, long lastModified, long length, String sha1) {
- mFile = file;
- mLastModified = lastModified;
- mLength = length;
- mSha1 = sha1;
- }
-
- /**
- * Creates an entity from a {@link File}.
- *
- * The sha1 is not computed yet, it'll be done on demand when {@link #getSha1()} is called.
- *
- * @param file the file.
- */
- FileEntity(File file) {
- mFile = file;
- mLastModified = file.lastModified();
- mLength = file.length();
- }
-
- /**
- * Returns the file's last modified info.
- * @return the file's last modified info.
- */
- long getLastModified() {
- return mLastModified;
- }
-
- /**
- * Return the file length.
- * @return the file length.
- */
- long getLength() {
- return mLength;
- }
-
- /**
- * Returns the file this entity represents.
- * @return the file.
- */
- File getFile() {
- return mFile;
- }
-
- /**
- * Returns the file's sha1, computing it if necessary.
- *
- * @return the fha1 or null if it couldn't be computed.
- */
- String getSha1() {
- try {
- return computeAndReturnSha1();
- } catch (Sha1Exception e) {
- return null;
- }
- }
-
- /**
- * Checks whether the {@link File#lastModified()} matches the cached value. If not, length
- * is updated and the sha1 is reset (but not recomputed, this is done on demand).
- *
- * @return return whether the file was changed.
- */
- private boolean checkValidity() {
- if (mLastModified != mFile.lastModified()) {
- mLength = mFile.length();
- mSha1 = null;
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns whether the two entity are different files.
- *
- * This will compute the files' sha1 if they are not yet computed.
- *
- * @param fileEntity the file to compare to.
- * @return true if the files are the same, false otherwise.
- */
- public boolean isDifferentThan(FileEntity fileEntity) {
- assert fileEntity.mFile.equals(mFile);
-
- // same date, same files.
- if (mLastModified == fileEntity.mLastModified) {
- return false;
- }
-
- try {
- // different date doesn't necessarily mean different file.
- // start with size, less computing intensive than sha1.
- return mLength != fileEntity.mLength ||
- !computeAndReturnSha1().equals(fileEntity.computeAndReturnSha1());
- } catch (Sha1Exception e) {
- // if we can't compute the sha1, we consider the files different.
- return true;
- }
- }
-
- /**
- * Returns the file's sha1, computing it if necessary.
- *
- * @return the sha1
- * @throws Sha1Exception
- */
- private String computeAndReturnSha1() throws Sha1Exception {
- if (mSha1 == null) {
- mSha1 = getSha1(mFile);
- }
- return mSha1;
- }
-
- /**
- * Computes the sha1 of a file and returns it.
- *
- * @param f the file to compute the sha1 for.
- * @return the sha1 value
- * @throws Sha1Exception if the sha1 value cannot be computed.
- */
- static String getSha1(File f) throws Sha1Exception {
- synchronized (sBuffer) {
-
- try {
- HashCode value = ByteStreams.hash(Files.newInputStreamSupplier(f), Hashing.sha1());
- return value.toString();
- } catch (Exception e) {
- throw new Sha1Exception(f, e);
- }
- }
- }
-
- @Override
- public String toString() {
- return "FileEntity{" +
- "mFile=" + mFile +
- ", mLastModified=" + mLastModified +
- ", mLength=" + mLength +
- ", mSha1='" + mSha1 + '\'' +
- '}';
- }
-}
diff --git a/builder/src/main/java/com/android/builder/internal/incremental/FileManager.java b/builder/src/main/java/com/android/builder/internal/incremental/FileManager.java
deleted file mode 100644
index 6408c26..0000000
--- a/builder/src/main/java/com/android/builder/internal/incremental/FileManager.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.builder.internal.incremental;
-
-import com.android.annotations.NonNull;
-import com.android.ide.common.res2.FileStatus;
-import com.google.common.base.Charsets;
-import com.google.common.collect.Maps;
-import com.google.common.io.Closeables;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Class handling changes in a set of files.
- *
- * The class can store the state of the files, and later reload it and compare it to the
- * previous known state.
- *
- */
-class FileManager {
-
- private static final Pattern READ_PATTERN = Pattern.compile(
- "^(\\d+)\\s+(\\d+)\\s+([0-9a-f]+)\\s+(.+)$");
-
- private Map<File, FileEntity> mLoadedFiles = Maps.newHashMap();
- private Map<File, FileEntity> mProcessedFiles = Maps.newHashMap();
- private Map<File, FileStatus> mResults = Maps.newHashMap();
- private Map<File, FileStatus> mReturnedMap = null;
-
- public FileManager() {
- }
-
- /**
- * Loads the known state.
- *
- * @param stateFile the file to load the state from.
- * @return false if the loading failed.
- *
- * @see #write(java.io.File)
- */
- public boolean load(File stateFile) {
- if (!stateFile.exists()) {
- return false;
- }
-
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(
- new FileInputStream(stateFile), Charsets.UTF_8));
-
- String line = null;
- while ((line = reader.readLine()) != null) {
- // skip comments
- if (line.charAt(0) == '#') {
- continue;
- }
-
- // get the data with a regexp
- Matcher m = READ_PATTERN.matcher(line);
- if (m.matches()) {
- String path = m.group(4);
- File f = new File(path);
-
- FileEntity entity = new FileEntity(
- f,
- Long.parseLong(m.group(1)),
- Long.parseLong(m.group(2)),
- m.group(3));
-
- mLoadedFiles.put(f, entity);
- }
- }
-
- return true;
- } catch (FileNotFoundException ignored) {
- // won't happen, we check up front.
- } catch (UnsupportedEncodingException ignored) {
- // shouldn't happen, but if it does, we just won't have a cache.
- } catch (IOException ignored) {
- // shouldn't happen, but if it does, we just won't have a cache.
- } finally {
- Closeables.closeQuietly(reader);
- }
-
- return false;
- }
-
- /**
- * Writes the state to a file
- * @param stateFile the file to write the state to.
- *
- * @throws IOException
- *
- * @see #load(java.io.File)
- */
- public void write(File stateFile) throws IOException {
- OutputStreamWriter writer = null;
- try {
- // first make sure the folders exist!
- File parentFolder = stateFile.getParentFile();
- if (!parentFolder.isDirectory() && !parentFolder.mkdirs()) {
- throw new IOException("Failed to create directory " + parentFolder);
- }
-
- // then write the file.
- writer = new OutputStreamWriter(new FileOutputStream(stateFile), Charsets.UTF_8);
-
- writer.write("# incremental data. DO NOT EDIT.\n");
- writer.write("# format is <lastModified> <length> <SHA-1> <path>\n");
- writer.write("# Encoding is UTF-8\n");
-
- for (FileEntity entity : mProcessedFiles.values()) {
- String sha1 = entity.getSha1();
- if (sha1 == null) {
- sha1 = "0123456789012345678901234567890123456789"; // TODO: find a better way to detect missing sha1
- }
-
- writer.write(String.format("%d %d %s %s\n",
- entity.getLastModified(),
- entity.getLength(),
- sha1,
- entity.getFile().getAbsolutePath()));
- }
- } finally {
- Closeables.closeQuietly(writer);
- }
- }
-
- /**
- * Add an input file or folder.
- * @param file the file.
- */
- public void addFile(File file) {
- processFile(file);
- }
-
- /**
- * Get the list of changed inputs. Empty list means no input changes.
- *
- * @return a map of (File, FileStatus) for all changed input.
- */
- @NonNull
- public Map<File, FileStatus> getChangedFiles() {
- if (mReturnedMap == null) {
- // create a map with the content of the result map.
- mReturnedMap = Maps.newHashMap(mResults);
-
- // at this point, all the files that needed processing have been processed,
- // but there may be removed files remaining in the loaded file map.
- for (File f : mLoadedFiles.keySet()) {
- mReturnedMap.put(f, FileStatus.REMOVED);
- }
-
- // wrap this
- mReturnedMap = Collections.unmodifiableMap(mReturnedMap);
- }
-
- return mReturnedMap;
- }
-
- private void processFile(File file) {
- if (file.isFile()) {
- if (file.getName().startsWith(".")) {
- return;
- }
-
- // get the FileEntity for the new(?) version.
- FileEntity newFileEntity = new FileEntity(file);
-
- // see if it existed before.
- FileEntity fileEntity = mLoadedFiles.get(file);
-
- if (fileEntity == null) {
- // new file!
- mResults.put(file, FileStatus.NEW);
-
- // add it to the list of processed files
- mProcessedFiles.put(file, newFileEntity);
- } else {
- // remove it from the loaded files.
- mLoadedFiles.remove(file);
-
- if (newFileEntity.isDifferentThan(fileEntity)) {
- mResults.put(file, FileStatus.CHANGED);
-
- // put the newFileEntity in the processed files.
- mProcessedFiles.put(file, newFileEntity);
- } else {
- // just move the original entity so avoid recomputing the sha1.
- // FileEntity.isDifferentThan doesn't necessarily compute it.
- mProcessedFiles.put(file, fileEntity);
- }
- }
- } else if (file.isDirectory()) {
- File[] files = file.listFiles();
- if (files != null && files.length > 0) {
- for (File f : files) {
- processFile(f);
- }
- }
- }
- }
-
- /**
- * Updates the existing files with the given files/folders.
- * @param files the new folders/files to process.
- */
- void update(Collection<File> files) {
- mLoadedFiles.clear();
- mLoadedFiles.putAll(mProcessedFiles);
- mResults.clear();
- mProcessedFiles.clear();
- for (File f : files) {
- processFile(f);
- }
- }
-}
diff --git a/builder/src/main/java/com/android/builder/internal/packaging/Packager.java b/builder/src/main/java/com/android/builder/internal/packaging/Packager.java
index 445d607..8c370d0 100644
--- a/builder/src/main/java/com/android/builder/internal/packaging/Packager.java
+++ b/builder/src/main/java/com/android/builder/internal/packaging/Packager.java
@@ -39,6 +39,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.regex.Pattern;
@@ -402,7 +403,7 @@
*
* This may or may not copy gdbserver into the apk based on whether the debug mode is set.
*
- * @param jniLibLocation the root folder containing the abi folders which contain the .so
+ * @param nativeFolder the root folder containing the abi folders which contain the .so
*
* @throws PackagerException if an error occurred
* @throws SealedPackageException if the APK is already sealed.
@@ -411,14 +412,12 @@
*
* @see #setJniDebugMode(boolean)
*/
- public void addNativeLibraries(String jniLibLocation)
+ public void addNativeLibraries(@NonNull File nativeFolder, @Nullable Set<String> abiFilters)
throws PackagerException, SealedPackageException, DuplicateFileException {
if (mIsSealed) {
throw new SealedPackageException("APK is already sealed");
}
- File nativeFolder = new File(jniLibLocation);
-
if (!nativeFolder.isDirectory()) {
// not a directory? check if it's a file or doesn't exist
if (nativeFolder.exists()) {
@@ -434,6 +433,10 @@
if (abiList != null) {
for (File abi : abiList) {
+ if (abiFilters != null && !abiFilters.contains(abi.getName())) {
+ continue;
+ }
+
if (abi.isDirectory()) { // ignore files
File[] libs = abi.listFiles();
@@ -441,14 +444,16 @@
for (File lib : libs) {
// only consider files that are .so or, if in debug mode, that
// are gdbserver executables
+ String libName = lib.getName();
if (lib.isFile() &&
(PATTERN_NATIVELIB_EXT.matcher(lib.getName()).matches() ||
- (mJniDebugMode &&
- SdkConstants.FN_GDBSERVER.equals(
- lib.getName())))) {
+ (mJniDebugMode &&
+ (SdkConstants.FN_GDBSERVER.equals(libName) ||
+ SdkConstants.FN_GDB_SETUP.equals(libName))))) {
+
String path =
SdkConstants.FD_APK_NATIVE_LIBS + "/" +
- abi.getName() + "/" + lib.getName();
+ abi.getName() + "/" + libName;
try {
doAddFile(lib, path);
diff --git a/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java b/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java
index 8a1aa64..7e6ae77 100644
--- a/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java
+++ b/builder/src/main/java/com/android/builder/testing/ConnectedDevice.java
@@ -25,9 +25,11 @@
import com.android.ddmlib.ShellCommandUnresponsiveException;
import com.android.ddmlib.TimeoutException;
import com.android.utils.ILogger;
+import com.google.common.collect.Lists;
import java.io.File;
import java.io.IOException;
+import java.util.List;
import java.util.concurrent.TimeUnit;
/**
@@ -115,8 +117,19 @@
@NonNull
@Override
- public String getAbi() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ public List<String> getAbis() {
+ List<String> abis = Lists.newArrayListWithExpectedSize(2);
+ String abi = iDevice.getProperty(IDevice.PROP_DEVICE_CPU_ABI);
+ if (abi != null) {
+ abis.add(abi);
+ }
+
+ abi = iDevice.getProperty(IDevice.PROP_DEVICE_CPU_ABI2);
+ if (abi != null) {
+ abis.add(abi);
+ }
+
+ return abis;
}
@Override
diff --git a/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java b/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java
index 85114d4..237d871 100644
--- a/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java
+++ b/builder/src/main/java/com/android/builder/testing/SimpleTestRunner.java
@@ -26,6 +26,7 @@
import java.io.File;
import java.util.List;
+import java.util.Set;
/**
* Basic {@link TestRunner} running tests on all devices.
@@ -47,21 +48,11 @@
WaitableExecutor<Boolean> executor = new WaitableExecutor<Boolean>(maxThreads);
- int minSdkVersion = testData.getMinSdkVersion();
for (DeviceConnector device : deviceList) {
- int deviceApiLevel = device.getApiLevel();
- if (minSdkVersion <= deviceApiLevel) {
+ if (filterOutDevice(device, testData, logger, projectName, variantName)) {
executor.execute(new SimpleTestCallable(device, projectName, variantName,
testApk, testedApk, testData,
resultsDir, timeout, logger));
- } else {
- if (deviceApiLevel == 0) {
- logger.info("Skipping device '%s' for '%s:%s': Unknown API Level",
- device.getName(), projectName, variantName);
- } else {
- logger.info("Skipping device '%s' for '%s:%s'",
- device.getName(), projectName, variantName);
- }
}
}
@@ -82,4 +73,45 @@
return success;
}
+
+ private boolean filterOutDevice(@NonNull DeviceConnector device, @NonNull TestData testData,
+ @NonNull ILogger logger,
+ @NonNull String projectName, @NonNull String variantName) {
+ int deviceApiLevel = device.getApiLevel();
+ if (deviceApiLevel == 0) {
+ logger.info("Skipping device '%s' for '%s:%s': Unknown API Level",
+ device.getName(), projectName, variantName);
+ return false;
+ }
+
+ if (testData.getMinSdkVersion() > deviceApiLevel) {
+ logger.info("Skipping device '%s' for '%s:%s'",
+ device.getName(), projectName, variantName);
+
+ return false;
+ }
+
+ Set<String> appAbis = testData.getSupportedAbis();
+ if (appAbis != null) {
+ List<String> deviceAbis = device.getAbis();
+ if (deviceAbis == null || deviceAbis.isEmpty()) {
+ logger.info("Skipping device '%s' for '%s:%s': Unknown ABI",
+ device.getName(), projectName, variantName);
+ return false;
+ }
+
+ boolean compatibleAbi = false;
+ for (String deviceAbi : deviceAbis) {
+ if (appAbis.contains(deviceAbi)) {
+ compatibleAbi = true;
+ }
+ }
+
+ if (!compatibleAbi) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/builder/src/main/java/com/android/builder/testing/TestData.java b/builder/src/main/java/com/android/builder/testing/TestData.java
index 2495659..a736026 100644
--- a/builder/src/main/java/com/android/builder/testing/TestData.java
+++ b/builder/src/main/java/com/android/builder/testing/TestData.java
@@ -44,8 +44,18 @@
@NonNull
String getInstrumentationRunner();
+ @NonNull
+ Boolean getHandleProfiling();
+
+ @NonNull
+ Boolean getFunctionalTest();
+
int getMinSdkVersion();
+ /**
+ * List of supported ABIs. Null means all.
+ * @return a list of abi or null for all
+ */
@Nullable
Set<String> getSupportedAbis();
}
diff --git a/builder/src/main/resources/com/android/builder/internal/AndroidManifest.template b/builder/src/main/resources/com/android/builder/internal/AndroidManifest.template
index 257e79d..ed50233 100644
--- a/builder/src/main/resources/com/android/builder/internal/AndroidManifest.template
+++ b/builder/src/main/resources/com/android/builder/internal/AndroidManifest.template
@@ -10,5 +10,7 @@
<instrumentation android:name="#TESTRUNNER#"
android:targetPackage="#TESTEDPACKAGE#"
+ android:handleProfiling="#HANDLEPROFILING#"
+ android:functionalTest="#FUNCTIONALTEST#"
android:label="Tests for #TESTEDPACKAGE#"/>
</manifest>
diff --git a/builder/src/main/resources/com/android/builder/internal/BuildConfig.template b/builder/src/main/resources/com/android/builder/internal/BuildConfig.template
deleted file mode 100644
index 618c013..0000000
--- a/builder/src/main/resources/com/android/builder/internal/BuildConfig.template
+++ /dev/null
@@ -1,7 +0,0 @@
-/** Automatically generated file. DO NOT MODIFY */
-package #PACKAGE#;
-
-public final class BuildConfig {
- public final static boolean DEBUG = #DEBUG#;
-
-#ADDITIONAL_LINES#}
\ No newline at end of file
diff --git a/builder/src/test/java/com/android/builder/DefaultProductFlavorTest.java b/builder/src/test/java/com/android/builder/DefaultProductFlavorTest.java
index 1e09828..f618085 100644
--- a/builder/src/test/java/com/android/builder/DefaultProductFlavorTest.java
+++ b/builder/src/test/java/com/android/builder/DefaultProductFlavorTest.java
@@ -39,6 +39,8 @@
mCustom.setPackageName("com.forty.two");
mCustom.setTestPackageName("com.forty.two.test");
mCustom.setTestInstrumentationRunner("com.forty.two.test.Runner");
+ mCustom.setTestHandleProfiling(true);
+ mCustom.setTestFunctionalTest(true);
}
public void testMergeOnDefault() {
@@ -52,6 +54,8 @@
assertEquals("com.forty.two", flavor.getPackageName());
assertEquals("com.forty.two.test", flavor.getTestPackageName());
assertEquals("com.forty.two.test.Runner", flavor.getTestInstrumentationRunner());
+ assertEquals(Boolean.TRUE, flavor.getTestHandleProfiling());
+ assertEquals(Boolean.TRUE, flavor.getTestFunctionalTest());
}
public void testMergeOnCustom() {
@@ -65,6 +69,8 @@
assertEquals("com.forty.two", flavor.getPackageName());
assertEquals("com.forty.two.test", flavor.getTestPackageName());
assertEquals("com.forty.two.test.Runner", flavor.getTestInstrumentationRunner());
+ assertEquals(Boolean.TRUE, flavor.getTestHandleProfiling());
+ assertEquals(Boolean.TRUE, flavor.getTestFunctionalTest());
}
public void testMergeDefaultOnDefault() {
@@ -78,5 +84,7 @@
assertNull(flavor.getPackageName());
assertNull(flavor.getTestPackageName());
assertNull(flavor.getTestInstrumentationRunner());
+ assertNull(flavor.getTestHandleProfiling());
+ assertNull(flavor.getTestFunctionalTest());
}
}
diff --git a/builder/src/test/java/com/android/builder/VariantConfigurationTest.java b/builder/src/test/java/com/android/builder/VariantConfigurationTest.java
index 6d244ac..e1ffc3d 100644
--- a/builder/src/test/java/com/android/builder/VariantConfigurationTest.java
+++ b/builder/src/test/java/com/android/builder/VariantConfigurationTest.java
@@ -57,6 +57,11 @@
public String getVersionName(@NonNull File manifestFile) {
return "1.0";
}
+
+ @Override
+ public int getVersionCode(@NonNull File manifestFile) {
+ return 1;
+ }
}
@Override
@@ -128,7 +133,7 @@
VariantConfiguration variant = new VariantConfiguration(
mDefaultConfig, new MockSourceProvider("main"),
mBuildType, new MockSourceProvider("debug"),
- VariantConfiguration.Type.DEFAULT, "test") {
+ VariantConfiguration.Type.DEFAULT) {
// don't do validation.
@Override
protected void validate() {
@@ -136,7 +141,7 @@
}
};
- variant.addProductFlavor(mFlavorConfig, new MockSourceProvider("custom"));
+ variant.addProductFlavor(mFlavorConfig, new MockSourceProvider("custom"), "");
return variant;
}
@@ -145,7 +150,7 @@
VariantConfiguration variant = new VariantConfiguration(
mDefaultConfig, new MockSourceProvider("main"),
mBuildType, new MockSourceProvider("debug"),
- VariantConfiguration.Type.DEFAULT, "test") {
+ VariantConfiguration.Type.DEFAULT) {
@Override
public String getPackageFromManifest() {
return packageName;
@@ -157,7 +162,7 @@
}
};
- variant.addProductFlavor(mFlavorConfig, new MockSourceProvider("custom"));
+ variant.addProductFlavor(mFlavorConfig, new MockSourceProvider("custom"), "");
return variant;
}
@@ -165,7 +170,7 @@
VariantConfiguration variant = new VariantConfiguration(
mDefaultConfig, new MockSourceProvider("main"),
mBuildType, new MockSourceProvider("debug"),
- VariantConfiguration.Type.DEFAULT, "test") {
+ VariantConfiguration.Type.DEFAULT) {
@Override
public String getVersionNameFromManifest() {
return versionName;
@@ -177,7 +182,7 @@
}
};
- variant.addProductFlavor(mFlavorConfig, new MockSourceProvider("custom"));
+ variant.addProductFlavor(mFlavorConfig, new MockSourceProvider("custom"), "");
return variant;
}
}
diff --git a/builder/src/test/java/com/android/builder/compiling/BuildConfigGeneratorTest.java b/builder/src/test/java/com/android/builder/compiling/BuildConfigGeneratorTest.java
new file mode 100644
index 0000000..0bb2200
--- /dev/null
+++ b/builder/src/test/java/com/android/builder/compiling/BuildConfigGeneratorTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.builder.compiling;
+
+import com.android.builder.AndroidBuilder;
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.List;
+
+@SuppressWarnings("ResultOfMethodCallIgnored")
+public class BuildConfigGeneratorTest extends TestCase {
+ public void testFalse() throws Exception {
+ File tempDir = Files.createTempDir();
+ BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
+ "my.app.pkg");
+
+ generator.addField("boolean", "DEBUG", "false").generate();
+
+ File file = generator.getBuildConfigFile();
+ assertTrue(file.exists());
+ String actual = Files.toString(file, Charsets.UTF_8);
+ assertEquals(
+ "/**\n" +
+ " * Automatically generated file. DO NOT MODIFY\n" +
+ " */\n" +
+ "package my.app.pkg;\n" +
+ "\n" +
+ "public final class BuildConfig {\n" +
+ " public static final boolean DEBUG = false;\n" +
+ "}\n", actual);
+ file.delete();
+ tempDir.delete();
+ }
+
+ public void testTrue() throws Exception {
+ File tempDir = Files.createTempDir();
+ BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
+ "my.app.pkg");
+ generator.addField("boolean", "DEBUG", "Boolean.parseBoolean(\"true\")").generate();
+
+ File file = generator.getBuildConfigFile();
+ assertTrue(file.exists());
+ String actual = Files.toString(file, Charsets.UTF_8);
+ assertEquals(
+ "/**\n" +
+ " * Automatically generated file. DO NOT MODIFY\n" +
+ " */\n" +
+ "package my.app.pkg;\n" +
+ "\n" +
+ "public final class BuildConfig {\n" +
+ " public static final boolean DEBUG = Boolean.parseBoolean(\"true\");\n" +
+ "}\n", actual);
+ file.delete();
+ tempDir.delete();
+ }
+
+ public void testExtra() throws Exception {
+ File tempDir = Files.createTempDir();
+ BuildConfigGenerator generator = new BuildConfigGenerator(tempDir.getPath(),
+ "my.app.pkg");
+
+ List<Object> items = Lists.newArrayList();
+ items.add("Extra line");
+ items.add(AndroidBuilder.createClassField("int", "EXTRA", "42"));
+
+ generator.addItems(items).generate();
+
+ File file = generator.getBuildConfigFile();
+ assertTrue(file.exists());
+ String actual = Files.toString(file, Charsets.UTF_8);
+ assertEquals(
+ "/**\n" +
+ " * Automatically generated file. DO NOT MODIFY\n" +
+ " */\n" +
+ "package my.app.pkg;\n" +
+ "\n" +
+ "public final class BuildConfig {\n" +
+ " // Extra line\n" +
+ " public static final int EXTRA = 42;\n" +
+ "}\n", actual);
+ file.delete();
+ tempDir.delete();
+ }
+}
diff --git a/builder/src/test/java/com/android/builder/internal/incremental/FileManagerTest.java b/builder/src/test/java/com/android/builder/internal/incremental/FileManagerTest.java
deleted file mode 100644
index 3ac6bb3..0000000
--- a/builder/src/test/java/com/android/builder/internal/incremental/FileManagerTest.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.builder.internal.incremental;
-
-import com.android.ide.common.res2.FileStatus;
-import com.android.testutils.TestUtils;
-import com.google.common.base.Charsets;
-import com.google.common.collect.Maps;
-import com.google.common.io.Files;
-import junit.framework.TestCase;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import java.util.regex.Matcher;
-
-public class FileManagerTest extends TestCase {
-
- private static FileManager sFileManager = null;
- private static File sFilesFolder = null;
-
- public void testUntouched() throws Exception {
- FileManager fileManager = getFileManager();
- Map<File, FileStatus> changedFiles = fileManager.getChangedFiles();
-
- File file = new File(sFilesFolder, "untouched.png");
- FileStatus status = changedFiles.get(file);
- assertNull(status);
- }
-
- public void testUntouchedDateBefore() throws Exception {
- FileManager fileManager = getFileManager();
- Map<File, FileStatus> changedFiles = fileManager.getChangedFiles();
-
- File file = new File(sFilesFolder, "untouched_date_before.png");
- FileStatus status = changedFiles.get(file);
- // no change
- assertNull(status);
- }
-
- public void testUntouchedDateAfter() throws Exception {
- FileManager fileManager = getFileManager();
- Map<File, FileStatus> changedFiles = fileManager.getChangedFiles();
-
- File file = new File(sFilesFolder, "untouched_date_after.png");
- FileStatus status = changedFiles.get(file);
- // no change
- assertNull(status);
- }
-
- public void testContentChanged() throws Exception {
- FileManager fileManager = getFileManager();
- Map<File, FileStatus> changedFiles = fileManager.getChangedFiles();
-
- File file = new File(sFilesFolder, "content_changed.png");
- FileStatus status = changedFiles.get(file);
- assertEquals(FileStatus.CHANGED, status);
- }
-
- public void testSizeChanged() throws Exception {
- FileManager fileManager = getFileManager();
- Map<File, FileStatus> changedFiles = fileManager.getChangedFiles();
-
- File file = new File(sFilesFolder, "size_changed.png");
- FileStatus status = changedFiles.get(file);
- assertEquals(FileStatus.CHANGED, status);
- }
-
- public void testRemoved() throws Exception {
- FileManager fileManager = getFileManager();
- Map<File, FileStatus> changedFiles = fileManager.getChangedFiles();
-
- File file = new File(sFilesFolder, "removed.png");
- FileStatus status = changedFiles.get(file);
- assertEquals(FileStatus.REMOVED, status);
- }
-
- public void testNew() throws Exception {
- FileManager fileManager = getFileManager();
- Map<File, FileStatus> changedFiles = fileManager.getChangedFiles();
-
- File file = new File(sFilesFolder, "new.png");
- FileStatus status = changedFiles.get(file);
- assertEquals(FileStatus.NEW, status);
- }
-
- private FileManager getFileManager() throws IOException {
- if (sFileManager == null) {
- File root = TestUtils.getCanonicalRoot("changeManager");
- File dataFile = new File(root, "files.data");
- sFilesFolder = new File(root, "files");
-
- // update the last modified on some of the files.
- Map<String, String> placeHolderMap = Maps.newHashMap();
- String[] files = new String[] { "untouched" };
- for (String filename : files) {
- File file = new File(sFilesFolder, filename + ".png");
- placeHolderMap.put(
- String.format("\\$lm_%s\\$", filename),
- String.format("%d", file.lastModified()));
- }
-
- File trueDataFile = getDataFile(dataFile, sFilesFolder, placeHolderMap);
-
- sFileManager = new FileManager();
- sFileManager.load(trueDataFile);
-
- sFileManager.addFile(sFilesFolder);
- }
-
- return sFileManager;
- }
-
- /**
- * Returns a data file where the placeholders have been updated with the real folder based
- * on where the tests are run from.
- *
- * @param file the data folder.
- * @param targetFolder the targetFolder
- * @param placeholders additional placeholders and values to replace.
- *
- * @return a new data file that's been updated with the targetFolder
- * @throws IOException
- */
- private static File getDataFile(File file, File targetFolder, Map<String, String> placeholders)
- throws IOException {
-
- String content = Files.toString(file, Charsets.UTF_8);
-
- // search and replace $TOP$ with the root and $SEP$ with the platform separator.
- content = content.replaceAll("\\$TOP\\$", Matcher.quoteReplacement(targetFolder.getAbsolutePath()))
- .replaceAll("\\$SEP\\$", Matcher.quoteReplacement(File.separator));
-
- // now replace the additional placeholders
- for (Map.Entry<String, String> entry : placeholders.entrySet()) {
- content = content.replaceAll(entry.getKey(), Matcher.quoteReplacement(entry.getValue()));
- }
-
- File tmp = File.createTempFile("android", "getDataFile");
- Files.write(content, tmp, Charsets.UTF_8);
-
- return tmp;
- }
-}
diff --git a/changelog.txt b/changelog.txt
index b9c8268..792cac0 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,6 +1,80 @@
+0.7.0
+- Requires Gradle 1.9
+- You can now have a variant specific source folder if you have flavors.
+ Only for app (not library or test). Name is src/flavorDebug/... or src/flavor1Flavor2Debug/
+ (note the camelcase naming, with lower case for first letter).
+ Its components (res, manifest, etc...) have higher priority than components from build type
+ or flavors.
+ There is also a "flavor combination" source folder available when more than one
+ flavor dimension is used.
+ For instance src/flavor1Flavor2/
+ Note that this is for all combinations of *all* dimensions.
+- Build config improvements and DSL changes.
+ The previous DSL proprety:
+ buildConfigLine "<value>"
+ has changed to
+ buildConfigField "<type>", "<name>", "<value>"
+ This allows override a field (see 'basic' sample)
+ Also, BuildConfig now automatically contains constants for
+ PACKAGE_NAME, VERSION_CODE, VERSION_NAME, BUILD_TYPE, FLAVOR as well as FLAVOR_<group>, FLAVOR_<group>, etc... if there are several flavor dimensions.
+- Switch to ProGuard 4.10
+ - Added ability to test proguarded (obfuscated) apps.
+- New option on product Flavor (and defaultConfig) allow filtering of resources through the -c option of aapt
+ You can pass single or multiple values through the DSL. All values from the default config and flavors
+ get combined and passed to aapt.
+ resConfig "en"
+ or
+ resConfig "nodpi","hdpi"
+
+- Jar files are now pre-dexed for faster dexing.
+- First pass at NDK integration
+- API to add new generated source folders:
+ variant.addJavaSourceFoldersToModel(sourceFolder1, sourceFolders2,...)
+ This adds the source folder to the model (for IDE support).
+ Another API:
+ variant.registerJavaGeneratingTask(task, sourceFolder1, sourceFolders2,...)
+ This automatically adds the dependency on the task, sets up the JavaCompile task inputs and propagates
+ the folders to the model for IDE integration.
+- API to add extra artifacts on variants. This will allow to register Java or Android artifacts, for instance
+ for alternative test artifacts.
+
+0.6.3
+- Fixed ClassNotFoundException:MergingException introduced in 0.6.2
+
+0.6.2
+- Lint now picks up the SDK home from sdk.dir in local.properties
+- Error message shown when using an unsupported version of Gradle now explains how to update the Gradle wrapper
+- Merged resource files no longer place their source markers into the R file as comments
+- Project path can contain '--' (two dashes)
+- Internal changes to improve integration with Android Studio
+
+0.6.1
+
+- Fixed issues with lint task found in 0.6.0
+
+0.6.0
+
+- Enabled support for Gradle 1.8
+- Gradle 1.8 is now the minimum supported version
+- Default encoding for compiling Java code is UTF-8
+- Users can now specify the encoding to use to compile Java code
+- Fixed Gradle 1.8-specific bugs
+ - Importing projects with missing dependencies was broken
+ - Compiling projects with AIDL files was broken
+
+0.5.7
+
+- Proguard support for libraries.
+ Note the current DSL property 'proguardFiles' for library now sets the proguard rule file used when proguarding the library code.
+ The new property 'consumerProguardFiles' is used to package a rule file inside an aar.
+- Improved IDE support, including loading project with broken dependencies and anchor task to generate Java code
+- New hook tasks: preBuild and prebuild<VariantName>
+- First lint integration. This is a work in progress and therefore the lint task is not added to the check task.
+- Enable compatibility with 1.8
+
0.5.6
-- Enable support for 1.7
+- Enabled support for 1.7
0.5.5
@@ -18,17 +92,17 @@
0.5.3
-- Fix a crashing bug in PrepareDependenciesTask
+- Fixed a crashing bug in PrepareDependenciesTask
0.5.2
- Better error reporting for cmd line tools, especially
if run in parallel in spawned threads
-- Fix an issue due to windows path in merged resource files.
+- Fixed an issue due to windows path in merged resource files.
0.5.1
-- Fix issue in the dependency checker.
+- Fixed issue in the dependency checker.
0.5.0:
@@ -47,10 +121,10 @@
0.4.3:
-- enable crunching for all png files, not just .9.png
-- fix dealing with non resource files in res/ and assets/
-- fix crash when doing incremental aidl compilation due to broken method name (ah the joy of Groovy...)
-- clean older R classes when the app package name has changed.
+- Enabled crunching for all png files, not just .9.png
+- Fixed dealing with non resource files in res/ and assets/
+- Fixed crash when doing incremental aidl compilation due to broken method name (ah the joy of Groovy...)
+- Cleaned older R classes when the app package name has changed.
0.4.2
diff --git a/gradle-model/build.gradle b/gradle-model/build.gradle
index f4a8458..929eaeb 100644
--- a/gradle-model/build.gradle
+++ b/gradle-model/build.gradle
@@ -30,14 +30,6 @@
sourceSets.test.compileClasspath += configurations.gradleRepo
sourceSets.test.runtimeClasspath += configurations.gradleRepo
-def getVersion() {
- if (project.has("release")) {
- return project.ext.baseVersion
- }
-
- return project.ext.baseVersion + '-SNAPSHOT'
-}
-
test.dependsOn ':gradle:publishLocal'
idea {
diff --git a/gradle-model/src/test/java/com/android/build/gradle/model/AndroidProjectTest.java b/gradle-model/src/test/java/com/android/build/gradle/model/AndroidProjectTest.java
index 6ef14ff..dc44dc8 100644
--- a/gradle-model/src/test/java/com/android/build/gradle/model/AndroidProjectTest.java
+++ b/gradle-model/src/test/java/com/android/build/gradle/model/AndroidProjectTest.java
@@ -17,15 +17,21 @@
package com.android.build.gradle.model;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.internal.StringHelper;
+import com.android.builder.model.AndroidArtifact;
import com.android.builder.model.AndroidLibrary;
import com.android.builder.model.AndroidProject;
-import com.android.builder.model.ArtifactInfo;
+import com.android.builder.model.ArtifactMetaData;
import com.android.builder.model.BuildTypeContainer;
import com.android.builder.model.Dependencies;
+import com.android.builder.model.JavaArtifact;
+import com.android.builder.model.JavaCompileOptions;
import com.android.builder.model.ProductFlavor;
import com.android.builder.model.ProductFlavorContainer;
import com.android.builder.model.SigningConfig;
import com.android.builder.model.SourceProvider;
+import com.android.builder.model.SourceProviderContainer;
import com.android.builder.model.Variant;
import com.android.builder.signing.KeystoreHelper;
import com.android.prefs.AndroidLocation;
@@ -41,14 +47,15 @@
import java.net.URL;
import java.security.CodeSource;
import java.security.KeyStore;
-import java.util.List;
+import java.util.Collection;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
+
+import static com.android.builder.model.AndroidProject.ARTIFACT_INSTRUMENT_TEST;
public class AndroidProjectTest extends TestCase {
- private final static String MODEL_VERSION = "0.5.0-SNAPSHOT";
+ private final static String MODEL_VERSION = "0.7.0-SNAPSHOT";
private static final Map<String, ProjectData> sProjectModelMap = Maps.newHashMap();
@@ -154,6 +161,10 @@
assertFalse("Library Project", model.isLibrary());
assertEquals("Compile Target", "android-15", model.getCompileTarget());
assertFalse("Non empty bootclasspath", model.getBootClasspath().isEmpty());
+
+ JavaCompileOptions javaCompileOptions = model.getJavaCompileOptions();
+ assertEquals("1.6", javaCompileOptions.getSourceCompatibility());
+ assertEquals("1.6", javaCompileOptions.getTargetCompatibility());
}
public void testBasicSourceProviders() throws Exception {
@@ -163,17 +174,90 @@
AndroidProject model = projectData.model;
File projectDir = projectData.projectDir;
+ testDefaultSourceSets(model, projectDir);
+
+ // test the source provider for the artifacts
+ for (Variant variant : model.getVariants()) {
+ AndroidArtifact artifact = variant.getMainArtifact();
+ assertNull(artifact.getVariantSourceProvider());
+ assertNull(artifact.getMultiFlavorSourceProvider());
+ }
+ }
+
+ public void testBasicMultiFlavorsSourceProviders() throws Exception {
+ // Load the custom model for the project
+ ProjectData projectData = getModelForProject("basicMultiFlavors");
+
+ AndroidProject model = projectData.model;
+ File projectDir = projectData.projectDir;
+
+ testDefaultSourceSets(model, projectDir);
+
+ // test the source provider for the flavor
+ Collection<ProductFlavorContainer> productFlavors = model.getProductFlavors();
+ assertEquals("Product Flavor Count", 4, productFlavors.size());
+
+ for (ProductFlavorContainer pfContainer : productFlavors) {
+ String name = pfContainer.getProductFlavor().getName();
+ new SourceProviderTester(
+ model.getName(),
+ projectDir,
+ name,
+ pfContainer.getSourceProvider())
+ .test();
+
+ assertEquals(1, pfContainer.getExtraSourceProviders().size());
+ SourceProviderContainer container = getSourceProviderContainer(
+ pfContainer.getExtraSourceProviders(), ARTIFACT_INSTRUMENT_TEST);
+ assertNotNull(container);
+
+ new SourceProviderTester(
+ model.getName(),
+ projectDir,
+ "instrumentTest" + StringHelper.capitalize(name),
+ container.getSourceProvider())
+ .test();
+ }
+
+ // test the source provider for the artifacts
+ for (Variant variant : model.getVariants()) {
+ AndroidArtifact artifact = variant.getMainArtifact();
+ assertNotNull(artifact.getVariantSourceProvider());
+ assertNotNull(artifact.getMultiFlavorSourceProvider());
+ }
+ }
+
+ private void testDefaultSourceSets(@NonNull AndroidProject model, @NonNull File projectDir) {
ProductFlavorContainer defaultConfig = model.getDefaultConfig();
+ // test the main source provider
new SourceProviderTester(model.getName(), projectDir,
"main", defaultConfig.getSourceProvider())
.test();
+
+ // test the main instrumentTest source provider
+ SourceProviderContainer testSourceProviders = getSourceProviderContainer(
+ defaultConfig.getExtraSourceProviders(), ARTIFACT_INSTRUMENT_TEST);
+ assertNotNull("InstrumentTest source Providers null-check", testSourceProviders);
+
new SourceProviderTester(model.getName(), projectDir,
- "instrumentTest", defaultConfig.getTestSourceProvider())
+ "instrumentTest", testSourceProviders.getSourceProvider())
+ .test();
+
+ // test the source provider for the build types
+ Collection<BuildTypeContainer> buildTypes = model.getBuildTypes();
+ assertEquals("Build Type Count", 2, buildTypes.size());
+
+ for (BuildTypeContainer btContainer : model.getBuildTypes()) {
+ new SourceProviderTester(
+ model.getName(),
+ projectDir,
+ btContainer.getBuildType().getName(),
+ btContainer.getSourceProvider())
.test();
- Map<String, BuildTypeContainer> buildTypes = model.getBuildTypes();
- assertEquals("Build Type Count", 2, buildTypes.size());
+ assertEquals(0, btContainer.getExtraSourceProviders().size());
+ }
}
public void testBasicVariantDetails() throws Exception {
@@ -182,47 +266,61 @@
AndroidProject model = projectData.model;
- Map<String, Variant> variants = model.getVariants();
+ Collection<Variant> variants = model.getVariants();
assertEquals("Variant Count", 2 , variants.size());
// debug variant
- Variant debugVariant = variants.get("Debug");
- assertNotNull("Debug Variant null-check", debugVariant);
+ Variant debugVariant = getVariant(variants, "debug");
+ assertNotNull("debug Variant null-check", debugVariant);
new ProductFlavorTester(debugVariant.getMergedFlavor(), "Debug Merged Flavor")
.setVersionCode(12)
.setVersionName("2.0")
.setMinSdkVersion(16)
.setTargetSdkVersion(16)
- .test();
+ .setTestInstrumentationRunner("android.test.InstrumentationTestRunner")
+ .setTestHandleProfiling(Boolean.FALSE)
+ .setTestFunctionalTest(null)
+ .test();
- ArtifactInfo debugMainInfo = debugVariant.getMainArtifactInfo();
+ AndroidArtifact debugMainInfo = debugVariant.getMainArtifact();
assertNotNull("Debug main info null-check", debugMainInfo);
assertEquals("Debug package name", "com.android.tests.basic.debug",
debugMainInfo.getPackageName());
assertTrue("Debug signed check", debugMainInfo.isSigned());
assertEquals("Debug signingConfig name", "myConfig", debugMainInfo.getSigningConfigName());
+ assertEquals("Debug sourceGenTask", "generateDebugSources", debugMainInfo.getSourceGenTaskName());
+ assertEquals("Debug javaCompileTask", "compileDebugJava", debugMainInfo.getJavaCompileTaskName());
+
+ Collection<AndroidArtifact> debugExtraAndroidArtifacts = debugVariant.getExtraAndroidArtifacts();
+
// this variant is tested.
- ArtifactInfo debugTestInfo = debugVariant.getTestArtifactInfo();
+ AndroidArtifact debugTestInfo = getAndroidArtifact(debugExtraAndroidArtifacts,
+ ARTIFACT_INSTRUMENT_TEST);
assertNotNull("Test info null-check", debugTestInfo);
assertEquals("Test package name", "com.android.tests.basic.debug.test",
debugTestInfo.getPackageName());
assertNotNull("Test output file null-check", debugTestInfo.getOutputFile());
assertTrue("Test signed check", debugTestInfo.isSigned());
assertEquals("Test signingConfig name", "myConfig", debugTestInfo.getSigningConfigName());
+ assertEquals("Test sourceGenTask", "generateDebugTestSources", debugTestInfo.getSourceGenTaskName());
+ assertEquals("Test javaCompileTask", "compileDebugTestJava", debugTestInfo.getJavaCompileTaskName());
// release variant, not tested.
- Variant releaseVariant = variants.get("Release");
- assertNotNull("Release Variant null-check", releaseVariant);
+ Variant releaseVariant = getVariant(variants, "release");
+ assertNotNull("release Variant null-check", releaseVariant);
- ArtifactInfo relMainInfo = releaseVariant.getMainArtifactInfo();
+ AndroidArtifact relMainInfo = releaseVariant.getMainArtifact();
assertNotNull("Release main info null-check", relMainInfo);
assertEquals("Release package name", "com.android.tests.basic",
relMainInfo.getPackageName());
assertFalse("Release signed check", relMainInfo.isSigned());
assertNull("Release signingConfig name", relMainInfo.getSigningConfigName());
+ assertEquals("Release sourceGenTask", "generateReleaseSources", relMainInfo.getSourceGenTaskName());
+ assertEquals("Release javaCompileTask", "compileReleaseJava", relMainInfo.getJavaCompileTaskName());
- ArtifactInfo relTestInfo = releaseVariant.getTestArtifactInfo();
+ Collection<AndroidArtifact> releaseExtraAndroidArtifacts = releaseVariant.getExtraAndroidArtifacts();
+ AndroidArtifact relTestInfo = getAndroidArtifact(releaseExtraAndroidArtifacts, ARTIFACT_INSTRUMENT_TEST);
assertNull("Release test info null-check", relTestInfo);
// check debug dependencies
@@ -231,7 +329,7 @@
assertEquals(2, dependencies.getJars().size());
assertEquals(1, dependencies.getLibraries().size());
- AndroidLibrary lib = dependencies.getLibraries().get(0);
+ AndroidLibrary lib = dependencies.getLibraries().iterator().next();
assertNotNull(lib);
assertNotNull(lib.getBundle());
assertNotNull(lib.getFolder());
@@ -245,12 +343,16 @@
AndroidProject model = projectData.model;
- assertEquals("Number of signingConfig", 2, model.getSigningConfigs().size());
+ Collection<SigningConfig> signingConfigs = model.getSigningConfigs();
+ assertNotNull("SigningConfigs null-check", signingConfigs);
+ assertEquals("Number of signingConfig", 2, signingConfigs.size());
- SigningConfig debugSigningConfig = model.getSigningConfigs().get("debug");
+ SigningConfig debugSigningConfig = getSigningConfig(signingConfigs, "debug");
+ assertNotNull("debug signing config null-check", debugSigningConfig);
new SigningConfigTester(debugSigningConfig, "debug", true).test();
- SigningConfig mySigningConfig = model.getSigningConfigs().get("myConfig");
+ SigningConfig mySigningConfig = getSigningConfig(signingConfigs, "myConfig");
+ assertNotNull("myConfig signing config null-check", mySigningConfig);
new SigningConfigTester(mySigningConfig, "myConfig", true)
.setStoreFile(new File(projectData.projectDir, "debug.keystore"))
.test();
@@ -280,8 +382,12 @@
.setManifestFile("AndroidManifest.xml")
.test();
+ SourceProviderContainer testSourceProviderContainer = getSourceProviderContainer(
+ defaultConfig.getExtraSourceProviders(), ARTIFACT_INSTRUMENT_TEST);
+ assertNotNull("InstrumentTest source Providers null-check", testSourceProviderContainer);
+
new SourceProviderTester(model.getName(), projectDir,
- "instrumentTest", defaultConfig.getTestSourceProvider())
+ "instrumentTest", testSourceProviderContainer.getSourceProvider())
.setJavaDir("tests/java")
.setResourcesDir("tests/resources")
.setAidlDir("tests/aidl")
@@ -303,13 +409,13 @@
assertNotNull("Model Object null-check", model);
assertEquals("Model Name", "renamedApk", model.getName());
- Map<String, Variant> variants = model.getVariants();
+ Collection<Variant> variants = model.getVariants();
assertEquals("Variant Count", 2 , variants.size());
File buildDir = new File(projectDir, "build");
- for (Variant variant : variants.values()) {
- ArtifactInfo mainInfo = variant.getMainArtifactInfo();
+ for (Variant variant : variants) {
+ AndroidArtifact mainInfo = variant.getMainArtifact();
assertNotNull(
"Null-check on mainArtifactInfo for " + variant.getDisplayName(),
mainInfo);
@@ -336,21 +442,26 @@
new SourceProviderTester(model.getName(), projectDir,
"main", defaultConfig.getSourceProvider())
.test();
+
+ SourceProviderContainer testSourceProviderContainer = getSourceProviderContainer(
+ defaultConfig.getExtraSourceProviders(), ARTIFACT_INSTRUMENT_TEST);
+ assertNotNull("InstrumentTest source Providers null-check", testSourceProviderContainer);
+
new SourceProviderTester(model.getName(), projectDir,
- "instrumentTest", defaultConfig.getTestSourceProvider())
+ "instrumentTest", testSourceProviderContainer.getSourceProvider())
.test();
- Map<String, BuildTypeContainer> buildTypes = model.getBuildTypes();
+ Collection<BuildTypeContainer> buildTypes = model.getBuildTypes();
assertEquals("Build Type Count", 2, buildTypes.size());
- Map<String, Variant> variants = model.getVariants();
- assertEquals("Variant Count", 8 , variants.size());
+ Collection<Variant> variants = model.getVariants();
+ assertEquals("Variant Count", 8, variants.size());
- Variant f1faDebugVariant = variants.get("F1FaDebug");
- assertNotNull("F1faDebug Variant null-check", f1faDebugVariant);
+ Variant f1faDebugVariant = getVariant(variants, "f1FaDebug");
+ assertNotNull("f1faDebug Variant null-check", f1faDebugVariant);
new ProductFlavorTester(f1faDebugVariant.getMergedFlavor(), "F1faDebug Merged Flavor")
.test();
- new VariantTester(f1faDebugVariant, projectDir, "flavors-f1fa-debug-unaligned.apk").test();
+ new VariantTester(f1faDebugVariant, projectDir, "flavors-f1-fa-debug-unaligned.apk").test();
}
public void testTicTacToe() throws Exception {
@@ -363,14 +474,18 @@
ProjectData appModelData = map.get(":app");
assertNotNull("app module model null-check", appModelData);
- Dependencies dependencies = appModelData.model.getVariants().get("Debug").getMainArtifactInfo().getDependencies();
+ Collection<Variant> variants = appModelData.model.getVariants();
+ Variant debugVariant = getVariant(variants, "debug");
+ assertNotNull("debug variant null-check", debugVariant);
+
+ Dependencies dependencies = debugVariant.getMainArtifact().getDependencies();
assertNotNull(dependencies);
- List<AndroidLibrary> libs = dependencies.getLibraries();
+ Collection<AndroidLibrary> libs = dependencies.getLibraries();
assertNotNull(libs);
assertEquals(1, libs.size());
- AndroidLibrary androidLibrary = libs.get(0);
+ AndroidLibrary androidLibrary = libs.iterator().next();
assertNotNull(androidLibrary);
assertEquals("Dependency project path", ":lib", androidLibrary.getProject());
@@ -388,36 +503,37 @@
assertFalse("Library Project", model.isLibrary());
- Map<String, Variant> variants = model.getVariants();
+ Collection<Variant> variants = model.getVariants();
+ Collection<ProductFlavorContainer> productFlavors = model.getProductFlavors();
- ProductFlavorContainer flavor1 = model.getProductFlavors().get("flavor1");
+ ProductFlavorContainer flavor1 = getProductFlavor(productFlavors, "flavor1");
assertNotNull(flavor1);
- Variant flavor1Debug = variants.get("Flavor1Debug");
+ Variant flavor1Debug = getVariant(variants, "flavor1Debug");
assertNotNull(flavor1Debug);
- Dependencies dependencies = flavor1Debug.getMainArtifactInfo().getDependencies();
+ Dependencies dependencies = flavor1Debug.getMainArtifact().getDependencies();
assertNotNull(dependencies);
- List<AndroidLibrary> libs = dependencies.getLibraries();
+ Collection<AndroidLibrary> libs = dependencies.getLibraries();
assertNotNull(libs);
assertEquals(1, libs.size());
- AndroidLibrary androidLibrary = libs.get(0);
+ AndroidLibrary androidLibrary = libs.iterator().next();
assertNotNull(androidLibrary);
// TODO: right now we can only test the folder name efficiently
assertEquals("FlavorlibLib1Unspecified.aar", androidLibrary.getFolder().getName());
- ProductFlavorContainer flavor2 = model.getProductFlavors().get("flavor2");
+ ProductFlavorContainer flavor2 = getProductFlavor(productFlavors, "flavor2");
assertNotNull(flavor2);
- Variant flavor2Debug = variants.get("Flavor2Debug");
+ Variant flavor2Debug = getVariant(variants, "flavor2Debug");
assertNotNull(flavor2Debug);
- dependencies = flavor2Debug.getMainArtifactInfo().getDependencies();
+ dependencies = flavor2Debug.getMainArtifact().getDependencies();
assertNotNull(dependencies);
libs = dependencies.getLibraries();
assertNotNull(libs);
assertEquals(1, libs.size());
- androidLibrary = libs.get(0);
+ androidLibrary = libs.iterator().next();
assertNotNull(androidLibrary);
// TODO: right now we can only test the folder name efficiently
assertEquals("FlavorlibLib2Unspecified.aar", androidLibrary.getFolder().getName());
@@ -430,29 +546,161 @@
assertNotNull("Module app null-check", baseLibModelData);
AndroidProject model = baseLibModelData.model;
- Map<String, Variant> variants = model.getVariants();
+ Collection<Variant> variants = model.getVariants();
assertEquals("Variant count", 2, variants.size());
- Variant variant = variants.get("Release");
- assertNotNull("Release variant null-check", variant);
+ Variant variant = getVariant(variants, "release");
+ assertNotNull("release variant null-check", variant);
- ArtifactInfo mainInfo = variant.getMainArtifactInfo();
+ AndroidArtifact mainInfo = variant.getMainArtifact();
assertNotNull("Main Artifact null-check", mainInfo);
Dependencies dependencies = mainInfo.getDependencies();
assertNotNull("Dependencies null-check", dependencies);
- List<String> projects = dependencies.getProjects();
+ Collection<String> projects = dependencies.getProjects();
assertNotNull("project dep list null-check", projects);
assertEquals("project dep count", 1, projects.size());
- assertEquals("dep on :util check", ":util", projects.get(0));
+ assertEquals("dep on :util check", ":util", projects.iterator().next());
- List<File> jars = dependencies.getJars();
+ Collection<File> jars = dependencies.getJars();
assertNotNull("jar dep list null-check", jars);
// TODO these are jars coming from ':util' They shouldn't be there.
assertEquals("jar dep count", 2, jars.size());
}
+ public void testGenFolderApi() throws Exception {
+ // Load the custom model for the project
+ ProjectData projectData = getModelForProject("genFolderApi");
+
+ AndroidProject model = projectData.model;
+ File projectDir = projectData.projectDir;
+
+ File buildDir = new File(projectDir, "build");
+
+ for (Variant variant : model.getVariants()) {
+
+ AndroidArtifact mainInfo = variant.getMainArtifact();
+ assertNotNull(
+ "Null-check on mainArtifactInfo for " + variant.getDisplayName(),
+ mainInfo);
+
+ // get the generated source folders.
+ Collection<File> genFolder = mainInfo.getGeneratedSourceFolders();
+
+ // We're looking for a custom folder
+ String folderStart = new File(buildDir, "customCode").getAbsolutePath() + File.separatorChar;
+ boolean found = false;
+ for (File f : genFolder) {
+ if (f.getAbsolutePath().startsWith(folderStart)) {
+ found = true;
+ break;
+ }
+ }
+
+ assertTrue("custom generated source folder check", found);
+ }
+ }
+
+ public void testArtifactApi() throws Exception {
+ // Load the custom model for the project
+ ProjectData projectData = getModelForProject("artifactApi");
+
+ AndroidProject model = projectData.model;
+
+ // check the Artifact Meta Data
+ Collection<ArtifactMetaData> extraArtifacts = model.getExtraArtifacts();
+ assertNotNull("Extra artifact collection null-check", extraArtifacts);
+ assertEquals("Extra artifact size check", 2, extraArtifacts.size());
+
+ assertNotNull("instrument test metadata null-check",
+ getArtifactMetaData(extraArtifacts, ARTIFACT_INSTRUMENT_TEST));
+
+ // get the custom one.
+ ArtifactMetaData extraArtifactMetaData = getArtifactMetaData(extraArtifacts, "__test__");
+ assertNotNull("custom extra metadata null-check", extraArtifactMetaData);
+ assertFalse("custom extra meta data is Test check", extraArtifactMetaData.isTest());
+ assertEquals("custom extra meta data type check", ArtifactMetaData.TYPE_JAVA, extraArtifactMetaData.getType());
+
+ // check the extra source provider on the build Types.
+ for (BuildTypeContainer btContainer : model.getBuildTypes()) {
+ String name = btContainer.getBuildType().getName();
+ Collection<SourceProviderContainer> extraSourceProviderContainers = btContainer.getExtraSourceProviders();
+ assertNotNull(
+ "Extra source provider containers for build type '" + name + "' null-check",
+ extraSourceProviderContainers);
+ assertEquals(
+ "Extra source provider containers for build type size '" + name + "' check",
+ 1,
+ extraSourceProviderContainers.size());
+
+ SourceProviderContainer sourceProviderContainer = extraSourceProviderContainers.iterator().next();
+ assertNotNull(
+ "Extra artifact source provider for " + name + " null check",
+ sourceProviderContainer);
+
+ assertEquals(
+ "Extra artifact source provider for " + name + " name check",
+ "__test__",
+ sourceProviderContainer.getArtifactName());
+
+ assertEquals(
+ "Extra artifact source provider for " + name + " value check",
+ "buildType:" + name,
+ sourceProviderContainer.getSourceProvider().getManifestFile().getPath());
+ }
+
+ // check the extra source provider on the product flavors.
+ for (ProductFlavorContainer pfContainer : model.getProductFlavors()) {
+ String name = pfContainer.getProductFlavor().getName();
+ Collection<SourceProviderContainer> extraSourceProviderContainers = pfContainer.getExtraSourceProviders();
+ assertNotNull(
+ "Extra source provider container for product flavor '" + name + "' null-check",
+ extraSourceProviderContainers);
+ assertEquals(
+ "Extra artifact source provider container for product flavor size '" + name + "' check",
+ 2,
+ extraSourceProviderContainers.size());
+
+ assertNotNull(
+ "Extra source provider container for product flavor '" + name + "': instTest check",
+ getSourceProviderContainer(extraSourceProviderContainers, ARTIFACT_INSTRUMENT_TEST));
+
+
+ SourceProviderContainer sourceProviderContainer = getSourceProviderContainer(
+ extraSourceProviderContainers, "__test__");
+ assertNotNull(
+ "Custom source provider container for " + name + " null check",
+ sourceProviderContainer);
+
+ assertEquals(
+ "Custom artifact source provider for " + name + " name check",
+ "__test__",
+ sourceProviderContainer.getArtifactName());
+
+ assertEquals(
+ "Extra artifact source provider for " + name + " value check",
+ "productFlavor:" + name,
+ sourceProviderContainer.getSourceProvider().getManifestFile().getPath());
+ }
+
+ // check the extra artifacts on the variants
+ for (Variant variant : model.getVariants()) {
+ String name = variant.getName();
+ Collection<JavaArtifact> javaArtifacts = variant.getExtraJavaArtifacts();
+ assertEquals(1, javaArtifacts.size());
+ JavaArtifact javaArtifact = javaArtifacts.iterator().next();
+ assertEquals("__test__", javaArtifact.getName());
+ assertEquals("assemble:" + name, javaArtifact.getAssembleTaskName());
+ assertEquals("compile:" + name, javaArtifact.getJavaCompileTaskName());
+ assertEquals(new File("classesFolder:" + name), javaArtifact.getClassesFolder());
+
+ SourceProvider variantSourceProvider = javaArtifact.getVariantSourceProvider();
+ assertNotNull(variantSourceProvider);
+ assertEquals("provider:" + name, variantSourceProvider.getManifestFile().getPath());
+ }
+ }
+
/**
* Returns the SDK folder as built from the Android source tree.
* @return the SDK
@@ -505,6 +753,95 @@
return new File(rootDir, "tests");
}
+ @Nullable
+ private static Variant getVariant(
+ @NonNull Collection<Variant> items,
+ @NonNull String name) {
+ for (Variant item : items) {
+ if (name.equals(item.getName())) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private static ProductFlavorContainer getProductFlavor(
+ @NonNull Collection<ProductFlavorContainer> items,
+ @NonNull String name) {
+ for (ProductFlavorContainer item : items) {
+ assertNotNull("ProductFlavorContainer list item null-check:" + name, item);
+ assertNotNull("ProductFlavorContainer.getProductFlavor() list item null-check: " + name, item.getProductFlavor());
+ assertNotNull("ProductFlavorContainer.getProductFlavor().getName() list item null-check: " + name, item.getProductFlavor().getName());
+ if (name.equals(item.getProductFlavor().getName())) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private static ArtifactMetaData getArtifactMetaData(
+ @NonNull Collection<ArtifactMetaData> items,
+ @NonNull String name) {
+ for (ArtifactMetaData item : items) {
+ assertNotNull("ArtifactMetaData list item null-check:" + name, item);
+ assertNotNull("ArtifactMetaData.getName() list item null-check: " + name, item.getName());
+ if (name.equals(item.getName())) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private static AndroidArtifact getAndroidArtifact(
+ @NonNull Collection<AndroidArtifact> items,
+ @NonNull String name) {
+ for (AndroidArtifact item : items) {
+ assertNotNull("AndroidArtifact list item null-check:" + name, item);
+ assertNotNull("AndroidArtifact.getName() list item null-check: " + name, item.getName());
+ if (name.equals(item.getName())) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private static SigningConfig getSigningConfig(
+ @NonNull Collection<SigningConfig> items,
+ @NonNull String name) {
+ for (SigningConfig item : items) {
+ assertNotNull("SigningConfig list item null-check:" + name, item);
+ assertNotNull("SigningConfig.getName() list item null-check: " + name, item.getName());
+ if (name.equals(item.getName())) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private static SourceProviderContainer getSourceProviderContainer(
+ @NonNull Collection<SourceProviderContainer> items,
+ @NonNull String name) {
+ for (SourceProviderContainer item : items) {
+ assertNotNull("SourceProviderContainer list item null-check:" + name, item);
+ assertNotNull("SourceProviderContainer.getName() list item null-check: " + name, item.getArtifactName());
+ if (name.equals(item.getArtifactName())) {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
private static final class ProductFlavorTester {
@NonNull private final ProductFlavor productFlavor;
@NonNull private final String name;
@@ -517,6 +854,8 @@
private int renderscriptTargetApi = -1;
private String testPackageName = null;
private String testInstrumentationRunner = null;
+ private Boolean testHandleProfiling = null;
+ private Boolean testFunctionalTest = null;
ProductFlavorTester(@NonNull ProductFlavor productFlavor, @NonNull String name) {
this.productFlavor = productFlavor;
@@ -533,36 +872,46 @@
return this;
}
- ProductFlavorTester setVersionName(String versionName) {
+ ProductFlavorTester setVersionName(String versionName) {
this.versionName = versionName;
return this;
}
- ProductFlavorTester setMinSdkVersion(int minSdkVersion) {
+ ProductFlavorTester setMinSdkVersion(int minSdkVersion) {
this.minSdkVersion = minSdkVersion;
return this;
}
- ProductFlavorTester setTargetSdkVersion(int targetSdkVersion) {
+ ProductFlavorTester setTargetSdkVersion(int targetSdkVersion) {
this.targetSdkVersion = targetSdkVersion;
return this;
}
- ProductFlavorTester setRenderscriptTargetApi(int renderscriptTargetApi) {
+ ProductFlavorTester setRenderscriptTargetApi(int renderscriptTargetApi) {
this.renderscriptTargetApi = renderscriptTargetApi;
return this;
}
- ProductFlavorTester setTestPackageName(String testPackageName) {
+ ProductFlavorTester setTestPackageName(String testPackageName) {
this.testPackageName = testPackageName;
return this;
}
- ProductFlavorTester setTestInstrumentationRunner(String testInstrumentationRunner) {
+ ProductFlavorTester setTestInstrumentationRunner(String testInstrumentationRunner) {
this.testInstrumentationRunner = testInstrumentationRunner;
return this;
}
+ ProductFlavorTester setTestHandleProfiling(Boolean testHandleProfiling) {
+ this.testHandleProfiling = testHandleProfiling;
+ return this;
+ }
+
+ ProductFlavorTester setTestFunctionalTest(Boolean testFunctionalTest) {
+ this.testFunctionalTest = testFunctionalTest;
+ return this;
+ }
+
void test() {
assertEquals(name + ":packageName", packageName, productFlavor.getPackageName());
assertEquals(name + ":VersionCode", versionCode, productFlavor.getVersionCode());
@@ -576,6 +925,10 @@
testPackageName, productFlavor.getTestPackageName());
assertEquals(name + ":testInstrumentationRunner",
testInstrumentationRunner, productFlavor.getTestInstrumentationRunner());
+ assertEquals(name + ":testHandleProfiling",
+ testHandleProfiling, productFlavor.getTestHandleProfiling());
+ assertEquals(name + ":testFunctionalTest",
+ testFunctionalTest, productFlavor.getTestFunctionalTest());
}
}
@@ -652,20 +1005,23 @@
}
void test() {
- testSinglePathSet("java", javaDir, sourceProvider.getJavaDirectories());
- testSinglePathSet("resources", resourcesDir, sourceProvider.getResourcesDirectories());
- testSinglePathSet("res", resDir, sourceProvider.getResDirectories());
- testSinglePathSet("assets", assetsDir, sourceProvider.getAssetsDirectories());
- testSinglePathSet("aidl", aidlDir, sourceProvider.getAidlDirectories());
- testSinglePathSet("rs", renderscriptDir, sourceProvider.getRenderscriptDirectories());
- testSinglePathSet("jni", jniDir, sourceProvider.getJniDirectories());
+ testSinglePathCollection("java", javaDir, sourceProvider.getJavaDirectories());
+ testSinglePathCollection("resources", resourcesDir, sourceProvider.getResourcesDirectories());
+ testSinglePathCollection("res", resDir, sourceProvider.getResDirectories());
+ testSinglePathCollection("assets", assetsDir, sourceProvider.getAssetsDirectories());
+ testSinglePathCollection("aidl", aidlDir, sourceProvider.getAidlDirectories());
+ testSinglePathCollection("rs", renderscriptDir, sourceProvider.getRenderscriptDirectories());
+ testSinglePathCollection("jni", jniDir, sourceProvider.getJniDirectories());
assertEquals("AndroidManifest",
new File(projectDir, manifestFile).getAbsolutePath(),
sourceProvider.getManifestFile().getAbsolutePath());
}
- private void testSinglePathSet(String setName, String referencePath, Set<File> pathSet) {
+ private void testSinglePathCollection(
+ @NonNull String setName,
+ @NonNull String referencePath,
+ @NonNull Collection<File> pathSet) {
assertEquals(1, pathSet.size());
assertEquals(projectName + ": " + configName + "/" + setName,
new File(projectDir, referencePath).getAbsolutePath(),
@@ -687,13 +1043,19 @@
}
void test() {
+ AndroidArtifact artifact = variant.getMainArtifact();
+ assertNotNull("Main Artifact null-check", artifact);
+
String variantName = variant.getName();
File build = new File(projectDir, "build");
File apk = new File(build, "apk/" + outputFileName);
- assertEquals(variantName + " output", apk, variant.getMainArtifactInfo().getOutputFile());
+ assertEquals(variantName + " output", apk, artifact.getOutputFile());
- List<File> sourceFolders = variant.getMainArtifactInfo().getGeneratedSourceFolders();
+ Collection<File> sourceFolders = artifact.getGeneratedSourceFolders();
assertEquals("Gen src Folder count", 4, sourceFolders.size());
+
+ File manifest = artifact.getGeneratedManifest();
+ assertNotNull(manifest);
}
}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..f66ad4d
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m
\ No newline at end of file
diff --git a/gradle/build.gradle b/gradle/build.gradle
index 16b99e6..fefe868 100644
--- a/gradle/build.gradle
+++ b/gradle/build.gradle
@@ -29,7 +29,12 @@
groovy localGroovy()
compile project(':builder')
- runtime 'net.sf.proguard:proguard-gradle:4.9'
+ compile "com.android.tools:sdklib:$project.ext.baseAndroidVersion"
+ compile "com.android.tools:sdk-common:$project.ext.baseAndroidVersion"
+ compile "com.android.tools:common:$project.ext.baseAndroidVersion"
+
+ compile "com.android.tools.lint:lint:$project.ext.baseAndroidVersion"
+ compile 'net.sf.proguard:proguard-gradle:4.10'
testCompile 'junit:junit:3.8.1'
@@ -52,7 +57,7 @@
}
dependencies{
- provided 'net.sf.proguard:proguard-gradle:4.9'
+ provided 'net.sf.proguard:proguard-gradle:4.10'
}
//Include provided for compilation
@@ -67,26 +72,13 @@
}
}
-def getVersion() {
- if (project.has("release")) {
- return project.ext.baseVersion
- }
-
- return project.ext.baseVersion + '-SNAPSHOT'
-}
-
-version = getVersion()
archivesBaseName = 'gradle'
-jar.manifest.attributes("Plugin-Version": version)
+project.ext.pomName = 'Gradle Plug-in for Android'
+project.ext.pomDesc = 'Gradle plug-in to build Android applications.'
-task publishLocal(type: Upload) {
- configuration = configurations.archives
- repositories {
- mavenDeployer {
- repository(url: uri("$rootProject.ext.androidHostOut/repo"))
- }
- }
-}
+apply from: '../publish.gradle'
+
+jar.manifest.attributes("Plugin-Version": version)
publishLocal.dependsOn ':builder:publishLocal'
task buildTest(type: Test, dependsOn: publishLocal) {
@@ -107,62 +99,6 @@
check.dependsOn buildTest
-project.ext.sonatypeUsername = project.hasProperty('sonatypeUsername') ? sonatypeUsername : ""
-project.ext.sonatypePassword = project.hasProperty('sonatypePassword') ? sonatypePassword : ""
-
-uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment ->
- if (!project.has("release")) {
- throw new StopExecutionException("uploadArchives must be called with the release.gradle init script")
- }
-
- if (project.ext.sonatypeUsername.length() == 0 || project.ext.sonatypePassword.length() == 0) {
- throw new StopExecutionException("uploadArchives cannot be called without sonatype username and password")
- }
-
- signing.signPom(deployment)
- }
-
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: project.ext.sonatypeUsername, password: project.ext.sonatypePassword)
- }
-
- pom.project {
- name 'Gradle Plug-in for Android'
- description 'Gradle plug-in to build Android applications.'
- url 'http://tools.android.com'
- inceptionYear '2007'
-
- licenses {
- license {
- name 'The Apache Software License, Version 2.0'
- url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
- distribution 'repo'
- }
- }
-
- scm {
- url "https://android.googlesource.com/platform/tools/build"
- connection "git://android.googlesource.com/platform/tools/build.git"
- }
-
- developers {
- developer {
- name 'The Android Open Source Project'
- }
- }
- }
- }
- }
-}
-
-// custom tasks for creating source/javadoc jars
-task sourcesJar(type: Jar, dependsOn:classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
-}
groovydoc {
exclude "**/internal/**"
@@ -178,15 +114,9 @@
classifier 'javadoc'
from groovydoc.destinationDir
}
-
-// add javadoc/source jar tasks as artifacts
+
+// add javadoc jar tasks as artifacts
artifacts {
- archives jar
- archives sourcesJar
archives javadocJar
}
-signing {
- required { project.has("release") && gradle.taskGraph.hasTask("uploadArchives") }
- sign configurations.archives
-}
diff --git a/gradle/src/build-test/groovy/com/android/build/gradle/AutomatedBuildTest.java b/gradle/src/build-test/groovy/com/android/build/gradle/AutomatedBuildTest.java
index b92239f..18e3277 100644
--- a/gradle/src/build-test/groovy/com/android/build/gradle/AutomatedBuildTest.java
+++ b/gradle/src/build-test/groovy/com/android/build/gradle/AutomatedBuildTest.java
@@ -35,10 +35,11 @@
private static final String[] sBuiltProjects = new String[] {
"aidl", "api", "applibtest", "assets", "attrOrder", "basic", "dependencies",
- "dependencyChecker", "flavored", "flavorlib", "flavors", "libTestDep", "libsTest",
- "localJars", "migrated", "multiproject", "multires", "overlay1", "overlay2",
- "pkgOverride", "proguard", "proguardLib", "renderscript", "renderscriptInLib",
- "renderscriptMultiSrc", "sameNamedLibs", "tictactoe" /*, "autorepo"*/
+ "dependencyChecker", "flavored", "flavorlib", "flavors", "genFolderApi",
+ "libProguardJarDep", "libProguardLibDep", "libTestDep", "libsTest", "localJars",
+ "migrated", "multiproject", "multires", "ndkSanAngeles", "ndkJniLib", "overlay1",
+ "overlay2", "pkgOverride", "proguard", "proguardLib", "renderscript", "renderscriptInLib",
+ "renderscriptMultiSrc", "rsSupportMode", "sameNamedLibs", "tictactoe" /*, "autorepo"*/
};
private static final String[] sReportProjects = new String[] {
@@ -50,6 +51,9 @@
suite.setName("AutomatedBuildTest");
for (String gradleVersion : BasePlugin.GRADLE_SUPPORTED_VERSIONS) {
+ if (isIgnoredGradleVersion(gradleVersion)) {
+ continue;
+ }
// first the project we build on all available versions of Gradle
for (String projectName : sBuiltProjects) {
String testName = "build_" + projectName + "_" + gradleVersion;
diff --git a/gradle/src/build-test/groovy/com/android/build/gradle/BuildTest.java b/gradle/src/build-test/groovy/com/android/build/gradle/BuildTest.java
index 8afb7ba..c81d0db 100644
--- a/gradle/src/build-test/groovy/com/android/build/gradle/BuildTest.java
+++ b/gradle/src/build-test/groovy/com/android/build/gradle/BuildTest.java
@@ -17,8 +17,10 @@
package com.android.build.gradle;
import com.android.build.gradle.internal.test.BaseTest;
+import com.google.common.collect.Lists;
import java.io.File;
+import java.util.Collection;
/**
* Base class for build tests.
@@ -27,14 +29,28 @@
* Android Source tree under out/host/<platform>/sdk/... (result of 'make sdk')
*/
abstract class BuildTest extends BaseTest {
+ private static final Collection<String> IGNORED_GRADLE_VERSIONS = Lists.newArrayList();
protected File testDir;
protected File sdkDir;
+ protected File ndkDir;
@Override
protected void setUp() throws Exception {
testDir = getTestDir();
sdkDir = getSdkDir();
+ ndkDir = getNdkDir();
+ }
+
+ /**
+ * Indicates whether the given Gradle version should be ignored in tests (for example, when a Gradle version has
+ * not been publicly released yet.)
+ *
+ * @param gradleVersion the given Gradle version.
+ * @return {@code true} if the given Gradle version should be ignored, {@code false} otherwise.
+ */
+ protected static boolean isIgnoredGradleVersion(String gradleVersion) {
+ return IGNORED_GRADLE_VERSIONS.contains(gradleVersion);
}
protected File buildProject(String name, String gradleVersion) {
@@ -45,12 +61,10 @@
File project = new File(testDir, name);
File buildGradle = new File(project, "build.gradle");
- if (!buildGradle.isFile()) {
- return null;
- }
+ assertTrue("Missing build.gradle for " + name, buildGradle.isFile());
// build the project
- runGradleTasks(sdkDir, gradleVersion, project, tasks);
+ runGradleTasks(sdkDir, ndkDir, gradleVersion, project, tasks);
return project;
}
diff --git a/gradle/src/build-test/groovy/com/android/build/gradle/ManualBuildTest.java b/gradle/src/build-test/groovy/com/android/build/gradle/ManualBuildTest.java
index 0ccfc24..e0c985b 100644
--- a/gradle/src/build-test/groovy/com/android/build/gradle/ManualBuildTest.java
+++ b/gradle/src/build-test/groovy/com/android/build/gradle/ManualBuildTest.java
@@ -16,6 +16,9 @@
package com.android.build.gradle;
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
@@ -29,36 +32,74 @@
*/
public class ManualBuildTest extends BuildTest {
+ private final static int RED = 0xFFFF0000;
+ private final static int GREEN = 0xFF00FF00;
+ private final static int BLUE = 0xFF0000FF;
+
public void testOverlay1Content() throws Exception {
File project = buildProject("overlay1", BasePlugin.GRADLE_MIN_VERSION);
File drawableOutput = new File(project, "build/res/all/debug/drawable");
- checkImageColor(drawableOutput, "no_overlay.png", (int) 0xFF00FF00);
- checkImageColor(drawableOutput, "type_overlay.png", (int) 0xFF00FF00);
+ checkImageColor(drawableOutput, "no_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "type_overlay.png", GREEN);
}
public void testOverlay2Content() throws Exception {
File project = buildProject("overlay2", BasePlugin.GRADLE_MIN_VERSION);
File drawableOutput = new File(project, "build/res/all/one/debug/drawable");
- checkImageColor(drawableOutput, "no_overlay.png", (int) 0xFF00FF00);
- checkImageColor(drawableOutput, "type_overlay.png", (int) 0xFF00FF00);
- checkImageColor(drawableOutput, "flavor_overlay.png", (int) 0xFF00FF00);
- checkImageColor(drawableOutput, "type_flavor_overlay.png", (int) 0xFF00FF00);
+ checkImageColor(drawableOutput, "no_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "type_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "flavor_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "type_flavor_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "variant_type_flavor_overlay.png", GREEN);
+ }
+
+ public void testOverlay3Content() throws Exception {
+ File project = buildProject("overlay3", BasePlugin.GRADLE_MIN_VERSION);
+ File drawableOutput = new File(project, "build/res/all/freebeta/debug/drawable");
+
+ checkImageColor(drawableOutput, "no_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "debug_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "beta_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "free_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "free_beta_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "free_beta_debug_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "free_normal_overlay.png", RED);
+
+ drawableOutput = new File(project, "build/res/all/freenormal/debug/drawable");
+
+ checkImageColor(drawableOutput, "no_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "debug_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "beta_overlay.png", RED);
+ checkImageColor(drawableOutput, "free_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "free_beta_overlay.png", RED);
+ checkImageColor(drawableOutput, "free_beta_debug_overlay.png", RED);
+ checkImageColor(drawableOutput, "free_normal_overlay.png", GREEN);
+
+ drawableOutput = new File(project, "build/res/all/paidbeta/debug/drawable");
+
+ checkImageColor(drawableOutput, "no_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "debug_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "beta_overlay.png", GREEN);
+ checkImageColor(drawableOutput, "free_overlay.png", RED);
+ checkImageColor(drawableOutput, "free_beta_overlay.png", RED);
+ checkImageColor(drawableOutput, "free_beta_debug_overlay.png", RED);
+ checkImageColor(drawableOutput, "free_normal_overlay.png", RED);
}
public void testRepo() {
File repo = new File(testDir, "repo");
try {
- runGradleTasks(sdkDir, BasePlugin.GRADLE_MIN_VERSION,
+ runGradleTasks(sdkDir, ndkDir, BasePlugin.GRADLE_MIN_VERSION,
new File(repo, "util"), "clean", "uploadArchives");
- runGradleTasks(sdkDir, BasePlugin.GRADLE_MIN_VERSION,
+ runGradleTasks(sdkDir, ndkDir, BasePlugin.GRADLE_MIN_VERSION,
new File(repo, "baseLibrary"), "clean", "uploadArchives");
- runGradleTasks(sdkDir, BasePlugin.GRADLE_MIN_VERSION,
+ runGradleTasks(sdkDir, ndkDir, BasePlugin.GRADLE_MIN_VERSION,
new File(repo, "library"), "clean", "uploadArchives");
- runGradleTasks(sdkDir, BasePlugin.GRADLE_MIN_VERSION,
+ runGradleTasks(sdkDir, ndkDir, BasePlugin.GRADLE_MIN_VERSION,
new File(repo, "app"), "clean", "assemble");
} finally {
// clean up the test repository.
@@ -67,11 +108,34 @@
}
}
+ // test whether a library project has its fields ProGuarded
+ public void testLibProguard() throws Exception {
+ File project = new File(testDir, "libProguard");
+ File fileOutput = new File(project, "build/proguard/release");
+
+ runGradleTasks(sdkDir, ndkDir, BasePlugin.GRADLE_MIN_VERSION,
+ project, "clean", "build");
+ checkFile(fileOutput, "mapping.txt", new String[]{"int proguardInt -> a"});
+
+ }
+
+ // test whether proguard.txt has been correctly merged
+ public void testLibProguardConsumerFile() throws Exception {
+ File project = new File(testDir, "libProguardConsumerFiles");
+ File debugFileOutput = new File(project, "build/bundles/debug");
+ File releaseFileOutput = new File(project, "build/bundles/release");
+
+ runGradleTasks(sdkDir, ndkDir, BasePlugin.GRADLE_MIN_VERSION,
+ project, "clean", "build");
+ checkFile(debugFileOutput, "proguard.txt", new String[]{"A"});
+ checkFile(releaseFileOutput, "proguard.txt", new String[]{"A", "B", "C"});
+ }
+
public void test3rdPartyTests() throws Exception {
// custom because we want to run deviceCheck even without devices, since we use
// a fake DeviceProvider that doesn't use a device, but only record the calls made
// to the DeviceProvider and the DeviceConnector.
- runGradleTasks(sdkDir, BasePlugin.GRADLE_MIN_VERSION,
+ runGradleTasks(sdkDir, ndkDir, BasePlugin.GRADLE_MIN_VERSION,
new File(testDir, "3rdPartyTests"), "clean", "deviceCheck");
}
@@ -86,4 +150,16 @@
expectedColor, rgb, f),
expectedColor, rgb);
}
+
+ private static void checkFile(File folder, String fileName, String[] expectedContents)
+ throws IOException {
+ File f = new File(folder, fileName);
+ assertTrue("File '" + f.getAbsolutePath() + "' does not exist.", f.isFile());
+
+ String contents = Files.toString(f, Charsets.UTF_8);
+ for (String expectedContent : expectedContents) {
+ assertTrue("File '" + f.getAbsolutePath() + "' does not contain: " + expectedContent,
+ contents.contains(expectedContent));
+ }
+ }
}
diff --git a/gradle/src/device-test/groovy/com/android/build/gradle/DeviceTest.java b/gradle/src/device-test/groovy/com/android/build/gradle/DeviceTest.java
index 93b53b6..0e410f1 100644
--- a/gradle/src/device-test/groovy/com/android/build/gradle/DeviceTest.java
+++ b/gradle/src/device-test/groovy/com/android/build/gradle/DeviceTest.java
@@ -39,8 +39,9 @@
private static final String[] sBuiltProjects = new String[] {
"api", "assets", "applibtest", "attrOrder", "basic", "dependencies", "flavored",
- "flavorlib", "flavors", "libTestDep", "libsTest", "migrated", "multires", "overlay1",
- "overlay2", "pkgOverride", "proguard", "proguardLib", "sameNamedLibs"
+ "flavorlib", "flavors", "libProguardJarDep", "libProguardLibDep", "libTestDep", "libsTest",
+ "migrated", "multires", "ndkJniLib", "overlay1", "overlay2", "pkgOverride", "proguard",
+ "proguardLib", "sameNamedLibs"
};
public static Test suite() {
@@ -48,6 +49,9 @@
suite.setName("DeviceTest");
for (String gradleVersion : BasePlugin.GRADLE_SUPPORTED_VERSIONS) {
+ if (isIgnoredGradleVersion(gradleVersion)) {
+ continue;
+ }
// first the project we build on all available versions of Gradle
for (String projectName : sBuiltProjects) {
String testName = "check_" + projectName + "_" + gradleVersion;
diff --git a/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/ClassPageRenderer.java b/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/ClassPageRenderer.java
index 223ca76..ee31146 100644
--- a/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/ClassPageRenderer.java
+++ b/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/ClassPageRenderer.java
@@ -21,7 +21,7 @@
import com.google.common.collect.Sets;
import org.gradle.api.internal.ErroringAction;
import org.gradle.api.internal.html.SimpleHtmlWriter;
-import org.gradle.api.internal.tasks.testing.junit.report.TestFailure;
+import org.gradle.api.internal.tasks.testing.junit.result.TestFailure;
import org.gradle.reporting.CodePanelRenderer;
import java.io.IOException;
diff --git a/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/TestResult.java b/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/TestResult.java
index a4435d5..90ecc8a 100644
--- a/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/TestResult.java
+++ b/gradle/src/fromGradle/groovy/com/android/build/gradle/internal/test/report/TestResult.java
@@ -15,7 +15,7 @@
*/
package com.android.build.gradle.internal.test.report;
-import org.gradle.api.internal.tasks.testing.junit.report.TestFailure;
+import org.gradle.api.internal.tasks.testing.junit.result.TestFailure;
import org.gradle.api.internal.tasks.testing.junit.report.TestResultModel;
import java.util.ArrayList;
@@ -101,7 +101,7 @@
public void addFailure(String message, String stackTrace,
String deviceName, String projectName, String flavorName) {
classResults.failed(this, deviceName, projectName, flavorName);
- failures.add(new TestFailure(message, stackTrace));
+ failures.add(new TestFailure(message, stackTrace, null));
}
public void ignored() {
diff --git a/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy
index 073aa7b..32a13ad 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy
@@ -15,7 +15,6 @@
*/
package com.android.build.gradle
-
import com.android.annotations.NonNull
import com.android.annotations.Nullable
import com.android.build.gradle.api.BaseVariant
@@ -57,7 +56,6 @@
import static com.android.builder.BuilderConstants.LINT
import static com.android.builder.BuilderConstants.RELEASE
import static com.android.builder.BuilderConstants.UI_TEST
-
/**
* Gradle plugin class for 'application' projects.
*/
@@ -141,7 +139,7 @@
throw new RuntimeException("BuildType names cannot collide with ProductFlavor names")
}
- def sourceSet = extension.sourceSetsContainer.create(name)
+ def sourceSet = extension.sourceSetsContainer.maybeCreate(name)
BuildTypeData buildTypeData = new BuildTypeData(buildType, sourceSet, project)
project.tasks.assemble.dependsOn buildTypeData.assembleTask
@@ -163,9 +161,9 @@
throw new RuntimeException("ProductFlavor names cannot collide with BuildType names")
}
- def mainSourceSet = (DefaultAndroidSourceSet) extension.sourceSetsContainer.create(productFlavor.name)
+ def mainSourceSet = (DefaultAndroidSourceSet) extension.sourceSetsContainer.maybeCreate(productFlavor.name)
String testName = "${INSTRUMENT_TEST}${productFlavor.name.capitalize()}"
- def testSourceSet = (DefaultAndroidSourceSet) extension.sourceSetsContainer.create(testName)
+ def testSourceSet = (DefaultAndroidSourceSet) extension.sourceSetsContainer.maybeCreate(testName)
ProductFlavorData<GroupableProductFlavorDsl> productFlavorData =
new ProductFlavorData<GroupableProductFlavorDsl>(
@@ -232,6 +230,12 @@
}
}
+ // Add a compile lint task
+ createLintCompileTask()
+
+ // create the lint tasks.
+ createLintTasks()
+
// create the test tasks.
createCheckTasks(!productFlavors.isEmpty(), false /*isLibrary*/)
@@ -289,13 +293,16 @@
for (BuildTypeData buildTypeData : buildTypes.values()) {
def variantConfig = new VariantConfiguration(
- defaultConfigData.productFlavor, defaultConfigData.sourceSet,
- buildTypeData.buildType, buildTypeData.sourceSet, project.name)
+ defaultConfigData.productFlavor,
+ defaultConfigData.sourceSet,
+ buildTypeData.buildType,
+ buildTypeData.sourceSet)
// create the variant and get its internal storage object.
ApplicationVariantData appVariantData = new ApplicationVariantData(variantConfig)
VariantDependencies variantDep = VariantDependencies.compute(
- project, appVariantData.name, buildTypeData, defaultConfigData.mainProvider)
+ project, appVariantData.variantConfiguration.fullName,
+ buildTypeData, defaultConfigData.mainProvider)
appVariantData.setVariantDependency(variantDep)
variantDataList.add(appVariantData)
@@ -309,10 +316,11 @@
// handle the test variant
def testVariantConfig = new VariantConfiguration(
- defaultConfigData.productFlavor, defaultConfigData.testSourceSet,
- testData.buildType, null,
- VariantConfiguration.Type.TEST, testedVariantData.variantConfiguration,
- project.name)
+ defaultConfigData.productFlavor,
+ defaultConfigData.testSourceSet,
+ testData.buildType,
+ null,
+ VariantConfiguration.Type.TEST, testedVariantData.variantConfiguration)
// create the internal storage for this variant.
def testVariantData = new TestVariantData(testVariantConfig, testedVariantData)
@@ -322,7 +330,8 @@
// dependencies for the test variant
VariantDependencies variantDep = VariantDependencies.compute(
- project, testVariantData.name, defaultConfigData.testProvider)
+ project, testVariantData.variantConfiguration.fullName,
+ defaultConfigData.testProvider)
testVariantData.setVariantDependency(variantDep)
// now loop on the VariantDependency and resolve them, and create the tasks
@@ -423,11 +432,21 @@
variantProviders.add(buildTypeData)
VariantConfiguration variantConfig = new VariantConfiguration(
- extension.defaultConfig, getDefaultConfigData().sourceSet,
- buildTypeData.buildType, buildTypeData.sourceSet, project.name)
+ extension.defaultConfig,
+ getDefaultConfigData().sourceSet,
+ buildTypeData.buildType,
+ buildTypeData.sourceSet)
for (ProductFlavorData data : flavorDataList) {
- variantConfig.addProductFlavor(data.productFlavor, data.sourceSet)
+ String dimensionName = "";
+ if (data.productFlavor instanceof GroupableProductFlavorDsl) {
+ dimensionName = ((GroupableProductFlavorDsl) data.productFlavor).flavorGroup
+ }
+ variantConfig.addProductFlavor(
+ data.productFlavor,
+ data.sourceSet,
+ dimensionName
+ )
variantProviders.add(data.mainProvider)
}
@@ -436,8 +455,21 @@
// create the variant and get its internal storage object.
ApplicationVariantData appVariantData = new ApplicationVariantData(variantConfig)
+
+ DefaultAndroidSourceSet variantSourceSet = (DefaultAndroidSourceSet) extension.sourceSetsContainer.maybeCreate(variantConfig.fullName)
+ variantConfig.setVariantSourceProvider(variantSourceSet)
+ // TODO: hmm this won't work
+ //variantProviders.add(new ConfigurationProviderImpl(project, variantSourceSet))
+
+ if (flavorDataList.size() > 1) {
+ DefaultAndroidSourceSet multiFlavorSourceSet = (DefaultAndroidSourceSet) extension.sourceSetsContainer.maybeCreate(variantConfig.flavorName)
+ variantConfig.setMultiFlavorSourceProvider(multiFlavorSourceSet)
+ // TODO: hmm this won't work
+ //variantProviders.add(new ConfigurationProviderImpl(project, multiFlavorSourceSet))
+ }
+
VariantDependencies variantDep = VariantDependencies.compute(
- project, appVariantData.name,
+ project, appVariantData.variantConfiguration.fullName,
variantProviders.toArray(new ConfigurationProvider[variantProviders.size()]))
appVariantData.setVariantDependency(variantDep)
@@ -452,10 +484,12 @@
// handle test variant
VariantConfiguration testVariantConfig = new VariantConfiguration(
- extension.defaultConfig, getDefaultConfigData().testSourceSet,
- testData.buildType, null,
+ extension.defaultConfig,
+ getDefaultConfigData().testSourceSet,
+ testData.buildType,
+ null,
VariantConfiguration.Type.TEST,
- testedVariantData.variantConfiguration, project.name)
+ testedVariantData.variantConfiguration)
/// add the container of dependencies
// the order of the libraries is important. In descending order:
@@ -463,7 +497,14 @@
List<ConfigurationProvider> testVariantProviders = []
for (ProductFlavorData data : flavorDataList) {
- testVariantConfig.addProductFlavor(data.productFlavor, data.testSourceSet)
+ String dimensionName = "";
+ if (data.productFlavor instanceof GroupableProductFlavorDsl) {
+ dimensionName = ((GroupableProductFlavorDsl) data.productFlavor).flavorGroup
+ }
+ testVariantConfig.addProductFlavor(
+ data.productFlavor,
+ data.testSourceSet,
+ dimensionName)
testVariantProviders.add(data.testProvider)
}
@@ -478,7 +519,7 @@
// dependencies for the test variant
VariantDependencies variantDep = VariantDependencies.compute(
- project, testVariantData.name,
+ project, testVariantData.variantConfiguration.fullName,
testVariantProviders.toArray(new ConfigurationProvider[testVariantProviders.size()]))
testVariantData.setVariantDependency(variantDep)
@@ -527,7 +568,7 @@
@NonNull ApplicationVariantData variant,
@Nullable Task assembleTask) {
- createPrepareDependenciesTask(variant)
+ createAnchorTasks(variant)
// Add a task to process the manifest(s)
createProcessManifestTask(variant, "manifests")
@@ -555,6 +596,9 @@
// Add a compile task
createCompileTask(variant, null/*testedVariant*/)
+ // Add NDK tasks
+ createNdkTasks(variant)
+
addPackageTasks(variant, assembleTask)
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/BaseExtension.groovy b/gradle/src/main/groovy/com/android/build/gradle/BaseExtension.groovy
index e800753..974fe16 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/BaseExtension.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/BaseExtension.groovy
@@ -17,9 +17,12 @@
import com.android.SdkConstants
import com.android.annotations.NonNull
+import com.android.annotations.Nullable
import com.android.build.gradle.api.AndroidSourceSet
+import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.TestVariant
import com.android.build.gradle.internal.CompileOptions
+import com.android.build.gradle.internal.SourceSetSourceProviderWrapper
import com.android.build.gradle.internal.dsl.AaptOptionsImpl
import com.android.build.gradle.internal.dsl.AndroidSourceSetFactory
import com.android.build.gradle.internal.dsl.DexOptionsImpl
@@ -27,6 +30,9 @@
import com.android.build.gradle.internal.test.TestOptions
import com.android.builder.BuilderConstants
import com.android.builder.DefaultProductFlavor
+import com.android.builder.model.BuildType
+import com.android.builder.model.ProductFlavor
+import com.android.builder.model.SourceProvider
import com.android.builder.testing.api.DeviceProvider
import com.android.builder.testing.api.TestServer
import com.android.sdklib.repository.FullRevision
@@ -38,8 +44,8 @@
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.internal.DefaultDomainObjectSet
import org.gradle.api.internal.project.ProjectInternal
+import org.gradle.api.tasks.SourceSet
import org.gradle.internal.reflect.Instantiator
-
/**
* Base android extension for all android plugins.
*/
@@ -72,7 +78,7 @@
this.plugin = plugin
defaultConfig = instantiator.newInstance(ProductFlavorDsl.class, BuilderConstants.MAIN,
- project.fileResolver)
+ project.fileResolver, instantiator)
aaptOptions = instantiator.newInstance(AaptOptionsImpl.class)
dexOptions = instantiator.newInstance(DexOptionsImpl.class)
@@ -201,6 +207,49 @@
testVariantList.add(testVariant)
}
+ public void registerArtifactType(@NonNull String name,
+ boolean isTest,
+ int artifactType) {
+ plugin.registerArtifactType(name, isTest, artifactType)
+ }
+
+ public void registerBuildTypeSourceProvider(
+ @NonNull String name,
+ @NonNull BuildType buildType,
+ @NonNull SourceProvider sourceProvider) {
+ plugin.registerBuildTypeSourceProvider(name, buildType, sourceProvider)
+ }
+
+ public void registerProductFlavorSourceProvider(
+ @NonNull String name,
+ @NonNull ProductFlavor productFlavor,
+ @NonNull SourceProvider sourceProvider) {
+ plugin.registerProductFlavorSourceProvider(name, productFlavor, sourceProvider)
+ }
+
+ public void registerJavaArtifact(
+ @NonNull String name,
+ @NonNull BaseVariant variant,
+ @NonNull String assembleTaskName,
+ @NonNull String javaCompileTaskName,
+ @NonNull File classesFolder,
+ @Nullable SourceProvider sourceProvider) {
+ plugin.registerJavaArtifact(name, variant, assembleTaskName, javaCompileTaskName,
+ classesFolder, sourceProvider)
+ }
+
+ public void registerMultiFlavorSourceProvider(
+ @NonNull String name,
+ @NonNull String flavorName,
+ @NonNull SourceProvider sourceProvider) {
+ plugin.registerMultiFlavorSourceProvider(name, flavorName, sourceProvider)
+ }
+
+ @NonNull
+ public SourceProvider wrapJavaSourceSet(@NonNull SourceSet sourceSet) {
+ return new SourceSetSourceProviderWrapper(sourceSet)
+ }
+
public String getCompileSdkVersion() {
return target
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
index e85c784..1e5fb45 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
@@ -19,6 +19,7 @@
import com.android.annotations.NonNull
import com.android.annotations.Nullable
import com.android.build.gradle.api.AndroidSourceSet
+import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.internal.BadPluginException
import com.android.build.gradle.internal.LoggerWrapper
import com.android.build.gradle.internal.ProductFlavorData
@@ -30,6 +31,8 @@
import com.android.build.gradle.internal.dependency.SymbolFileProviderImpl
import com.android.build.gradle.internal.dependency.VariantDependencies
import com.android.build.gradle.internal.dsl.SigningConfigDsl
+import com.android.build.gradle.internal.model.ArtifactMetaDataImpl
+import com.android.build.gradle.internal.model.JavaArtifactImpl
import com.android.build.gradle.internal.model.ModelBuilder
import com.android.build.gradle.internal.tasks.AndroidReportTask
import com.android.build.gradle.internal.tasks.DependencyReportTask
@@ -47,15 +50,19 @@
import com.android.build.gradle.internal.variant.ApkVariantData
import com.android.build.gradle.internal.variant.ApplicationVariantData
import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.DefaultSourceProviderContainer
import com.android.build.gradle.internal.variant.LibraryVariantData
import com.android.build.gradle.internal.variant.TestVariantData
import com.android.build.gradle.internal.variant.TestedVariantData
import com.android.build.gradle.tasks.AidlCompile
import com.android.build.gradle.tasks.Dex
import com.android.build.gradle.tasks.GenerateBuildConfig
+import com.android.build.gradle.tasks.Lint
import com.android.build.gradle.tasks.MergeAssets
import com.android.build.gradle.tasks.MergeResources
+import com.android.build.gradle.tasks.NdkCompile
import com.android.build.gradle.tasks.PackageApplication
+import com.android.build.gradle.tasks.PreDex
import com.android.build.gradle.tasks.ProcessAndroidResources
import com.android.build.gradle.tasks.ProcessAppManifest
import com.android.build.gradle.tasks.ProcessTestManifest
@@ -67,17 +74,25 @@
import com.android.builder.VariantConfiguration
import com.android.builder.dependency.JarDependency
import com.android.builder.dependency.LibraryDependency
+import com.android.builder.model.AndroidArtifact
+import com.android.builder.model.AndroidProject
+import com.android.builder.model.ArtifactMetaData
+import com.android.builder.model.BuildType
+import com.android.builder.model.JavaArtifact
import com.android.builder.model.ProductFlavor
import com.android.builder.model.SigningConfig
import com.android.builder.model.SourceProvider
+import com.android.builder.model.SourceProviderContainer
import com.android.builder.testing.ConnectedDeviceProvider
import com.android.builder.testing.api.DeviceProvider
import com.android.builder.testing.api.TestServer
import com.android.utils.ILogger
import com.google.common.collect.ArrayListMultimap
+import com.google.common.collect.ListMultimap
import com.google.common.collect.Lists
import com.google.common.collect.Maps
import com.google.common.collect.Multimap
+import com.google.common.collect.Sets
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Project
@@ -87,11 +102,14 @@
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.SelfResolvingDependency
+import org.gradle.api.artifacts.result.DependencyResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.artifacts.result.ResolvedModuleVersionResult
+import org.gradle.api.artifacts.result.UnresolvedDependencyResult
import org.gradle.api.logging.LogLevel
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPlugin
+import org.gradle.api.specs.Specs
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.internal.reflect.Instantiator
@@ -113,13 +131,16 @@
import static com.android.builder.BuilderConstants.FD_INSTRUMENT_TESTS
import static com.android.builder.BuilderConstants.FD_REPORTS
import static com.android.builder.BuilderConstants.INSTRUMENT_TEST
+import static java.io.File.separator
/**
* Base class for all Android plugins
*/
public abstract class BasePlugin {
- public static final String GRADLE_MIN_VERSION = "1.6"
- public static final String[] GRADLE_SUPPORTED_VERSIONS = [ GRADLE_MIN_VERSION, "1.7" ]
+ protected final static String DIR_BUNDLES = "bundles";
+
+ public static final String GRADLE_MIN_VERSION = "1.9"
+ public static final String[] GRADLE_SUPPORTED_VERSIONS = [ GRADLE_MIN_VERSION ]
public static final String INSTALL_GROUP = "Install"
@@ -142,13 +163,18 @@
private boolean hasCreatedTasks = false
private ProductFlavorData<DefaultProductFlavor> defaultConfigData
+ private final Collection<String> unresolvedDependencies = Sets.newHashSet();
+
protected DefaultAndroidSourceSet mainSourceSet
protected DefaultAndroidSourceSet testSourceSet
+ protected Task mainPreBuild
protected Task uninstallAll
protected Task assembleTest
protected Task deviceCheck
protected Task connectedCheck
+ protected Task lint
+ protected Task lintCompile
protected BasePlugin(Instantiator instantiator, ToolingModelBuilderRegistry registry) {
this.instantiator = instantiator
@@ -190,6 +216,21 @@
connectedCheck.description = "Runs all device checks on currently connected devices."
connectedCheck.group = JavaBasePlugin.VERIFICATION_GROUP
+ mainPreBuild = project.tasks.create("preBuild")
+
+ lint = project.tasks.create("lint", Lint)
+ lint.description = "Runs lint on all variants."
+ lint.group = JavaBasePlugin.VERIFICATION_GROUP
+ lint.setPlugin(this)
+ int count = variantDataList.size()
+ for (int i = 0 ; i < count ; i++) {
+ final BaseVariantData baseVariantData = variantDataList.get(i)
+ if (isLintVariant(baseVariantData)) {
+ lint.dependsOn baseVariantData.javaCompileTask
+ }
+ }
+ project.tasks.check.dependsOn lint
+
project.afterEvaluate {
createAndroidTasks(false)
}
@@ -215,10 +256,15 @@
}
if (!foundMatch) {
+ File file = new File("gradle" + separator + "wrapper" + separator +
+ "gradle-wrapper.properties");
throw new BuildException(
- String.format(
- "Gradle version %s is required. Current version is %s",
- GRADLE_MIN_VERSION, project.getGradle().gradleVersion), null);
+ String.format(
+ "Gradle version %s is required. Current version is %s. " +
+ "If using the gradle wrapper, try editing the distributionUrl in %s " +
+ "to gradle-%s-all.zip",
+ GRADLE_MIN_VERSION, project.getGradle().gradleVersion, file.getAbsolutePath(),
+ GRADLE_MIN_VERSION), null);
}
}
@@ -263,6 +309,10 @@
return defaultConfigData
}
+ Collection<String> getUnresolvedDependencies() {
+ return unresolvedDependencies
+ }
+
SdkParser getSdkParser() {
return sdk.parser
}
@@ -272,7 +322,11 @@
}
File getSdkDirectory() {
- return sdk.directory
+ return sdk.sdkDirectory
+ }
+
+ File getNdkDirectory() {
+ return sdk.ndkDirectory
}
ILogger getLogger() {
@@ -293,6 +347,9 @@
if (androidBuilder == null) {
SdkParser parser = getLoadedSdkParser()
androidBuilder = new AndroidBuilder(parser, creator, logger, verbose)
+ if (this instanceof LibraryPlugin) {
+ androidBuilder.setBuildingLibrary(true);
+ }
builders.put(variantData, androidBuilder)
}
@@ -312,7 +369,8 @@
protected void createProcessManifestTask(BaseVariantData variantData,
String manifestOurDir) {
- def processManifestTask = project.tasks.create("process${variantData.name}Manifest",
+ def processManifestTask = project.tasks.create(
+ "process${variantData.variantConfiguration.fullName.capitalize()}Manifest",
ProcessAppManifest)
variantData.processManifestTask = processManifestTask
processManifestTask.dependsOn variantData.prepareDependenciesTask
@@ -339,7 +397,7 @@
getManifestDependencies(config.directLibraries)
}
processManifestTask.conventionMapping.versionCode = {
- mergedFlavor.versionCode
+ config.versionCode
}
processManifestTask.conventionMapping.minSdkVersion = {
mergedFlavor.minSdkVersion
@@ -349,13 +407,14 @@
}
processManifestTask.conventionMapping.manifestOutputFile = {
project.file(
- "$project.buildDir/${manifestOurDir}/$variantData.dirName/AndroidManifest.xml")
+ "$project.buildDir/${manifestOurDir}/${variantData.variantConfiguration.dirName}/AndroidManifest.xml")
}
}
protected void createProcessTestManifestTask(BaseVariantData variantData,
String manifestOurDir) {
- def processTestManifestTask = project.tasks.create("process${variantData.name}TestManifest",
+ def processTestManifestTask = project.tasks.create(
+ "process${variantData.variantConfiguration.fullName.capitalize()}Manifest",
ProcessTestManifest)
variantData.processManifestTask = processTestManifestTask
processTestManifestTask.dependsOn variantData.prepareDependenciesTask
@@ -380,27 +439,44 @@
processTestManifestTask.conventionMapping.instrumentationRunner = {
config.instrumentationRunner
}
+ processTestManifestTask.conventionMapping.handleProfiling = {
+ config.handleProfiling
+ }
+ processTestManifestTask.conventionMapping.functionalTest = {
+ config.functionalTest
+ }
processTestManifestTask.conventionMapping.libraries = {
getManifestDependencies(config.directLibraries)
}
processTestManifestTask.conventionMapping.manifestOutputFile = {
project.file(
- "$project.buildDir/${manifestOurDir}/$variantData.dirName/AndroidManifest.xml")
+ "$project.buildDir/${manifestOurDir}/${variantData.variantConfiguration.dirName}/AndroidManifest.xml")
}
}
protected void createRenderscriptTask(BaseVariantData variantData) {
VariantConfiguration config = variantData.variantConfiguration
- def renderscriptTask = project.tasks.create("compile${variantData.name}Renderscript",
+ def renderscriptTask = project.tasks.create(
+ "compile${variantData.variantConfiguration.fullName.capitalize()}Renderscript",
RenderscriptCompile)
variantData.renderscriptCompileTask = renderscriptTask
+ ProductFlavor mergedFlavor = config.mergedFlavor
+ boolean ndkMode = mergedFlavor.renderscriptNdkMode
+
+ // only put this dependency if rs will generate Java code
+ if (!ndkMode) {
+ variantData.sourceGenTask.dependsOn renderscriptTask
+ }
+
renderscriptTask.dependsOn variantData.prepareDependenciesTask
renderscriptTask.plugin = this
renderscriptTask.variant = variantData
- renderscriptTask.targetApi = config.mergedFlavor.renderscriptTargetApi
+ renderscriptTask.targetApi = mergedFlavor.renderscriptTargetApi
+ renderscriptTask.supportMode = mergedFlavor.renderscriptSupportMode
+ renderscriptTask.ndkMode = ndkMode
renderscriptTask.debugBuild = config.buildType.renderscriptDebugBuild
renderscriptTask.optimLevel = config.buildType.renderscriptOptimLevel
@@ -408,11 +484,18 @@
renderscriptTask.conventionMapping.importDirs = { config.renderscriptImports }
renderscriptTask.conventionMapping.sourceOutputDir = {
- project.file("$project.buildDir/source/rs/$variantData.dirName")
+ project.file("$project.buildDir/source/rs/${variantData.variantConfiguration.dirName}")
}
renderscriptTask.conventionMapping.resOutputDir = {
- project.file("$project.buildDir/res/rs/$variantData.dirName")
+ project.file("$project.buildDir/res/rs/${variantData.variantConfiguration.dirName}")
}
+ renderscriptTask.conventionMapping.objOutputDir = {
+ project.file("$project.buildDir/rs/${variantData.variantConfiguration.dirName}/obj")
+ }
+ renderscriptTask.conventionMapping.libOutputDir = {
+ project.file("$project.buildDir/rs/${variantData.variantConfiguration.dirName}/lib")
+ }
+ renderscriptTask.conventionMapping.ndkConfig = { config.ndkConfig }
}
protected void createMergeResourcesTask(@NonNull BaseVariantData variantData,
@@ -420,7 +503,7 @@
MergeResources mergeResourcesTask = basicCreateMergeResourcesTask(
variantData,
"merge",
- "$project.buildDir/res/all/$variantData.dirName",
+ "$project.buildDir/res/all/${variantData.variantConfiguration.dirName}",
true /*includeDependencies*/,
process9Patch)
variantData.mergeResourcesTask = mergeResourcesTask
@@ -433,13 +516,14 @@
final boolean includeDependencies,
final boolean process9Patch) {
MergeResources mergeResourcesTask = project.tasks.create(
- "$taskNamePrefix${variantData.name}Resources", MergeResources)
+ "$taskNamePrefix${variantData.variantConfiguration.fullName.capitalize()}Resources",
+ MergeResources)
mergeResourcesTask.dependsOn variantData.prepareDependenciesTask, variantData.renderscriptCompileTask
mergeResourcesTask.plugin = this
mergeResourcesTask.variant = variantData
mergeResourcesTask.incrementalFolder = project.file(
- "$project.buildDir/incremental/${taskNamePrefix}Resources/$variantData.dirName")
+ "$project.buildDir/incremental/${taskNamePrefix}Resources/${variantData.variantConfiguration.dirName}")
mergeResourcesTask.process9Patch = process9Patch
@@ -458,17 +542,19 @@
@Nullable String outputLocation,
final boolean includeDependencies) {
if (outputLocation == null) {
- outputLocation = "$project.buildDir/assets/$variantData.dirName"
+ outputLocation = "$project.buildDir/assets/${variantData.variantConfiguration.dirName}"
}
- def mergeAssetsTask = project.tasks.create("merge${variantData.name}Assets", MergeAssets)
+ def mergeAssetsTask = project.tasks.create(
+ "merge${variantData.variantConfiguration.fullName.capitalize()}Assets",
+ MergeAssets)
variantData.mergeAssetsTask = mergeAssetsTask
mergeAssetsTask.dependsOn variantData.prepareDependenciesTask
mergeAssetsTask.plugin = this
mergeAssetsTask.variant = variantData
mergeAssetsTask.incrementalFolder =
- project.file("$project.buildDir/incremental/mergeAssets/$variantData.dirName")
+ project.file("$project.buildDir/incremental/mergeAssets/${variantData.variantConfiguration.dirName}")
mergeAssetsTask.conventionMapping.inputAssetSets = {
variantData.variantConfiguration.getAssetSets(includeDependencies)
@@ -478,11 +564,13 @@
protected void createBuildConfigTask(BaseVariantData variantData) {
def generateBuildConfigTask = project.tasks.create(
- "generate${variantData.name}BuildConfig", GenerateBuildConfig)
+ "generate${variantData.variantConfiguration.fullName.capitalize()}BuildConfig",
+ GenerateBuildConfig)
variantData.generateBuildConfigTask = generateBuildConfigTask
VariantConfiguration variantConfiguration = variantData.variantConfiguration
+ variantData.sourceGenTask.dependsOn generateBuildConfigTask
if (variantConfiguration.type == VariantConfiguration.Type.TEST) {
// in case of a test project, the manifest is generated so we need to depend
// on its creation.
@@ -492,31 +580,58 @@
generateBuildConfigTask.plugin = this
generateBuildConfigTask.variant = variantData
- generateBuildConfigTask.conventionMapping.packageName = {
+ generateBuildConfigTask.conventionMapping.buildConfigPackageName = {
variantConfiguration.originalPackageName
}
+ generateBuildConfigTask.conventionMapping.appPackageName = {
+ variantConfiguration.packageName
+ }
+
+ generateBuildConfigTask.conventionMapping.versionName = {
+ variantConfiguration.versionName
+ }
+
+ generateBuildConfigTask.conventionMapping.versionCode = {
+ variantConfiguration.versionCode
+ }
+
generateBuildConfigTask.conventionMapping.debuggable = {
variantConfiguration.buildType.isDebuggable()
}
- generateBuildConfigTask.conventionMapping.javaLines = {
- variantConfiguration.buildConfigLines
+ generateBuildConfigTask.conventionMapping.buildTypeName = {
+ variantConfiguration.buildType.name
+ }
+
+ generateBuildConfigTask.conventionMapping.flavorName = {
+ variantConfiguration.flavorName
+ }
+
+ generateBuildConfigTask.conventionMapping.flavorNamesWithDimensionNames = {
+ variantConfiguration.flavorNamesWithDimensionNames
+ }
+
+ generateBuildConfigTask.conventionMapping.items = {
+ variantConfiguration.buildConfigItems
}
generateBuildConfigTask.conventionMapping.sourceOutputDir = {
- project.file("$project.buildDir/source/buildConfig/${variantData.dirName}")
+ project.file("$project.buildDir/source/buildConfig/${variantData.variantConfiguration.dirName}")
}
}
protected void createProcessResTask(BaseVariantData variantData) {
- createProcessResTask(variantData, "$project.buildDir/symbols/$variantData.dirName")
+ createProcessResTask(variantData, "$project.buildDir/symbols/${variantData.variantConfiguration.dirName}")
}
protected void createProcessResTask(BaseVariantData variantData, final String symbolLocation) {
- def processResources = project.tasks.create("process${variantData.name}Resources",
+ def processResources = project.tasks.create(
+ "process${variantData.variantConfiguration.fullName.capitalize()}Resources",
ProcessAndroidResources)
variantData.processResourcesTask = processResources
+
+ variantData.sourceGenTask.dependsOn processResources
processResources.dependsOn variantData.processManifestTask, variantData.mergeResourcesTask, variantData.mergeAssetsTask
processResources.plugin = this
@@ -545,32 +660,34 @@
// TODO: unify with generateBuilderConfig, compileAidl, and library packaging somehow?
processResources.conventionMapping.sourceOutputDir = {
- project.file("$project.buildDir/source/r/$variantData.dirName")
+ project.file("$project.buildDir/source/r/${variantData.variantConfiguration.dirName}")
}
processResources.conventionMapping.textSymbolOutputDir = {
project.file(symbolLocation)
}
processResources.conventionMapping.packageOutputFile = {
project.file(
- "$project.buildDir/libs/${project.archivesBaseName}-${variantData.baseName}.ap_")
+ "$project.buildDir/libs/${project.archivesBaseName}-${variantData.variantConfiguration.baseName}.ap_")
}
- if (variantData.runProguard) {
+ if (variantConfiguration.buildType.runProguard) {
processResources.conventionMapping.proguardOutputFile = {
- project.file("$project.buildDir/proguard/${variantData.dirName}/aapt_rules.txt")
+ project.file("$project.buildDir/proguard/${variantData.variantConfiguration.dirName}/aapt_rules.txt")
}
}
processResources.conventionMapping.type = { variantConfiguration.type }
processResources.conventionMapping.debuggable = { variantConfiguration.buildType.debuggable }
processResources.conventionMapping.aaptOptions = { extension.aaptOptions }
+ processResources.conventionMapping.resourceConfigs = { variantConfiguration.mergedFlavor.resourceConfigurations }
}
protected void createProcessJavaResTask(BaseVariantData variantData) {
VariantConfiguration variantConfiguration = variantData.variantConfiguration
- Copy processResources = project.tasks.create("process${variantData.name}JavaRes",
+ Copy processResources = project.tasks.create(
+ "process${variantData.variantConfiguration.fullName.capitalize()}JavaRes",
ProcessResources);
- variantData.processJavaResources = processResources
+ variantData.processJavaResourcesTask = processResources
// set the input
processResources.from(((AndroidSourceSet) variantConfiguration.defaultSourceSet).resources)
@@ -580,58 +697,65 @@
((AndroidSourceSet) variantConfiguration.buildTypeSourceSet).resources)
}
if (variantConfiguration.hasFlavors()) {
- for (SourceProvider flavorSourceSet : variantConfiguration.flavorSourceSets) {
+ for (SourceProvider flavorSourceSet : variantConfiguration.flavorSourceProviders) {
processResources.from(((AndroidSourceSet) flavorSourceSet).resources)
}
}
processResources.conventionMapping.destinationDir = {
- project.file("$project.buildDir/javaResources/$variantData.dirName")
+ project.file("$project.buildDir/javaResources/${variantData.variantConfiguration.dirName}")
}
}
protected void createAidlTask(BaseVariantData variantData) {
VariantConfiguration variantConfiguration = variantData.variantConfiguration
- def compileTask = project.tasks.create("compile${variantData.name}Aidl", AidlCompile)
+ def compileTask = project.tasks.create(
+ "compile${variantData.variantConfiguration.fullName.capitalize()}Aidl",
+ AidlCompile)
variantData.aidlCompileTask = compileTask
+
+ variantData.sourceGenTask.dependsOn compileTask
variantData.aidlCompileTask.dependsOn variantData.prepareDependenciesTask
compileTask.plugin = this
compileTask.variant = variantData
compileTask.incrementalFolder =
- project.file("$project.buildDir/incremental/aidl/$variantData.dirName")
-
+ project.file("$project.buildDir/incremental/aidl/${variantData.variantConfiguration.dirName}")
compileTask.conventionMapping.sourceDirs = { variantConfiguration.aidlSourceList }
compileTask.conventionMapping.importDirs = { variantConfiguration.aidlImports }
compileTask.conventionMapping.sourceOutputDir = {
- project.file("$project.buildDir/source/aidl/$variantData.dirName")
+ project.file("$project.buildDir/source/aidl/${variantData.variantConfiguration.dirName}")
}
}
protected void createCompileTask(BaseVariantData variantData,
BaseVariantData testedVariantData) {
- def compileTask = project.tasks.create("compile${variantData.name}", JavaCompile)
+ def compileTask = project.tasks.create(
+ "compile${variantData.variantConfiguration.fullName.capitalize()}Java",
+ JavaCompile)
variantData.javaCompileTask = compileTask
- compileTask.dependsOn variantData.processResourcesTask, variantData.generateBuildConfigTask, variantData.aidlCompileTask
+ compileTask.dependsOn variantData.sourceGenTask
VariantConfiguration config = variantData.variantConfiguration
- List<Object> sourceList = new ArrayList<Object>();
+ List<Object> sourceList = Lists.newArrayList()
sourceList.add(((AndroidSourceSet) config.defaultSourceSet).java)
sourceList.add({ variantData.processResourcesTask.sourceOutputDir })
sourceList.add({ variantData.generateBuildConfigTask.sourceOutputDir })
sourceList.add({ variantData.aidlCompileTask.sourceOutputDir })
- sourceList.add({ variantData.renderscriptCompileTask.sourceOutputDir })
+ if (!config.mergedFlavor.renderscriptNdkMode) {
+ sourceList.add({ variantData.renderscriptCompileTask.sourceOutputDir })
+ }
if (config.getType() != VariantConfiguration.Type.TEST) {
sourceList.add(((AndroidSourceSet) config.buildTypeSourceSet).java)
}
if (config.hasFlavors()) {
- for (SourceProvider flavorSourceSet : config.flavorSourceSets) {
- sourceList.add(((AndroidSourceSet) flavorSourceSet).java)
+ for (SourceProvider flavorSourceProvider : config.flavorSourceProviders) {
+ sourceList.add(((AndroidSourceSet) flavorSourceProvider).java)
}
}
compileTask.source = sourceList.toArray()
@@ -641,11 +765,11 @@
// dependency.
if (testedVariantData instanceof ApplicationVariantData) {
compileTask.conventionMapping.classpath = {
- project.files(config.compileClasspath) + testedVariantData.javaCompileTask.classpath + testedVariantData.javaCompileTask.outputs.files
+ project.files(getAndroidBuilder(variantData).getCompileClasspath(config)) + testedVariantData.javaCompileTask.classpath + testedVariantData.javaCompileTask.outputs.files
}
} else {
compileTask.conventionMapping.classpath = {
- project.files(config.compileClasspath)
+ project.files(getAndroidBuilder(variantData).getCompileClasspath(config))
}
}
@@ -654,10 +778,10 @@
compileTask.dependsOn project.configurations.compile.buildDependencies
compileTask.conventionMapping.destinationDir = {
- project.file("$project.buildDir/classes/$variantData.dirName")
+ project.file("$project.buildDir/classes/${variantData.variantConfiguration.dirName}")
}
compileTask.conventionMapping.dependencyCacheDir = {
- project.file("$project.buildDir/dependency-cache/$variantData.dirName")
+ project.file("$project.buildDir/dependency-cache/${variantData.variantConfiguration.dirName}")
}
// set source/target compatibility
@@ -667,6 +791,7 @@
compileTask.conventionMapping.targetCompatibility = {
extension.compileOptions.targetCompatibility.toString()
}
+ compileTask.options.encoding = extension.compileOptions.encoding
// setup the boot classpath just before the task actually runs since this will
// force the sdk to be parsed.
@@ -675,6 +800,57 @@
}
}
+ protected void createNdkTasks(@NonNull BaseVariantData variantData) {
+ createNdkTasks(
+ variantData,
+ { project.file("$project.buildDir/ndk/${variantData.variantConfiguration.dirName}/lib") }
+ )
+ }
+
+ protected void createNdkTasks(@NonNull BaseVariantData variantData,
+ @NonNull Closure<File> soFolderClosure) {
+ NdkCompile ndkCompile = project.tasks.create(
+ "compile${variantData.variantConfiguration.fullName.capitalize()}Ndk",
+ NdkCompile)
+
+ ndkCompile.plugin = this
+ ndkCompile.variant = variantData
+ variantData.ndkCompileTask = ndkCompile
+
+ VariantConfiguration variantConfig = variantData.variantConfiguration
+
+ if (variantConfig.mergedFlavor.renderscriptNdkMode) {
+ ndkCompile.ndkRenderScriptMode = true
+ ndkCompile.dependsOn variantData.renderscriptCompileTask
+ } else {
+ ndkCompile.ndkRenderScriptMode = false
+ }
+
+ ndkCompile.conventionMapping.sourceFolders = {
+ List<File> sourceList = variantConfig.jniSourceList
+ if (variantConfig.mergedFlavor.renderscriptNdkMode) {
+ sourceList.add(variantData.renderscriptCompileTask.sourceOutputDir)
+ }
+
+ return sourceList
+ }
+
+ ndkCompile.conventionMapping.generatedMakefile = {
+ project.file("$project.buildDir/ndk/${variantData.variantConfiguration.dirName}/Android.mk")
+ }
+
+ ndkCompile.conventionMapping.ndkConfig = { variantConfig.ndkConfig }
+
+ ndkCompile.conventionMapping.debuggable = {
+ variantConfig.buildType.jniDebugBuild
+ }
+
+ ndkCompile.conventionMapping.objFolder = {
+ project.file("$project.buildDir/ndk/${variantData.variantConfiguration.dirName}/obj")
+ }
+ ndkCompile.conventionMapping.soFolder = soFolderClosure
+ }
+
/**
* Creates the tasks to build the test apk.
*
@@ -688,10 +864,10 @@
// to test both.
if (!variantData.isSigned()) {
throw new GradleException(
- "Tested Variant '${testedVariantData.name}' is not configured to create a signed APK.")
+ "Tested Variant '${testedVariantData.variantConfiguration.fullName}' is not configured to create a signed APK.")
}
- createPrepareDependenciesTask(variantData)
+ createAnchorTasks(variantData)
// Add a task to process the manifest
createProcessTestManifestTask(variantData, "manifests")
@@ -727,6 +903,9 @@
// Add a task to compile the test application
createCompileTask(variantData, testedVariantData)
+ // Add NDK tasks
+ createNdkTasks(variantData)
+
addPackageTasks(variantData, null)
if (assembleTest != null) {
@@ -734,6 +913,54 @@
}
}
+ // TODO - should compile src/lint/java from src/lint/java and jar it into build/lint/lint.jar
+ protected void createLintCompileTask() {
+ lintCompile = project.tasks.create("compileLint", Task)
+ File outputDir = new File("$project.buildDir/lint")
+
+ lintCompile.doFirst{
+ // create the directory for lint output if it does not exist.
+ if (!outputDir.exists()) {
+ boolean mkdirs = outputDir.mkdirs();
+ if (!mkdirs) {
+ throw new GradleException("Unable to create lint output directory.")
+ }
+ }
+ }
+ }
+
+ /** Is the given variant relevant for lint? */
+ private static boolean isLintVariant(@NonNull BaseVariantData baseVariantData) {
+ // Only create lint targets for variants like debug and release, not debugTest
+ VariantConfiguration config = baseVariantData.variantConfiguration
+ return config.getType() != VariantConfiguration.Type.TEST;
+ }
+
+ // Add tasks for running lint on individual variants. We've already added a
+ // lint task earlier which runs on all variants.
+ protected void createLintTasks() {
+ int count = variantDataList.size()
+ for (int i = 0 ; i < count ; i++) {
+ final BaseVariantData baseVariantData = variantDataList.get(i)
+ if (!isLintVariant(baseVariantData)) {
+ continue;
+ }
+
+ String variantName = baseVariantData.variantConfiguration.fullName
+ def capitalizedVariantName = variantName.capitalize()
+ Task lintCheck = project.tasks.create("lint" + capitalizedVariantName, Lint)
+ lintCheck.dependsOn baseVariantData.javaCompileTask, lintCompile
+ // Note that we don't do "lint.dependsOn lintCheck"; the "lint" target will
+ // on its own run through all variants (and compare results), it doesn't delegate
+ // to the individual tasks (since it needs to coordinate data collection and
+ // reporting)
+ lintCheck.setPlugin(this)
+ lintCheck.setVariantName(variantName)
+ lintCheck.description = "Runs lint on the " + capitalizedVariantName + " build"
+ lintCheck.group = JavaBasePlugin.VERIFICATION_GROUP
+ }
+ }
+
protected void createCheckTasks(boolean hasFlavors, boolean isLibraryTest) {
List<AndroidReportTask> reportTasks = Lists.newArrayListWithExpectedSize(2)
@@ -813,8 +1040,8 @@
// first the connected one.
def connectedTask = createDeviceProviderInstrumentTestTask(
hasFlavors ?
- "${connectedRootName}${baseVariantData.name}" : connectedRootName,
- "Installs and runs the tests for Build '${baseVariantData.name}' on connected devices.",
+ "${connectedRootName}${baseVariantData.variantConfiguration.fullName.capitalize()}" : connectedRootName,
+ "Installs and runs the tests for Build '${baseVariantData.variantConfiguration.fullName}' on connected devices.",
isLibraryTest ?
DeviceProviderInstrumentTestLibraryTask :
DeviceProviderInstrumentTestTask,
@@ -831,9 +1058,9 @@
for (DeviceProvider deviceProvider : providers) {
DefaultTask providerTask = createDeviceProviderInstrumentTestTask(
hasFlavors ?
- "${deviceProvider.name}${INSTRUMENT_TEST.capitalize()}${baseVariantData.name}" :
+ "${deviceProvider.name}${INSTRUMENT_TEST.capitalize()}${baseVariantData.variantConfiguration.fullName.capitalize()}" :
"${deviceProvider.name}${INSTRUMENT_TEST.capitalize()}",
- "Installs and runs the tests for Build '${baseVariantData.name}' using Provider '${deviceProvider.name.capitalize()}'.",
+ "Installs and runs the tests for Build '${baseVariantData.variantConfiguration.fullName}' using Provider '${deviceProvider.name.capitalize()}'.",
isLibraryTest ?
DeviceProviderInstrumentTestLibraryTask :
DeviceProviderInstrumentTestTask,
@@ -856,10 +1083,10 @@
for (TestServer testServer : servers) {
DefaultTask serverTask = project.tasks.create(
hasFlavors ?
- "${testServer.name}${"upload".capitalize()}${baseVariantData.name}" :
+ "${testServer.name}${"upload".capitalize()}${baseVariantData.variantConfiguration.fullName}" :
"${testServer.name}${"upload".capitalize()}",
TestServerTask)
- serverTask.description = "Uploads APKs for Build '${baseVariantData.name}' to Test Server '${testServer.name.capitalize()}'."
+ serverTask.description = "Uploads APKs for Build '${baseVariantData.variantConfiguration.fullName}' to Test Server '${testServer.name.capitalize()}'."
serverTask.group = JavaBasePlugin.VERIFICATION_GROUP
serverTask.dependsOn testVariantData.assembleTask, baseVariantData.assembleTask
@@ -870,7 +1097,7 @@
serverTask.conventionMapping.testedApk = { baseVariantData.outputFile }
}
- serverTask.conventionMapping.variantName = { baseVariantData.name }
+ serverTask.conventionMapping.variantName = { baseVariantData.variantConfiguration.fullName }
deviceCheck.dependsOn serverTask
@@ -916,7 +1143,7 @@
testTask.plugin = this
testTask.variant = variantData
- testTask.flavorName = variantData.flavorName
+ testTask.flavorName = variantData.variantConfiguration.flavorName.capitalize()
testTask.deviceProvider = deviceProvider
testTask.conventionMapping.testApp = { variantData.outputFile }
@@ -929,7 +1156,7 @@
extension.testOptions.resultsDir :
"$project.buildDir/$FD_INSTRUMENT_RESULTS"
- String flavorFolder = variantData.flavorDirName
+ String flavorFolder = variantData.variantConfiguration.flavorName
if (!flavorFolder.isEmpty()) {
flavorFolder = "$FD_FLAVORS/" + flavorFolder
}
@@ -941,7 +1168,7 @@
extension.testOptions.reportDir :
"$project.buildDir/$FD_REPORTS/$FD_INSTRUMENT_TESTS"
- String flavorFolder = variantData.flavorDirName
+ String flavorFolder = variantData.variantConfiguration.flavorName
if (!flavorFolder.isEmpty()) {
flavorFolder = "$FD_FLAVORS/" + flavorFolder
}
@@ -960,113 +1187,116 @@
*/
protected void addPackageTasks(@NonNull ApkVariantData variantData,
@Nullable Task assembleTask) {
-
VariantConfiguration variantConfig = variantData.variantConfiguration
- Closure libraryClosure = { project.files(variantConfig.packagedJars) }
- Closure sourceClosure = { variantData.javaCompileTask.outputs.files }
- Closure proguardFileClosure = { }
+ boolean runProguard = variantConfig.buildType.runProguard &&
+ (variantConfig.type != VariantConfiguration.Type.TEST ||
+ (variantConfig.type == VariantConfiguration.Type.TEST &&
+ variantConfig.testedConfig.type != VariantConfiguration.Type.LIBRARY))
- if (!(variantData instanceof TestVariantData) && variantConfig.buildType.runProguard) {
-
- def proguardTask = project.tasks.create("proguard${variantData.name}", ProGuardTask);
- proguardTask.dependsOn variantData.javaCompileTask
- variantData.proguardTask = proguardTask
-
- File outFile = project.file(
- "${project.buildDir}/classes-proguard/${variantData.dirName}/classes.jar")
-
- libraryClosure = { Collections.emptyList() }
- sourceClosure = { Collections.emptyList() }
- proguardFileClosure = { outFile }
-
- // because the Proguard task acts on all the config right away and not when the
- // task actually runs, let's configure it in its doFirst
-
- proguardTask.doFirst {
-
- // all the config files coming from build type, product flavors.
- List<Object> proguardFiles = variantConfig.getProguardFiles(true /*includeLibs*/);
- for (Object proguardFile : proguardFiles) {
- proguardTask.configuration(proguardFile)
- }
-
- // also the config file output by aapt
- proguardTask.configuration(variantData.processResourcesTask.proguardOutputFile)
-
- // injar: the compilation output
- proguardTask.injars(variantData.javaCompileTask.destinationDir)
-
- // injar: the dependencies
- for (File inJar : variantConfig.packagedJars) {
- proguardTask.injars(inJar, filter: '!META-INF/MANIFEST.MF')
- }
-
- // libraryJars: the runtime jars
- for (String runtimeJar : getRuntimeJarList()) {
- proguardTask.libraryjars(runtimeJar)
- }
-
- proguardTask.outjars(outFile)
-
- proguardTask.dump("${project.buildDir}/proguard/${variantData.dirName}/dump.txt")
- proguardTask.printseeds(
- "${project.buildDir}/proguard/${variantData.dirName}/seeds.txt")
- proguardTask.printusage(
- "${project.buildDir}/proguard/${variantData.dirName}/usage.txt")
- proguardTask.printmapping(
- "${project.buildDir}/proguard/${variantData.dirName}/mapping.txt")
- }
- }
-
- // Add a dex task
- def dexTaskName = "dex${variantData.name}"
- def dexTask = project.tasks.create(dexTaskName, Dex)
+ // common dex task configuration
+ String dexTaskName = "dex${variantData.variantConfiguration.fullName.capitalize()}"
+ Dex dexTask = project.tasks.create(dexTaskName, Dex)
variantData.dexTask = dexTask
- if (variantData.proguardTask != null) {
- dexTask.dependsOn variantData.proguardTask
- } else {
- dexTask.dependsOn variantData.javaCompileTask
- }
dexTask.plugin = this
dexTask.variant = variantData
- dexTask.incrementalFolder =
- project.file("$project.buildDir/incremental/dex/$variantData.dirName")
- dexTask.conventionMapping.libraries = libraryClosure
- dexTask.conventionMapping.sourceFiles = sourceClosure
- dexTask.conventionMapping.proguardedJar = proguardFileClosure
dexTask.conventionMapping.outputFile = {
project.file(
- "${project.buildDir}/libs/${project.archivesBaseName}-${variantData.baseName}.dex")
+ "${project.buildDir}/libs/${project.archivesBaseName}-${variantData.variantConfiguration.baseName}.dex")
}
dexTask.dexOptions = extension.dexOptions
+ if (runProguard) {
+
+ // first proguard task.
+ BaseVariantData testedVariantData = variantData instanceof TestVariantData ? variantData.testedVariantData : null as BaseVariantData
+ File outFile = createProguardTasks(variantData, testedVariantData)
+
+ // then dexing task
+ dexTask.dependsOn variantData.proguardTask
+ dexTask.conventionMapping.inputFiles = { project.files(outFile) }
+ dexTask.conventionMapping.preDexedLibraries = { Collections.emptyList() }
+
+ } else {
+
+ // if required, pre-dexing task.
+ PreDex preDexTask = null;
+ boolean runPreDex = extension.dexOptions.preDexLibraries
+ if (runPreDex) {
+ def preDexTaskName = "preDex${variantData.variantConfiguration.fullName.capitalize()}"
+ preDexTask = project.tasks.create(preDexTaskName, PreDex)
+
+ preDexTask.dependsOn variantData.javaCompileTask
+ preDexTask.plugin = this
+ preDexTask.dexOptions = extension.dexOptions
+
+ preDexTask.conventionMapping.inputFiles = {
+ project.files(getAndroidBuilder(variantData).getPackagedJars(variantConfig))
+ }
+ preDexTask.conventionMapping.outputFolder = {
+ project.file(
+ "${project.buildDir}/pre-dexed/${variantData.variantConfiguration.dirName}")
+ }
+ }
+
+ // then dexing task
+ dexTask.dependsOn variantData.javaCompileTask
+ if (runPreDex) {
+ dexTask.dependsOn preDexTask
+ }
+
+ dexTask.conventionMapping.inputFiles = { variantData.javaCompileTask.outputs.files }
+ if (runPreDex) {
+ dexTask.conventionMapping.preDexedLibraries = {
+ project.fileTree(preDexTask.outputFolder).files
+ }
+ } else {
+ dexTask.conventionMapping.preDexedLibraries = {
+ project.files(getAndroidBuilder(variantData).getPackagedJars(variantConfig))
+ }
+ }
+ }
+
// Add a task to generate application package
- def packageApp = project.tasks.create("package${variantData.name}", PackageApplication)
+ def packageApp = project.tasks.create(
+ "package${variantData.variantConfiguration.fullName.capitalize()}",
+ PackageApplication)
variantData.packageApplicationTask = packageApp
- packageApp.dependsOn variantData.processResourcesTask, dexTask, variantData.processJavaResources
+ packageApp.dependsOn variantData.processResourcesTask, dexTask, variantData.processJavaResourcesTask, variantData.ndkCompileTask
packageApp.plugin = this
packageApp.variant = variantData
- VariantConfiguration config = variantData.variantConfiguration
-
packageApp.conventionMapping.resourceFile = {
variantData.processResourcesTask.packageOutputFile
}
packageApp.conventionMapping.dexFile = { dexTask.outputFile }
-
- packageApp.conventionMapping.packagedJars = { config.packagedJars }
-
+ packageApp.conventionMapping.packagedJars = { getAndroidBuilder(variantData).getPackagedJars(variantConfig) }
packageApp.conventionMapping.javaResourceDir = {
- getOptionalDir(variantData.processJavaResources.destinationDir)
+ getOptionalDir(variantData.processJavaResourcesTask.destinationDir)
}
+ packageApp.conventionMapping.jniFolders = {
+ // for now only the project's compilation output.
+ Set<File> set = Sets.newHashSet()
+ set.addAll(variantData.ndkCompileTask.soFolder)
+ set.addAll(variantData.renderscriptCompileTask.libOutputDir)
+ set.addAll(variantConfig.libraryJniFolders)
- packageApp.conventionMapping.jniDebugBuild = { config.buildType.jniDebugBuild }
+ if (variantConfig.mergedFlavor.renderscriptSupportMode) {
+ File rsLibs = getAndroidBuilder(variantData).getSupportNativeLibFolder()
+ if (rsLibs.isDirectory()) {
+ set.add(rsLibs);
+ }
+ }
- SigningConfigDsl sc = (SigningConfigDsl) config.signingConfig
+ return set
+ }
+ packageApp.conventionMapping.abiFilters = { variantConfig.supportedAbis }
+ packageApp.conventionMapping.jniDebugBuild = { variantConfig.buildType.jniDebugBuild }
+
+ SigningConfigDsl sc = (SigningConfigDsl) variantConfig.signingConfig
packageApp.conventionMapping.signingConfig = { sc }
if (sc != null) {
ValidateSigningTask validateSigningTask = validateSigningTaskMap.get(sc)
@@ -1084,8 +1314,8 @@
def signedApk = variantData.isSigned()
def apkName = signedApk ?
- "${project.archivesBaseName}-${variantData.baseName}-unaligned.apk" :
- "${project.archivesBaseName}-${variantData.baseName}-unsigned.apk"
+ "${project.archivesBaseName}-${variantData.variantConfiguration.baseName}-unaligned.apk" :
+ "${project.archivesBaseName}-${variantData.variantConfiguration.baseName}-unsigned.apk"
packageApp.conventionMapping.outputFile = {
project.file("$project.buildDir/apk/${apkName}")
@@ -1097,25 +1327,29 @@
if (signedApk) {
if (variantData.zipAlign) {
// Add a task to zip align application package
- def zipAlignTask = project.tasks.create("zipalign${variantData.name}", ZipAlign)
+ def zipAlignTask = project.tasks.create(
+ "zipalign${variantData.variantConfiguration.fullName.capitalize()}",
+ ZipAlign)
variantData.zipAlignTask = zipAlignTask
zipAlignTask.dependsOn packageApp
zipAlignTask.conventionMapping.inputFile = { packageApp.outputFile }
zipAlignTask.conventionMapping.outputFile = {
project.file(
- "$project.buildDir/apk/${project.archivesBaseName}-${variantData.baseName}.apk")
+ "$project.buildDir/apk/${project.archivesBaseName}-${variantData.variantConfiguration.baseName}.apk")
}
zipAlignTask.conventionMapping.zipAlignExe = { getSdkParser().zipAlign }
appTask = zipAlignTask
outputFileTask = zipAlignTask
variantData.outputFile = project.file(
- "$project.buildDir/apk/${project.archivesBaseName}-${variantData.baseName}.apk")
+ "$project.buildDir/apk/${project.archivesBaseName}-${variantData.variantConfiguration.baseName}.apk")
}
// Add a task to install the application package
- def installTask = project.tasks.create("install${variantData.name}", InstallTask)
+ def installTask = project.tasks.create(
+ "install${variantData.variantConfiguration.fullName.capitalize()}",
+ InstallTask)
installTask.description = "Installs the " + variantData.description
installTask.group = INSTALL_GROUP
installTask.dependsOn appTask
@@ -1127,7 +1361,7 @@
// Add an assemble task
if (assembleTask == null) {
- assembleTask = project.tasks.create("assemble${variantData.name}")
+ assembleTask = project.tasks.create("assemble${variantData.variantConfiguration.fullName.capitalize()}")
assembleTask.description = "Assembles the " + variantData.description
assembleTask.group = org.gradle.api.plugins.BasePlugin.BUILD_GROUP
}
@@ -1137,7 +1371,9 @@
variantData.outputFile = { outputFileTask.outputFile }
// add an uninstall task
- def uninstallTask = project.tasks.create("uninstall${variantData.name}", UninstallTask)
+ def uninstallTask = project.tasks.create(
+ "uninstall${variantData.variantConfiguration.fullName.capitalize()}",
+ UninstallTask)
uninstallTask.description = "Uninstalls the " + variantData.description
uninstallTask.group = INSTALL_GROUP
uninstallTask.variant = variantData
@@ -1147,6 +1383,146 @@
uninstallAll.dependsOn uninstallTask
}
+ /**
+ * Creates the proguarding task for the given Variant.
+ * @param variantData the variant data.
+ * @param testedVariantData optional. variant data representing the tested variant, null if the
+ * variant is not a test variant
+ * @return outFile file outputted by proguard
+ */
+ @NonNull
+ protected File createProguardTasks(@NonNull BaseVariantData variantData,
+ @Nullable BaseVariantData testedVariantData) {
+ VariantConfiguration variantConfig = variantData.variantConfiguration
+
+ def proguardTask = project.tasks.create(
+ "proguard${variantData.variantConfiguration.fullName.capitalize()}",
+ ProGuardTask)
+ proguardTask.dependsOn variantData.javaCompileTask
+ if (testedVariantData != null) {
+ proguardTask.dependsOn testedVariantData.proguardTask
+ }
+
+ variantData.proguardTask = proguardTask
+
+ // --- Output File ---
+
+ File outFile;
+ if (variantData instanceof LibraryVariantData) {
+ outFile = project.file(
+ "${project.buildDir}/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/classes.jar")
+ } else {
+ outFile = project.file(
+ "${project.buildDir}/classes-proguard/${variantData.variantConfiguration.dirName}/classes.jar")
+ }
+
+ // --- Proguard Config ---
+
+ if (testedVariantData != null) {
+ // don't remove any code in tested app
+ proguardTask.dontshrink()
+ proguardTask.keepnames("class * extends junit.framework.TestCase")
+ proguardTask.keepclassmembers("class * extends junit.framework.TestCase {\n" +
+ " void test*(...);\n" +
+ "}")
+
+ // input the mapping from the tested app so that we can deal with obfuscated code
+ proguardTask.applymapping("${project.buildDir}/proguard/${testedVariantData.variantConfiguration.dirName}/mapping.txt")
+
+ // for tested app, we only care about their aapt config since the base
+ // configs are the same files anyway.
+ proguardTask.configuration(testedVariantData.processResourcesTask.proguardOutputFile)
+ }
+
+ // all the config files coming from build type, product flavors.
+ List<Object> proguardFiles = variantConfig.getProguardFiles(true /*includeLibs*/)
+ for (Object proguardFile : proguardFiles) {
+ proguardTask.configuration(proguardFile)
+ }
+
+ // also the config file output by aapt
+ proguardTask.configuration(variantData.processResourcesTask.proguardOutputFile)
+
+ // --- InJars / LibraryJars ---
+
+ List<File> packagedJars = getAndroidBuilder(variantData).getPackagedJars(variantConfig)
+
+ if (variantData instanceof LibraryVariantData) {
+ String packageName = variantConfig.getPackageFromManifest()
+ if (packageName == null) {
+ throw new BuildException("Failed to read manifest", null)
+ }
+ packageName = packageName.replace('.', '/');
+
+ // injar: the compilation output
+ // exclude R files and such from output
+ String exclude = '!' + packageName + "/R.class"
+ exclude += (', !' + packageName + "/R\$*.class")
+ exclude += (', !' + packageName + "/Manifest.class")
+ exclude += (', !' + packageName + "/Manifest\$*.class")
+ exclude += (', !' + packageName + "/BuildConfig.class")
+ proguardTask.injars(variantData.javaCompileTask.destinationDir, filter: exclude)
+
+ // include R files and such for compilation
+ String include = exclude.replace('!', '')
+ proguardTask.libraryjars(variantData.javaCompileTask.destinationDir, filter: include)
+
+ // injar: the local dependencies, filter out local jars from packagedJars
+ Object[] jars = LibraryPlugin.getLocalJarFileList(variantData.variantDependency)
+ for (Object inJar : jars) {
+ if (packagedJars.contains(inJar)) {
+ packagedJars.remove(inJar);
+ }
+ proguardTask.injars((File) inJar, filter: '!META-INF/MANIFEST.MF')
+ }
+
+ // libjar: the library dependencies
+ for (File libJar : packagedJars) {
+ proguardTask.libraryjars(libJar, filter: '!META-INF/MANIFEST.MF')
+ }
+
+ // ensure local jars keep their package names
+ proguardTask.keeppackagenames()
+ } else {
+ // injar: the compilation output
+ proguardTask.injars(variantData.javaCompileTask.destinationDir)
+
+ // injar: the dependencies
+ for (File inJar : packagedJars) {
+ proguardTask.injars(inJar, filter: '!META-INF/MANIFEST.MF')
+ }
+ }
+
+ // libraryJars: the runtime jars
+ for (String runtimeJar : getRuntimeJarList()) {
+ proguardTask.libraryjars(runtimeJar)
+ }
+
+ if (testedVariantData != null) {
+ // input the tested app as library
+ proguardTask.libraryjars(testedVariantData.javaCompileTask.destinationDir)
+ // including its dependencies
+ List<File> testedPackagedJars = getAndroidBuilder(testedVariantData).getPackagedJars(testedVariantData.variantConfiguration)
+ for (File inJar : testedPackagedJars) {
+ proguardTask.libraryjars(inJar, filter: '!META-INF/MANIFEST.MF')
+ }
+ }
+
+ // --- Out files ---
+
+ proguardTask.outjars(outFile)
+
+ proguardTask.dump("${project.buildDir}/proguard/${variantData.variantConfiguration.dirName}/dump.txt")
+ proguardTask.printseeds(
+ "${project.buildDir}/proguard/${variantData.variantConfiguration.dirName}/seeds.txt")
+ proguardTask.printusage(
+ "${project.buildDir}/proguard/${variantData.variantConfiguration.dirName}/usage.txt")
+ proguardTask.printmapping(
+ "${project.buildDir}/proguard/${variantData.variantConfiguration.dirName}/mapping.txt")
+
+ return outFile
+ }
+
private void createReportTasks() {
def dependencyReportTask = project.tasks.create("androidDependencies", DependencyReportTask)
dependencyReportTask.setDescription("Displays the Android dependencies of the project")
@@ -1159,16 +1535,17 @@
signingReportTask.setGroup("Android")
}
+ protected void createAnchorTasks(@NonNull BaseVariantData variantData) {
+ variantData.preBuildTask = project.tasks.create(
+ "pre${variantData.variantConfiguration.fullName.capitalize()}Build")
+ variantData.preBuildTask.dependsOn mainPreBuild
- //----------------------------------------------------------------------------------------------
- //------------------------------ START DEPENDENCY STUFF ----------------------------------------
- //----------------------------------------------------------------------------------------------
-
-
- protected void createPrepareDependenciesTask(@NonNull BaseVariantData variantData) {
- def prepareDependenciesTask = project.tasks.create("prepare${variantData.name}Dependencies",
+ def prepareDependenciesTask = project.tasks.create(
+ "prepare${variantData.variantConfiguration.fullName.capitalize()}Dependencies",
PrepareDependenciesTask)
+
variantData.prepareDependenciesTask = prepareDependenciesTask
+ prepareDependenciesTask.dependsOn variantData.preBuildTask
prepareDependenciesTask.plugin = this
prepareDependenciesTask.variant = variantData
@@ -1179,19 +1556,135 @@
prepareDependenciesTask.addChecker(configurationDependencies.checker)
for (LibraryDependencyImpl lib : configurationDependencies.libraries) {
- addDependencyToPrepareTask(prepareDependenciesTask, lib)
+ addDependencyToPrepareTask(variantData, prepareDependenciesTask, lib)
}
+
+ // also create sourceGenTask
+ variantData.sourceGenTask = project.tasks.create(
+ "generate${variantData.variantConfiguration.fullName.capitalize()}Sources")
}
- def addDependencyToPrepareTask(PrepareDependenciesTask prepareDependenciesTask,
- LibraryDependencyImpl lib) {
+
+ private final Map<String, ArtifactMetaData> extraArtifactMap = Maps.newHashMap()
+ private final ListMultimap<String, AndroidArtifact> extraAndroidArtifacts = ArrayListMultimap.create()
+ private final ListMultimap<String, JavaArtifact> extraJavaArtifacts = ArrayListMultimap.create()
+ private final ListMultimap<String, SourceProviderContainer> extraVariantSourceProviders = ArrayListMultimap.create()
+ private final ListMultimap<String, SourceProviderContainer> extraBuildTypeSourceProviders = ArrayListMultimap.create()
+ private final ListMultimap<String, SourceProviderContainer> extraProductFlavorSourceProviders = ArrayListMultimap.create()
+ private final ListMultimap<String, SourceProviderContainer> extraMultiFlavorSourceProviders = ArrayListMultimap.create()
+
+
+ public Collection<ArtifactMetaData> getExtraArtifacts() {
+ return extraArtifactMap.values()
+ }
+
+ public Collection<AndroidArtifact> getExtraAndroidArtifacts(@NonNull String variantName) {
+ return extraAndroidArtifacts.get(variantName)
+ }
+
+ public Collection<JavaArtifact> getExtraJavaArtifacts(@NonNull String variantName) {
+ return extraJavaArtifacts.get(variantName)
+ }
+
+ public Collection<SourceProviderContainer> getExtraVariantSourceProviders(@NonNull String variantName) {
+ return extraVariantSourceProviders.get(variantName)
+ }
+
+ public Collection<SourceProviderContainer> getExtraFlavorSourceProviders(@NonNull String flavorName) {
+ return extraProductFlavorSourceProviders.get(flavorName)
+ }
+
+ public Collection<SourceProviderContainer> getExtraBuildTypeSourceProviders(@NonNull String buildTypeName) {
+ return extraBuildTypeSourceProviders.get(buildTypeName)
+ }
+
+ public void registerArtifactType(@NonNull String name,
+ boolean isTest,
+ int artifactType) {
+
+ if (extraArtifactMap.get(name) != null) {
+ throw new IllegalArgumentException("Artifact with name $name already registered.")
+ }
+
+ extraArtifactMap.put(name, new ArtifactMetaDataImpl(name, isTest, artifactType))
+ }
+
+ public void registerBuildTypeSourceProvider(@NonNull String name,
+ @NonNull BuildType buildType,
+ @NonNull SourceProvider sourceProvider) {
+ if (extraArtifactMap.get(name) == null) {
+ throw new IllegalArgumentException(
+ "Artifact with name $name is not yet registered. Use registerArtifactType()")
+ }
+
+ extraBuildTypeSourceProviders.put(buildType.name,
+ new DefaultSourceProviderContainer(name, sourceProvider))
+
+ }
+
+ public void registerProductFlavorSourceProvider(@NonNull String name,
+ @NonNull ProductFlavor productFlavor,
+ @NonNull SourceProvider sourceProvider) {
+ if (extraArtifactMap.get(name) == null) {
+ throw new IllegalArgumentException(
+ "Artifact with name $name is not yet registered. Use registerArtifactType()")
+ }
+
+ extraProductFlavorSourceProviders.put(productFlavor.name,
+ new DefaultSourceProviderContainer(name, sourceProvider))
+
+ }
+
+ public void registerMultiFlavorSourceProvider(@NonNull String name,
+ @NonNull String flavorName,
+ @NonNull SourceProvider sourceProvider) {
+ if (extraArtifactMap.get(name) == null) {
+ throw new IllegalArgumentException(
+ "Artifact with name $name is not yet registered. Use registerArtifactType()")
+ }
+
+ extraMultiFlavorSourceProviders.put(flavorName,
+ new DefaultSourceProviderContainer(name, sourceProvider))
+ }
+
+ public void registerJavaArtifact(
+ @NonNull String name,
+ @NonNull BaseVariant variant,
+ @NonNull String assembleTaskName,
+ @NonNull String javaCompileTaskName,
+ @NonNull File classesFolder,
+ @Nullable SourceProvider sourceProvider) {
+ ArtifactMetaData artifactMetaData = extraArtifactMap.get(name)
+ if (artifactMetaData == null) {
+ throw new IllegalArgumentException(
+ "Artifact with name $name is not yet registered. Use registerArtifactType()")
+ }
+ if (artifactMetaData.type != ArtifactMetaData.TYPE_JAVA) {
+ throw new IllegalArgumentException(
+ "Artifact with name $name is not of type JAVA")
+ }
+
+ JavaArtifact artifact = new JavaArtifactImpl(
+ name, assembleTaskName, javaCompileTaskName, classesFolder,
+ null, sourceProvider, null)
+ extraJavaArtifacts.put(variant.name, artifact)
+ }
+
+ //----------------------------------------------------------------------------------------------
+ //------------------------------ START DEPENDENCY STUFF ----------------------------------------
+ //----------------------------------------------------------------------------------------------
+
+ def addDependencyToPrepareTask(@NonNull BaseVariantData variantData,
+ @NonNull PrepareDependenciesTask prepareDependenciesTask,
+ @NonNull LibraryDependencyImpl lib) {
def prepareLibTask = prepareTaskMap.get(lib)
if (prepareLibTask != null) {
prepareDependenciesTask.dependsOn prepareLibTask
+ prepareLibTask.dependsOn variantData.preBuildTask
}
for (LibraryDependencyImpl childLib : lib.dependencies) {
- addDependencyToPrepareTask(prepareDependenciesTask, childLib)
+ addDependencyToPrepareTask(variantData, prepareDependenciesTask, childLib)
}
}
@@ -1246,14 +1739,23 @@
variantDeps.checker = new DependencyChecker(variantDeps, logger)
+ Set<String> currentUnresolvedDependencies = Sets.newHashSet()
+
// TODO - defer downloading until required -- This is hard to do as we need the info to build the variant config.
List<LibraryDependencyImpl> bundles = []
List<JarDependency> jars = []
List<JarDependency> localJars = []
collectArtifacts(compileClasspath, artifacts)
- compileClasspath.incoming.resolutionResult.root.dependencies.each { ResolvedDependencyResult dep ->
- addDependency(dep.selected, variantDeps, bundles, jars, modules,
- artifacts, reverseMap)
+ def dependencies = compileClasspath.incoming.resolutionResult.root.dependencies
+ dependencies.each { DependencyResult dep ->
+ if (dep instanceof ResolvedDependencyResult) {
+ addDependency(dep.selected, variantDeps, bundles, jars, modules, artifacts, reverseMap)
+ } else if (dep instanceof UnresolvedDependencyResult) {
+ def attempted = dep.attempted;
+ if (attempted != null) {
+ currentUnresolvedDependencies.add(attempted.toString())
+ }
+ }
}
// also need to process local jar files, as they are not processed by the
@@ -1273,21 +1775,26 @@
// in compile and remove all dependencies already in compile to get package-only jar
// files.
Configuration packageClasspath = variantDeps.packageConfiguration
- Set<File> compileFiles = compileClasspath.files
- Set<File> packageFiles = packageClasspath.files
- for (File f : packageFiles) {
- if (compileFiles.contains(f)) {
- continue
- }
+ if (!compileClasspath.resolvedConfiguration.hasError()) {
+ Set<File> compileFiles = compileClasspath.files
+ Set<File> packageFiles = packageClasspath.files
- if (f.getName().toLowerCase().endsWith(".jar")) {
- jars.add(new JarDependency(f, false /*compiled*/, true /*packaged*/))
- } else {
- throw new RuntimeException("Package-only dependency '" +
- f.absolutePath +
- "' is not supported")
+ for (File f : packageFiles) {
+ if (compileFiles.contains(f)) {
+ continue
+ }
+
+ if (f.getName().toLowerCase().endsWith(".jar")) {
+ jars.add(new JarDependency(f, false /*compiled*/, true /*packaged*/))
+ } else {
+ throw new RuntimeException("Package-only dependency '" +
+ f.absolutePath +
+ "' is not supported")
+ }
}
+ } else if (!currentUnresolvedDependencies.isEmpty()) {
+ unresolvedDependencies.addAll(currentUnresolvedDependencies)
}
variantDeps.addLibraries(bundles)
@@ -1308,7 +1815,15 @@
static def collectArtifacts(Configuration configuration, Map<ModuleVersionIdentifier,
List<ResolvedArtifact>> artifacts) {
- configuration.resolvedConfiguration.resolvedArtifacts.each { ResolvedArtifact artifact ->
+ boolean buildModelOnly = Boolean.getBoolean(AndroidProject.BUILD_MODEL_ONLY_SYSTEM_PROPERTY);
+ def allArtifacts
+ if (buildModelOnly) {
+ allArtifacts = configuration.resolvedConfiguration.lenientConfiguration.getArtifacts(Specs.satisfyAll())
+ } else {
+ allArtifacts = configuration.resolvedConfiguration.resolvedArtifacts
+ }
+
+ allArtifacts.each { ResolvedArtifact artifact ->
def id = artifact.moduleVersion.id
List<ResolvedArtifact> moduleArtifacts = artifacts[id]
if (moduleArtifacts == null) {
@@ -1337,9 +1852,12 @@
modules[id] = bundlesForThisModule
def nestedBundles = []
- moduleVersion.dependencies.each { ResolvedDependencyResult dep ->
- addDependency(dep.selected, configDependencies, nestedBundles,
- jars, modules, artifacts, reverseMap)
+ def dependencies = moduleVersion.dependencies
+ dependencies.each { DependencyResult dep ->
+ if (dep instanceof ResolvedDependencyResult) {
+ addDependency(dep.selected, configDependencies, nestedBundles,
+ jars, modules, artifacts, reverseMap)
+ }
}
def moduleArtifacts = artifacts[id]
@@ -1443,17 +1961,25 @@
}
private static String getLocalVersion() {
- Class clazz = BasePlugin.class
- String className = clazz.getSimpleName() + ".class"
- String classPath = clazz.getResource(className).toString()
- if (!classPath.startsWith("jar")) {
- // Class not from JAR, unlikely
- return null
+ try {
+ Class clazz = BasePlugin.class
+ String className = clazz.getSimpleName() + ".class"
+ String classPath = clazz.getResource(className).toString()
+ if (!classPath.startsWith("jar")) {
+ // Class not from JAR, unlikely
+ return null
+ }
+ String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
+ "/META-INF/MANIFEST.MF";
+ Manifest manifest = new Manifest(new URL(manifestPath).openStream());
+ Attributes attr = manifest.getMainAttributes();
+ return attr.getValue("Plugin-Version");
+ } catch (Throwable t) {
+ return null;
}
- String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
- "/META-INF/MANIFEST.MF";
- Manifest manifest = new Manifest(new URL(manifestPath).openStream());
- Attributes attr = manifest.getMainAttributes();
- return attr.getValue("Plugin-Version");
+ }
+
+ public Project getProject() {
+ return project
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/LibraryExtension.groovy b/gradle/src/main/groovy/com/android/build/gradle/LibraryExtension.groovy
index 6d6015b..e1cf6a3 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/LibraryExtension.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/LibraryExtension.groovy
@@ -45,9 +45,12 @@
BuilderConstants.DEBUG)
debugSigningConfig.initDebug()
- debug = instantiator.newInstance(BuildTypeDsl.class, BuilderConstants.DEBUG, project.fileResolver)
+ debug = instantiator.newInstance(BuildTypeDsl.class,
+ BuilderConstants.DEBUG, project.fileResolver, instantiator)
debug.init(debugSigningConfig)
- release = instantiator.newInstance(BuildTypeDsl.class, BuilderConstants.RELEASE, project.fileResolver)
+
+ release = instantiator.newInstance(BuildTypeDsl.class,
+ BuilderConstants.RELEASE, project.fileResolver, instantiator)
release.init(null)
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy b/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy
index 93420e8..14cce5e 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy
@@ -45,6 +45,7 @@
import org.gradle.api.Project
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.plugins.MavenPlugin
+import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Sync
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip
@@ -58,8 +59,6 @@
*/
public class LibraryPlugin extends BasePlugin implements Plugin<Project> {
- private final static String DIR_BUNDLES = "bundles";
-
LibraryExtension extension
BuildTypeData debugBuildTypeData
BuildTypeData releaseBuildTypeData
@@ -80,9 +79,9 @@
// create the source sets for the build type.
// the ones for the main product flavors are handled by the base plugin.
DefaultAndroidSourceSet debugSourceSet =
- (DefaultAndroidSourceSet) extension.sourceSetsContainer.create(BuilderConstants.DEBUG)
+ (DefaultAndroidSourceSet) extension.sourceSetsContainer.maybeCreate(BuilderConstants.DEBUG)
DefaultAndroidSourceSet releaseSourceSet =
- (DefaultAndroidSourceSet) extension.sourceSetsContainer.create(BuilderConstants.RELEASE)
+ (DefaultAndroidSourceSet) extension.sourceSetsContainer.maybeCreate(BuilderConstants.RELEASE)
debugBuildTypeData = new BuildTypeData(extension.debug, debugSourceSet, project)
releaseBuildTypeData = new BuildTypeData(extension.release, releaseSourceSet, project)
@@ -127,23 +126,29 @@
LibraryVariantData releaseVariantData = createLibVariant(defaultConfigData,
releaseBuildTypeData)
+ // Add a compile lint task before library is bundled
+ createLintCompileTask()
+
// Need to create the tasks for these before doing the test variant as it
// references the debug variant and its output
createLibraryVariant(debugVariantData, false)
createLibraryVariant(releaseVariantData, true)
VariantConfiguration testVariantConfig = new VariantConfiguration(
- defaultConfigData.productFlavor, defaultConfigData.testSourceSet,
- debugBuildTypeData.buildType, null,
+ defaultConfigData.productFlavor,
+ defaultConfigData.testSourceSet,
+ debugBuildTypeData.buildType,
+ null,
VariantConfiguration.Type.TEST,
- debugVariantData.variantConfiguration, project.name)
+ debugVariantData.variantConfiguration)
TestVariantData testVariantData = new TestVariantData(testVariantConfig, debugVariantData)
// link the testVariant to the tested variant in the other direction
debugVariantData.setTestVariantData(testVariantData);
// dependencies for the test variant
- variantDep = VariantDependencies.compute(project, testVariantData.name,
+ variantDep = VariantDependencies.compute(project,
+ testVariantData.variantConfiguration.fullName,
defaultConfigData.testProvider, debugVariantData.variantDependency)
testVariantData.setVariantDependency(variantDep)
@@ -151,6 +156,9 @@
createTestVariant(testVariantData, debugVariantData)
+ // create the lint tasks.
+ createLintTasks()
+
// create the test tasks.
createCheckTasks(false /*hasFlavors*/, true /*isLibrary*/)
@@ -161,14 +169,16 @@
protected LibraryVariantData createLibVariant(@NonNull ProductFlavorData configData,
@NonNull BuildTypeData buildTypeData) {
VariantConfiguration variantConfig = new VariantConfiguration(
- configData.productFlavor, configData.sourceSet,
- buildTypeData.buildType, buildTypeData.sourceSet,
- VariantConfiguration.Type.LIBRARY, project.name)
+ configData.productFlavor,
+ configData.sourceSet,
+ buildTypeData.buildType,
+ buildTypeData.sourceSet,
+ VariantConfiguration.Type.LIBRARY)
LibraryVariantData variantData = new LibraryVariantData(variantConfig)
VariantDependencies debugVariantDep = VariantDependencies.compute(
- project, variantData.name,
+ project, variantData.variantConfiguration.fullName,
buildTypeData, configData.mainProvider)
variantData.setVariantDependency(debugVariantDep)
@@ -185,12 +195,7 @@
VariantConfiguration variantConfig = variantData.variantConfiguration
DefaultBuildType buildType = variantConfig.buildType
- String packageName = variantConfig.getPackageFromManifest()
- if (packageName == null) {
- throw new BuildException("Failed to read manifest", null)
- }
-
- createPrepareDependenciesTask(variantData)
+ createAnchorTasks(variantData)
// Add a task to process the manifest(s)
createProcessManifestTask(variantData, DIR_BUNDLES)
@@ -206,13 +211,13 @@
// the dependencies. This is what gets packaged in the aar.
MergeResources packageRes = basicCreateMergeResourcesTask(variantData,
"package",
- "$project.buildDir/$DIR_BUNDLES/${variantData.dirName}/res",
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/res",
false /*includeDependencies*/,
false /*process9Patch*/)
// Add a task to merge the assets folders
createMergeAssetsTask(variantData,
- "$project.buildDir/$DIR_BUNDLES/${variantData.dirName}/assets",
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/assets",
false /*includeDependencies*/)
// Add a task to create the BuildConfig class
@@ -220,7 +225,8 @@
// Add a task to generate resource source files, directing the location
// of the r.txt file to be directly in the bundle.
- createProcessResTask(variantData, "$project.buildDir/$DIR_BUNDLES/${variantData.dirName}")
+ createProcessResTask(variantData,
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}")
// process java resources
createProcessJavaResTask(variantData)
@@ -230,61 +236,101 @@
// Add a compile task
createCompileTask(variantData, null/*testedVariant*/)
- // jar the classes.
- Jar jar = project.tasks.create("package${buildType.name.capitalize()}Jar", Jar);
- jar.dependsOn variantData.javaCompileTask, variantData.processJavaResources
- jar.from(variantData.javaCompileTask.outputs);
- jar.from(variantData.processJavaResources.destinationDir)
-
- jar.destinationDir = project.file("$project.buildDir/$DIR_BUNDLES/${variantData.dirName}")
- jar.archiveName = "classes.jar"
- packageName = packageName.replace('.', '/');
- jar.exclude(packageName + "/R.class")
- jar.exclude(packageName + "/R\$*.class")
- jar.exclude(packageName + "/Manifest.class")
- jar.exclude(packageName + "/Manifest\$*.class")
- jar.exclude(packageName + "/BuildConfig.class")
+ // Add NDK tasks
+ createNdkTasks(
+ variantData,
+ { project.file("$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/jni") });
// package the aidl files into the bundle folder
- Sync packageAidl = project.tasks.create("package${variantData.name}Aidl", Sync)
+ Sync packageAidl = project.tasks.create(
+ "package${variantData.variantConfiguration.fullName.capitalize()}Aidl",
+ Sync)
// packageAidl from 3 sources. the order is important to make sure the override works well.
packageAidl.from(variantConfig.aidlSourceList).include("**/*.aidl")
packageAidl.into(project.file(
- "$project.buildDir/$DIR_BUNDLES/${variantData.dirName}/$SdkConstants.FD_AIDL"))
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/$SdkConstants.FD_AIDL"))
// package the renderscript header files files into the bundle folder
- Sync packageRenderscript = project.tasks.create("package${variantData.name}Renderscript",
+ Sync packageRenderscript = project.tasks.create(
+ "package${variantData.variantConfiguration.fullName.capitalize()}Renderscript",
Sync)
// package from 3 sources. the order is important to make sure the override works well.
packageRenderscript.from(variantConfig.renderscriptSourceList).include("**/*.rsh")
packageRenderscript.into(project.file(
- "$project.buildDir/$DIR_BUNDLES/${variantData.dirName}/$SdkConstants.FD_RENDERSCRIPT"))
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/$SdkConstants.FD_RENDERSCRIPT"))
- // package the renderscript header files files into the bundle folder
- Sync packageLocalJar = project.tasks.create("package${variantData.name}LocalJar", Sync)
- packageLocalJar.from(getLocalJarFileList(variantData.variantDependency))
- packageLocalJar.into(project.file(
- "$project.buildDir/$DIR_BUNDLES/${variantData.dirName}/$SdkConstants.LIBS_FOLDER"))
-
- // merge the proguard files together
- MergeFileTask mergeFileTask = project.tasks.create("merge${variantData.name}ProguardFiles",
+ // merge consumer proguard files from different build types and flavors
+ MergeFileTask mergeProGuardFileTask = project.tasks.create(
+ "merge${variantData.variantConfiguration.fullName.capitalize()}ProguardFiles",
MergeFileTask)
- mergeFileTask.conventionMapping.inputFiles = {
- project.files(variantConfig.getProguardFiles(false)).files }
- mergeFileTask.conventionMapping.outputFile = {
+ mergeProGuardFileTask.conventionMapping.inputFiles = {
+ project.files(variantConfig.getConsumerProguardFiles()).files }
+ mergeProGuardFileTask.conventionMapping.outputFile = {
project.file(
- "$project.buildDir/$DIR_BUNDLES/${variantData.dirName}/$LibraryBundle.FN_PROGUARD_TXT")
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/$LibraryBundle.FN_PROGUARD_TXT")
}
- Zip bundle = project.tasks.create("bundle${variantData.name}", Zip)
- bundle.dependsOn packageRes, jar, packageAidl, packageRenderscript, packageLocalJar, mergeFileTask
- bundle.setDescription("Assembles a bundle containing the library in ${variantData.name}.");
+ // copy lint.jar into the bundle folder
+ Copy lintCopy = project.tasks.create(
+ "copy${variantData.variantConfiguration.fullName.capitalize()}Lint",
+ Copy)
+ lintCopy.dependsOn lintCompile
+ lintCopy.from("$project.buildDir/lint/lint.jar")
+ lintCopy.into("$project.buildDir/$DIR_BUNDLES/$variantData.variantConfiguration.dirName")
+
+ Zip bundle = project.tasks.create(
+ "bundle${variantData.variantConfiguration.fullName.capitalize()}",
+ Zip)
+
+ if (variantConfig.buildType.runProguard) {
+ // run proguard on output of compile task
+ createProguardTasks(variantData, null)
+
+ // hack since bundle can't depend on variantData.proguardTask
+ mergeProGuardFileTask.dependsOn variantData.proguardTask
+
+ bundle.dependsOn packageRes, packageAidl, packageRenderscript, mergeProGuardFileTask, lintCopy, variantData.ndkCompileTask
+ } else {
+ Sync packageLocalJar = project.tasks.create(
+ "package${variantData.variantConfiguration.fullName.capitalize()}LocalJar",
+ Sync)
+ packageLocalJar.from(getLocalJarFileList(variantData.variantDependency))
+ packageLocalJar.into(project.file(
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/$SdkConstants.LIBS_FOLDER"))
+
+ // jar the classes.
+ Jar jar = project.tasks.create("package${buildType.name.capitalize()}Jar", Jar);
+ jar.dependsOn variantData.javaCompileTask, variantData.processJavaResourcesTask
+ jar.from(variantData.javaCompileTask.outputs);
+ jar.from(variantData.processJavaResourcesTask.destinationDir)
+
+ jar.destinationDir = project.file(
+ "$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}")
+ jar.archiveName = "classes.jar"
+
+ String packageName = variantConfig.getPackageFromManifest()
+ if (packageName == null) {
+ throw new BuildException("Failed to read manifest", null)
+ }
+ packageName = packageName.replace('.', '/');
+
+ jar.exclude(packageName + "/R.class")
+ jar.exclude(packageName + "/R\$*.class")
+ jar.exclude(packageName + "/Manifest.class")
+ jar.exclude(packageName + "/Manifest\$*.class")
+ jar.exclude(packageName + "/BuildConfig.class")
+
+ bundle.dependsOn packageRes, jar, packageAidl, packageRenderscript, packageLocalJar,
+ mergeProGuardFileTask, lintCopy, variantData.ndkCompileTask
+ }
+
+ bundle.setDescription("Assembles a bundle containing the library in ${variantData.variantConfiguration.fullName.capitalize()}.");
bundle.destinationDir = project.file("$project.buildDir/libs")
bundle.extension = BuilderConstants.EXT_LIB_ARCHIVE
- if (variantData.baseName != BuilderConstants.RELEASE) {
- bundle.classifier = variantData.baseName
+ if (variantData.variantConfiguration.baseName != BuilderConstants.RELEASE) {
+ bundle.classifier = variantData.variantConfiguration.baseName
}
- bundle.from(project.file("$project.buildDir/$DIR_BUNDLES/${variantData.dirName}"))
+ bundle.from(project.file("$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}"))
variantData.packageLibTask = bundle
variantData.outputFile = bundle.archivePath
@@ -302,7 +348,7 @@
// configure the variant to be testable.
variantConfig.output = new LibraryBundle(
bundle.archivePath,
- project.file("$project.buildDir/$DIR_BUNDLES/${variantData.dirName}"),
+ project.file("$project.buildDir/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}"),
variantData.getName()) {
@Nullable
diff --git a/gradle/src/main/groovy/com/android/build/gradle/api/ApkVariant.java b/gradle/src/main/groovy/com/android/build/gradle/api/ApkVariant.java
index d28b6dd..404625e 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/api/ApkVariant.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/api/ApkVariant.java
@@ -21,7 +21,6 @@
import com.android.build.gradle.tasks.Dex;
import com.android.build.gradle.tasks.PackageApplication;
import com.android.build.gradle.tasks.ZipAlign;
-import com.android.builder.DefaultBuildType;
import com.android.builder.DefaultProductFlavor;
import com.android.builder.model.SigningConfig;
import org.gradle.api.DefaultTask;
@@ -33,11 +32,6 @@
*/
public interface ApkVariant extends BaseVariant {
- /**
- * Returns the {@link com.android.builder.DefaultBuildType} for this build variant.
- */
- @NonNull
- DefaultBuildType getBuildType();
/**
* Returns the list of {@link com.android.builder.DefaultProductFlavor} for this build variant.
diff --git a/gradle/src/main/groovy/com/android/build/gradle/api/BaseVariant.java b/gradle/src/main/groovy/com/android/build/gradle/api/BaseVariant.java
index 190bf47..4357456 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/api/BaseVariant.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/api/BaseVariant.java
@@ -25,11 +25,14 @@
import com.android.build.gradle.tasks.ProcessAndroidResources;
import com.android.build.gradle.tasks.ProcessManifest;
import com.android.build.gradle.tasks.RenderscriptCompile;
+import com.android.builder.DefaultBuildType;
+import com.android.builder.DefaultProductFlavor;
import org.gradle.api.Task;
import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.compile.JavaCompile;
import java.io.File;
+import java.util.Collection;
/**
* A Build variant and all its public data. This is the base class for items common to apps,
@@ -68,6 +71,27 @@
String getBaseName();
/**
+ * Returns the flavor name of the variant. This is a concatenation of all the
+ * applied flavors
+ * @return the name of the flavors, or an empty string if there is not flavors.
+ */
+ @NonNull
+ String getFlavorName();
+
+ /**
+ * Returns the {@link com.android.builder.DefaultBuildType} for this build variant.
+ */
+ @NonNull
+ DefaultBuildType getBuildType();
+
+ /**
+ * Returns a {@link com.android.builder.DefaultProductFlavor} that represents the merging
+ * of the default config and the flavors of this build variant.
+ */
+ @NonNull
+ DefaultProductFlavor getConfig();
+
+ /**
* Returns the output file for this build variants. Depending on the configuration, this could
* be an apk (regular and test project) or a bundled library (library project).
*
@@ -137,4 +161,52 @@
*/
@Nullable
Task getAssemble();
+
+ /**
+ * Adds new Java source folders to the model.
+ *
+ * These source folders will not be used for the default build
+ * system, but will be passed along the default Java source folders
+ * to whoever queries the model.
+ *
+ * @param sourceFolders the source folders where the generated source code is.
+ */
+ void addJavaSourceFoldersToModel(@NonNull File... sourceFolders);
+
+ /**
+ * Adds new Java source folders to the model.
+ *
+ * These source folders will not be used for the default build
+ * system, but will be passed along the default Java source folders
+ * to whoever queries the model.
+ *
+ * @param sourceFolders the source folders where the generated source code is.
+ */
+ void addJavaSourceFoldersToModel(@NonNull Collection<File> sourceFolders);
+
+ /**
+ * Adds to the variant a task that generates Java source code.
+ *
+ * This will make the compileJava task depend on this task and add the
+ * new source folders as compilation inputs.
+ *
+ * The new source folders are also added to the model.
+ *
+ * @param task the task
+ * @param sourceFolders the source folders where the generated source code is.
+ */
+ void registerJavaGeneratingTask(@NonNull Task task, @NonNull File... sourceFolders);
+
+ /**
+ * Adds to the variant a task that generates Java source code.
+ *
+ * This will make the compileJava task depend on this task and add the
+ * new source folders as compilation inputs.
+ *
+ * The new source folders are also added to the model.
+ *
+ * @param task the task
+ * @param sourceFolders the source folders where the generated source code is.
+ */
+ void registerJavaGeneratingTask(@NonNull Task task, @NonNull Collection<File> sourceFolders);
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/api/LibraryVariant.java b/gradle/src/main/groovy/com/android/build/gradle/api/LibraryVariant.java
index 5bcfd9f..8db077d 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/api/LibraryVariant.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/api/LibraryVariant.java
@@ -16,10 +16,7 @@
package com.android.build.gradle.api;
-import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
-import com.android.builder.DefaultBuildType;
-import com.android.builder.DefaultProductFlavor;
import org.gradle.api.tasks.bundling.Zip;
/**
@@ -28,19 +25,6 @@
public interface LibraryVariant extends BaseVariant {
/**
- * Returns the {@link com.android.builder.DefaultBuildType} for this build variant.
- */
- @NonNull
- DefaultBuildType getBuildType();
-
- /**
- * Returns a {@link com.android.builder.DefaultProductFlavor} that represents the merging
- * of the default config and the flavors of this build variant.
- */
- @NonNull
- DefaultProductFlavor getConfig();
-
- /**
* Returns the build variant that will test this build variant.
*
* Will return null if this build variant is a test build already.
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java b/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java
index 2de5ad0..6704129 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java
@@ -31,6 +31,7 @@
import org.gradle.util.GUtil;
import java.io.IOException;
+import java.util.Collection;
import java.util.List;
import static org.gradle.logging.StyledTextOutput.Style.Description;
@@ -69,7 +70,8 @@
renderer.visit(new Action<StyledTextOutput>() {
@Override
public void execute(StyledTextOutput styledTextOutput) {
- getTextOutput().withStyle(Identifier).text(variantData.getName());
+ getTextOutput().withStyle(Identifier).text(
+ variantData.getVariantConfiguration().getFullName());
getTextOutput().withStyle(Description).text("");
}
}, true);
@@ -131,15 +133,16 @@
}
private void renderChildren(@NonNull List<LibraryDependency> libraries,
- @Nullable List<JarDependency> localJars) {
+ @Nullable Collection<JarDependency> localJars) {
renderer.startChildren();
if (localJars != null) {
final boolean emptyChildren = libraries.isEmpty();
final int count = localJars.size();
- for (int i = 0; i < count; i++) {
- JarDependency jarDependency = localJars.get(i);
+ int i = 0;
+ for (JarDependency jarDependency : localJars) {
render(jarDependency, emptyChildren && i == count - 1);
+ i++;
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/CompileOptions.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/CompileOptions.groovy
index 9ee110c..de70e31 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/CompileOptions.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/CompileOptions.groovy
@@ -25,4 +25,5 @@
JavaVersion sourceCompatibility = JavaVersion.VERSION_1_6
JavaVersion targetCompatibility = JavaVersion.VERSION_1_6
+ String encoding = "UTF-8"
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleClient.java b/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleClient.java
new file mode 100644
index 0000000..3bf7b8d
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleClient.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.build.gradle.BasePlugin;
+import com.android.builder.model.AndroidProject;
+import com.android.builder.model.Variant;
+import com.android.tools.lint.LintCliClient;
+import com.android.tools.lint.LintCliFlags;
+import com.android.tools.lint.Warning;
+import com.android.tools.lint.client.api.IssueRegistry;
+import com.android.tools.lint.client.api.LintRequest;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.Project;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class LintGradleClient extends LintCliClient {
+ private final AndroidProject mModelProject;
+ private final String mVariantName;
+ private final BasePlugin mPlugin;
+ private List<File> mCustomRules = Lists.newArrayList();
+
+ public LintGradleClient(
+ @NonNull IssueRegistry registry,
+ @NonNull LintCliFlags flags,
+ @NonNull BasePlugin plugin,
+ @NonNull AndroidProject modelProject,
+ @Nullable String variantName) {
+ super(flags);
+ mPlugin = plugin;
+ mModelProject = modelProject;
+ mVariantName = variantName;
+ mRegistry = registry;
+ }
+
+ @NonNull
+ public BasePlugin getPlugin() {
+ return mPlugin;
+ }
+
+ public void setCustomRules(List<File> customRules) {
+ mCustomRules = customRules;
+ }
+
+ @Override
+ public List<File> findRuleJars(@NonNull Project project) {
+ return mCustomRules;
+ }
+
+ @Override
+ protected Project createProject(@NonNull File dir, @NonNull File referenceDir) {
+ // Should not be called by lint since we supply an explicit set of projects
+ // to the LintRequest
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public File getSdkHome() {
+ File sdkHome = mPlugin.getSdkDirectory();
+ if (sdkHome != null) {
+ return sdkHome;
+ }
+ return super.getSdkHome();
+ }
+
+ @Override
+ @NonNull
+ protected LintRequest createLintRequest(@NonNull List<File> files) {
+ return new LintGradleRequest(this, mModelProject, mPlugin, mVariantName, files);
+ }
+
+ /** Run lint with the given registry and return the resulting warnings */
+ @NonNull
+ public List<Warning> run(@NonNull IssueRegistry registry) throws IOException {
+ run(registry, Collections.<File>emptyList());
+ return mWarnings;
+ }
+
+ /**
+ * Given a list of results from separate variants, merge them into a single
+ * list of warnings, and mark their
+ * @param warningMap a map from variant to corresponding warnings
+ * @param project the project model
+ * @return a merged list of issues
+ */
+ @NonNull
+ public static List<Warning> merge(
+ @NonNull Map<Variant,List<Warning>> warningMap,
+ @NonNull AndroidProject project) {
+ // Easy merge?
+ if (warningMap.size() == 1) {
+ return warningMap.values().iterator().next();
+ }
+ int maxCount = 0;
+ for (List<Warning> warnings : warningMap.values()) {
+ int size = warnings.size();
+ maxCount = Math.max(size, maxCount);
+ }
+ if (maxCount == 0) {
+ return Collections.emptyList();
+ }
+
+ int totalVariantCount = project.getVariants().size();
+
+ List<Warning> merged = Lists.newArrayListWithExpectedSize(2 * maxCount);
+
+ // Map fro issue to message to line number to file name to canonical warning
+ Map<Issue,Map<String, Map<Integer, Map<String, Warning>>>> map =
+ Maps.newHashMapWithExpectedSize(2 * maxCount);
+
+ for (Map.Entry<Variant,List<Warning>> entry : warningMap.entrySet()) {
+ Variant variant = entry.getKey();
+ List<Warning> warnings = entry.getValue();
+ for (Warning warning : warnings) {
+ Map<String,Map<Integer,Map<String,Warning>>> messageMap = map.get(warning.issue);
+ if (messageMap == null) {
+ messageMap = Maps.newHashMap();
+ map.put(warning.issue, messageMap);
+ }
+ Map<Integer, Map<String, Warning>> lineMap = messageMap.get(warning.message);
+ if (lineMap == null) {
+ lineMap = Maps.newHashMap();
+ messageMap.put(warning.message, lineMap);
+ }
+ Map<String, Warning> fileMap = lineMap.get(warning.line);
+ if (fileMap == null) {
+ fileMap = Maps.newHashMap();
+ lineMap.put(warning.line, fileMap);
+ }
+ String fileName = warning.file != null ? warning.file.getName() : "<unknown>";
+ Warning canonical = fileMap.get(fileName);
+ if (canonical == null) {
+ canonical = warning;
+ fileMap.put(fileName, canonical);
+ canonical.variants = Sets.newHashSet();
+ canonical.gradleProject = project;
+ }
+ merged.add(canonical);
+ canonical.variants.add(variant);
+ }
+ }
+
+ // Clear out variants on any nodes that don't define all
+ for (Warning warning : merged) {
+ if (warning.variants != null && warning.variants.size() == totalVariantCount) {
+ // If this error is present in all variants, just clear it out
+ warning.variants = null;
+ }
+
+ }
+
+ Collections.sort(merged);
+ return merged;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleProject.java b/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleProject.java
new file mode 100644
index 0000000..79304d8
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleProject.java
@@ -0,0 +1,460 @@
+package com.android.build.gradle.internal;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.model.AndroidArtifact;
+import com.android.builder.model.AndroidLibrary;
+import com.android.builder.model.AndroidProject;
+import com.android.builder.model.BuildTypeContainer;
+import com.android.builder.model.Dependencies;
+import com.android.builder.model.ProductFlavor;
+import com.android.builder.model.ProductFlavorContainer;
+import com.android.builder.model.SourceProvider;
+import com.android.builder.model.Variant;
+import com.android.sdklib.AndroidTargetHash;
+import com.android.sdklib.AndroidVersion;
+import com.android.tools.lint.detector.api.Project;
+import com.android.utils.Pair;
+import com.android.utils.XmlUtils;
+
+import org.w3c.dom.Document;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static java.io.File.separatorChar;
+
+/**
+ * An implementation of Lint's {@link Project} class wrapping a Gradle model (project or
+ * library)
+ */
+public class LintGradleProject extends Project {
+ private LintGradleProject(
+ @NonNull LintGradleClient client,
+ @NonNull File dir,
+ @NonNull File referenceDir,
+ @NonNull File manifest) {
+ super(client, dir, referenceDir);
+ mGradleProject = true;
+ mMergeManifests = true;
+ mDirectLibraries = Lists.newArrayList();
+ readManifest(manifest);
+ }
+
+ /**
+ * Creates a {@link com.android.build.gradle.internal.LintGradleProject} from
+ * the given {@link com.android.builder.model.AndroidProject} definition for
+ * a given {@link com.android.builder.model.Variant}, and returns it along with
+ * a set of lint custom rule jars applicable for the given model project.
+ *
+ * @param client the client
+ * @param project the model project
+ * @param variant the variant
+ * @param gradleProject the gradle project
+ * @return a pair of new project and list of custom rule jars
+ */
+ @NonNull
+ public static Pair<LintGradleProject, List<File>> create(
+ @NonNull LintGradleClient client,
+ @NonNull AndroidProject project,
+ @NonNull Variant variant,
+ @NonNull org.gradle.api.Project gradleProject) {
+ File dir = gradleProject.getRootDir();
+ AppGradleProject lintProject = new AppGradleProject(client, dir,
+ dir, project, variant);
+
+ List<File> customRules = Lists.newArrayList();
+ File appLintJar = new File(gradleProject.getBuildDir(),
+ "lint" + separatorChar + "lint.jar");
+ if (appLintJar.exists()) {
+ customRules.add(appLintJar);
+ }
+
+ Set<AndroidLibrary> libraries = Sets.newHashSet();
+ Dependencies dependencies = variant.getMainArtifact().getDependencies();
+ for (AndroidLibrary library : dependencies.getLibraries()) {
+ lintProject.addDirectLibrary(createLibrary(client, library, libraries, customRules));
+ }
+
+ return Pair.<LintGradleProject,List<File>>of(lintProject, customRules);
+ }
+
+
+ @Override
+ protected void initialize() {
+ // Deliberately not calling super; that code is for ADT compatibility
+ }
+
+ protected void readManifest(File manifest) {
+ if (manifest.exists()) {
+ try {
+ String xml = Files.toString(manifest, Charsets.UTF_8);
+ Document document = XmlUtils.parseDocumentSilently(xml, true);
+ readManifest(document);
+ } catch (IOException e) {
+ mClient.log(e, "Could not read manifest %1$s", manifest);
+ }
+ }
+ }
+
+ @Override
+ public boolean isGradleProject() {
+ return true;
+ }
+
+ void addDirectLibrary(@NonNull Project project) {
+ mDirectLibraries.add(project);
+ }
+
+ @NonNull
+ private static LibraryProject createLibrary(@NonNull LintGradleClient client,
+ @NonNull AndroidLibrary library,
+ @NonNull Set<AndroidLibrary> seen, List<File> customRules) {
+ seen.add(library);
+ File dir = library.getFolder();
+ LibraryProject project = new LibraryProject(client, dir, dir, library);
+
+ File ruleJar = library.getLintJar();
+ if (ruleJar.exists()) {
+ customRules.add(ruleJar);
+ }
+
+ for (AndroidLibrary dependent : library.getLibraryDependencies()) {
+ if (!seen.contains(dependent)) {
+ project.addDirectLibrary(createLibrary(client, dependent, seen, customRules));
+ }
+ }
+
+ return project;
+ }
+
+ private static class AppGradleProject extends LintGradleProject {
+ private AndroidProject mProject;
+ private Variant mVariant;
+ private List<SourceProvider> mProviders;
+
+ private AppGradleProject(
+ @NonNull LintGradleClient client,
+ @NonNull File dir,
+ @NonNull File referenceDir,
+ @NonNull AndroidProject project,
+ @NonNull Variant variant) {
+ super(client, dir, referenceDir, variant.getMainArtifact().getGeneratedManifest());
+
+ mProject = project;
+ mVariant = variant;
+ }
+
+ @Override
+ public boolean isLibrary() {
+ return mProject.isLibrary();
+ }
+
+ @Override
+ public AndroidProject getGradleProjectModel() {
+ return mProject;
+ }
+
+ @Override
+ public Variant getCurrentVariant() {
+ return mVariant;
+ }
+
+ private List<SourceProvider> getSourceProviders() {
+ if (mProviders == null) {
+ List<SourceProvider> providers = Lists.newArrayList();
+ AndroidArtifact mainArtifact = mVariant.getMainArtifact();
+
+ SourceProvider defaultProvider = mProject.getDefaultConfig().getSourceProvider();
+ if (defaultProvider != null) {
+ providers.add(defaultProvider);
+ }
+
+ for (String flavorName : mVariant.getProductFlavors()) {
+ for (ProductFlavorContainer flavor : mProject.getProductFlavors()) {
+ if (flavorName.equals(flavor.getProductFlavor().getName())) {
+ SourceProvider provider = flavor.getSourceProvider();
+ if (provider != null) {
+ providers.add(provider);
+ }
+ break;
+ }
+ }
+ }
+
+ SourceProvider multiProvider = mainArtifact.getMultiFlavorSourceProvider();
+ if (multiProvider != null) {
+ providers.add(multiProvider);
+ }
+
+ String buildTypeName = mVariant.getBuildType();
+ for (BuildTypeContainer buildType : mProject.getBuildTypes()) {
+ if (buildTypeName.equals(buildType.getBuildType().getName())) {
+ SourceProvider provider = buildType.getSourceProvider();
+ if (provider != null) {
+ providers.add(provider);
+ }
+ break;
+ }
+ }
+
+ SourceProvider variantProvider = mainArtifact.getVariantSourceProvider();
+ if (variantProvider != null) {
+ providers.add(variantProvider);
+ }
+
+ mProviders = providers;
+ }
+
+ return mProviders;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getManifestFiles() {
+ if (mManifestFiles == null) {
+ mManifestFiles = Lists.newArrayList();
+ for (SourceProvider provider : getSourceProviders()) {
+ File manifestFile = provider.getManifestFile();
+ if (manifestFile.exists()) { // model returns path whether or not it exists
+ mManifestFiles.add(manifestFile);
+ }
+ }
+ }
+
+ return mManifestFiles;
+ }
+
+ @Override
+ public List<File> getProguardFiles() {
+ if (mProguardFiles == null) {
+ ProductFlavor flavor = mProject.getDefaultConfig().getProductFlavor();
+ mProguardFiles = Lists.newArrayList();
+ mProguardFiles.addAll(flavor.getProguardFiles());
+ // TODO: This is currently broken:
+ //mProguardFiles.addAll(flavor.getConsumerProguardFiles());
+ // It will throw
+ //org.gradle.tooling.model.UnsupportedMethodException: Unsupported method: BaseConfig.getConsumerProguardFiles().
+ // The version of Gradle you connect to does not support that method.
+ // To resolve the problem you can change/upgrade the target version of Gradle you connect to.
+ // Alternatively, you can ignore this exception and read other information from the model.
+ //at org.gradle.tooling.model.internal.Exceptions.unsupportedMethod(Exceptions.java:33)
+ //at org.gradle.tooling.internal.adapter.ProtocolToModelAdapter$InvocationHandlerImpl.invoke(ProtocolToModelAdapter.java:239)
+ //at com.sun.proxy.$Proxy129.getConsumerProguardFiles(Unknown Source)
+ }
+
+ return mProguardFiles;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getResourceFolders() {
+ if (mResourceFolders == null) {
+ mResourceFolders = Lists.newArrayList();
+ for (SourceProvider provider : getSourceProviders()) {
+ Collection<File> resDirs = provider.getResDirectories();
+ for (File res : resDirs) {
+ if (res.exists()) { // model returns path whether or not it exists
+ mResourceFolders.add(res);
+ }
+ }
+ }
+ }
+
+ return mResourceFolders;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getJavaSourceFolders() {
+ if (mJavaSourceFolders == null) {
+ mJavaSourceFolders = Lists.newArrayList();
+ for (SourceProvider provider : getSourceProviders()) {
+ Collection<File> resDirs = provider.getJavaDirectories();
+ for (File res : resDirs) {
+ if (res.exists()) { // model returns path whether or not it exists
+ mJavaSourceFolders.add(res);
+ }
+ }
+ }
+ }
+
+ return mJavaSourceFolders;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getJavaClassFolders() {
+ if (mJavaClassFolders == null) {
+ mJavaClassFolders = new ArrayList<File>(1);
+ File outputClassFolder = mVariant.getMainArtifact().getClassesFolder();
+ if (outputClassFolder != null && outputClassFolder.exists()) {
+ mJavaClassFolders.add(outputClassFolder);
+ }
+ }
+
+ return mJavaClassFolders;
+ }
+
+ @Override
+ public List<File> getJavaLibraries() {
+ if (mJavaLibraries == null) {
+ Collection<File> jars = mVariant.getMainArtifact().getDependencies().getJars();
+ mJavaLibraries = Lists.newArrayListWithExpectedSize(jars.size());
+ for (File jar : jars) {
+ if (jar.exists()) {
+ mJavaLibraries.add(jar);
+ }
+ }
+ }
+ return mJavaLibraries;
+ }
+
+ @Nullable
+ @Override
+ public String getPackage() {
+ // For now, lint only needs the manifest package; not the potentially variant specific
+ // package. As part of the Gradle work on the Lint API we should make two separate
+ // package lookup methods -- one for the manifest package, one for the build package
+ if (mPackage == null) { // only used as a fallback in case manifest somehow is null
+ String packageName = mProject.getDefaultConfig().getProductFlavor().getPackageName();
+ if (packageName != null) {
+ return packageName;
+ }
+ }
+
+ return mPackage; // from manifest
+ }
+
+ @Override
+ public int getMinSdk() {
+ int minSdk = mProject.getDefaultConfig().getProductFlavor().getMinSdkVersion();
+ if (minSdk != -1) {
+ return minSdk;
+ }
+
+ return mMinSdk; // from manifest
+ }
+
+ @Override
+ public int getTargetSdk() {
+ int targetSdk = mProject.getDefaultConfig().getProductFlavor().getTargetSdkVersion();
+ if (targetSdk != -1) {
+ return targetSdk;
+ }
+
+ return targetSdk; // from manifest
+ }
+
+ @Override
+ public int getBuildSdk() {
+ String compileTarget = mProject.getCompileTarget();
+ if (compileTarget != null) {
+ AndroidVersion version = AndroidTargetHash.getPlatformVersion(compileTarget);
+ if (version != null) {
+ return version.getApiLevel();
+ }
+ }
+
+ return super.getBuildSdk();
+ }
+ }
+
+ private static class LibraryProject extends LintGradleProject {
+ private AndroidLibrary mLibrary;
+
+ private LibraryProject(
+ @NonNull LintGradleClient client,
+ @NonNull File dir,
+ @NonNull File referenceDir,
+ @NonNull AndroidLibrary library) {
+ super(client, dir, referenceDir, library.getManifest());
+ mLibrary = library;
+
+ // TODO: Make sure we don't use this project for any source library projects!
+ mReportIssues = false;
+ }
+
+ @Override
+ public boolean isLibrary() {
+ return true;
+ }
+
+ @Override
+ public AndroidLibrary getGradleLibraryModel() {
+ return mLibrary;
+ }
+
+ @Override
+ public Variant getCurrentVariant() {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getManifestFiles() {
+ if (mManifestFiles == null) {
+ File manifest = mLibrary.getManifest();
+ if (manifest.exists()) {
+ mManifestFiles = Collections.singletonList(manifest);
+ } else {
+ mManifestFiles = Collections.emptyList();
+ }
+ }
+
+ return mManifestFiles;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getResourceFolders() {
+ if (mResourceFolders == null) {
+ File folder = mLibrary.getResFolder();
+ if (folder.exists()) {
+ mResourceFolders = Collections.singletonList(folder);
+ } else {
+ mResourceFolders = Collections.emptyList();
+ }
+ }
+
+ return mResourceFolders;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getJavaSourceFolders() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public List<File> getJavaClassFolders() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public List<File> getJavaLibraries() {
+ if (mJavaLibraries == null) {
+ File jarFile = mLibrary.getJarFile();
+ if (jarFile.exists()) {
+ mJavaLibraries = Collections.singletonList(jarFile);
+ } else {
+ mJavaLibraries = Collections.emptyList();
+ }
+ }
+
+ return mJavaLibraries;
+ }
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleRequest.java b/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleRequest.java
new file mode 100644
index 0000000..b5674f9
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/LintGradleRequest.java
@@ -0,0 +1,63 @@
+package com.android.build.gradle.internal;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.build.gradle.BasePlugin;
+import com.android.builder.model.AndroidProject;
+import com.android.builder.model.Variant;
+import com.android.tools.lint.client.api.LintRequest;
+import com.android.tools.lint.detector.api.Project;
+import com.android.utils.Pair;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+class LintGradleRequest extends LintRequest {
+ @NonNull private final LintGradleClient mLintClient;
+ @NonNull private final BasePlugin mPlugin;
+ @NonNull private final String mVariantName;
+ @NonNull private final AndroidProject mModelProject;
+
+ public LintGradleRequest(
+ @NonNull LintGradleClient client,
+ @NonNull AndroidProject modelProject,
+ @NonNull BasePlugin plugin,
+ @Nullable String variantName,
+ @NonNull List<File> files) {
+ super(client, files);
+ mLintClient = client;
+ mModelProject = modelProject;
+ mPlugin = plugin;
+ mVariantName = variantName;
+ }
+
+ @Nullable
+ @Override
+ public Collection<Project> getProjects() {
+ if (mProjects == null) {
+ Variant variant = findVariant(mModelProject, mVariantName);
+ assert variant != null : mVariantName;
+ Pair<LintGradleProject,List<File>> result = LintGradleProject.create(
+ mLintClient, mModelProject, variant, mPlugin.getProject());
+ mProjects = Collections.<Project>singletonList(result.getFirst());
+ mLintClient.setCustomRules(result.getSecond());
+ }
+
+ return mProjects;
+ }
+
+ private static Variant findVariant(@NonNull AndroidProject project,
+ @NonNull String variantName) {
+ if (variantName != null) {
+ for (Variant variant : project.getVariants()) {
+ if (variantName.equals(variant.getName())) {
+ return variant;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/LoggerWrapper.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/LoggerWrapper.groovy
index c57f1e8..575c07e 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/LoggerWrapper.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/LoggerWrapper.groovy
@@ -15,6 +15,7 @@
*/
package com.android.build.gradle.internal
+import com.android.ide.common.res2.MergingException
import com.android.utils.ILogger
import org.gradle.api.logging.LogLevel
import org.gradle.api.logging.Logger
@@ -32,6 +33,17 @@
@Override
void error(Throwable throwable, String s, Object... objects) {
+ if (throwable instanceof MergingException) {
+ // MergingExceptions have a known cause: they aren't internal errors, they
+ // are errors in the user's code, so a full exception is not helpful (and
+ // these exceptions should include a pointer to the user's error right in
+ // the message).
+ //
+ // Furthermore, these exceptions are already caught by the MergeResources
+ // and MergeAsset tasks, so don't duplicate the output
+ return
+ }
+
if (objects != null && objects.length > 0) {
s = String.format(s, objects)
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/Sdk.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/Sdk.groovy
index 022239c..88c8726 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/Sdk.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/Sdk.groovy
@@ -43,6 +43,7 @@
private boolean isSdkParserInitialized = false
private File androidSdkDir
+ private File androidNdkDir
private boolean isPlatformSdk = false
private BaseExtension extension
@@ -80,7 +81,7 @@
if (isPlatformSdk) {
parser = new PlatformSdkParser(androidSdkDir.absolutePath)
} else {
- parser = new DefaultSdkParser(androidSdkDir.absolutePath)
+ parser = new DefaultSdkParser(androidSdkDir.absolutePath, androidNdkDir)
}
List<File> repositories = parser.repositories
@@ -130,11 +131,16 @@
return theParser
}
- public File getDirectory() {
+ public File getSdkDirectory() {
checkLocation()
return androidSdkDir
}
+ public File getNdkDirectory() {
+ checkLocation()
+ return androidNdkDir
+ }
+
private void checkLocation() {
// don't complain in test mode
if (TEST_SDK_DIR != null) {
@@ -179,6 +185,12 @@
"No sdk.dir property defined in local.properties file.")
}
}
+
+ def ndkDirProp = properties.getProperty('ndk.dir')
+ if (ndkDirProp != null) {
+ androidNdkDir = new File(ndkDirProp)
+ }
+
} else {
String envVar = System.getenv("ANDROID_HOME")
if (envVar != null) {
@@ -189,6 +201,11 @@
androidSdkDir = new File(property)
}
}
+
+ envVar = System.getenv("ANDROID_NDK_HOME")
+ if (envVar != null) {
+ androidNdkDir = new File(envVar)
+ }
}
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/SourceSetSourceProviderWrapper.java b/gradle/src/main/groovy/com/android/build/gradle/internal/SourceSetSourceProviderWrapper.java
new file mode 100644
index 0000000..0cc3f7c
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/SourceSetSourceProviderWrapper.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal;
+
+import com.android.annotations.NonNull;
+import com.android.builder.model.SourceProvider;
+import org.gradle.api.tasks.SourceSet;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * An implementation of SourceProvider that's wrapper around a Java SourceSet.
+ * This is useful for the case where we store SourceProviders but don't want to
+ * query the content of the SourceSet at the moment the SourceProvider is created.
+ */
+public class SourceSetSourceProviderWrapper implements SourceProvider {
+
+ @NonNull
+ private final SourceSet sourceSet;
+
+ public SourceSetSourceProviderWrapper(@NonNull SourceSet sourceSet) {
+
+ this.sourceSet = sourceSet;
+ }
+
+ @NonNull
+ @Override
+ public File getManifestFile() {
+ throw new IllegalAccessError("Shouldn't access manifest from SourceSetSourceProviderWrapper");
+ }
+
+ @NonNull
+ @Override
+ public Collection<File> getJavaDirectories() {
+ return sourceSet.getAllJava().getSrcDirs();
+ }
+
+ @NonNull
+ @Override
+ public Collection<File> getResourcesDirectories() {
+ return sourceSet.getResources().getSrcDirs();
+ }
+
+ @NonNull
+ @Override
+ public Collection<File> getAidlDirectories() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public Collection<File> getRenderscriptDirectories() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public Collection<File> getJniDirectories() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public Collection<File> getResDirectories() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public Collection<File> getAssetsDirectories() {
+ return Collections.emptyList();
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/api/ApplicationVariantImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/api/ApplicationVariantImpl.java
index efbbad3..fcc3d0b 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/api/ApplicationVariantImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/api/ApplicationVariantImpl.java
@@ -21,23 +21,13 @@
import com.android.build.gradle.api.ApplicationVariant;
import com.android.build.gradle.api.TestVariant;
import com.android.build.gradle.internal.variant.ApplicationVariantData;
-import com.android.build.gradle.tasks.AidlCompile;
+import com.android.build.gradle.internal.variant.BaseVariantData;
import com.android.build.gradle.tasks.Dex;
-import com.android.build.gradle.tasks.GenerateBuildConfig;
-import com.android.build.gradle.tasks.MergeAssets;
-import com.android.build.gradle.tasks.MergeResources;
import com.android.build.gradle.tasks.PackageApplication;
-import com.android.build.gradle.tasks.ProcessAndroidResources;
-import com.android.build.gradle.tasks.ProcessManifest;
-import com.android.build.gradle.tasks.RenderscriptCompile;
import com.android.build.gradle.tasks.ZipAlign;
-import com.android.builder.DefaultBuildType;
import com.android.builder.DefaultProductFlavor;
import com.android.builder.model.SigningConfig;
import org.gradle.api.DefaultTask;
-import org.gradle.api.Task;
-import org.gradle.api.tasks.Copy;
-import org.gradle.api.tasks.compile.JavaCompile;
import java.io.File;
import java.util.List;
@@ -46,7 +36,7 @@
* implementation of the {@link ApplicationVariant} interface around an
* {@link ApplicationVariantData} object.
*/
-public class ApplicationVariantImpl implements ApplicationVariant {
+public class ApplicationVariantImpl extends BaseVariantImpl implements ApplicationVariant {
@NonNull
private final ApplicationVariantData variantData;
@@ -57,42 +47,17 @@
this.variantData = variantData;
}
+ @Override
+ protected BaseVariantData getVariantData() {
+ return variantData;
+ }
+
public void setTestVariant(@Nullable TestVariant testVariant) {
this.testVariant = testVariant;
}
@Override
@NonNull
- public String getName() {
- return variantData.getName();
- }
-
- @Override
- @NonNull
- public String getDescription() {
- return variantData.getDescription();
- }
-
- @Override
- @NonNull
- public String getDirName() {
- return variantData.getDirName();
- }
-
- @Override
- @NonNull
- public String getBaseName() {
- return variantData.getBaseName();
- }
-
- @Override
- @NonNull
- public DefaultBuildType getBuildType() {
- return variantData.getVariantConfiguration().getBuildType();
- }
-
- @Override
- @NonNull
public List<DefaultProductFlavor> getProductFlavors() {
return variantData.getVariantConfiguration().getFlavorConfigs();
}
@@ -104,12 +69,6 @@
}
@Override
- @NonNull
- public File getOutputFile() {
- return variantData.getOutputFile();
- }
-
- @Override
public void setOutputFile(@NonNull File outputFile) {
if (variantData.zipAlignTask != null) {
variantData.zipAlignTask.setOutputFile(outputFile);
@@ -125,57 +84,6 @@
}
@Override
- @NonNull
- public ProcessManifest getProcessManifest() {
- return variantData.processManifestTask;
- }
-
- @Override
- @NonNull
- public AidlCompile getAidlCompile() {
- return variantData.aidlCompileTask;
- }
-
- @Override
- @NonNull
- public RenderscriptCompile getRenderscriptCompile() {
- return variantData.renderscriptCompileTask;
- }
-
- @Override
- public MergeResources getMergeResources() {
- return variantData.mergeResourcesTask;
- }
-
- @Override
- public MergeAssets getMergeAssets() {
- return variantData.mergeAssetsTask;
- }
-
- @Override
- @NonNull
- public ProcessAndroidResources getProcessResources() {
- return variantData.processResourcesTask;
- }
-
- @Override
- public GenerateBuildConfig getGenerateBuildConfig() {
- return variantData.generateBuildConfigTask;
- }
-
- @Override
- @NonNull
- public JavaCompile getJavaCompile() {
- return variantData.javaCompileTask;
- }
-
- @Override
- @NonNull
- public Copy getProcessJavaResources() {
- return variantData.processJavaResources;
- }
-
- @Override
public Dex getDex() {
return variantData.dexTask;
}
@@ -191,11 +99,6 @@
}
@Override
- public Task getAssemble() {
- return variantData.assembleTask;
- }
-
- @Override
public DefaultTask getInstall() {
return variantData.installTask;
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/api/BaseVariantImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/api/BaseVariantImpl.java
new file mode 100644
index 0000000..894fe8a
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/api/BaseVariantImpl.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.api;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.build.gradle.api.BaseVariant;
+import com.android.build.gradle.internal.variant.BaseVariantData;
+import com.android.build.gradle.tasks.AidlCompile;
+import com.android.build.gradle.tasks.GenerateBuildConfig;
+import com.android.build.gradle.tasks.MergeAssets;
+import com.android.build.gradle.tasks.MergeResources;
+import com.android.build.gradle.tasks.ProcessAndroidResources;
+import com.android.build.gradle.tasks.ProcessManifest;
+import com.android.build.gradle.tasks.RenderscriptCompile;
+import com.android.builder.DefaultBuildType;
+import com.android.builder.DefaultProductFlavor;
+import org.gradle.api.Task;
+import org.gradle.api.tasks.Copy;
+import org.gradle.api.tasks.compile.JavaCompile;
+
+import java.io.File;
+import java.util.Collection;
+
+abstract class BaseVariantImpl implements BaseVariant {
+
+ protected abstract BaseVariantData getVariantData();
+
+ @Override
+ @NonNull
+ public String getName() {
+ return getVariantData().getVariantConfiguration().getFullName();
+ }
+
+ @Override
+ @NonNull
+ public String getDescription() {
+ return getVariantData().getDescription();
+ }
+
+ @Override
+ @NonNull
+ public String getDirName() {
+ return getVariantData().getVariantConfiguration().getDirName();
+ }
+
+ @Override
+ @NonNull
+ public String getBaseName() {
+ return getVariantData().getVariantConfiguration().getBaseName();
+ }
+
+ @NonNull
+ @Override
+ public String getFlavorName() {
+ return getVariantData().getVariantConfiguration().getFlavorName();
+ }
+
+ @Override
+ @NonNull
+ public DefaultBuildType getBuildType() {
+ return getVariantData().getVariantConfiguration().getBuildType();
+ }
+
+ @NonNull
+ @Override
+ public DefaultProductFlavor getConfig() {
+ return getVariantData().getVariantConfiguration().getDefaultConfig();
+ }
+
+ @Override
+ @NonNull
+ public File getOutputFile() {
+ return getVariantData().getOutputFile();
+ }
+
+ @Override
+ @NonNull
+ public ProcessManifest getProcessManifest() {
+ return getVariantData().processManifestTask;
+ }
+
+ @Override
+ @NonNull
+ public AidlCompile getAidlCompile() {
+ return getVariantData().aidlCompileTask;
+ }
+
+ @Override
+ @NonNull
+ public RenderscriptCompile getRenderscriptCompile() {
+ return getVariantData().renderscriptCompileTask;
+ }
+
+ @Override
+ public MergeResources getMergeResources() {
+ return getVariantData().mergeResourcesTask;
+ }
+
+ @Override
+ public MergeAssets getMergeAssets() {
+ return getVariantData().mergeAssetsTask;
+ }
+
+ @Override
+ @NonNull
+ public ProcessAndroidResources getProcessResources() {
+ return getVariantData().processResourcesTask;
+ }
+
+ @Override
+ public GenerateBuildConfig getGenerateBuildConfig() {
+ return getVariantData().generateBuildConfigTask;
+ }
+
+ @Override
+ @NonNull
+ public JavaCompile getJavaCompile() {
+ return getVariantData().javaCompileTask;
+ }
+
+ @Override
+ @NonNull
+ public Copy getProcessJavaResources() {
+ return getVariantData().processJavaResourcesTask;
+ }
+
+ @Override
+ @Nullable
+ public Task getAssemble() {
+ return getVariantData().assembleTask;
+ }
+
+ @Override
+ public void addJavaSourceFoldersToModel(@NonNull File... generatedSourceFolders) {
+ getVariantData().addJavaSourceFoldersToModel(generatedSourceFolders);
+ }
+
+ @Override
+ public void addJavaSourceFoldersToModel(@NonNull Collection<File> generatedSourceFolders) {
+ getVariantData().addJavaSourceFoldersToModel(generatedSourceFolders);
+ }
+
+ @Override
+ public void registerJavaGeneratingTask(@NonNull Task task, @NonNull File... sourceFolders) {
+ getVariantData().registerJavaGeneratingTask(task, sourceFolders);
+ }
+
+ @Override
+ public void registerJavaGeneratingTask(@NonNull Task task, @NonNull Collection<File> sourceFolders) {
+ getVariantData().registerJavaGeneratingTask(task, sourceFolders);
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/api/DefaultAndroidSourceSet.java b/gradle/src/main/groovy/com/android/build/gradle/internal/api/DefaultAndroidSourceSet.java
index aab4146..0520fa5 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/api/DefaultAndroidSourceSet.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/api/DefaultAndroidSourceSet.java
@@ -267,7 +267,6 @@
// --- SourceProvider
-
@NonNull
@Override
public Set<File> getJavaDirectories() {
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/api/LibraryVariantImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/api/LibraryVariantImpl.java
index a4acfd6..f48a529 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/api/LibraryVariantImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/api/LibraryVariantImpl.java
@@ -20,20 +20,9 @@
import com.android.annotations.Nullable;
import com.android.build.gradle.api.LibraryVariant;
import com.android.build.gradle.api.TestVariant;
+import com.android.build.gradle.internal.variant.BaseVariantData;
import com.android.build.gradle.internal.variant.LibraryVariantData;
-import com.android.build.gradle.tasks.AidlCompile;
-import com.android.build.gradle.tasks.GenerateBuildConfig;
-import com.android.build.gradle.tasks.MergeAssets;
-import com.android.build.gradle.tasks.MergeResources;
-import com.android.build.gradle.tasks.ProcessAndroidResources;
-import com.android.build.gradle.tasks.ProcessManifest;
-import com.android.build.gradle.tasks.RenderscriptCompile;
-import com.android.builder.DefaultBuildType;
-import com.android.builder.DefaultProductFlavor;
-import org.gradle.api.Task;
-import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.bundling.Zip;
-import org.gradle.api.tasks.compile.JavaCompile;
import java.io.File;
@@ -41,7 +30,7 @@
* implementation of the {@link LibraryVariant} interface around a
* {@link LibraryVariantData} object.
*/
-public class LibraryVariantImpl implements LibraryVariant {
+public class LibraryVariantImpl extends BaseVariantImpl implements LibraryVariant {
@NonNull
private final LibraryVariantData variantData;
@@ -52,48 +41,17 @@
this.variantData = variantData;
}
+ @Override
+ protected BaseVariantData getVariantData() {
+ return variantData;
+ }
+
public void setTestVariant(@Nullable TestVariant testVariant) {
this.testVariant = testVariant;
}
@Override
@NonNull
- public String getName() {
- return variantData.getName();
- }
-
- @Override
- @NonNull
- public String getDescription() {
- return variantData.getDescription();
- }
-
- @Override
- @NonNull
- public String getDirName() {
- return variantData.getDirName();
- }
-
- @Override
- @NonNull
- public String getBaseName() {
- return variantData.getBaseName();
- }
-
- @Override
- @NonNull
- public DefaultBuildType getBuildType() {
- return variantData.getVariantConfiguration().getBuildType();
- }
-
- @NonNull
- @Override
- public DefaultProductFlavor getConfig() {
- return variantData.getVariantConfiguration().getDefaultConfig();
- }
-
- @Override
- @NonNull
public File getOutputFile() {
return variantData.packageLibTask.getArchivePath();
}
@@ -111,63 +69,7 @@
}
@Override
- @NonNull
- public ProcessManifest getProcessManifest() {
- return variantData.processManifestTask;
- }
-
- @Override
- @NonNull
- public AidlCompile getAidlCompile() {
- return variantData.aidlCompileTask;
- }
-
- @Override
- @NonNull
- public RenderscriptCompile getRenderscriptCompile() {
- return variantData.renderscriptCompileTask;
- }
-
- @Override
- public MergeResources getMergeResources() {
- return variantData.mergeResourcesTask;
- }
-
- @Override
- public MergeAssets getMergeAssets() {
- return variantData.mergeAssetsTask;
- }
-
- @Override
- @NonNull
- public ProcessAndroidResources getProcessResources() {
- return variantData.processResourcesTask;
- }
-
- @Override
- public GenerateBuildConfig getGenerateBuildConfig() {
- return variantData.generateBuildConfigTask;
- }
-
- @Override
- @NonNull
- public JavaCompile getJavaCompile() {
- return variantData.javaCompileTask;
- }
-
- @Override
- @NonNull
- public Copy getProcessJavaResources() {
- return variantData.processJavaResources;
- }
-
- @Override
public Zip getPackageLibrary() {
return variantData.packageLibTask;
}
-
- @Override
- public Task getAssemble() {
- return variantData.assembleTask;
- }
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/api/TestVariantImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/api/TestVariantImpl.java
index 305c2e5..073c49d 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/api/TestVariantImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/api/TestVariantImpl.java
@@ -19,24 +19,14 @@
import com.android.annotations.NonNull;
import com.android.build.gradle.api.BaseVariant;
import com.android.build.gradle.api.TestVariant;
+import com.android.build.gradle.internal.variant.BaseVariantData;
import com.android.build.gradle.internal.variant.TestVariantData;
-import com.android.build.gradle.tasks.AidlCompile;
import com.android.build.gradle.tasks.Dex;
-import com.android.build.gradle.tasks.GenerateBuildConfig;
-import com.android.build.gradle.tasks.MergeAssets;
-import com.android.build.gradle.tasks.MergeResources;
import com.android.build.gradle.tasks.PackageApplication;
-import com.android.build.gradle.tasks.ProcessAndroidResources;
-import com.android.build.gradle.tasks.ProcessManifest;
-import com.android.build.gradle.tasks.RenderscriptCompile;
import com.android.build.gradle.tasks.ZipAlign;
-import com.android.builder.DefaultBuildType;
import com.android.builder.DefaultProductFlavor;
import com.android.builder.model.SigningConfig;
import org.gradle.api.DefaultTask;
-import org.gradle.api.Task;
-import org.gradle.api.tasks.Copy;
-import org.gradle.api.tasks.compile.JavaCompile;
import java.io.File;
import java.util.List;
@@ -44,7 +34,7 @@
/**
* implementation of the {@link TestVariant} interface around an {@link TestVariantData} object.
*/
-public class TestVariantImpl implements TestVariant {
+public class TestVariantImpl extends BaseVariantImpl implements TestVariant {
@NonNull
private final TestVariantData variantData;
@@ -56,33 +46,8 @@
}
@Override
- @NonNull
- public String getName() {
- return variantData.getName();
- }
-
- @Override
- @NonNull
- public String getDescription() {
- return variantData.getDescription();
- }
-
- @Override
- @NonNull
- public String getDirName() {
- return variantData.getDirName();
- }
-
- @Override
- @NonNull
- public String getBaseName() {
- return variantData.getBaseName();
- }
-
- @Override
- @NonNull
- public DefaultBuildType getBuildType() {
- return variantData.getVariantConfiguration().getBuildType();
+ protected BaseVariantData getVariantData() {
+ return variantData;
}
@Override
@@ -98,12 +63,6 @@
}
@Override
- @NonNull
- public File getOutputFile() {
- return variantData.getOutputFile();
- }
-
- @Override
public void setOutputFile(@NonNull File outputFile) {
if (variantData.zipAlignTask != null) {
variantData.zipAlignTask.setOutputFile(outputFile);
@@ -123,57 +82,6 @@
}
@Override
- @NonNull
- public ProcessManifest getProcessManifest() {
- return variantData.processManifestTask;
- }
-
- @Override
- @NonNull
- public AidlCompile getAidlCompile() {
- return variantData.aidlCompileTask;
- }
-
- @Override
- @NonNull
- public RenderscriptCompile getRenderscriptCompile() {
- return variantData.renderscriptCompileTask;
- }
-
- @Override
- public MergeResources getMergeResources() {
- return variantData.mergeResourcesTask;
- }
-
- @Override
- public MergeAssets getMergeAssets() {
- return variantData.mergeAssetsTask;
- }
-
- @Override
- @NonNull
- public ProcessAndroidResources getProcessResources() {
- return variantData.processResourcesTask;
- }
-
- @Override
- public GenerateBuildConfig getGenerateBuildConfig() {
- return variantData.generateBuildConfigTask;
- }
-
- @Override
- @NonNull
- public JavaCompile getJavaCompile() {
- return variantData.javaCompileTask;
- }
-
- @Override
- @NonNull
- public Copy getProcessJavaResources() {
- return variantData.processJavaResources;
- }
-
- @Override
public Dex getDex() {
return variantData.dexTask;
}
@@ -189,11 +97,6 @@
}
@Override
- public Task getAssemble() {
- return variantData.assembleTask;
- }
-
- @Override
public DefaultTask getInstall() {
return variantData.installTask;
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/AaptOptionsImpl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/AaptOptionsImpl.groovy
index 449a43f..d50371e 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/AaptOptionsImpl.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/AaptOptionsImpl.groovy
@@ -45,7 +45,7 @@
}
@Override
- List<String> getNoCompress() {
+ Collection<String> getNoCompress() {
return noCompressList
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy
index 6c4f97f..6b51bc4 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeDsl.groovy
@@ -16,11 +16,16 @@
package com.android.build.gradle.internal.dsl
import com.android.annotations.NonNull
+import com.android.annotations.Nullable
+import com.android.annotations.VisibleForTesting
+import com.android.builder.AndroidBuilder
import com.android.builder.BuilderConstants
import com.android.builder.DefaultBuildType
+import com.android.builder.model.NdkConfig
import com.android.builder.model.SigningConfig
+import org.gradle.api.Action
import org.gradle.api.internal.file.FileResolver
-
+import org.gradle.internal.reflect.Instantiator
/**
* DSL overlay to make methods that accept String... work.
*/
@@ -30,9 +35,28 @@
@NonNull
private final FileResolver fileResolver
- BuildTypeDsl(@NonNull String name, @NonNull FileResolver fileResolver) {
+ private final NdkConfigDsl ndkConfig
+
+ public BuildTypeDsl(@NonNull String name,
+ @NonNull FileResolver fileResolver,
+ @NonNull Instantiator instantiator) {
super(name)
this.fileResolver = fileResolver
+ ndkConfig = instantiator.newInstance(NdkConfigDsl.class)
+ }
+
+ @VisibleForTesting
+ BuildTypeDsl(@NonNull String name,
+ @NonNull FileResolver fileResolver) {
+ super(name)
+ this.fileResolver = fileResolver
+ ndkConfig = null
+ }
+
+ @Override
+ @Nullable
+ public NdkConfig getNdkConfig() {
+ return ndkConfig;
}
public void init(SigningConfig debugSigningConfig) {
@@ -58,12 +82,11 @@
// -- DSL Methods. TODO remove once the instantiator does what I expect it to do.
- public void buildConfig(String... lines) {
- setBuildConfig(lines)
- }
-
- public void buildConfig(String line) {
- setBuildConfig(line)
+ public void buildConfigField(
+ @NonNull String type,
+ @NonNull String name,
+ @NonNull String value) {
+ addBuildConfigField(AndroidBuilder.createClassField(type, name, value));
}
@NonNull
@@ -86,4 +109,23 @@
}
return this;
}
+
+ @NonNull
+ public BuildTypeDsl consumerProguardFiles(Object... proguardFileArray) {
+ consumerProguardFiles.addAll(fileResolver.resolveFiles(proguardFileArray).files);
+ return this;
+ }
+
+ @NonNull
+ public BuildTypeDsl setConsumerProguardFiles(Iterable<?> proguardFileIterable) {
+ consumerProguardFiles.clear();
+ for (Object proguardFile : proguardFileIterable) {
+ consumerProguardFiles.add(fileResolver.resolve(proguardFile));
+ }
+ return this;
+ }
+
+ void ndk(Action<NdkConfigDsl> action) {
+ action.execute(ndkConfig)
+ }
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeFactory.java b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeFactory.java
index 3bdfe19..486727e 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeFactory.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/BuildTypeFactory.java
@@ -40,6 +40,6 @@
@Override
public DefaultBuildType create(String name) {
- return instantiator.newInstance(BuildTypeDsl.class, name, fileResolver);
+ return instantiator.newInstance(BuildTypeDsl.class, name, fileResolver, instantiator);
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/DexOptionsImpl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/DexOptionsImpl.groovy
index 899337a..767b9d3 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/DexOptionsImpl.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/DexOptionsImpl.groovy
@@ -26,7 +26,13 @@
private boolean coreLibraryFlag
@Input
- private boolean isIncrementalFlag = true
+ private boolean isIncrementalFlag = false
+
+ @Input
+ private boolean isPreDexLibrariesFlag = true
+
+ @Input
+ private boolean isJumboModeFlag = false
@Input
@Optional
@@ -50,6 +56,24 @@
return isIncrementalFlag
}
+ @Override
+ boolean getPreDexLibraries() {
+ return isPreDexLibrariesFlag
+ }
+
+ void setPreDexLibraries(boolean flag) {
+ isPreDexLibrariesFlag = flag
+ }
+
+ public void setJumboMode(boolean flag) {
+ isJumboModeFlag = flag
+ }
+
+ @Override
+ boolean getJumboMode() {
+ return isJumboModeFlag
+ }
+
public void setJavaMaxHeapSize(String theJavaMaxHeapSize) {
if (theJavaMaxHeapSize.matches("\\d+[kKmMgGtT]?")) {
javaMaxHeapSize = theJavaMaxHeapSize
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorDsl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorDsl.groovy
index d60334b..621ac85 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorDsl.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorDsl.groovy
@@ -18,6 +18,7 @@
import com.android.annotations.NonNull
import org.gradle.api.internal.file.FileResolver
+import org.gradle.internal.reflect.Instantiator
/**
* A version of ProductFlavorDsl that can receive a group name
@@ -27,7 +28,10 @@
String flavorGroup
- public GroupableProductFlavorDsl(@NonNull String name, @NonNull FileResolver fileResolver) {
- super(name, fileResolver)
+ public GroupableProductFlavorDsl(
+ @NonNull String name,
+ @NonNull FileResolver fileResolver,
+ @NonNull Instantiator instantiator) {
+ super(name, fileResolver, instantiator)
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorFactory.java b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorFactory.java
index 7ad9043..ed422d9 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorFactory.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/GroupableProductFlavorFactory.java
@@ -40,6 +40,7 @@
@Override
public GroupableProductFlavorDsl create(String name) {
- return instantiator.newInstance(GroupableProductFlavorDsl.class, name, fileResolver);
+ return instantiator.newInstance(GroupableProductFlavorDsl.class,
+ name, fileResolver, instantiator);
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/NdkConfigDsl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/NdkConfigDsl.java
new file mode 100644
index 0000000..6b708e5
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/NdkConfigDsl.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.dsl;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.model.NdkConfig;
+import com.google.common.collect.Sets;
+import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.Optional;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Implementation of NdkConfig to be used in the gradle DSL.
+ */
+public class NdkConfigDsl implements NdkConfig, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String moduleName;
+ private String cFlags;
+ private Set<String> ldLibs;
+ private Set<String> abiFilters;
+ private String stl;
+
+ public NdkConfigDsl() {
+ }
+
+ public NdkConfigDsl(@NonNull NdkConfigDsl ndkConfig) {
+ moduleName = ndkConfig.moduleName;
+ cFlags = ndkConfig.cFlags;
+ setLdLibs(ndkConfig.ldLibs);
+ setAbiFilters(ndkConfig.abiFilters);
+ }
+
+ @Override
+ @Input @Optional
+ public String getModuleName() {
+ return moduleName;
+ }
+
+ public void setModuleName(String moduleName) {
+ this.moduleName = moduleName;
+ }
+
+ @Override
+ @Input @Optional
+ public String getcFlags() {
+ return cFlags;
+ }
+
+ public void setcFlags(String cFlags) {
+ this.cFlags = cFlags;
+ }
+
+ @Override
+ @Input @Optional
+ public Set<String> getLdLibs() {
+ return ldLibs;
+ }
+
+ @NonNull
+ public NdkConfigDsl ldLibs(String lib) {
+ if (ldLibs == null) {
+ ldLibs = Sets.newHashSet();
+ }
+ ldLibs.add(lib);
+ return this;
+ }
+
+ @NonNull
+ public NdkConfigDsl ldLibs(String... libs) {
+ if (ldLibs == null) {
+ ldLibs = Sets.newHashSetWithExpectedSize(libs.length);
+ }
+ Collections.addAll(ldLibs, libs);
+ return this;
+ }
+
+ @NonNull
+ public NdkConfigDsl setLdLibs(Collection<String> libs) {
+ if (libs != null) {
+ if (abiFilters == null) {
+ abiFilters = Sets.newHashSetWithExpectedSize(libs.size());
+ } else {
+ abiFilters.clear();
+ }
+ for (String filter : libs) {
+ abiFilters.add(filter);
+ }
+ } else {
+ abiFilters = null;
+ }
+ return this;
+ }
+
+
+ @Override
+ @Input @Optional
+ public Set<String> getAbiFilters() {
+ return abiFilters;
+ }
+
+ @NonNull
+ public NdkConfigDsl abiFilter(String filter) {
+ if (abiFilters == null) {
+ abiFilters = Sets.newHashSetWithExpectedSize(2);
+ }
+ abiFilters.add(filter);
+ return this;
+ }
+
+ @NonNull
+ public NdkConfigDsl abiFilters(String... filters) {
+ if (abiFilters == null) {
+ abiFilters = Sets.newHashSetWithExpectedSize(2);
+ }
+ Collections.addAll(abiFilters, filters);
+ return this;
+ }
+
+ @NonNull
+ public NdkConfigDsl setAbiFilters(Collection<String> filters) {
+ if (filters != null) {
+ if (abiFilters == null) {
+ abiFilters = Sets.newHashSetWithExpectedSize(filters.size());
+ } else {
+ abiFilters.clear();
+ }
+ for (String filter : filters) {
+ abiFilters.add(filter);
+ }
+ } else {
+ abiFilters = null;
+ }
+ return this;
+ }
+
+ @Override
+ @Nullable
+ public String getStl() {
+ return stl;
+ }
+
+ public void setStl(String stl) {
+ this.stl = stl;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy
index 91a27b1..669fc8f 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/dsl/ProductFlavorDsl.groovy
@@ -15,10 +15,15 @@
*/
package com.android.build.gradle.internal.dsl
-import com.android.annotations.NonNull
-import com.android.builder.DefaultProductFlavor
-import org.gradle.api.internal.file.FileResolver
+import com.android.annotations.NonNull
+import com.android.annotations.Nullable
+import com.android.builder.AndroidBuilder
+import com.android.builder.DefaultProductFlavor
+import com.android.builder.model.NdkConfig
+import org.gradle.api.Action
+import org.gradle.api.internal.file.FileResolver
+import org.gradle.internal.reflect.Instantiator
/**
* DSL overlay to make methods that accept String... work.
*/
@@ -28,39 +33,80 @@
@NonNull
private final FileResolver fileResolver
- ProductFlavorDsl(String name, @NonNull FileResolver fileResolver) {
+ private final NdkConfigDsl ndkConfig
+
+ ProductFlavorDsl(@NonNull String name,
+ @NonNull FileResolver fileResolver,
+ @NonNull Instantiator instantiator) {
super(name)
this.fileResolver = fileResolver
+
+ ndkConfig = instantiator.newInstance(NdkConfigDsl.class)
+ }
+
+ @Override
+ @Nullable
+ public NdkConfig getNdkConfig() {
+ return ndkConfig;
}
// -- DSL Methods. TODO remove once the instantiator does what I expect it to do.
- public void buildConfig(String... lines) {
- setBuildConfig(lines)
- }
-
- public void buildConfig(String line) {
- setBuildConfig(line)
+ public void buildConfigField(
+ @NonNull String type,
+ @NonNull String name,
+ @NonNull String value) {
+ addBuildConfigField(AndroidBuilder.createClassField(type, name, value));
}
@NonNull
public ProductFlavorDsl proguardFile(Object proguardFile) {
- proguardFiles.add(fileResolver.resolve(proguardFile));
- return this;
+ proguardFiles.add(fileResolver.resolve(proguardFile))
+ return this
}
@NonNull
public ProductFlavorDsl proguardFiles(Object... proguardFileArray) {
- proguardFiles.addAll(fileResolver.resolveFiles(proguardFileArray).files);
- return this;
+ proguardFiles.addAll(fileResolver.resolveFiles(proguardFileArray).files)
+ return this
}
@NonNull
public ProductFlavorDsl setProguardFiles(Iterable<?> proguardFileIterable) {
- proguardFiles.clear();
+ proguardFiles.clear()
for (Object proguardFile : proguardFileIterable) {
- proguardFiles.add(fileResolver.resolve(proguardFile));
+ proguardFiles.add(fileResolver.resolve(proguardFile))
}
- return this;
+ return this
+ }
+
+ @NonNull
+ public ProductFlavorDsl consumerProguardFiles(Object... proguardFileArray) {
+ consumerProguardFiles.addAll(fileResolver.resolveFiles(proguardFileArray).files)
+ return this
+ }
+
+ @NonNull
+ public ProductFlavorDsl setconsumerProguardFiles(Iterable<?> proguardFileIterable) {
+ consumerProguardFiles.clear()
+ for (Object proguardFile : proguardFileIterable) {
+ consumerProguardFiles.add(fileResolver.resolve(proguardFile))
+ }
+ return this
+ }
+
+ void ndk(Action<NdkConfigDsl> action) {
+ action.execute(ndkConfig)
+ }
+
+ void resConfig(@NonNull String config) {
+ addResourceConfiguration(config);
+ }
+
+ void resConfigs(@NonNull String... config) {
+ addResourceConfigurations(config);
+ }
+ void resConfigs(@NonNull Collection<String> config) {
+ addResourceConfigurations(config);
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/AndroidArtifactImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/AndroidArtifactImpl.java
new file mode 100644
index 0000000..f27a055
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/AndroidArtifactImpl.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.model;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.model.AndroidArtifact;
+import com.android.builder.model.Dependencies;
+import com.android.builder.model.SourceProvider;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Implementation of AndroidArtifact that is serializable
+ */
+public class AndroidArtifactImpl extends BaseArtifactImpl implements AndroidArtifact, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @NonNull
+ private final File outputFile;
+ private final boolean isSigned;
+ @Nullable
+ private final String signingConfigName;
+ @NonNull
+ private final String packageName;
+ @NonNull
+ private final String sourceGenTaskName;
+ @NonNull
+ private final File generatedManifest;
+ @NonNull
+ private final List<File> generatedSourceFolders;
+ @NonNull
+ private final List<File> generatedResourceFolders;
+
+ AndroidArtifactImpl(@NonNull String name,
+ @NonNull String assembleTaskName,
+ @NonNull File outputFile,
+ boolean isSigned,
+ @Nullable String signingConfigName,
+ @NonNull String packageName,
+ @NonNull String sourceGenTaskName,
+ @NonNull String javaCompileTaskName,
+ @NonNull File generatedManifest,
+ @NonNull List<File> generatedSourceFolders,
+ @NonNull List<File> generatedResourceFolders,
+ @NonNull File classesFolder,
+ @NonNull Dependencies dependencies,
+ @Nullable SourceProvider variantSourceProvider,
+ @Nullable SourceProvider multiFlavorSourceProviders) {
+ super(name, assembleTaskName, javaCompileTaskName, classesFolder, dependencies,
+ variantSourceProvider, multiFlavorSourceProviders);
+
+ this.outputFile = outputFile;
+ this.isSigned = isSigned;
+ this.signingConfigName = signingConfigName;
+ this.packageName = packageName;
+ this.sourceGenTaskName = sourceGenTaskName;
+ this.generatedManifest = generatedManifest;
+ this.generatedSourceFolders = generatedSourceFolders;
+ this.generatedResourceFolders = generatedResourceFolders;
+ }
+
+ @NonNull
+ @Override
+ public File getOutputFile() {
+ return outputFile;
+ }
+
+ @Override
+ public boolean isSigned() {
+ return isSigned;
+ }
+
+ @Nullable
+ @Override
+ public String getSigningConfigName() {
+ return signingConfigName;
+ }
+
+ @NonNull
+ @Override
+ public String getPackageName() {
+ return packageName;
+ }
+
+ @NonNull
+ @Override
+ public String getSourceGenTaskName() {
+ return sourceGenTaskName;
+ }
+
+ @NonNull
+ @Override
+ public File getGeneratedManifest() {
+ return generatedManifest;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getGeneratedSourceFolders() {
+ return generatedSourceFolders;
+ }
+
+ @NonNull
+ @Override
+ public List<File> getGeneratedResourceFolders() {
+ return generatedResourceFolders;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/AndroidLibraryImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/AndroidLibraryImpl.java
index d931e28..8635ce8 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/AndroidLibraryImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/AndroidLibraryImpl.java
@@ -23,6 +23,7 @@
import java.io.File;
import java.io.Serializable;
+import java.util.Collection;
import java.util.List;
public class AndroidLibraryImpl implements AndroidLibrary, Serializable {
@@ -35,9 +36,11 @@
@NonNull
private final File folder;
@NonNull
+ private final File manifest;
+ @NonNull
private final File jarFile;
@NonNull
- private final List<File> localJars;
+ private final Collection<File> localJars;
@NonNull
private final File resFolder;
@NonNull
@@ -61,6 +64,7 @@
this.dependencies = dependencies;
bundle = libraryDependency.getBundle();
folder = libraryDependency.getFolder();
+ manifest = libraryDependency.getManifest();
jarFile = libraryDependency.getJarFile();
localJars = libraryDependency.getLocalJars();
resFolder = libraryDependency.getResFolder();
@@ -100,13 +104,19 @@
@NonNull
@Override
+ public File getManifest() {
+ return manifest;
+ }
+
+ @NonNull
+ @Override
public File getJarFile() {
return jarFile;
}
@NonNull
@Override
- public List<File> getLocalJars() {
+ public Collection<File> getLocalJars() {
return localJars;
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ArtifactInfoImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ArtifactInfoImpl.java
deleted file mode 100644
index d400261..0000000
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ArtifactInfoImpl.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.build.gradle.internal.model;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.builder.model.ArtifactInfo;
-import com.android.builder.model.Dependencies;
-
-import java.io.File;
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * Implementation of ArtifactInfo that is serializable
- */
-public class ArtifactInfoImpl implements ArtifactInfo, Serializable {
-
- @NonNull
- private final File outputFile;
- private final boolean isSigned;
- @Nullable
- private final String signingConfigName;
- @NonNull
- private final String assembleTaskName;
- @NonNull
- private final String packageName;
- @NonNull
- private final List<File> generatedSourceFolders;
- @NonNull
- private final List<File> generatedResourceFolders;
- @NonNull
- private final File classesFolder;
- @NonNull
- private final Dependencies dependencies;
-
-
- ArtifactInfoImpl(@NonNull String assembleTaskName,
- @NonNull File outputFile,
- boolean isSigned,
- @Nullable String signingConfigName,
- @NonNull String packageName,
- @NonNull List<File> generatedSourceFolders,
- @NonNull List<File> generatedResourceFolders,
- @NonNull File classesFolder,
- @NonNull Dependencies dependencies) {
- this.assembleTaskName = assembleTaskName;
- this.outputFile = outputFile;
- this.isSigned = isSigned;
- this.signingConfigName = signingConfigName;
- this.packageName = packageName;
- this.generatedSourceFolders = generatedSourceFolders;
- this.generatedResourceFolders = generatedResourceFolders;
- this.classesFolder = classesFolder;
- this.dependencies = dependencies;
- }
-
- @NonNull
- @Override
- public File getOutputFile() {
- return outputFile;
- }
-
- @Override
- public boolean isSigned() {
- return isSigned;
- }
-
- @Nullable
- @Override
- public String getSigningConfigName() {
- return signingConfigName;
- }
-
- @NonNull
- @Override
- public String getPackageName() {
- return packageName;
- }
-
- @NonNull
- @Override
- public String getSourceGenTaskName() {
- return "TODO";
- }
-
- @NonNull
- @Override
- public String getAssembleTaskName() {
- return assembleTaskName;
- }
-
- @NonNull
- @Override
- public List<File> getGeneratedSourceFolders() {
- return generatedSourceFolders;
- }
-
- @NonNull
- @Override
- public List<File> getGeneratedResourceFolders() {
- return generatedResourceFolders;
- }
-
- @NonNull
- @Override
- public File getClassesFolder() {
- return classesFolder;
- }
-
- @NonNull
- @Override
- public Dependencies getDependencies() {
- return dependencies;
- }
-}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ArtifactMetaDataImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ArtifactMetaDataImpl.java
new file mode 100644
index 0000000..8f33c2d
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ArtifactMetaDataImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.model;
+
+import com.android.annotations.NonNull;
+import com.android.builder.model.ArtifactMetaData;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of ArtifactMetaData that is serializable
+ */
+public class ArtifactMetaDataImpl implements ArtifactMetaData, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @NonNull
+ private final String name;
+ private final boolean isTest;
+ private final int type;
+
+ public ArtifactMetaDataImpl(@NonNull String name, boolean isTest, int type) {
+ this.name = name;
+ this.isTest = isTest;
+ this.type = type;
+ }
+
+ @NonNull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isTest() {
+ return isTest;
+ }
+
+ @Override
+ public int getType() {
+ return type;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/BaseArtifactImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BaseArtifactImpl.java
new file mode 100644
index 0000000..65c0c87
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BaseArtifactImpl.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.model;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.model.BaseArtifact;
+import com.android.builder.model.Dependencies;
+import com.android.builder.model.SourceProvider;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * Implementation of BaseArtifact that is serializable
+ */
+class BaseArtifactImpl implements BaseArtifact, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String name;
+ @NonNull
+ private final String assembleTaskName;
+ @NonNull
+ private final String javaCompileTaskName;
+ @NonNull
+ private final File classesFolder;
+ @NonNull
+ private final Dependencies dependencies;
+ @Nullable
+ private final SourceProvider variantSourceProvider;
+ @Nullable
+ private final SourceProvider multiFlavorSourceProviders;
+
+
+ BaseArtifactImpl(@NonNull String name,
+ @NonNull String assembleTaskName,
+ @NonNull String javaCompileTaskName,
+ @NonNull File classesFolder,
+ @NonNull Dependencies dependencies,
+ @Nullable SourceProvider variantSourceProvider,
+ @Nullable SourceProvider multiFlavorSourceProviders) {
+ this.name = name;
+ this.assembleTaskName = assembleTaskName;
+ this.javaCompileTaskName = javaCompileTaskName;
+ this.classesFolder = classesFolder;
+ this.dependencies = dependencies;
+ this.variantSourceProvider = variantSourceProvider;
+ this.multiFlavorSourceProviders = multiFlavorSourceProviders;
+ }
+
+ @NonNull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @NonNull
+ @Override
+ public String getJavaCompileTaskName() {
+ return javaCompileTaskName;
+ }
+
+ @NonNull
+ @Override
+ public String getAssembleTaskName() {
+ return assembleTaskName;
+ }
+
+ @NonNull
+ @Override
+ public File getClassesFolder() {
+ return classesFolder;
+ }
+
+ @NonNull
+ @Override
+ public Dependencies getDependencies() {
+ return dependencies;
+ }
+
+ @Nullable
+ @Override
+ public SourceProvider getVariantSourceProvider() {
+ return variantSourceProvider;
+ }
+
+ @Nullable
+ @Override
+ public SourceProvider getMultiFlavorSourceProvider() {
+ return multiFlavorSourceProviders;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeContainerImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeContainerImpl.java
index db8dc17..a4c302f 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeContainerImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeContainerImpl.java
@@ -17,11 +17,14 @@
package com.android.build.gradle.internal.model;
import com.android.annotations.NonNull;
-import com.android.builder.model.BuildTypeContainer;
+import com.android.build.gradle.internal.BuildTypeData;
import com.android.builder.model.BuildType;
+import com.android.builder.model.BuildTypeContainer;
import com.android.builder.model.SourceProvider;
+import com.android.builder.model.SourceProviderContainer;
import java.io.Serializable;
+import java.util.Collection;
class BuildTypeContainerImpl implements BuildTypeContainer, Serializable {
private static final long serialVersionUID = 1L;
@@ -30,11 +33,35 @@
private final BuildType buildType;
@NonNull
private final SourceProvider sourceProvider;
+ @NonNull
+ private final Collection<SourceProviderContainer> extraSourceProviders;
- BuildTypeContainerImpl(@NonNull BuildTypeImpl buildType,
- @NonNull SourceProviderImpl sourceProvider) {
+ /**
+ * Create a BuildTypeContainer from a BuildTypeData
+ *
+ * @param buildTypeData the build type data
+ * @param sourceProviderContainers collection of extra source providers
+ *
+ * @return a non-null BuildTypeContainer
+ */
+ @NonNull
+ static BuildTypeContainer createBTC(
+ @NonNull BuildTypeData buildTypeData,
+ @NonNull Collection<SourceProviderContainer> sourceProviderContainers) {
+
+ return new BuildTypeContainerImpl(
+ BuildTypeImpl.cloneBuildType(buildTypeData.getBuildType()),
+ SourceProviderImpl.cloneProvider(buildTypeData.getSourceSet()),
+ SourceProviderContainerImpl.cloneCollection(sourceProviderContainers));
+ }
+
+ private BuildTypeContainerImpl(
+ @NonNull BuildTypeImpl buildType,
+ @NonNull SourceProviderImpl sourceProvider,
+ @NonNull Collection<SourceProviderContainer> extraSourceProviders) {
this.buildType = buildType;
this.sourceProvider = sourceProvider;
+ this.extraSourceProviders = extraSourceProviders;
}
@Override
@@ -48,4 +75,10 @@
public SourceProvider getSourceProvider() {
return sourceProvider;
}
+
+ @NonNull
+ @Override
+ public Collection<SourceProviderContainer> getExtraSourceProviders() {
+ return extraSourceProviders;
+ }
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java
index f5fa46c..e3f5cdc 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/BuildTypeImpl.java
@@ -19,6 +19,8 @@
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.builder.model.BuildType;
+import com.android.builder.model.ClassField;
+import com.android.builder.model.NdkConfig;
import java.io.File;
import java.io.Serializable;
@@ -111,12 +113,25 @@
@NonNull
@Override
- public List<String> getBuildConfig() {
+ public List<ClassField> getBuildConfigFields() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public List<File> getProguardFiles() {
+ return Collections.emptyList();
+ }
+
+ @NonNull
+ @Override
+ public List<File> getConsumerProguardFiles() {
return Collections.emptyList();
}
@Override
- public @NonNull List<File> getProguardFiles() {
- return Collections.emptyList();
+ @Nullable
+ public NdkConfig getNdkConfig() {
+ return null;
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/DefaultAndroidProject.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/DefaultAndroidProject.java
index 589243f..fab28d1 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/DefaultAndroidProject.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/DefaultAndroidProject.java
@@ -17,17 +17,20 @@
package com.android.build.gradle.internal.model;
import com.android.annotations.NonNull;
-import com.android.builder.model.AndroidProject;
-import com.android.builder.model.BuildTypeContainer;
-import com.android.builder.model.ProductFlavorContainer;
-import com.android.builder.model.Variant;
+import com.android.build.gradle.internal.CompileOptions;
import com.android.builder.model.AaptOptions;
+import com.android.builder.model.AndroidProject;
+import com.android.builder.model.ArtifactMetaData;
+import com.android.builder.model.BuildTypeContainer;
+import com.android.builder.model.JavaCompileOptions;
+import com.android.builder.model.ProductFlavorContainer;
import com.android.builder.model.SigningConfig;
-import com.google.common.collect.Maps;
+import com.android.builder.model.Variant;
+import com.google.common.collect.Lists;
+import java.io.File;
import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
+import java.util.Collection;
/**
* Implementation of the AndroidProject model object.
@@ -42,27 +45,44 @@
@NonNull
private final String compileTarget;
@NonNull
- private final List<String> bootClasspath;
+ private final Collection<String> bootClasspath;
@NonNull
- private final Map<String, SigningConfig> signingConfigs;
+ private final Collection<File> frameworkSource;
+ @NonNull
+ private final Collection<SigningConfig> signingConfigs;
+ @NonNull
+ private final Collection<ArtifactMetaData> extraArtifacts;
+ @NonNull
+ private final Collection<String> unresolvedDependencies;
+ @NonNull
+ private final JavaCompileOptions javaCompileOptions;
private final boolean isLibrary;
- private final Map<String, BuildTypeContainer> buildTypes = Maps.newHashMap();
- private final Map<String, ProductFlavorContainer> productFlavors = Maps.newHashMap();
- private final Map<String, Variant> variants = Maps.newHashMap();
+ private final Collection<BuildTypeContainer> buildTypes = Lists.newArrayList();
+ private final Collection<ProductFlavorContainer> productFlavors = Lists.newArrayList();
+ private final Collection<Variant> variants = Lists.newArrayList();
private ProductFlavorContainer defaultConfig;
DefaultAndroidProject(@NonNull String modelVersion,
- @NonNull String name, @NonNull String compileTarget,
- @NonNull List<String> bootClasspath,
- @NonNull Map<String, SigningConfig> signingConfigs,
+ @NonNull String name,
+ @NonNull String compileTarget,
+ @NonNull Collection<String> bootClasspath,
+ @NonNull Collection<File> frameworkSource,
+ @NonNull Collection<SigningConfig> signingConfigs,
+ @NonNull Collection<ArtifactMetaData> extraArtifacts,
+ @NonNull Collection<String> unresolvedDependencies,
+ @NonNull CompileOptions compileOptions,
boolean isLibrary) {
this.modelVersion = modelVersion;
this.name = name;
this.compileTarget = compileTarget;
this.bootClasspath = bootClasspath;
+ this.frameworkSource = frameworkSource;
this.signingConfigs = signingConfigs;
+ this.extraArtifacts = extraArtifacts;
+ this.unresolvedDependencies = unresolvedDependencies;
+ javaCompileOptions = new DefaultJavaCompileOptions(compileOptions);
this.isLibrary = isLibrary;
}
@@ -74,26 +94,25 @@
@NonNull
DefaultAndroidProject addBuildType(@NonNull BuildTypeContainer buildTypeContainer) {
- buildTypes.put(buildTypeContainer.getBuildType().getName(), buildTypeContainer);
+ buildTypes.add(buildTypeContainer);
return this;
}
@NonNull
DefaultAndroidProject addProductFlavors(
@NonNull ProductFlavorContainer productFlavorContainer) {
- productFlavors.put(productFlavorContainer.getProductFlavor().getName(),
- productFlavorContainer);
+ productFlavors.add(productFlavorContainer);
return this;
}
@NonNull
DefaultAndroidProject addVariant(@NonNull VariantImpl variant) {
- variants.put(variant.getName(), variant);
+ variants.add(variant);
return this;
}
- @NonNull
@Override
+ @NonNull
public String getModelVersion() {
return modelVersion;
}
@@ -104,28 +123,34 @@
return name;
}
- @NonNull
@Override
+ @NonNull
public ProductFlavorContainer getDefaultConfig() {
return defaultConfig;
}
- @NonNull
@Override
- public Map<String, BuildTypeContainer> getBuildTypes() {
+ @NonNull
+ public Collection<BuildTypeContainer> getBuildTypes() {
return buildTypes;
}
- @NonNull
@Override
- public Map<String, ProductFlavorContainer> getProductFlavors() {
+ @NonNull
+ public Collection<ProductFlavorContainer> getProductFlavors() {
return productFlavors;
}
+ @Override
+ @NonNull
+ public Collection<Variant> getVariants() {
+ return variants;
+ }
+
@NonNull
@Override
- public Map<String, Variant> getVariants() {
- return variants;
+ public Collection<ArtifactMetaData> getExtraArtifacts() {
+ return extraArtifacts;
}
@Override
@@ -133,27 +158,45 @@
return isLibrary;
}
- @NonNull
@Override
+ @NonNull
public String getCompileTarget() {
return compileTarget;
}
- @NonNull
@Override
- public List<String> getBootClasspath() {
+ @NonNull
+ public Collection<String> getBootClasspath() {
return bootClasspath;
}
- @NonNull
@Override
- public Map<String,SigningConfig> getSigningConfigs() {
+ @NonNull
+ public Collection<File> getFrameworkSources() {
+ return frameworkSource;
+ }
+
+ @Override
+ @NonNull
+ public Collection<SigningConfig> getSigningConfigs() {
return signingConfigs;
}
- @NonNull
@Override
+ @NonNull
public AaptOptions getAaptOptions() {
return null;
}
+
+ @Override
+ @NonNull
+ public Collection<String> getUnresolvedDependencies() {
+ return unresolvedDependencies;
+ }
+
+ @Override
+ @NonNull
+ public JavaCompileOptions getJavaCompileOptions() {
+ return javaCompileOptions;
+ }
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/DefaultJavaCompileOptions.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/DefaultJavaCompileOptions.java
new file mode 100644
index 0000000..4de4a89
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/DefaultJavaCompileOptions.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.model;
+
+import com.android.annotations.NonNull;
+import com.android.build.gradle.internal.CompileOptions;
+import com.android.builder.model.JavaCompileOptions;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of {@link JavaCompileOptions}.
+ */
+class DefaultJavaCompileOptions implements JavaCompileOptions, Serializable {
+ @NonNull
+ private final String sourceCompatibility;
+ @NonNull
+ private final String targetCompatibility;
+
+ DefaultJavaCompileOptions(@NonNull CompileOptions options) {
+ sourceCompatibility = options.getSourceCompatibility().toString();
+ targetCompatibility = options.getTargetCompatibility().toString();
+ }
+
+ @NonNull
+ @Override
+ public String getSourceCompatibility() {
+ return sourceCompatibility;
+ }
+
+ @NonNull
+ @Override
+ public String getTargetCompatibility() {
+ return targetCompatibility;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/JavaArtifactImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/JavaArtifactImpl.java
new file mode 100644
index 0000000..4c7584c
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/JavaArtifactImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.model;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.builder.model.Dependencies;
+import com.android.builder.model.JavaArtifact;
+import com.android.builder.model.SourceProvider;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * Implementation of JavaArtifact that is serializable
+ */
+public class JavaArtifactImpl extends BaseArtifactImpl implements JavaArtifact, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public static JavaArtifactImpl clone(@NonNull JavaArtifact javaArtifact) {
+ return new JavaArtifactImpl(
+ javaArtifact.getName(),
+ javaArtifact.getAssembleTaskName(),
+ javaArtifact.getJavaCompileTaskName(),
+ javaArtifact.getClassesFolder(),
+ javaArtifact.getDependencies(), // TODO:FixME
+ SourceProviderImpl.cloneProvider(javaArtifact.getVariantSourceProvider()),
+ SourceProviderImpl.cloneProvider(javaArtifact.getMultiFlavorSourceProvider()));
+ }
+
+ public JavaArtifactImpl(@NonNull String name,
+ @NonNull String assembleTaskName,
+ @NonNull String javaCompileTaskName,
+ @NonNull File classesFolder,
+ @NonNull Dependencies dependencies,
+ @Nullable SourceProvider variantSourceProvider,
+ @Nullable SourceProvider multiFlavorSourceProviders) {
+ super(name, assembleTaskName, javaCompileTaskName, classesFolder, dependencies,
+ variantSourceProvider, multiFlavorSourceProviders);
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.groovy
index 45806e4..41ec14f 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.groovy
@@ -26,23 +26,27 @@
import com.android.build.gradle.internal.variant.BaseVariantData
import com.android.build.gradle.internal.variant.LibraryVariantData
import com.android.build.gradle.internal.variant.TestVariantData
-import com.android.builder.model.AndroidProject
-import com.android.builder.model.ArtifactInfo
-import com.android.builder.model.BuildTypeContainer
-import com.android.builder.model.ProductFlavorContainer
import com.android.builder.DefaultProductFlavor
import com.android.builder.SdkParser
import com.android.builder.VariantConfiguration
+import com.android.builder.model.AndroidArtifact
+import com.android.builder.model.AndroidProject
+import com.android.builder.model.ArtifactMetaData
+import com.android.builder.model.JavaArtifact
import com.android.builder.model.SigningConfig
import com.android.builder.model.SourceProvider
+import com.android.builder.model.SourceProviderContainer
import com.google.common.collect.Lists
-import com.google.common.collect.Maps
import org.gradle.api.Project
import org.gradle.api.plugins.UnknownPluginException
import org.gradle.tooling.provider.model.ToolingModelBuilder
import java.util.jar.Attributes
import java.util.jar.Manifest
+
+import static com.android.builder.model.AndroidProject.ARTIFACT_INSTRUMENT_TEST
+import static com.android.builder.model.AndroidProject.ARTIFACT_MAIN
+
/**
* Builder for the custom Android model.
*/
@@ -78,36 +82,60 @@
SdkParser sdkParser = basePlugin.getLoadedSdkParser()
List<String> bootClasspath = basePlugin.runtimeJarList
+ List<File> frameworkSource = Collections.emptyList();
String compileTarget = sdkParser.target.hashString()
+ // list of extra artifacts
+ List<ArtifactMetaData> artifactMetaDataList = Lists.newArrayList(basePlugin.extraArtifacts)
+ // plus the instrumentation test one.
+ artifactMetaDataList.add(
+ new ArtifactMetaDataImpl(
+ ARTIFACT_INSTRUMENT_TEST,
+ true /*isTest*/,
+ ArtifactMetaData.TYPE_ANDROID));
+
//noinspection GroovyVariableNotAssigned
DefaultAndroidProject androidProject = new DefaultAndroidProject(
getModelVersion(),
project.name,
compileTarget,
bootClasspath,
+ frameworkSource,
cloneSigningConfigs(signingConfigs),
+ artifactMetaDataList,
+ basePlugin.unresolvedDependencies,
+ basePlugin.extension.compileOptions,
libPlugin != null)
- .setDefaultConfig(createPFC(basePlugin.defaultConfigData))
+ .setDefaultConfig(ProductFlavorContainerImpl.createPFC(
+ basePlugin.defaultConfigData,
+ basePlugin.getExtraFlavorSourceProviders(basePlugin.defaultConfigData.productFlavor.name)))
if (appPlugin != null) {
for (BuildTypeData btData : appPlugin.buildTypes.values()) {
- androidProject.addBuildType(createBTC(btData))
+ androidProject.addBuildType(BuildTypeContainerImpl.createBTC(
+ btData,
+ basePlugin.getExtraBuildTypeSourceProviders(btData.buildType.name)))
}
for (ProductFlavorData pfData : appPlugin.productFlavors.values()) {
- androidProject.addProductFlavors(createPFC(pfData))
+ androidProject.addProductFlavors(ProductFlavorContainerImpl.createPFC(
+ pfData,
+ basePlugin.getExtraFlavorSourceProviders(pfData.productFlavor.name)))
}
} else if (libPlugin != null) {
- androidProject.addBuildType(createBTC(libPlugin.debugBuildTypeData))
- .addBuildType(createBTC(libPlugin.releaseBuildTypeData))
+ androidProject.addBuildType(BuildTypeContainerImpl.createBTC(
+ libPlugin.debugBuildTypeData,
+ basePlugin.getExtraBuildTypeSourceProviders(libPlugin.debugBuildTypeData.buildType.name)))
+ .addBuildType(BuildTypeContainerImpl.createBTC(
+ libPlugin.releaseBuildTypeData,
+ basePlugin.getExtraBuildTypeSourceProviders(libPlugin.releaseBuildTypeData.buildType.name)))
}
Set<Project> gradleProjects = project.getRootProject().getAllprojects();
for (BaseVariantData variantData : basePlugin.variantDataList) {
if (!(variantData instanceof TestVariantData)) {
- androidProject.addVariant(createVariant(variantData, gradleProjects))
+ androidProject.addVariant(createVariant(variantData, basePlugin, gradleProjects))
}
}
@@ -137,6 +165,7 @@
@NonNull
private static VariantImpl createVariant(@NonNull BaseVariantData variantData,
+ @NonNull BasePlugin basePlugin,
@NonNull Set<Project> gradleProjects) {
TestVariantData testVariantData = null
if (variantData instanceof ApplicationVariantData ||
@@ -144,24 +173,43 @@
testVariantData = variantData.testVariantData
}
- ArtifactInfo mainArtifact = createArtifactInfo(variantData, gradleProjects)
- ArtifactInfo testArtifact = testVariantData != null ?
- createArtifactInfo(testVariantData, gradleProjects) : null
+ AndroidArtifact mainArtifact = createArtifactInfo(
+ ARTIFACT_MAIN, variantData, basePlugin, gradleProjects)
+
+ String variantName = variantData.variantConfiguration.fullName
+
+ // extra Android Artifacts
+ AndroidArtifact testArtifact = testVariantData != null ?
+ createArtifactInfo(ARTIFACT_INSTRUMENT_TEST, testVariantData, basePlugin, gradleProjects) : null
+
+ List<AndroidArtifact> extraAndroidArtifacts = Lists.newArrayList(
+ basePlugin.getExtraAndroidArtifacts(variantName))
+ if (testArtifact != null) {
+ extraAndroidArtifacts.add(testArtifact)
+ }
+
+ // extra Java Artifacts
+ List<JavaArtifact> extraJavaArtifacts = Lists.newArrayList(
+ basePlugin.getExtraJavaArtifacts(variantName))
VariantImpl variant = new VariantImpl(
- variantData.name,
- variantData.baseName,
+ variantName,
+ variantData.variantConfiguration.baseName,
variantData.variantConfiguration.buildType.name,
getProductFlavorNames(variantData),
ProductFlavorImpl.cloneFlavor(variantData.variantConfiguration.mergedFlavor),
mainArtifact,
- testArtifact)
+ extraAndroidArtifacts,
+ extraJavaArtifacts)
return variant
}
- private static ArtifactInfo createArtifactInfo(@NonNull BaseVariantData variantData,
- @NonNull Set<Project> gradleProjects) {
+ private static AndroidArtifact createArtifactInfo(
+ @NonNull String name,
+ @NonNull BaseVariantData variantData,
+ @NonNull BasePlugin basePlugin,
+ @NonNull Set<Project> gradleProjects) {
VariantConfiguration vC = variantData.variantConfiguration
SigningConfig signingConfig = vC.signingConfig
@@ -170,17 +218,40 @@
signingConfigName = signingConfig.name
}
- return new ArtifactInfoImpl(
+ SourceProvider variantSourceProvider = null;
+ SourceProvider multiFlavorSourceProvider = null;
+
+ if (ARTIFACT_MAIN.equals(name)) {
+ variantSourceProvider = variantData.variantConfiguration.variantSourceProvider
+ multiFlavorSourceProvider = variantData.variantConfiguration.multiFlavorSourceProvider
+ } else {
+ SourceProviderContainer container = getSourceProviderContainer(
+ basePlugin.getExtraVariantSourceProviders(variantData.getVariantConfiguration().getFullName()),
+ name)
+ if (container != null) {
+ variantSourceProvider = container.sourceProvider
+ }
+ }
+
+ variantSourceProvider = variantSourceProvider != null ? SourceProviderImpl.cloneProvider(variantSourceProvider) : null
+ multiFlavorSourceProvider = multiFlavorSourceProvider != null ? SourceProviderImpl.cloneProvider(multiFlavorSourceProvider) : null
+
+ return new AndroidArtifactImpl(
+ name,
variantData.assembleTask.name,
variantData.outputFile,
vC.isSigningReady(),
signingConfigName,
vC.packageName,
+ variantData.sourceGenTask.name,
+ variantData.javaCompileTask.name,
+ variantData.processManifestTask.manifestOutputFile,
getGeneratedSourceFolders(variantData),
getGeneratedResourceFolders(variantData),
variantData.javaCompileTask.destinationDir,
- DependenciesImpl.cloneDependencies(variantData.variantDependency, gradleProjects)
- )
+ DependenciesImpl.cloneDependencies(variantData.variantDependency, gradleProjects),
+ variantSourceProvider,
+ multiFlavorSourceProvider)
}
@NonNull
@@ -204,8 +275,15 @@
folders.add(variantData.processResourcesTask.sourceOutputDir)
folders.add(variantData.aidlCompileTask.sourceOutputDir)
- folders.add(variantData.renderscriptCompileTask.sourceOutputDir)
folders.add(variantData.generateBuildConfigTask.sourceOutputDir)
+ if (!variantData.variantConfiguration.mergedFlavor.renderscriptNdkMode) {
+ folders.add(variantData.renderscriptCompileTask.sourceOutputDir)
+ }
+
+ List<File> extraFolders = variantData.extraGeneratedSourceFolders
+ if (extraFolders != null) {
+ folders.addAll(extraFolders)
+ }
return folders
}
@@ -219,54 +297,29 @@
return Collections.singletonList(variantData.renderscriptCompileTask.resOutputDir)
}
- /**
- * Create a ProductFlavorContainer from a ProductFlavorData
- * @param productFlavorData the product flavor data
- * @return a non-null ProductFlavorContainer
- */
@NonNull
- private static ProductFlavorContainer createPFC(@NonNull ProductFlavorData productFlavorData) {
- return new ProductFlavorContainerImpl(
- ProductFlavorImpl.cloneFlavor(productFlavorData.productFlavor),
- SourceProviderImpl.cloneProvider((SourceProvider) productFlavorData.sourceSet),
- SourceProviderImpl.cloneProvider((SourceProvider) productFlavorData.testSourceSet))
- }
-
- /**
- * Create a BuildTypeContainer from a BuildTypeData
- * @param buildTypeData the build type data
- * @return a non-null BuildTypeContainer
- */
- @NonNull
- private static BuildTypeContainer createBTC(@NonNull BuildTypeData buildTypeData) {
- return new BuildTypeContainerImpl(
- BuildTypeImpl.cloneBuildType(buildTypeData.buildType),
- SourceProviderImpl.cloneProvider((SourceProvider) buildTypeData.sourceSet))
- }
-
- @NonNull
- private static Map<String, SigningConfig> cloneSigningConfigs(
+ private static Collection<SigningConfig> cloneSigningConfigs(
@NonNull Collection<SigningConfig> signingConfigs) {
- Map<String, SigningConfig> results = Maps.newHashMapWithExpectedSize(signingConfigs.size())
+ Collection<SigningConfig> results = Lists.newArrayListWithCapacity(signingConfigs.size())
for (SigningConfig signingConfig : signingConfigs) {
- SigningConfig clonedSigningConfig = createSigningConfig(signingConfig)
- results.put(clonedSigningConfig.name, clonedSigningConfig)
+ results.add(SigningConfigImpl.createSigningConfig(signingConfig))
}
return results
}
- @NonNull
- private static SigningConfig createSigningConfig(@NonNull SigningConfig signingConfig) {
- return new SigningConfigImpl(
- signingConfig.getName(),
- signingConfig.getStoreFile(),
- signingConfig.getStorePassword(),
- signingConfig.getKeyAlias(),
- signingConfig.getKeyPassword(),
- signingConfig.getStoreType(),
- signingConfig.isSigningReady())
+ @Nullable
+ private static SourceProviderContainer getSourceProviderContainer(
+ @NonNull Collection<SourceProviderContainer> items,
+ @NonNull String name) {
+ for (SourceProviderContainer item : items) {
+ if (name.equals(item.getArtifactName())) {
+ return item;
+ }
+ }
+
+ return null;
}
/**
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorContainerImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorContainerImpl.java
index dac38e6..92fa794 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorContainerImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorContainerImpl.java
@@ -17,11 +17,16 @@
package com.android.build.gradle.internal.model;
import com.android.annotations.NonNull;
-import com.android.builder.model.ProductFlavorContainer;
+import com.android.build.gradle.internal.ProductFlavorData;
+import com.android.builder.model.AndroidProject;
import com.android.builder.model.ProductFlavor;
+import com.android.builder.model.ProductFlavorContainer;
import com.android.builder.model.SourceProvider;
+import com.android.builder.model.SourceProviderContainer;
import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
/**
*/
@@ -33,15 +38,43 @@
@NonNull
private final SourceProvider sourceProvider;
@NonNull
- private final SourceProvider testSourceProvider;
+ private final Collection<SourceProviderContainer> extraSourceProviders;
- ProductFlavorContainerImpl(@NonNull ProductFlavorImpl productFlavor,
- @NonNull SourceProviderImpl sourceProvider,
- @NonNull SourceProviderImpl testSourceProvider) {
+ /**
+ * Create a ProductFlavorContainer from a ProductFlavorData
+ *
+ * @param productFlavorData the product flavor data
+ * @param sourceProviderContainers collection of extra source providers
+ *
+ * @return a non-null ProductFlavorContainer
+ */
+ @NonNull
+ static ProductFlavorContainer createPFC(
+ @NonNull ProductFlavorData productFlavorData,
+ @NonNull Collection<SourceProviderContainer> sourceProviderContainers) {
+
+ List<SourceProviderContainer> clonedContainer = SourceProviderContainerImpl.cloneCollection(sourceProviderContainers);
+
+ // instrument test Source Provider
+ SourceProviderContainer testASP = SourceProviderContainerImpl.create(
+ AndroidProject.ARTIFACT_INSTRUMENT_TEST, productFlavorData.getTestSourceSet());
+
+ clonedContainer.add(testASP);
+
+ return new ProductFlavorContainerImpl(
+ ProductFlavorImpl.cloneFlavor(productFlavorData.getProductFlavor()),
+ SourceProviderImpl.cloneProvider(productFlavorData.getSourceSet()),
+ clonedContainer);
+ }
+
+ private ProductFlavorContainerImpl(
+ @NonNull ProductFlavorImpl productFlavor,
+ @NonNull SourceProviderImpl sourceProvider,
+ @NonNull Collection<SourceProviderContainer> extraSourceProviders) {
this.productFlavor = productFlavor;
this.sourceProvider = sourceProvider;
- this.testSourceProvider = testSourceProvider;
+ this.extraSourceProviders = extraSourceProviders;
}
@NonNull
@@ -58,7 +91,7 @@
@NonNull
@Override
- public SourceProvider getTestSourceProvider() {
- return testSourceProvider;
+ public Collection<SourceProviderContainer> getExtraSourceProviders() {
+ return extraSourceProviders;
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java
index db4cb6b..9f25e30 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/ProductFlavorImpl.java
@@ -18,12 +18,17 @@
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.builder.model.ClassField;
+import com.android.builder.model.NdkConfig;
import com.android.builder.model.ProductFlavor;
+import com.google.common.collect.Sets;
import java.io.File;
import java.io.Serializable;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
/**
* Implementation of ProductFlavor that is serializable. Objects used in the DSL cannot be
@@ -36,12 +41,16 @@
private int mMinSdkVersion = -1;
private int mTargetSdkVersion = -1;
private int mRenderscriptTargetApi = -1;
+ private boolean mRenderscriptSupportMode = false;
+ private boolean mRenderscriptNdkMode = false;
private int mVersionCode = -1;
private String mVersionName = null;
private String mPackageName = null;
private String mTestPackageName = null;
private String mTestInstrumentationRunner = null;
-
+ private Boolean mTestHandleProfiling = null;
+ private Boolean mTestFunctionalTest = null;
+ private Set<String> mResourceConfigurations = null;
@NonNull
static ProductFlavorImpl cloneFlavor(ProductFlavor productFlavor) {
@@ -51,6 +60,8 @@
clonedFlavor.mMinSdkVersion = productFlavor.getMinSdkVersion();
clonedFlavor.mTargetSdkVersion = productFlavor.getTargetSdkVersion();
clonedFlavor.mRenderscriptTargetApi = productFlavor.getRenderscriptTargetApi();
+ clonedFlavor.mRenderscriptSupportMode = productFlavor.getRenderscriptSupportMode();
+ clonedFlavor.mRenderscriptNdkMode = productFlavor.getRenderscriptNdkMode();
clonedFlavor.mVersionCode = productFlavor.getVersionCode();
clonedFlavor.mVersionName = productFlavor.getVersionName();
@@ -59,6 +70,11 @@
clonedFlavor.mTestPackageName = productFlavor.getTestPackageName();
clonedFlavor.mTestInstrumentationRunner = productFlavor.getTestInstrumentationRunner();
+ clonedFlavor.mTestHandleProfiling = productFlavor.getTestHandleProfiling();
+ clonedFlavor.mTestFunctionalTest = productFlavor.getTestFunctionalTest();
+
+ clonedFlavor.mResourceConfigurations = Sets.newHashSet(
+ productFlavor.getResourceConfigurations());
return clonedFlavor;
}
@@ -104,6 +120,16 @@
return mRenderscriptTargetApi;
}
+ @Override
+ public boolean getRenderscriptSupportMode() {
+ return mRenderscriptSupportMode;
+ }
+
+ @Override
+ public boolean getRenderscriptNdkMode() {
+ return mRenderscriptNdkMode;
+ }
+
@Nullable
@Override
public String getTestPackageName() {
@@ -116,24 +142,22 @@
return mTestInstrumentationRunner;
}
+ @Nullable
@Override
- public String toString() {
- return "ProductFlavorImpl{" +
- "name='" + name + '\'' +
- ", mMinSdkVersion=" + mMinSdkVersion +
- ", mTargetSdkVersion=" + mTargetSdkVersion +
- ", mRenderscriptTargetApi=" + mRenderscriptTargetApi +
- ", mVersionCode=" + mVersionCode +
- ", mVersionName='" + mVersionName + '\'' +
- ", mPackageName='" + mPackageName + '\'' +
- ", mTestPackageName='" + mTestPackageName + '\'' +
- ", mTestInstrumentationRunner='" + mTestInstrumentationRunner + '\'' +
- '}';
+ public Boolean getTestHandleProfiling() {
+ return mTestHandleProfiling;
}
+ @Nullable
+ @Override
+ public Boolean getTestFunctionalTest() {
+ return mTestFunctionalTest;
+ }
+
+
@NonNull
@Override
- public List<String> getBuildConfig() {
+ public List<ClassField> getBuildConfigFields() {
return Collections.emptyList();
}
@@ -142,4 +166,42 @@
public List<File> getProguardFiles() {
return Collections.emptyList();
}
+
+ @NonNull
+ @Override
+ public List<File> getConsumerProguardFiles() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ @Nullable
+ public NdkConfig getNdkConfig() {
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public Collection<String> getResourceConfigurations() {
+ return mResourceConfigurations;
+ }
+
+ @Override
+ public String toString() {
+ return "ProductFlavorImpl{" +
+ "name='" + name + '\'' +
+ ", mMinSdkVersion=" + mMinSdkVersion +
+ ", mTargetSdkVersion=" + mTargetSdkVersion +
+ ", mRenderscriptTargetApi=" + mRenderscriptTargetApi +
+ ", mRenderscriptSupportMode=" + mRenderscriptSupportMode +
+ ", mRenderscriptNdkMode=" + mRenderscriptNdkMode +
+ ", mVersionCode=" + mVersionCode +
+ ", mVersionName='" + mVersionName + '\'' +
+ ", mPackageName='" + mPackageName + '\'' +
+ ", mTestPackageName='" + mTestPackageName + '\'' +
+ ", mTestInstrumentationRunner='" + mTestInstrumentationRunner + '\'' +
+ ", mTestHandleProfiling='" + mTestHandleProfiling + '\'' +
+ ", mTestFunctionalTest='" + mTestFunctionalTest + '\'' +
+ ", mResourceConfigurations='" + mResourceConfigurations + '\'' +
+ '}';
+ }
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/SigningConfigImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/SigningConfigImpl.java
index 06e219c..19c867c 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/SigningConfigImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/SigningConfigImpl.java
@@ -44,7 +44,19 @@
private final String storeType;
private final boolean signingReady;
- SigningConfigImpl(@NonNull String name,
+ @NonNull
+ static SigningConfig createSigningConfig(@NonNull SigningConfig signingConfig) {
+ return new SigningConfigImpl(
+ signingConfig.getName(),
+ signingConfig.getStoreFile(),
+ signingConfig.getStorePassword(),
+ signingConfig.getKeyAlias(),
+ signingConfig.getKeyPassword(),
+ signingConfig.getStoreType(),
+ signingConfig.isSigningReady());
+ }
+
+ private SigningConfigImpl(@NonNull String name,
@Nullable File storeFile,
@Nullable String storePassword,
@Nullable String keyAlias,
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/SourceProviderContainerImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/SourceProviderContainerImpl.java
new file mode 100644
index 0000000..fe41180
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/SourceProviderContainerImpl.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.model;
+
+import com.android.annotations.NonNull;
+import com.android.builder.model.SourceProvider;
+import com.android.builder.model.SourceProviderContainer;
+import com.google.common.collect.Lists;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Implementation of SourceProviderContainer that is serializable and is meant to be used
+ * in the model sent to the tooling API.
+ *
+ * It also provides convenient methods to create an instance, cloning the original
+ * SourceProvider.
+ *
+ * When the source Provider is cloned, its values are queried and then statically stored.
+ * Any further change through the DSL will not be impact. Therefore instances of this class
+ * should only be used when the model is built.
+ *
+ * To create more dynamic isntances of SourceProviderContainer, use
+ * {@link com.android.build.gradle.internal.variant.DefaultSourceProviderContainer}
+ */
+class SourceProviderContainerImpl implements SourceProviderContainer, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @NonNull
+ private final String name;
+ @NonNull
+ private final SourceProvider sourceProvider;
+
+ /**
+ * Create a {@link SourceProviderContainer} that is serializable to
+ * use in the model sent through the tooling API.
+ *
+ * @param sourceProviderContainer the source provider
+ *
+ * @return a non-null SourceProviderContainer
+ */
+ @NonNull
+ static SourceProviderContainer clone(
+ @NonNull SourceProviderContainer sourceProviderContainer) {
+ return create(
+ sourceProviderContainer.getArtifactName(),
+ sourceProviderContainer.getSourceProvider());
+ }
+
+ @NonNull
+ static List<SourceProviderContainer> cloneCollection(@NonNull Collection<SourceProviderContainer> containers) {
+ List<SourceProviderContainer> clones = Lists.newArrayListWithCapacity(containers.size());
+
+ for (SourceProviderContainer container : containers) {
+ clones.add(clone(container));
+ }
+
+ return clones;
+ }
+
+ @NonNull
+ static SourceProviderContainer create(
+ @NonNull String name,
+ @NonNull SourceProvider sourceProvider) {
+ return new SourceProviderContainerImpl(name,
+ SourceProviderImpl.cloneProvider(sourceProvider));
+ }
+
+ private SourceProviderContainerImpl(@NonNull String name,
+ @NonNull SourceProvider sourceProvider) {
+ this.name = name;
+ this.sourceProvider = sourceProvider;
+ }
+
+ @NonNull
+ @Override
+ public String getArtifactName() {
+ return name;
+ }
+
+ @NonNull
+ @Override
+ public SourceProvider getSourceProvider() {
+ return sourceProvider;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/SourceProviderImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/SourceProviderImpl.java
index 7d0293b..de02737 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/SourceProviderImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/SourceProviderImpl.java
@@ -18,10 +18,11 @@
import com.android.annotations.NonNull;
import com.android.builder.model.SourceProvider;
+import com.google.common.collect.Lists;
import java.io.File;
import java.io.Serializable;
-import java.util.Set;
+import java.util.Collection;
/**
* Implementation of SourceProvider that is serializable. Objects used in the DSL cannot be
@@ -31,13 +32,13 @@
private static final long serialVersionUID = 1L;
private File manifestFile;
- private Set<File> javaDirs;
- private Set<File> resourcesDirs;
- private Set<File> aidlDirs;
- private Set<File> rsDirs;
- private Set<File> jniDirs;
- private Set<File> resDirs;
- private Set<File> assetsDirs;
+ private Collection<File> javaDirs;
+ private Collection<File> resourcesDirs;
+ private Collection<File> aidlDirs;
+ private Collection<File> rsDirs;
+ private Collection<File> jniDirs;
+ private Collection<File> resDirs;
+ private Collection<File> assetsDirs;
@NonNull
static SourceProviderImpl cloneProvider(SourceProvider sourceProvider) {
@@ -55,6 +56,17 @@
return sourceProviderClone;
}
+ @NonNull
+ static Collection<SourceProvider> cloneCollection(
+ @NonNull Collection<SourceProvider> sourceProviders) {
+ Collection<SourceProvider> results = Lists.newArrayListWithCapacity(sourceProviders.size());
+ for (SourceProvider sourceProvider : sourceProviders) {
+ results.add(SourceProviderImpl.cloneProvider(sourceProvider));
+ }
+
+ return results;
+ }
+
private SourceProviderImpl() {
}
@@ -66,43 +78,43 @@
@NonNull
@Override
- public Set<File> getJavaDirectories() {
+ public Collection<File> getJavaDirectories() {
return javaDirs;
}
@NonNull
@Override
- public Set<File> getResourcesDirectories() {
+ public Collection<File> getResourcesDirectories() {
return resourcesDirs;
}
@NonNull
@Override
- public Set<File> getAidlDirectories() {
+ public Collection<File> getAidlDirectories() {
return aidlDirs;
}
@NonNull
@Override
- public Set<File> getRenderscriptDirectories() {
+ public Collection<File> getRenderscriptDirectories() {
return rsDirs;
}
@NonNull
@Override
- public Set<File> getJniDirectories() {
+ public Collection<File> getJniDirectories() {
return jniDirs;
}
@NonNull
@Override
- public Set<File> getResDirectories() {
+ public Collection<File> getResDirectories() {
return resDirs;
}
@NonNull
@Override
- public Set<File> getAssetsDirectories() {
+ public Collection<File> getAssetsDirectories() {
return assetsDirs;
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/model/VariantImpl.java b/gradle/src/main/groovy/com/android/build/gradle/internal/model/VariantImpl.java
index f9a5c86..b8a04e6 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/model/VariantImpl.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/model/VariantImpl.java
@@ -17,12 +17,13 @@
package com.android.build.gradle.internal.model;
import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.builder.model.ArtifactInfo;
-import com.android.builder.model.Variant;
+import com.android.builder.model.AndroidArtifact;
+import com.android.builder.model.JavaArtifact;
import com.android.builder.model.ProductFlavor;
+import com.android.builder.model.Variant;
import java.io.Serializable;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -43,24 +44,28 @@
@NonNull
private final ProductFlavor mergedFlavor;
@NonNull
- private final ArtifactInfo mainArtifactInfo;
- @Nullable
- private final ArtifactInfo testArtifactInfo;
+ private final AndroidArtifact mainArtifactInfo;
+ @NonNull
+ private final Collection<AndroidArtifact> extraAndroidArtifacts;
+ @NonNull
+ private final Collection<JavaArtifact> extraJavaArtifacts;
- VariantImpl(@NonNull String name,
- @NonNull String displayName,
- @NonNull String buildTypeName,
- @NonNull List<String> productFlavorNames,
- @NonNull ProductFlavorImpl mergedFlavor,
- @NonNull ArtifactInfo mainArtifactInfo,
- @Nullable ArtifactInfo testArtifactInfo) {
+ VariantImpl(@NonNull String name,
+ @NonNull String displayName,
+ @NonNull String buildTypeName,
+ @NonNull List<String> productFlavorNames,
+ @NonNull ProductFlavorImpl mergedFlavor,
+ @NonNull AndroidArtifact mainArtifactInfo,
+ @NonNull Collection<AndroidArtifact> extraAndroidArtifacts,
+ @NonNull Collection<JavaArtifact> extraJavaArtifacts) {
this.name = name;
this.displayName = displayName;
this.buildTypeName = buildTypeName;
this.productFlavorNames = productFlavorNames;
this.mergedFlavor = mergedFlavor;
this.mainArtifactInfo = mainArtifactInfo;
- this.testArtifactInfo = testArtifactInfo;
+ this.extraAndroidArtifacts = extraAndroidArtifacts;
+ this.extraJavaArtifacts = extraJavaArtifacts;
}
@Override
@@ -95,19 +100,19 @@
@NonNull
@Override
- public ArtifactInfo getMainArtifactInfo() {
+ public AndroidArtifact getMainArtifact() {
return mainArtifactInfo;
}
- @Nullable
+ @NonNull
@Override
- public ArtifactInfo getTestArtifactInfo() {
- return testArtifactInfo;
+ public Collection<AndroidArtifact> getExtraAndroidArtifacts() {
+ return extraAndroidArtifacts;
}
- @Override
@NonNull
- public List<String> getResourceConfigurations() {
- return Collections.emptyList();
+ @Override
+ public Collection<JavaArtifact> getExtraJavaArtifacts() {
+ return extraJavaArtifacts;
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/DependencyBasedCompileTask.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/DependencyBasedCompileTask.groovy
index 4e10aa8..f264bc9 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/DependencyBasedCompileTask.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/DependencyBasedCompileTask.groovy
@@ -15,7 +15,6 @@
*/
package com.android.build.gradle.internal.tasks
-
import com.android.annotations.NonNull
import com.android.annotations.Nullable
import com.android.builder.compiling.DependencyFileProcessor
@@ -28,7 +27,6 @@
import org.gradle.api.tasks.OutputDirectory
import java.util.concurrent.Callable
-
/**
* Base task for source generators that generate and use dependency files.
*/
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/IncrementalTask.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/IncrementalTask.groovy
index aef4319..2a86114 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/IncrementalTask.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/IncrementalTask.groovy
@@ -14,16 +14,14 @@
* limitations under the License.
*/
package com.android.build.gradle.internal.tasks
-
-import com.android.builder.internal.incremental.ChangeManager
import com.android.ide.common.res2.FileStatus
import com.android.ide.common.res2.SourceSet
import com.google.common.collect.Lists
-import org.gradle.api.file.FileCollection
+import com.google.common.collect.Maps
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.TaskInputs
+import org.gradle.api.tasks.incremental.IncrementalTaskInputs
public abstract class IncrementalTask extends BaseTask {
@@ -31,7 +29,7 @@
File incrementalFolder
/**
- * Whether this task can support incremental update using the {@link ChangeManager}
+ * Whether this task can support incremental update.
*
* @return whether this task can support incremental update.
*/
@@ -44,7 +42,7 @@
* {@link #isIncremental()} returns false.
*
*/
- protected abstract void doFullTaskAction();
+ protected abstract void doFullTaskAction()
/**
* Optional incremental task action.
@@ -56,79 +54,44 @@
// do nothing.
}
- protected Collection<File> getOutputForIncrementalBuild() {
- return Collections.emptyList();
- }
-
/**
* Actual entry point for the action.
* Calls out to the doTaskAction as needed.
*/
@TaskAction
- void taskAction() {
- try {
- if (!isIncremental() || incrementalFolder == null) {
- doFullTaskAction()
- return;
- }
-
- // load known state.
- ChangeManager changeManager = new ChangeManager()
- boolean fullBuild = !changeManager.load(incrementalFolder)
-
- // update with current files.
- TaskInputs inputs = getInputs()
- FileCollection inputCollection = inputs.getFiles()
-
- for (File f : inputCollection.files) {
- changeManager.addInput(f)
- }
-
- for (File f : getOutputForIncrementalBuild()) {
- changeManager.addOutput(f);
- }
-
- // force full build if output changed somehow.
- Map<File, FileStatus> changedOutputs = changeManager.getChangedOutputs()
- Map<File, FileStatus> changedInputs = changeManager.getChangedInputs()
- if (fullBuild) {
- project.logger.info("No incremental data: full task run")
- doFullTaskAction();
- } else if (!changedOutputs.isEmpty()) {
- project.logger.info("Changed output: full task run")
-
- doFullTaskAction();
- } else if (changedInputs.isEmpty() && changedOutputs.isEmpty()) {
- // both input and output are empty, this is something we don't control
- // through files, just do a full run
- project.logger.info("Changed non file input/output: full task run")
- doFullTaskAction()
- } else {
- doIncrementalTaskAction(changeManager.getChangedInputs())
- }
-
- // update the outputs post task-action, to record their state
- // for the next run
- changeManager.updateOutputs(getOutputForIncrementalBuild())
-
- // write the result down to be used next time the task is run.
- changeManager.write(incrementalFolder)
- } catch (Exception e) {
- // Easiest to do here, is to delete the incremental Data so that
- // next run is full.
- ChangeManager.delete(incrementalFolder)
-
- throw e
+ void taskAction(IncrementalTaskInputs inputs) {
+ if (!isIncremental()) {
+ doFullTaskAction()
+ return
}
+
+ if (!inputs.isIncremental()) {
+ project.logger.info("Unable do incremental execution: full task run")
+ doFullTaskAction()
+ return
+ }
+
+ Map<File, FileStatus> changedInputs = Maps.newHashMap()
+ inputs.outOfDate { change ->
+ //noinspection GroovyAssignabilityCheck
+ changedInputs.put(change.file, change.isAdded() ? FileStatus.NEW : FileStatus.CHANGED)
+ }
+
+ inputs.removed { change ->
+ //noinspection GroovyAssignabilityCheck
+ changedInputs.put(change.file, FileStatus.REMOVED)
+ }
+
+ doIncrementalTaskAction(changedInputs)
}
public static List<File> flattenSourceSets(List<? extends SourceSet> resourceSets) {
- List<File> list = Lists.newArrayList();
+ List<File> list = Lists.newArrayList()
for (SourceSet sourceSet : resourceSets) {
list.addAll(sourceSet.sourceFiles)
}
- return list;
+ return list
}
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/NdkTask.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/NdkTask.groovy
new file mode 100644
index 0000000..ba48552
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/tasks/NdkTask.groovy
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.tasks
+
+import com.android.builder.model.NdkConfig
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Optional
+
+/**
+ * Base task for tasks that require an NdkConfig
+ */
+class NdkTask extends BaseTask {
+
+ NdkConfig ndkConfig
+
+ @Input @Optional
+ String getModuleName() {
+ return getNdkConfig()?.moduleName
+ }
+
+ @Input @Optional
+ String getcFlags() {
+ return getNdkConfig()?.cFlags
+ }
+
+ @Input @Optional
+ Set<String> getLdLibs() {
+ return getNdkConfig()?.ldLibs
+ }
+
+ @Input @Optional
+ Set<String> getAbiFilters() {
+ return getNdkConfig()?.abiFilters
+ }
+
+ @Input @Optional
+ String getStl() {
+ return getNdkConfig().stl
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApkVariantData.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApkVariantData.java
index 822cdfe..9c1f580 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApkVariantData.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApkVariantData.java
@@ -21,14 +21,12 @@
import com.android.build.gradle.tasks.ZipAlign;
import com.android.builder.VariantConfiguration;
import org.gradle.api.DefaultTask;
-import proguard.gradle.ProGuardTask;
/**
* Base data about a variant that generates an APK file.
*/
public abstract class ApkVariantData extends BaseVariantData {
- public ProGuardTask proguardTask;
public Dex dexTask;
public PackageApplication packageApplicationTask;
public ZipAlign zipAlignTask;
@@ -46,34 +44,12 @@
if (getVariantConfiguration().hasFlavors()) {
return String.format("%s build for flavor %s",
getCapitalizedBuildTypeName(),
- getFlavoredName(true));
+ getCapitalizedFlavorName());
} else {
return String.format("%s build", getCapitalizedBuildTypeName());
}
}
- @Override
- @NonNull
- public String getDirName() {
- if (getVariantConfiguration().hasFlavors()) {
- return String.format("%s/%s",
- getFlavoredName(false), getVariantConfiguration().getBuildType().getName());
- } else {
- return getVariantConfiguration().getBuildType().getName();
- }
- }
-
- @Override
- @NonNull
- public String getBaseName() {
- if (getVariantConfiguration().hasFlavors()) {
- return String.format("%s-%s",
- getFlavoredName(false), getVariantConfiguration().getBuildType().getName());
- } else {
- return getVariantConfiguration().getBuildType().getName();
- }
- }
-
public boolean isSigned() {
return getVariantConfiguration().isSigningReady();
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApplicationVariantData.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApplicationVariantData.java
index 0f8d4ed..91c4d08 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApplicationVariantData.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/ApplicationVariantData.java
@@ -31,20 +31,6 @@
super(config);
}
- @NonNull
- @Override
- protected String computeName() {
- return getVariantConfiguration().hasFlavors() ?
- String.format("%s%s",
- getFlavoredName(true), getCapitalizedBuildTypeName()) :
- getCapitalizedBuildTypeName();
- }
-
- @Override
- public boolean getRunProguard() {
- return getVariantConfiguration().getBuildType().isRunProguard();
- }
-
@Override
public void setTestVariantData(@Nullable TestVariantData testVariantData) {
this.testVariantData = testVariantData;
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java
index 135eeaf..83794e8 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java
@@ -17,6 +17,7 @@
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.annotations.VisibleForTesting;
import com.android.build.gradle.internal.StringHelper;
import com.android.build.gradle.internal.dependency.VariantDependencies;
import com.android.build.gradle.internal.tasks.PrepareDependenciesTask;
@@ -24,29 +25,34 @@
import com.android.build.gradle.tasks.GenerateBuildConfig;
import com.android.build.gradle.tasks.MergeAssets;
import com.android.build.gradle.tasks.MergeResources;
+import com.android.build.gradle.tasks.NdkCompile;
import com.android.build.gradle.tasks.ProcessAndroidResources;
import com.android.build.gradle.tasks.ProcessManifest;
import com.android.build.gradle.tasks.RenderscriptCompile;
-import com.android.builder.BuilderConstants;
-import com.android.builder.DefaultProductFlavor;
import com.android.builder.VariantConfiguration;
+import com.google.common.collect.Lists;
import groovy.lang.Closure;
import org.gradle.api.Task;
import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.compile.JavaCompile;
+import proguard.gradle.ProGuardTask;
import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
/**
* Base data about a variant.
*/
public abstract class BaseVariantData {
- private String name;
private final VariantConfiguration variantConfiguration;
private VariantDependencies variantDependency;
+ public Task preBuildTask;
public PrepareDependenciesTask prepareDependenciesTask;
+ public Task sourceGenTask;
public ProcessManifest processManifestTask;
public RenderscriptCompile renderscriptCompileTask;
@@ -57,21 +63,21 @@
public GenerateBuildConfig generateBuildConfigTask;
public JavaCompile javaCompileTask;
- public Copy processJavaResources;
+ public ProGuardTask proguardTask;
+ public Copy processJavaResourcesTask;
+ public NdkCompile ndkCompileTask;
private Object outputFile;
public Task assembleTask;
+ private List<File> extraGeneratedSourceFolders;
+
public BaseVariantData(@NonNull VariantConfiguration variantConfiguration) {
this.variantConfiguration = variantConfiguration;
- this.name = computeName();
}
@NonNull
- protected abstract String computeName();
-
- @NonNull
public VariantConfiguration getVariantConfiguration() {
return variantConfiguration;
}
@@ -86,60 +92,21 @@
}
@NonNull
- public String getName() {
- return name;
- }
-
- @NonNull
public abstract String getDescription();
- @NonNull
- public abstract String getDirName();
-
- @NonNull
- public String getFlavorDirName() {
- if (variantConfiguration.hasFlavors()) {
- return getFlavoredName(false);
- } else {
- return "";
- }
- }
-
- @NonNull
- public String getFlavorName() {
- if (variantConfiguration.hasFlavors()) {
- return getFlavoredName(true);
- } else {
- return StringHelper.capitalize(BuilderConstants.MAIN);
- }
- }
-
- @NonNull
- public abstract String getBaseName();
-
@Nullable
public String getPackageName() {
return variantConfiguration.getPackageName();
}
@NonNull
- protected String getFlavoredName(boolean capitalized) {
- StringBuilder builder = new StringBuilder();
- for (DefaultProductFlavor flavor : variantConfiguration.getFlavorConfigs()) {
- String name = flavor.getName();
- builder.append(capitalized ? StringHelper.capitalize(name) : name);
- }
-
- return builder.toString();
- }
-
- @NonNull
protected String getCapitalizedBuildTypeName() {
return StringHelper.capitalize(variantConfiguration.getBuildType().getName());
}
- public boolean getRunProguard() {
- return false;
+ @NonNull
+ protected String getCapitalizedFlavorName() {
+ return StringHelper.capitalize(variantConfiguration.getFlavorName());
}
public void setOutputFile(Object file) {
@@ -157,4 +124,51 @@
assert false;
return null;
}
+
+ @VisibleForTesting
+ @NonNull
+ String getName() {
+ return variantConfiguration.getFullName();
+ }
+
+ @Nullable
+ public List<File> getExtraGeneratedSourceFolders() {
+ return extraGeneratedSourceFolders;
+ }
+
+ public void addJavaSourceFoldersToModel(@NonNull File... generatedSourceFolders) {
+ Collections.addAll(extraGeneratedSourceFolders, generatedSourceFolders);
+ }
+
+ public void addJavaSourceFoldersToModel(@NonNull Collection<File> generatedSourceFolders) {
+ extraGeneratedSourceFolders.addAll(generatedSourceFolders);
+ }
+
+ public void registerJavaGeneratingTask(@NonNull Task task, @NonNull File... generatedSourceFolders) {
+ if (extraGeneratedSourceFolders == null) {
+ extraGeneratedSourceFolders = Lists.newArrayList();
+ }
+
+ javaCompileTask.dependsOn(task);
+
+ for (File f : generatedSourceFolders) {
+ javaCompileTask.source(f);
+ }
+
+ addJavaSourceFoldersToModel(generatedSourceFolders);
+ }
+
+ public void registerJavaGeneratingTask(@NonNull Task task, @NonNull Collection<File> generatedSourceFolders) {
+ if (extraGeneratedSourceFolders == null) {
+ extraGeneratedSourceFolders = Lists.newArrayList();
+ }
+
+ javaCompileTask.dependsOn(task);
+
+ for (File f : generatedSourceFolders) {
+ javaCompileTask.source(f);
+ }
+
+ addJavaSourceFoldersToModel(generatedSourceFolders);
+ }
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/DefaultSourceProviderContainer.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/DefaultSourceProviderContainer.java
new file mode 100644
index 0000000..06f2e5f
--- /dev/null
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/DefaultSourceProviderContainer.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.build.gradle.internal.variant;
+
+import com.android.annotations.NonNull;
+import com.android.builder.model.SourceProvider;
+import com.android.builder.model.SourceProviderContainer;
+
+/**
+ * Default implementation of a SourceProviderContainer that wraps an existing instance of a
+ * SourceProvider.
+ */
+public class DefaultSourceProviderContainer implements SourceProviderContainer {
+
+ @NonNull
+ private final String name;
+ @NonNull
+ private final SourceProvider sourceProvider;
+
+ public DefaultSourceProviderContainer(@NonNull String name,
+ @NonNull SourceProvider sourceProvider) {
+ this.name = name;
+ this.sourceProvider = sourceProvider;
+ }
+
+ @NonNull
+ @Override
+ public String getArtifactName() {
+ return name;
+ }
+
+ @NonNull
+ @Override
+ public SourceProvider getSourceProvider() {
+ return sourceProvider;
+ }
+}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/LibraryVariantData.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/LibraryVariantData.java
index 852b8c5..8a86851 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/LibraryVariantData.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/LibraryVariantData.java
@@ -36,36 +36,17 @@
@Override
@NonNull
- protected String computeName() {
- return getVariantConfiguration().hasFlavors() ?
- String.format("%s%s",
- getFlavoredName(true), getCapitalizedBuildTypeName()) :
- getCapitalizedBuildTypeName();
- }
-
- @Override
- @NonNull
public String getDescription() {
if (getVariantConfiguration().hasFlavors()) {
- return "Test build for the ${getFlavoredName(true)}${config.buildType.name.capitalize()} build";
+ return String.format("%s build for flavor %s",
+ getCapitalizedBuildTypeName(),
+ getCapitalizedFlavorName());
} else {
- return "Test for the ${config.buildType.name.capitalize()} build";
+ return String.format("%s build", getCapitalizedBuildTypeName());
}
}
@Override
- @NonNull
- public String getDirName() {
- return getVariantConfiguration().getBuildType().getName();
- }
-
- @Override
- @NonNull
- public String getBaseName() {
- return getVariantConfiguration().getBuildType().getName();
- }
-
- @Override
public void setTestVariantData(@Nullable TestVariantData testVariantData) {
this.testVariantData = testVariantData;
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java
index ebd336c..b8d45ed 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java
+++ b/gradle/src/main/groovy/com/android/build/gradle/internal/variant/TestVariantData.java
@@ -43,20 +43,12 @@
return testedVariantData;
}
- @NonNull
- @Override
- protected String computeName() {
- return getVariantConfiguration().hasFlavors() ?
- String.format("%sTest", getFlavoredName(true)) :
- "Test";
- }
-
@Override
@NonNull
public String getDescription() {
if (getVariantConfiguration().hasFlavors()) {
return String.format("Test build for the %s%s build",
- getFlavoredName(true), getCapitalizedBuildTypeName());
+ getCapitalizedFlavorName(), getCapitalizedBuildTypeName());
} else {
return String.format("Test build for the %s build",
getCapitalizedBuildTypeName());
@@ -64,26 +56,6 @@
}
@Override
- @NonNull
- public String getDirName() {
- if (getVariantConfiguration().hasFlavors()) {
- return String.format("%s/test", getFlavoredName(false));
- } else {
- return "test";
- }
- }
-
- @Override
- @NonNull
- public String getBaseName() {
- if (getVariantConfiguration().hasFlavors()) {
- return String.format("%s-test", getFlavoredName(false));
- } else {
- return "test";
- }
- }
-
- @Override
public boolean getZipAlign() {
return false;
}
diff --git a/gradle/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy b/gradle/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy
index d698bd7..6ad9277 100644
--- a/gradle/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy
+++ b/gradle/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy
@@ -47,11 +47,6 @@
}
@Override
- protected Collection<File> getOutputForIncrementalBuild() {
- return Collections.singletonList(getSourceOutputDir())
- }
-
- @Override
protected void compileAllFiles(DependencyFileProcessor dependencyFileProcessor) {
getBuilder().compileAllAidlFiles(
getSourceDirs(),
diff --git a/gradle/src/main/groovy/com/android/build/gradle/tasks/Dex.groovy b/gradle/src/main/groovy/com/android/build/gradle/tasks/Dex.groovy
index 3db6c45..c74cdb3 100644
--- a/gradl