/*
* 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.annotations.Nullable;
import com.android.annotations.VisibleForTesting;
import com.android.build.FilterData;
import com.android.build.OutputFile;
import com.android.build.gradle.BasePlugin;
import com.android.build.gradle.api.AndroidSourceSet;
import com.android.build.gradle.internal.StringHelper;
import com.android.build.gradle.internal.core.GradleVariantConfiguration;
import com.android.build.gradle.internal.coverage.JacocoInstrumentTask;
import com.android.build.gradle.internal.dependency.VariantDependencies;
import com.android.build.gradle.internal.tasks.CheckManifest;
import com.android.build.gradle.internal.tasks.GenerateApkDataTask;
import com.android.build.gradle.internal.tasks.PrepareDependenciesTask;
import com.android.build.gradle.tasks.AidlCompile;
import com.android.build.gradle.tasks.GenerateBuildConfig;
import com.android.build.gradle.tasks.GenerateResValues;
import com.android.build.gradle.tasks.JackTask;
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.RenderscriptCompile;
import com.android.builder.model.SourceProvider;
import com.google.common.collect.Lists;
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;
import java.util.Collections;
import java.util.List;
/**
* Base data about a variant.
*/
public abstract class BaseVariantData<T extends BaseVariantOutputData> {
public enum SplitHandlingPolicy {
/**
* Any release before L will create fake splits where each split will be the entire
* application with the split specific resources.
*/
PRE_21_POLICY,
/**
* Android L and after, the splits are pure splits where splits only contain resources
* specific to the split characteristics.
*/
RELEASE_21_AND_AFTER_POLICY
}
@NonNull
protected final BasePlugin basePlugin;
@NonNull
private final GradleVariantConfiguration variantConfiguration;
private VariantDependencies variantDependency;
public Task preBuildTask;
public PrepareDependenciesTask prepareDependenciesTask;
public ProcessAndroidResources generateRClassTask;
public Task sourceGenTask;
public Task resourceGenTask;
public Task assetGenTask;
public CheckManifest checkManifestTask;
public RenderscriptCompile renderscriptCompileTask;
public AidlCompile aidlCompileTask;
public MergeResources mergeResourcesTask;
public MergeAssets mergeAssetsTask;
public GenerateBuildConfig generateBuildConfigTask;
public GenerateResValues generateResValuesTask;
public Copy copyApkTask;
public GenerateApkDataTask generateApkDataTask;
public Copy processJavaResourcesTask;
public NdkCompile ndkCompileTask;
public JavaCompile javaCompileTask;
public JackTask jackTask;
public Task compileTask;
public JacocoInstrumentTask jacocoInstrumentTask;
public Task obfuscationTask;
public File obfuscatedClassesJar;
public File mappingFile;
// Task to assemble the variant and all its output.
public Task assembleVariantTask;
private Object[] javaSources;
private List<File> extraGeneratedSourceFolders;
private final List<T> outputs = Lists.newArrayListWithExpectedSize(4);
private SplitHandlingPolicy mSplitHandlingPolicy;
public BaseVariantData(
@NonNull BasePlugin basePlugin,
@NonNull GradleVariantConfiguration variantConfiguration) {
this.basePlugin = basePlugin;
this.variantConfiguration = variantConfiguration;
// eventually, this will require a more open ended comparison.
mSplitHandlingPolicy =
basePlugin.getExtension().getGeneratePureSplits()
&& variantConfiguration.getMinSdkVersion().getApiLevel() == 21
? SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY
: SplitHandlingPolicy.PRE_21_POLICY;
variantConfiguration.checkSourceProviders();
}
public SplitHandlingPolicy getSplitHandlingPolicy() {
return mSplitHandlingPolicy;
}
@NonNull
protected abstract T doCreateOutput(
OutputFile.OutputType outputType,
Collection<FilterData> filters);
@NonNull
public T createOutput(OutputFile.OutputType outputType,
Collection<FilterData> filters) {
T data = doCreateOutput(outputType, filters);
// if it's the first time we add an output, mark previous output as part of a multi-output
// setup.
if (outputs.size() == 1) {
outputs.get(0).setMultiOutput(true);
data.setMultiOutput(true);
} else if (outputs.size() > 1) {
data.setMultiOutput(true);
}
outputs.add(data);
return data;
}
@NonNull
public List<T> getOutputs() {
return outputs;
}
@NonNull
public GradleVariantConfiguration getVariantConfiguration() {
return variantConfiguration;
}
public void setVariantDependency(@NonNull VariantDependencies variantDependency) {
this.variantDependency = variantDependency;
}
@NonNull
public VariantDependencies getVariantDependency() {
return variantDependency;
}
@NonNull
public abstract String getDescription();
@NonNull
public String getApplicationId() {
return variantConfiguration.getApplicationId();
}
@NonNull
protected String getCapitalizedBuildTypeName() {
return StringHelper.capitalize(variantConfiguration.getBuildType().getName());
}
@NonNull
protected String getCapitalizedFlavorName() {
return StringHelper.capitalize(variantConfiguration.getFlavorName());
}
@VisibleForTesting
@NonNull
String getName() {
return variantConfiguration.getFullName();
}
@Nullable
public List<File> getExtraGeneratedSourceFolders() {
return extraGeneratedSourceFolders;
}
public void addJavaSourceFoldersToModel(@NonNull File... generatedSourceFolders) {
if (extraGeneratedSourceFolders == null) {
extraGeneratedSourceFolders = Lists.newArrayList();
}
Collections.addAll(extraGeneratedSourceFolders, generatedSourceFolders);
}
public void addJavaSourceFoldersToModel(@NonNull Collection<File> generatedSourceFolders) {
if (extraGeneratedSourceFolders == null) {
extraGeneratedSourceFolders = Lists.newArrayList();
}
extraGeneratedSourceFolders.addAll(generatedSourceFolders);
}
public void registerJavaGeneratingTask(@NonNull Task task, @NonNull File... generatedSourceFolders) {
sourceGenTask.dependsOn(task);
for (File f : generatedSourceFolders) {
javaCompileTask.source(f);
}
addJavaSourceFoldersToModel(generatedSourceFolders);
}
public void registerJavaGeneratingTask(@NonNull Task task, @NonNull Collection<File> generatedSourceFolders) {
sourceGenTask.dependsOn(task);
for (File f : generatedSourceFolders) {
javaCompileTask.source(f);
}
addJavaSourceFoldersToModel(generatedSourceFolders);
}
/**
* Computes the Java sources to use for compilation. This Object[] contains
* {@link org.gradle.api.file.FileCollection} and {@link File} instances
*/
@NonNull
public Object[] getJavaSources() {
if (javaSources == null) {
// Build the list of source folders.
List<Object> sourceList = Lists.newArrayList();
// First the actual source folders.
List<SourceProvider> providers = variantConfiguration.getSortedSourceProviders();
for (SourceProvider provider : providers) {
sourceList.add(((AndroidSourceSet) provider).getJava().getSourceFiles());
}
// then all the generated src folders.
sourceList.add(generateRClassTask.getSourceOutputDir());
// for the other, there's no duplicate so no issue.
sourceList.add(generateBuildConfigTask.getSourceOutputDir());
sourceList.add(aidlCompileTask.getSourceOutputDir());
if (!variantConfiguration.getRenderscriptNdkModeEnabled()) {
sourceList.add(renderscriptCompileTask.getSourceOutputDir());
}
javaSources = sourceList.toArray();
}
return javaSources;
}
/**
* Returns the Java folders needed for code coverage report.
*
* This includes all the source folders except for the ones containing R and buildConfig.
*/
@NonNull
public List<File> getJavaSourceFoldersForCoverage() {
// Build the list of source folders.
List<File> sourceFolders = Lists.newArrayList();
// First the actual source folders.
List<SourceProvider> providers = variantConfiguration.getSortedSourceProviders();
for (SourceProvider provider : providers) {
for (File sourceFolder : provider.getJavaDirectories()) {
if (sourceFolder.isDirectory()) {
sourceFolders.add(sourceFolder);
}
}
}
File sourceFolder;
// then all the generated src folders, except the ones for the R/Manifest and
// BuildConfig classes.
sourceFolder = aidlCompileTask.getSourceOutputDir();
if (sourceFolder.isDirectory()) {
sourceFolders.add(sourceFolder);
}
if (!variantConfiguration.getRenderscriptNdkModeEnabled()) {
sourceFolder = renderscriptCompileTask.getSourceOutputDir();
if (sourceFolder.isDirectory()) {
sourceFolders.add(sourceFolder);
}
}
return sourceFolders;
}
}