com.android.build.gradle.tasks.ProcessAndroidResources Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-core Show documentation
Show all versions of gradle-core Show documentation
Core library to build Android Gradle plugin.
/*
* 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.build.gradle.tasks;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.build.gradle.internal.LoggingUtil;
import com.android.build.gradle.internal.core.GradleVariantConfiguration;
import com.android.build.gradle.internal.dependency.SymbolFileProviderImpl;
import com.android.build.gradle.internal.dsl.AaptOptions;
import com.android.build.gradle.internal.scope.ConventionMappingHelper;
import com.android.build.gradle.internal.scope.TaskConfigAction;
import com.android.build.gradle.internal.scope.VariantOutputScope;
import com.android.build.gradle.internal.tasks.IncrementalTask;
import com.android.build.gradle.internal.variant.BaseVariantData;
import com.android.build.gradle.internal.variant.BaseVariantOutputData;
import com.android.builder.core.AaptPackageProcessBuilder;
import com.android.builder.core.AndroidBuilder;
import com.android.builder.core.VariantType;
import com.android.builder.dependency.LibraryDependency;
import com.android.ide.common.blame.MergingLog;
import com.android.ide.common.blame.MergingLogRewriter;
import com.android.ide.common.blame.ParsingProcessOutputHandler;
import com.android.ide.common.blame.parser.ToolOutputParser;
import com.android.ide.common.blame.parser.aapt.AaptOutputParser;
import com.android.ide.common.process.ProcessException;
import com.android.ide.common.process.ProcessOutputHandler;
import com.android.utils.FileUtils;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import org.gradle.api.logging.Logging;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.ParallelizableTask;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
@ParallelizableTask
public class ProcessAndroidResources extends IncrementalTask {
private File manifestFile;
private File resDir;
private File assetsDir;
private File sourceOutputDir;
private File textSymbolOutputDir;
private File packageOutputFile;
private File proguardOutputFile;
private Collection resourceConfigs;
private String preferredDensity;
private List libraries;
private String packageForR;
private Collection splits;
private boolean enforceUniquePackageName;
private VariantType type;
private boolean debuggable;
private boolean pseudoLocalesEnabled;
private AaptOptions aaptOptions;
private File mergeBlameLogFolder;
@Override
protected void doFullTaskAction() throws IOException {
// we have to clean the source folder output in case the package name changed.
File srcOut = getSourceOutputDir();
if (srcOut != null) {
FileUtils.emptyFolder(srcOut);
}
File resOutBaseNameFile = getPackageOutputFile();
AaptPackageProcessBuilder aaptPackageCommandBuilder =
new AaptPackageProcessBuilder(getManifestFile(), getAaptOptions())
.setAssetsFolder(getAssetsDir())
.setResFolder(getResDir())
.setLibraries(getLibraries())
.setPackageForR(getPackageForR())
.setSourceOutputDir(absolutePath(srcOut))
.setSymbolOutputDir(absolutePath(getTextSymbolOutputDir()))
.setResPackageOutput(absolutePath(resOutBaseNameFile))
.setProguardOutput(absolutePath(getProguardOutputFile()))
.setType(getType())
.setDebuggable(getDebuggable())
.setPseudoLocalesEnabled(getPseudoLocalesEnabled())
.setResourceConfigs(getResourceConfigs())
.setSplits(getSplits())
.setPreferredDensity(getPreferredDensity());
@NonNull
AndroidBuilder builder = getBuilder();
MergingLog mergingLog = new MergingLog(getMergeBlameLogFolder());
ProcessOutputHandler processOutputHandler = new ParsingProcessOutputHandler(
new ToolOutputParser(new AaptOutputParser(), getILogger()),
new MergingLogRewriter(mergingLog, builder.getErrorReporter()));
try {
builder.processResources(
aaptPackageCommandBuilder,
getEnforceUniquePackageName(),
processOutputHandler);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ProcessException e) {
throw new RuntimeException(e);
}
}
private boolean isSplitPackage(File file, File resBaseName) {
if (file.getName().startsWith(resBaseName.getName())) {
for (String split : splits) {
if (file.getName().contains(split)) {
return true;
}
}
}
return false;
}
@Nullable
private static String absolutePath(@Nullable File file) {
return file == null ? null : file.getAbsolutePath();
}
public static class ConfigAction implements TaskConfigAction {
private VariantOutputScope scope;
private File symbolLocation;
private boolean generateResourcePackage;
public ConfigAction(
VariantOutputScope scope, File symbolLocation, boolean generateResourcePackage) {
this.scope = scope;
this.symbolLocation = symbolLocation;
this.generateResourcePackage = generateResourcePackage;
}
@NonNull
@Override
public String getName() {
return scope.getTaskName("process", "Resources");
}
@NonNull
@Override
public Class getType() {
return ProcessAndroidResources.class;
}
@Override
public void execute(@NonNull ProcessAndroidResources processResources) {
final BaseVariantOutputData variantOutputData = scope.getVariantOutputData();
final BaseVariantData extends BaseVariantOutputData> variantData =
scope.getVariantScope().getVariantData();
variantOutputData.processResourcesTask = processResources;
final GradleVariantConfiguration config = variantData.getVariantConfiguration();
processResources.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder());
processResources.setVariantName(config.getFullName());
if (variantData.getSplitHandlingPolicy() ==
BaseVariantData.SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY) {
Set allFilters = new HashSet();
allFilters.addAll(
variantData.getFilters(com.android.build.OutputFile.FilterType.DENSITY));
allFilters.addAll(
variantData.getFilters(com.android.build.OutputFile.FilterType.LANGUAGE));
processResources.splits = allFilters;
}
// only generate code if the density filter is null, and if we haven't generated
// it yet (if you have abi + density splits, then several abi output will have no
// densityFilter)
if (variantOutputData.getMainOutputFile()
.getFilter(com.android.build.OutputFile.DENSITY) == null
&& variantData.generateRClassTask == null) {
variantData.generateRClassTask = processResources;
processResources.enforceUniquePackageName = scope.getGlobalScope().getExtension()
.getEnforceUniquePackageName();
ConventionMappingHelper.map(processResources, "libraries",
new Callable>() {
@Override
public List call() throws Exception {
return getTextSymbolDependencies(config.getAllLibraries());
}
});
ConventionMappingHelper.map(processResources, "packageForR",
new Callable() {
@Override
public String call() throws Exception {
return config.getOriginalApplicationId();
}
});
// TODO: unify with generateBuilderConfig, compileAidl, and library packaging somehow?
processResources
.setSourceOutputDir(scope.getVariantScope().getRClassSourceOutputDir());
processResources.setTextSymbolOutputDir(symbolLocation);
if (config.getBuildType().isMinifyEnabled()) {
if (config.getBuildType().isShrinkResources() && config.getUseJack()) {
LoggingUtil.displayWarning(Logging.getLogger(getClass()),
scope.getGlobalScope().getProject(),
"shrinkResources does not yet work with useJack=true");
}
processResources.setProguardOutputFile(
scope.getVariantScope().getProcessAndroidResourcesProguardOutputFile());
} else if (config.getBuildType().isShrinkResources()) {
LoggingUtil.displayWarning(Logging.getLogger(getClass()),
scope.getGlobalScope().getProject(),
"To shrink resources you must also enable ProGuard");
}
}
ConventionMappingHelper.map(processResources, "manifestFile", new Callable() {
@Override
public File call() throws Exception {
return variantOutputData.manifestProcessorTask.getOutputFile();
}
});
ConventionMappingHelper.map(processResources, "resDir", new Callable() {
@Override
public File call() throws Exception {
return scope.getVariantScope().getFinalResourcesDir();
}
});
ConventionMappingHelper.map(processResources, "assetsDir", new Callable() {
@Override
public File call() throws Exception {
return variantData.mergeAssetsTask.getOutputDir();
}
});
if (generateResourcePackage) {
processResources.setPackageOutputFile(scope.getProcessResourcePackageOutputFile());
}
processResources.setType(config.getType());
processResources.setDebuggable(config.getBuildType().isDebuggable());
processResources.setAaptOptions(scope.getGlobalScope().getExtension().getAaptOptions());
processResources
.setPseudoLocalesEnabled(config.getBuildType().isPseudoLocalesEnabled());
ConventionMappingHelper.map(processResources, "resourceConfigs",
new Callable>() {
@Override
public Collection call() throws Exception {
Collection resConfigs =
config.getMergedFlavor().getResourceConfigurations();
if (resConfigs.size() == 1 &&
Iterators.getOnlyElement(resConfigs.iterator())
.equals("auto")) {
if (scope.getGlobalScope().getAndroidBuilder().getTargetInfo()
.getBuildTools().getRevision().getMajor() >= 21) {
return variantData.discoverListOfResourceConfigsNotDensities();
} else {
return variantData.discoverListOfResourceConfigs();
}
}
return config.getMergedFlavor().getResourceConfigurations();
}
});
ConventionMappingHelper.map(processResources, "preferredDensity",
new Callable() {
@Override
public String call() throws Exception {
return variantOutputData.getMainOutputFile()
.getFilter(com.android.build.OutputFile.DENSITY);
}
});
processResources.setMergeBlameLogFolder(
scope.getVariantScope().getResourceBlameLogDir());
}
@NonNull
private static List getTextSymbolDependencies(
List libraries) {
List list = Lists.newArrayListWithCapacity(libraries.size());
for (LibraryDependency lib : libraries) {
list.add(new SymbolFileProviderImpl(lib));
}
return list;
}
}
@InputFile
public File getManifestFile() {
return manifestFile;
}
public void setManifestFile(File manifestFile) {
this.manifestFile = manifestFile;
}
@NonNull
@InputDirectory
public File getResDir() {
return resDir;
}
public void setResDir(@NonNull File resDir) {
this.resDir = resDir;
}
@InputDirectory
@Optional
public File getAssetsDir() {
return assetsDir;
}
public void setAssetsDir(File assetsDir) {
this.assetsDir = assetsDir;
}
@OutputDirectory
@Optional
public File getSourceOutputDir() {
return sourceOutputDir;
}
public void setSourceOutputDir(File sourceOutputDir) {
this.sourceOutputDir = sourceOutputDir;
}
@OutputDirectory
@Optional
public File getTextSymbolOutputDir() {
return textSymbolOutputDir;
}
public void setTextSymbolOutputDir(File textSymbolOutputDir) {
this.textSymbolOutputDir = textSymbolOutputDir;
}
@OutputFile
@Optional
public File getPackageOutputFile() {
return packageOutputFile;
}
public void setPackageOutputFile(File packageOutputFile) {
this.packageOutputFile = packageOutputFile;
}
@OutputFile
@Optional
public File getProguardOutputFile() {
return proguardOutputFile;
}
public void setProguardOutputFile(File proguardOutputFile) {
this.proguardOutputFile = proguardOutputFile;
}
@Input
public Collection getResourceConfigs() {
return resourceConfigs;
}
public void setResourceConfigs(Collection resourceConfigs) {
this.resourceConfigs = resourceConfigs;
}
@Input
@Optional
public String getPreferredDensity() {
return preferredDensity;
}
public void setPreferredDensity(String preferredDensity) {
this.preferredDensity = preferredDensity;
}
@Input
String getBuildToolsVersion() {
return getBuildTools().getRevision().toString();
}
@Nested
@Optional
public List getLibraries() {
return libraries;
}
public void setLibraries(
List libraries) {
this.libraries = libraries;
}
@Input
@Optional
public String getPackageForR() {
return packageForR;
}
public void setPackageForR(String packageForR) {
this.packageForR = packageForR;
}
@Input
@Optional
public Collection getSplits() {
return splits;
}
public void setSplits(Collection splits) {
this.splits = splits;
}
@Input
public boolean getEnforceUniquePackageName() {
return enforceUniquePackageName;
}
public void setEnforceUniquePackageName(boolean enforceUniquePackageName) {
this.enforceUniquePackageName = enforceUniquePackageName;
}
/** Does not change between incremental builds, so does not need to be @Input. */
public VariantType getType() {
return type;
}
public void setType(VariantType type) {
this.type = type;
}
@Input
public boolean getDebuggable() {
return debuggable;
}
public void setDebuggable(boolean debuggable) {
this.debuggable = debuggable;
}
@Input
public boolean getPseudoLocalesEnabled() {
return pseudoLocalesEnabled;
}
public void setPseudoLocalesEnabled(boolean pseudoLocalesEnabled) {
this.pseudoLocalesEnabled = pseudoLocalesEnabled;
}
@Nested
public AaptOptions getAaptOptions() {
return aaptOptions;
}
public void setAaptOptions(AaptOptions aaptOptions) {
this.aaptOptions = aaptOptions;
}
@Input
public File getMergeBlameLogFolder() {
return mergeBlameLogFolder;
}
public void setMergeBlameLogFolder(File mergeBlameLogFolder) {
this.mergeBlameLogFolder = mergeBlameLogFolder;
}
}