All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.android.build.gradle.tasks.MergeResources Maven / Gradle / Ivy

The newest version!
/*
 * 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.scope.ConventionMappingHelper;
import com.android.build.gradle.internal.scope.TaskConfigAction;
import com.android.build.gradle.internal.scope.VariantScope;
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.model.AndroidProject;
import com.android.builder.png.QueuedCruncher;
import com.android.ide.common.internal.PngCruncher;
import com.android.ide.common.res2.FileStatus;
import com.android.ide.common.res2.FileValidity;
import com.android.ide.common.res2.MergedResourceWriter;
import com.android.ide.common.res2.MergingException;
import com.android.ide.common.res2.ResourceMerger;
import com.android.ide.common.res2.ResourceSet;
import com.android.sdklib.BuildToolInfo;
import com.android.sdklib.repository.FullRevision;
import com.google.common.collect.Lists;

import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.ParallelizableTask;
import org.gradle.api.tasks.OutputFile;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

@ParallelizableTask
public class MergeResources extends IncrementalTask {

    /**
     * The first version of build tools that normalizes resources when packaging the APK.
     *
     * 

This means that e.g. drawable-hdpi becomes drawable-hdpi-v4 to make it clear it was not * available before API 4. */ public static final FullRevision NORMALIZE_RESOURCES_BUILD_TOOLS = new FullRevision(21, 0, 0); // ----- PUBLIC TASK API ----- /** * Directory to write the merged resources to */ private File outputDir; // ----- PRIVATE TASK API ----- /** * Optional file to write any publicly imported resource types and names to */ private File publicFile; private boolean process9Patch; private boolean crunchPng; private boolean useNewCruncher; private boolean insertSourceMarkers = true; private boolean normalizeResources; // actual inputs private List inputResourceSets; private final FileValidity fileValidity = new FileValidity(); // fake input to detect changes. Not actually used by the task @InputFiles public Iterable getRawInputFolders() { return flattenSourceSets(getInputResourceSets()); } @Input public String getBuildToolsVersion() { return getBuildTools().getRevision().toString(); } @Override protected boolean isIncremental() { return true; } private PngCruncher getCruncher() { if (getUseNewCruncher()) { if (getBuilder().getTargetInfo().getBuildTools().getRevision().getMajor() >= 22) { return QueuedCruncher.Builder.INSTANCE.newCruncher( getBuilder().getTargetInfo().getBuildTools().getPath( BuildToolInfo.PathId.AAPT), getILogger()); } getLogger().info("New PNG cruncher will be enabled with build tools 22 and above."); } return getBuilder().getAaptCruncher(); } @Override protected void doFullTaskAction() { // this is full run, clean the previous output File destinationDir = getOutputDir(); emptyFolder(destinationDir); List resourceSets = getInputResourceSets(); // create a new merger and populate it with the sets. ResourceMerger merger = new ResourceMerger(); try { for (ResourceSet resourceSet : resourceSets) { resourceSet.setNormalizeResources(normalizeResources); // set needs to be loaded. resourceSet.loadFromFiles(getILogger()); merger.addDataSet(resourceSet); } // get the merged set and write it down. MergedResourceWriter writer = new MergedResourceWriter( destinationDir, getCruncher(), getCrunchPng(), getProcess9Patch(), getPublicFile()); writer.setInsertSourceMarkers(getInsertSourceMarkers()); merger.mergeData(writer, false /*doCleanUp*/); // No exception? Write the known state. merger.writeBlobTo(getIncrementalFolder(), writer); } catch (MergingException e) { System.out.println(e.getMessage()); merger.cleanBlob(getIncrementalFolder()); throw new ResourceException(e.getMessage(), e); } } @Override protected void doIncrementalTaskAction(Map changedInputs) { // create a merger and load the known state. ResourceMerger merger = new ResourceMerger(); try { if (!merger.loadFromBlob(getIncrementalFolder(), true /*incrementalState*/)) { doFullTaskAction(); return; } // compare the known state to the current sets to detect incompatibility. // This is in case there's a change that's too hard to do incrementally. In this case // we'll simply revert to full build. List resourceSets = getInputResourceSets(); for (ResourceSet resourceSet : resourceSets) { resourceSet.setNormalizeResources(normalizeResources); } if (!merger.checkValidUpdate(resourceSets)) { getLogger().info("Changed Resource sets: full task run!"); doFullTaskAction(); return; } // The incremental process is the following: // Loop on all the changed files, find which ResourceSet it belongs to, then ask // the resource set to update itself with the new file. for (Map.Entry entry : changedInputs.entrySet()) { File changedFile = entry.getKey(); merger.findDataSetContaining(changedFile, fileValidity); if (fileValidity.getStatus() == FileValidity.FileStatus.UNKNOWN_FILE) { doFullTaskAction(); return; } else if (fileValidity.getStatus() == FileValidity.FileStatus.VALID_FILE) { if (!fileValidity.getDataSet().updateWith( fileValidity.getSourceFile(), changedFile, entry.getValue(), getILogger())) { getLogger().info( String.format("Failed to process %s event! Full task run", entry.getValue())); doFullTaskAction(); return; } } } MergedResourceWriter writer = new MergedResourceWriter( getOutputDir(), getCruncher(), getCrunchPng(), getProcess9Patch(), getPublicFile()); writer.setInsertSourceMarkers(getInsertSourceMarkers()); merger.mergeData(writer, false /*doCleanUp*/); // No exception? Write the known state. merger.writeBlobTo(getIncrementalFolder(), writer); } catch (MergingException e) { merger.cleanBlob(getIncrementalFolder()); throw new ResourceException(e.getMessage(), e); } finally { // some clean up after the task to help multi variant/module builds. fileValidity.clear(); } } @Input public boolean isProcess9Patch() { return process9Patch; } @Input public boolean isCrunchPng() { return crunchPng; } @Input public boolean isUseNewCruncher() { return useNewCruncher; } @Input public boolean isInsertSourceMarkers() { return insertSourceMarkers; } @Input public boolean isNormalizeResources() { return normalizeResources; } public void setNormalizeResources(boolean normalizeResources) { this.normalizeResources = normalizeResources; } public List getInputResourceSets() { return inputResourceSets; } public void setInputResourceSets( List inputResourceSets) { this.inputResourceSets = inputResourceSets; } public boolean getUseNewCruncher() { return useNewCruncher; } public void setUseNewCruncher(boolean useNewCruncher) { this.useNewCruncher = useNewCruncher; } @OutputDirectory public File getOutputDir() { return outputDir; } public void setOutputDir(File outputDir) { this.outputDir = outputDir; } public boolean getCrunchPng() { return crunchPng; } public void setCrunchPng(boolean crunchPng) { this.crunchPng = crunchPng; } public boolean getProcess9Patch() { return process9Patch; } public void setProcess9Patch(boolean process9Patch) { this.process9Patch = process9Patch; } @Optional @OutputFile public File getPublicFile() { return publicFile; } public void setPublicFile(File publicFile) { this.publicFile = publicFile; } public boolean getInsertSourceMarkers() { return insertSourceMarkers; } public void setInsertSourceMarkers(boolean insertSourceMarkers) { this.insertSourceMarkers = insertSourceMarkers; } public static class ConfigAction implements TaskConfigAction { @NonNull private VariantScope scope; @NonNull private String taskNamePrefix; @Nullable private File outputLocation; private boolean includeDependencies; private boolean process9Patch; public ConfigAction( @NonNull VariantScope scope, @NonNull String taskNamePrefix, @Nullable File outputLocation, boolean includeDependencies, boolean process9Patch) { this.scope = scope; this.taskNamePrefix = taskNamePrefix; this.outputLocation = outputLocation; this.includeDependencies = includeDependencies; this.process9Patch = process9Patch; scope.setMergeResourceOutputDir(outputLocation); } @Override public String getName() { return scope.getTaskName(taskNamePrefix, "Resources"); } @Override public Class getType() { return MergeResources.class; } @Override public void execute(MergeResources mergeResourcesTask) { final BaseVariantData variantData = scope .getVariantData(); mergeResourcesTask.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder()); mergeResourcesTask.setIncrementalFolder(new File( scope.getGlobalScope().getBuildDir() + "/" + AndroidProject.FD_INTERMEDIATES + "/incremental/" + taskNamePrefix + "Resources" + variantData.getVariantConfiguration().getDirName())); mergeResourcesTask.process9Patch = process9Patch; mergeResourcesTask.crunchPng = scope.getGlobalScope().getExtension().getAaptOptions() .getCruncherEnabled(); mergeResourcesTask.normalizeResources = scope.getGlobalScope().getExtension().getBuildToolsRevision() .compareTo(NORMALIZE_RESOURCES_BUILD_TOOLS) < 0; ConventionMappingHelper.map(mergeResourcesTask, "useNewCruncher", new Callable() { @Override public Boolean call() throws Exception { return scope.getGlobalScope().getExtension().getAaptOptions() .getUseNewCruncher(); } }); ConventionMappingHelper.map(mergeResourcesTask, "inputResourceSets", new Callable>() { @Override public List call() throws Exception { List generatedResFolders = Lists.newArrayList( scope.getRenderscriptResOutputDir(), scope.getGeneratedResOutputDir()); if (variantData.getExtraGeneratedResFolders() != null) { generatedResFolders.addAll( variantData.getExtraGeneratedResFolders()); } if (variantData.generateApkDataTask != null && variantData.getVariantConfiguration().getBuildType() .isEmbedMicroApp()) { generatedResFolders.add( variantData.generateApkDataTask.getResOutputDir()); } return variantData.getVariantConfiguration() .getResourceSets(generatedResFolders, includeDependencies); } }); ConventionMappingHelper.map(mergeResourcesTask, "outputDir", new Callable() { @Override public File call() throws Exception { return outputLocation != null ? outputLocation : scope.getDefaultMergeResourcesOutputDir(); } }); variantData.mergeResourcesTask = mergeResourcesTask; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy