Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * 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.core;
  
  import static com.android.SdkConstants.DOT_XML;
  import static com.android.SdkConstants.FD_RES_XML;
  import static com.android.builder.core.BuilderConstants.ANDROID_WEAR;
  import static com.android.builder.core.BuilderConstants.ANDROID_WEAR_MICRO_APK;
  import static com.android.manifmerger.ManifestMerger2.Invoker;
  import static com.android.manifmerger.ManifestMerger2.SystemProperty;
  import static com.google.common.base.Preconditions.checkArgument;
  import static com.google.common.base.Preconditions.checkNotNull;
  import static com.google.common.base.Preconditions.checkState;
  
  
  import java.io.File;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
This is the main builder class. It is given all the data to process the build (such as DefaultProductFlavors, DefaultBuildType and dependencies) and use them when doing specific build steps. To use: create a builder with AndroidBuilder(java.lang.String,java.lang.String,com.android.utils.ILogger,boolean) then build steps can be done with mergeManifests(java.io.File,java.util.List,java.util.List,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String,java.lang.Integer,java.lang.String,com.android.manifmerger.ManifestMerger2.MergeType,java.util.Map) processTestManifest2(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.Boolean,java.lang.Boolean,java.io.File,java.util.List,java.io.File,java.io.File) processResources(java.io.File,java.io.File,java.io.File,java.util.List,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,com.android.builder.core.VariantConfiguration.Type,boolean,com.android.builder.model.AaptOptions,java.util.Collection,boolean) compileAllAidlFiles(java.util.List,java.io.File,java.io.File,java.util.List,com.android.builder.compiling.DependencyFileProcessor) convertByteCode(java.lang.Iterable,java.lang.Iterable,java.io.File,com.android.builder.core.DexOptions,java.util.List,boolean) packageApk(java.lang.String,java.io.File,java.util.Collection,java.lang.String,java.util.Collection,java.util.Set,boolean,com.android.builder.model.SigningConfig,com.android.builder.model.PackagingOptions,java.lang.String) Java compilation is not handled but the builder provides the bootclasspath with getBootClasspath().
 
 public class AndroidBuilder {
 
     private static final FullRevision MIN_BUILD_TOOLS_REV = new FullRevision(19, 1, 0);
 
         @Override
         public DependencyData processFile(@NonNull File dependencyFile) {
             return null;
         }
     };
 
     private final String mProjectId;
     private final ILogger mLogger;
     private final CommandLineRunner mCmdLineRunner;
     private final boolean mVerboseExec;
 
     private String mCreatedBy;
 
     private SdkInfo mSdkInfo;
     private TargetInfo mTargetInfo;

    
Creates an AndroidBuilder.

verboseExec is needed on top of the ILogger due to remote exec tools not being able to output info and verbose messages separately.

Parameters:
createdBy the createdBy String for the apk manifest.
logger the Logger
verboseExec whether external tools are launched in verbose mode
 
     public AndroidBuilder(
             @NonNull String projectId,
             @Nullable String createdBy,
             @NonNull ILogger logger,
             boolean verboseExec) {
          = projectId;
          = createdBy;
          = checkNotNull(logger);
          = verboseExec;
          = new CommandLineRunner();
     }
 
             @NonNull String projectId,
             @NonNull CommandLineRunner cmdLineRunner,
             @NonNull ILogger logger,
             boolean verboseExec) {
          = projectId;
          = checkNotNull(cmdLineRunner);
          = checkNotNull(logger);
          = verboseExec;
     }

    
Sets the SdkInfo and the targetInfo on the builder. This is required to actually build (some of the steps).

Parameters:
sdkInfo the SdkInfo
targetInfo the TargetInfo
See also:
com.android.builder.sdk.SdkLoader
 
     public void setTargetInfo(@NonNull SdkInfo sdkInfo, @NonNull TargetInfo targetInfo) {
          = sdkInfo;
          = targetInfo;
 
             throw new IllegalArgumentException(String.format(
                     "The SDK Build Tools revision (%1$s) is too low for project '%2$s'. Minimum required is %3$s",
                     .getBuildTools().getRevision(), ));
         }
     }

    
Returns the SdkInfo, if set.
 
     @Nullable
     public SdkInfo getSdkInfo() {
         return ;
     }

    
Returns the TargetInfo, if set.
 
     @Nullable
     public TargetInfo getTargetInfo() {
         return ;
     }

    
Returns the compilation target, if set.
 
     @Nullable
     public IAndroidTarget getTarget() {
         checkState( != null,
                 "Cannot call getTarget() before setTargetInfo() is called.");
         return .getTarget();
     }

    
Returns whether the compilation target is a preview.
 
     public boolean isPreviewTarget() {
         checkState( != null,
                 "Cannot call isTargetAPreview() before setTargetInfo() is called.");
         return .getTarget().getVersion().isPreview();
     }
 
     public String getTargetCodename() {
         checkState( != null,
                 "Cannot call getTargetCodename() before setTargetInfo() is called.");
         return .getTarget().getVersion().getCodename();
     }

    
Helper method to get the boot classpath to be used during compilation.
 
     @NonNull
     public List<StringgetBootClasspath() {
         checkState( != null,
                 "Cannot call getBootClasspath() before setTargetInfo() is called.");
 
         List<Stringclasspath = Lists.newArrayList();
 
         IAndroidTarget target = .getTarget();
 
         classpath.addAll(target.getBootClasspath());
 
         // add optional libraries if any
         IAndroidTarget.IOptionalLibrary[] libs = target.getOptionalLibraries();
         if (libs != null) {
             for (IAndroidTarget.IOptionalLibrary lib : libs) {
                 classpath.add(lib.getJarPath());
             }
         }
 
         // add annotations.jar if needed.
         if (target.getVersion().getApiLevel() <= 15) {
             classpath.add(.getAnnotationsJar().getPath());
         }
 
         return classpath;
     }

    
Returns the jar file for the renderscript mode. This may return null if the SDK has not been loaded yet.

 
     @Nullable
     public File getRenderScriptSupportJar() {
         if ( != null) {
             return RenderScriptProcessor.getSupportJar(
                     .getBuildTools().getLocation().getAbsolutePath());
         }
 
         return null;
     }

    
Returns the compile classpath for this config. If the config tests a library, this will include the classpath of the tested config. If the SDK was loaded, this may include the renderscript support jar.

Returns:
a non null, but possibly empty set.
 
     @NonNull
     public Set<FilegetCompileClasspath(@NonNull VariantConfiguration variantConfiguration) {
         Set<FilecompileClasspath = variantConfiguration.getCompileClasspath();
 
         ProductFlavor mergedFlavor = variantConfiguration.getMergedFlavor();
 
         if (mergedFlavor.getRenderscriptSupportMode()) {
             File renderScriptSupportJar = getRenderScriptSupportJar();
 
             Set<FilefullJars = Sets.newHashSetWithExpectedSize(compileClasspath.size() + 1);
             fullJars.addAll(compileClasspath);
             if (renderScriptSupportJar != null) {
                 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 If the SDK was loaded, this may include the renderscript support jar.

Returns:
a non null, but possibly empty list.
 
     @NonNull
     public Set<FilegetPackagedJars(@NonNull VariantConfiguration variantConfiguration) {
         Set<FilepackagedJars = variantConfiguration.getPackagedJars();
 
         ProductFlavor mergedFlavor = variantConfiguration.getMergedFlavor();
 
         if (mergedFlavor.getRenderscriptSupportMode()) {
             File renderScriptSupportJar = getRenderScriptSupportJar();
 
             Set<FilefullJars = Sets.newHashSetWithExpectedSize(packagedJars.size() + 1);
             fullJars.addAll(packagedJars);
             if (renderScriptSupportJar != null) {
                 fullJars.add(renderScriptSupportJar);
             }
             packagedJars = fullJars;
         }
 
         return packagedJars;
     }

    
Returns the native lib folder for the renderscript mode. This may return null if the SDK has not been loaded yet.

 
     @Nullable
     public File getSupportNativeLibFolder() {
         if ( != null) {
             return RenderScriptProcessor.getSupportNativeLibFolder(
                     .getBuildTools().getLocation().getAbsolutePath());
         }
 
         return null;
     }

    
Returns an com.android.ide.common.internal.PngCruncher using aapt underneath

Returns:
an PngCruncher object
 
     @NonNull
     public PngCruncher getAaptCruncher() {
         checkState( != null,
                 "Cannot call getAaptCruncher() before setTargetInfo() is called.");
         return new AaptCruncher(
                 .getBuildTools().getPath(..),
                 );
     }
 
     @NonNull
         return ;
     }
 
     @NonNull
     public static ClassField createClassField(@NonNull String type, @NonNull String name, @NonNull String value) {
         return new ClassFieldImpl(typenamevalue);
     }

    
Invoke the Manifest Merger version 2.
 
     public void mergeManifests(
             @NonNull File mainManifest,
             @NonNull List<FilemanifestOverlays,
             @NonNull List<? extends ManifestDependencylibraries,
             String packageOverride,
             int versionCode,
             String versionName,
             @Nullable String minSdkVersion,
             @Nullable String targetSdkVersion,
             @Nullable Integer maxSdkVersion,
             @NonNull String outManifestLocation,
             ManifestMerger2.MergeType mergeType,
             Map<StringStringplaceHolders) {
 
         try {
             Invoker manifestMergerInvoker =
                     ManifestMerger2.newMerger(mainManifestmergeType)
                     .setPlaceHolderValues(placeHolders)
                     .addFlavorAndBuildTypeManifests(
                             manifestOverlays.toArray(new File[manifestOverlays.size()]))
                     .addLibraryManifests(collectLibraries(libraries));
 
             if (mergeType == ..) {
                 manifestMergerInvoker.withFeatures(..);
             }
 
             setInjectableValues(manifestMergerInvoker,
                     packageOverrideversionCodeversionName,
                     minSdkVersiontargetSdkVersionmaxSdkVersion);
 
             MergingReport mergingReport = manifestMergerInvoker.merge();
             .info("Merging result:" + mergingReport.getResult());
             switch (mergingReport.getResult()) {
                 case :
                     mergingReport.log();
                     // fall through since these are just warnings.
                 case :
                     XmlDocument xmlDocument = mergingReport.getMergedDocument().get();
                     try {
                         String annotatedDocument = mergingReport.getActions().blame(xmlDocument);
                         .verbose(annotatedDocument);
                     } catch (Exception e) {
                         .error(e"cannot print resulting xml");
                     }
                     save(xmlDocumentnew File(outManifestLocation));
                     .info("Merged manifest saved to " + outManifestLocation);
                     break;
                 case :
                     mergingReport.log();
                     throw new RuntimeException(mergingReport.getReportString());
                 default:
                     throw new RuntimeException("Unhandled result type : "
                             + mergingReport.getResult());
             }
         } catch (ManifestMerger2.MergeFailureException e) {
             // TODO: unacceptable.
             throw new RuntimeException(e);
         }
     }

    
Sets the com.android.manifmerger.ManifestMerger2.SystemProperty that can be injected in the manifest file.
 
     private static void setInjectableValues(
             ManifestMerger2.Invoker<?> invoker,
             String packageOverride,
             int versionCode,
             String versionName,
             @Nullable String minSdkVersion,
             @Nullable String targetSdkVersion,
             @Nullable Integer maxSdkVersion) {
 
         if (!Strings.isNullOrEmpty(packageOverride)) {
             invoker.setOverride(.packageOverride);
         }
         if (versionCode > 0) {
             invoker.setOverride(.,
                     String.valueOf(versionCode));
         }
         if (!Strings.isNullOrEmpty(versionName)) {
             invoker.setOverride(.versionName);
         }
         if (!Strings.isNullOrEmpty(minSdkVersion)) {
             invoker.setOverride(.minSdkVersion);
         }
         if (!Strings.isNullOrEmpty(targetSdkVersion)) {
             invoker.setOverride(.targetSdkVersion);
         }
         if (maxSdkVersion != null) {
             invoker.setOverride(.maxSdkVersion.toString());
         }
     }

    
Saves the com.android.manifmerger.XmlDocument to a file in UTF-8 encoding.

Parameters:
xmlDocument xml document to save.
out file to save to.
 
     private void save(XmlDocument xmlDocumentFile out) {
         try {
             Files.write(xmlDocument.prettyPrint(), out.);
         } catch(IOException e) {
             throw new RuntimeException(e);
         }
     }

    
Collect the list of libraries' manifest files.

Parameters:
libraries declared dependencies
Returns:
a list of files and names for the libraries' manifest files.
 
     private static ImmutableList<Pair<StringFile>> collectLibraries(
             List<? extends ManifestDependencylibraries) {
 
         ImmutableList.Builder<Pair<StringFile>> manifestFiles = ImmutableList.builder();
         if (libraries != null) {
             collectLibraries(librariesmanifestFiles);
         }
         return manifestFiles.build();
     }

    
recursively calculate the list of libraries to merge the manifests files from.

Parameters:
libraries the dependencies
manifestFiles list of files and names identifiers for the libraries' manifest files.
 
     private static void collectLibraries(List<? extends ManifestDependencylibraries,
             ImmutableList.Builder<Pair<StringFile>> manifestFiles) {
 
         for (ManifestDependency library : libraries) {
             manifestFiles.add(Pair.of(library.getName(), library.getManifest()));
             List<? extends ManifestDependencymanifestDependencies = library
                     .getManifestDependencies();
             if (!manifestDependencies.isEmpty()) {
                 collectLibraries(manifestDependenciesmanifestFiles);
             }
         }
     }

    
Merges all the manifests into a single manifest

Parameters:
mainManifest The main manifest of the application.
manifestOverlays manifest overlays coming from flavors and build types
libraries the library dependency graph
packageOverride a package name override. Can be null.
versionCode a version code to inject in the manifest or -1 to do nothing.
versionName a version name to inject in the manifest or null to do nothing.
minSdkVersion a minSdkVersion to inject in the manifest or -1 to do nothing.
targetSdkVersion a targetSdkVersion to inject in the manifest or -1 to do nothing.
outManifestLocation the output location for the merged manifest
See also:
VariantConfiguration.getMainManifest()
VariantConfiguration.getManifestOverlays()
VariantConfiguration.getDirectLibraries()
VariantConfiguration.getMergedFlavor()
DefaultProductFlavor.getVersionCode()
DefaultProductFlavor.getVersionName()
DefaultProductFlavor.getMinSdkVersion()
DefaultProductFlavor.getTargetSdkVersion()
 
     public void processManifest(
             @NonNull  File mainManifest,
             @NonNull  List<FilemanifestOverlays,
             @NonNull  List<? extends ManifestDependencylibraries,
                       String packageOverride,
                       int versionCode,
                       String versionName,
             @Nullable String minSdkVersion,
             @Nullable String targetSdkVersion,
             @NonNull  String outManifestLocation) {
         checkNotNull(mainManifest"mainManifest cannot be null.");
         checkNotNull(manifestOverlays"manifestOverlays cannot be null.");
         checkNotNull(libraries"libraries cannot be null.");
         checkNotNull(outManifestLocation"outManifestLocation cannot be null.");
         checkState( != null,
                 "Cannot call processManifest() before setTargetInfo() is called.");
 
         final IAndroidTarget target = .getTarget();
 
         ICallback callback = new ICallback() {
             @Override
             public int queryCodenameApiLevel(@NonNull String codename) {
                 if (codename.equals(target.getVersion().getCodename())) {
                     return target.getVersion().getApiLevel();
                 }
                 return .;
             }
         };
 
         try {
             Map<StringStringattributeInjection = getAttributeInjectionMap(
                     versionCodeversionNameminSdkVersiontargetSdkVersion);
 
             if (manifestOverlays.isEmpty() && libraries.isEmpty()) {
                 // if no manifest to merge, just copy to location, unless we have to inject
                 // attributes
                 if (attributeInjection.isEmpty() && packageOverride == null) {
                     SdkUtils.copyXmlWithSourceReference(mainManifest,
                             new File(outManifestLocation));
                 } else {
                     ManifestMerger merger = new ManifestMerger(MergerLog.wrapSdkLog(),
                             callback);
                     doMerge(mergernew File(outManifestLocation), mainManifest,
                             attributeInjectionpackageOverride);
                 }
             } else {
                 File outManifest = new File(outManifestLocation);
 
                 // first merge the app manifest.
                 if (!manifestOverlays.isEmpty()) {
                     File mainManifestOut = outManifest;
 
                     // if there is also libraries, put this in a temp file.
                     if (!libraries.isEmpty()) {
                         // TODO find better way of storing intermediary file?
                         mainManifestOut = File.createTempFile("manifestMerge"".xml");
                         mainManifestOut.deleteOnExit();
                     }
 
                     ManifestMerger merger = new ManifestMerger(MergerLog.wrapSdkLog(),
                             callback);
                     doMerge(mergermainManifestOutmainManifestmanifestOverlays,
                             attributeInjectionpackageOverride);
 
                     // now the main manifest is the newly merged one
                     mainManifest = mainManifestOut;
                     // and the attributes have been inject, no need to do it below
                     attributeInjection = null;
                 }
 
                 if (!libraries.isEmpty()) {
                     // recursively merge all manifests starting with the leaves and up toward the
                     // root (the app)
                     mergeLibraryManifests(mainManifestlibraries,
                             new File(outManifestLocation), attributeInjectionpackageOverride,
                             callback);
                 }
             }
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }

    
Creates the manifest for a test variant

Parameters:
testApplicationId the application id of the test application
minSdkVersion the minSdkVersion of the test application
targetSdkVersion the targetSdkVersion of the test application
testedApplicationId the application id of the tested application
instrumentationRunner the name of the instrumentation runner
handleProfiling whether or not the Instrumentation object will turn profiling on and off
functionalTest whether or not the Instrumentation class should run as a functional test
libraries the library dependency graph
outManifest the output location for the merged manifest
See also:
VariantConfiguration.getApplicationId()
VariantConfiguration.getTestedConfig()
VariantConfiguration.getMinSdkVersion()
VariantConfiguration.getTestedApplicationId()
VariantConfiguration.getInstrumentationRunner()
VariantConfiguration.getHandleProfiling()
VariantConfiguration.getFunctionalTest()
VariantConfiguration.getDirectLibraries()
 
     public void processTestManifest(
             @NonNull  String testApplicationId,
             @Nullable String minSdkVersion,
             @Nullable String targetSdkVersion,
             @NonNull  String testedApplicationId,
             @NonNull  String instrumentationRunner,
             @NonNull  Boolean handleProfiling,
             @NonNull  Boolean functionalTest,
             @NonNull  List<? extends ManifestDependencylibraries,
             @NonNull  File outManifest) {
         checkNotNull(testApplicationId"testApplicationId cannot be null.");
         checkNotNull(testedApplicationId"testedApplicationId 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(outManifest"outManifestLocation cannot be null.");
         checkState( != null,
                 "Cannot call processTestManifest() before setTargetInfo() is called.");
 
         final IAndroidTarget target = .getTarget();
 
         ICallback callback = new ICallback() {
             @Override
             public int queryCodenameApiLevel(@NonNull String codename) {
                 if (codename.equals(target.getVersion().getCodename())) {
                     return target.getVersion().getApiLevel();
                 }
                 return .;
             }
         };
 
         if (!libraries.isEmpty()) {
             try {
                 // create the test manifest, merge the libraries in it
                 File generatedTestManifest = File.createTempFile("manifestMerge"".xml");
 
                 generateTestManifest(
                         testApplicationId,
                         minSdkVersion,
                         targetSdkVersion,
                         testedApplicationId,
                         instrumentationRunner,
                         handleProfiling,
                         functionalTest,
                         generatedTestManifest);
 
                 mergeLibraryManifests(
                         generatedTestManifest,
                         libraries,
                         outManifest,
                         nullnull,
                         callback);
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
         } else {
             generateTestManifest(
                     testApplicationId,
                     minSdkVersion,
                     targetSdkVersion,
                     testedApplicationId,
                     instrumentationRunner,
                     handleProfiling,
                     functionalTest,
                     outManifest);
         }
     }

    
Creates the manifest for a test variant

Parameters:
testApplicationId the application id of the test application
minSdkVersion the minSdkVersion of the test application
targetSdkVersion the targetSdkVersion of the test application
testedApplicationId the application id of the tested application
instrumentationRunner the name of the instrumentation runner
handleProfiling whether or not the Instrumentation object will turn profiling on and off
functionalTest whether or not the Instrumentation class should run as a functional test
testManifestFile optionally user provided AndroidManifest.xml for testing application
libraries the library dependency graph
outManifest the output location for the merged manifest
See also:
VariantConfiguration.getApplicationId()
VariantConfiguration.getTestedConfig()
VariantConfiguration.getMinSdkVersion()
VariantConfiguration.getTestedApplicationId()
VariantConfiguration.getInstrumentationRunner()
VariantConfiguration.getHandleProfiling()
VariantConfiguration.getFunctionalTest()
VariantConfiguration.getDirectLibraries()
 
     public void processTestManifest2(
             @NonNull  String testApplicationId,
             @Nullable String minSdkVersion,
             @Nullable String targetSdkVersion,
             @NonNull  String testedApplicationId,
             @NonNull  String instrumentationRunner,
             @NonNull  Boolean handleProfiling,
             @NonNull  Boolean functionalTest,
             @Nullable File testManifestFile,
             @NonNull  List<? extends ManifestDependencylibraries,
             @NonNull  File outManifest,
             @NonNull  File tmpDir) {
         checkNotNull(testApplicationId"testApplicationId cannot be null.");
         checkNotNull(testedApplicationId"testedApplicationId 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(outManifest"outManifestLocation cannot be null.");
 
         try {
             tmpDir.mkdirs();
             File generatedTestManifest = libraries.isEmpty() && testManifestFile == null
                     ? outManifest : File.createTempFile("manifestMerger"".xml"tmpDir);
 
             .verbose("Generating in %1$s"generatedTestManifest.getAbsolutePath());
             generateTestManifest(
                     testApplicationId,
                     minSdkVersion,
                     targetSdkVersion.equals("-1") ? null : targetSdkVersion,
                     testedApplicationId,
                     instrumentationRunner,
                     handleProfiling,
                     functionalTest,
                     generatedTestManifest);
 
             if (testManifestFile != null) {
                 File mergedTestManifest = File.createTempFile("manifestMerger"".xml"tmpDir);
                 .verbose("Merging user supplied manifest in %1$s",
                         generatedTestManifest.getAbsolutePath());
                 Invoker invoker = ManifestMerger2.newMerger(
                         testManifestFile..)
                         .setOverride(.testApplicationId)
                         .setPlaceHolderValue(.,
                                 instrumentationRunner)
                         .addLibraryManifests(generatedTestManifest);
                 if (minSdkVersion != null) {
                     invoker.setOverride(.minSdkVersion);
                 }
                 if (!targetSdkVersion.equals("-1")) {
                     invoker.setOverride(.targetSdkVersion);
                 }
                 MergingReport mergingReport = invoker.merge();
                 if (libraries.isEmpty()) {
                     handleMergingResult(mergingReportoutManifest);
                 } else {
                     handleMergingResult(mergingReportmergedTestManifest);
                     generatedTestManifest = mergedTestManifest;
                 }
             }
 
             if (!libraries.isEmpty()) {
                 MergingReport mergingReport = ManifestMerger2.newMerger(
                         generatedTestManifest..)
                         .withFeatures(..)
                         .setOverride(.testApplicationId)
                         .addLibraryManifests(collectLibraries(libraries))
                         .merge();
 
                 handleMergingResult(mergingReportoutManifest);
             }
         } catch(Exception e) {
             throw new RuntimeException(e);
         }
     }
 
     private void handleMergingResult(@NonNull MergingReport mergingReport, @NonNull File outFile) {
         switch (mergingReport.getResult()) {
             case :
                 mergingReport.log();
                 // fall through since these are just warnings.
             case :
                 XmlDocument xmlDocument = mergingReport.getMergedDocument().get();
                 try {
                     String annotatedDocument = mergingReport.getActions().blame(xmlDocument);
                     .verbose(annotatedDocument);
                 } catch (Exception e) {
                     .error(e"cannot print resulting xml");
                 }
                 save(xmlDocumentoutFile);
                 .info("Merged manifest saved to " + outFile);
                 break;
             case :
                 mergingReport.log();
                 throw new RuntimeException(mergingReport.getReportString());
             default:
                 throw new RuntimeException("Unhandled result type : "
                         + mergingReport.getResult());
         }
     }
 
     private static void generateTestManifest(
             @NonNull String testApplicationId,
             @Nullable String minSdkVersion,
             @Nullable String targetSdkVersion,
             @NonNull String testedApplicationId,
             @NonNull String instrumentationRunner,
             @NonNull Boolean handleProfiling,
             @NonNull Boolean functionalTest,
             @NonNull File outManifestLocation) {
         TestManifestGenerator generator = new TestManifestGenerator(
                 outManifestLocation,
                 testApplicationId,
                 minSdkVersion,
                 targetSdkVersion,
                 testedApplicationId,
                 instrumentationRunner,
                 handleProfiling,
                 functionalTest);
         try {
             generator.generate();
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 
     @NonNull
     private static Map<StringStringgetAttributeInjectionMap(
                       int versionCode,
             @Nullable String versionName,
             @Nullable String minSdkVersion,
             @Nullable String targetSdkVersion) {
 
         Map<StringStringattributeInjection = Maps.newHashMap();
 
         if (versionCode != -1) {
             attributeInjection.put(
                     "/manifest|http://schemas.android.com/apk/res/android versionCode",
                     Integer.toString(versionCode));
         }
 
         if (versionName != null) {
             attributeInjection.put(
                     "/manifest|http://schemas.android.com/apk/res/android versionName",
                     versionName);
         }
 
         if (minSdkVersion != null) {
             attributeInjection.put(
                     "/manifest/uses-sdk|http://schemas.android.com/apk/res/android minSdkVersion",
                     minSdkVersion);
         }
 
         if (targetSdkVersion != null) {
             attributeInjection.put(
                     "/manifest/uses-sdk|http://schemas.android.com/apk/res/android targetSdkVersion",
                     targetSdkVersion);
         }
         return attributeInjection;
     }

    
Merges library manifests into a main manifest.

Parameters:
mainManifest the main manifest
directLibraries the libraries to merge
outManifest the output file
Throws:
java.io.IOException
 
     private void mergeLibraryManifests(
             File mainManifest,
             Iterable<? extends ManifestDependencydirectLibraries,
             File outManifestMap<StringStringattributeInjection,
             String packageOverride,
             @NonNull ICallback callback)
             throws IOException {
 
         List<Filemanifests = Lists.newArrayList();
         for (ManifestDependency library : directLibraries) {
             Collection<? extends ManifestDependencysubLibraries = library.getManifestDependencies();
             if (subLibraries.isEmpty()) {
                 manifests.add(library.getManifest());
             } else {
                 File mergeLibManifest = File.createTempFile("manifestMerge"".xml");
                 mergeLibManifest.deleteOnExit();
 
                 // don't insert the attribute injection into libraries
                 mergeLibraryManifests(
                         library.getManifest(), subLibrariesmergeLibManifestnullnullcallback);
 
                 manifests.add(mergeLibManifest);
             }
         }
 
         ManifestMerger merger = new ManifestMerger(MergerLog.wrapSdkLog(), callback);
         doMerge(mergeroutManifestmainManifestmanifestsattributeInjectionpackageOverride);
     }
 
     private void doMerge(ManifestMerger mergerFile outputFile input,
                                Map<StringStringinjectionMapString packageOverride) {
         List<Filelist = Collections.emptyList();
         doMerge(mergeroutputinputlistinjectionMappackageOverride);
     }
 
     private void doMerge(ManifestMerger mergerFile outputFile inputList<FilesubManifests,
                                Map<StringStringinjectionMapString packageOverride) {
         if (!merger.process(outputinput,
                 subManifests.toArray(new File[subManifests.size()]),
                 injectionMappackageOverride)) {
             throw new RuntimeException("Manifest merging failed. See console for more info.");
         }
     }

    
Process the resources and generate R.java and/or the packaged resources.

Parameters:
manifestFile the location of the manifest file
resFolder the merged res folder
assetsDir the merged asset folder
libraries the flat list of libraries
packageForR Package override to generate the R class in a different package.
sourceOutputDir optional source folder to generate R.java
resPackageOutput optional filepath for packaged resources
proguardOutput optional filepath for proguard file to generate
type the type of the variant being built
debuggable whether the app is debuggable
options the com.android.builder.model.AaptOptions
resourceConfigs a list of resource config filters to pass to aapt.
enforceUniquePackageName if true method will fail if some libraries share the same package name
Throws:
java.io.IOException
java.lang.InterruptedException
com.android.ide.common.internal.LoggedErrorException
 
     public void processResources(
             @NonNull  File manifestFile,
             @NonNull  File resFolder,
             @Nullable File assetsDir,
             @Nullable  List<? extends SymbolFileProviderlibraries,
             @Nullable String packageForR,
             @Nullable String sourceOutputDir,
             @Nullable String symbolOutputDir,
             @Nullable String resPackageOutput,
             @Nullable String proguardOutput,
                       VariantConfiguration.Type type,
                       boolean debuggable,
             @NonNull  AaptOptions options,
             @NonNull  Collection<StringresourceConfigs,
                       boolean enforceUniquePackageName)
             throws IOExceptionInterruptedExceptionLoggedErrorException {
 
         checkNotNull(manifestFile"manifestFile cannot be null.");
        checkNotNull(resFolder"resFolder cannot be null.");
        checkNotNull(options"options cannot be null.");
        // if both output types are empty, then there's nothing to do and this is an error
        checkArgument(sourceOutputDir != null || resPackageOutput != null,
                "No output provided for aapt task");
        checkState( != null,
                "Cannot call processResources() before setTargetInfo() is called.");
        if (symbolOutputDir != null || sourceOutputDir != null) {
            checkNotNull(libraries"libraries cannot be null if symbolOutputDir or sourceOutputDir is non-null");
        }
        BuildToolInfo buildToolInfo = .getBuildTools();
        IAndroidTarget target = .getTarget();
        // launch aapt: create the command line
        ArrayList<Stringcommand = Lists.newArrayList();
        String aapt = buildToolInfo.getPath(..);
        if (aapt == null || !new File(aapt).isFile()) {
            throw new IllegalStateException("aapt is missing");
        }
        command.add(aapt);
        command.add("package");
        if () {
            command.add("-v");
        }
        command.add("-f");
        command.add("--no-crunch");
        // inputs
        command.add("-I");
        command.add(target.getPath(.));
        command.add("-M");
        command.add(manifestFile.getAbsolutePath());
        if (resFolder.isDirectory()) {
            command.add("-S");
            command.add(resFolder.getAbsolutePath());
        }
        if (assetsDir != null && assetsDir.isDirectory()) {
            command.add("-A");
            command.add(assetsDir.getAbsolutePath());
        }
        // outputs
        if (sourceOutputDir != null) {
            command.add("-m");
            command.add("-J");
            command.add(sourceOutputDir);
        }
        if (resPackageOutput != null) {
            command.add("-F");
            command.add(resPackageOutput);
        }
        if (proguardOutput != null) {
            command.add("-G");
            command.add(proguardOutput);
        }
        // options controlled by build variants
        if (debuggable) {
            command.add("--debug-mode");
        }
        if (type != ..) {
            if (packageForR != null) {
                command.add("--custom-package");
                command.add(packageForR);
                .verbose("Custom package for R class: '%s'"packageForR);
            }
        }
        // library specific options
        if (type == ..) {
            command.add("--non-constant-id");
        }
        // AAPT options
        String ignoreAssets = options.getIgnoreAssets();
        if (ignoreAssets != null) {
            command.add("--ignore-assets");
            command.add(ignoreAssets);
        }
        if (options.getFailOnMissingConfigEntry()) {
            if (buildToolInfo.getRevision().getMajor() > 20) {
                command.add("--error-on-missing-config-entry");
            } else {
                throw new IllegalStateException("aaptOptions:failOnMissingConfigEntry cannot be used"
                        + " with SDK Build Tools revision earlier than 21.0.0");
            }
        }
        // never compress apks.
        command.add("-0");
        command.add("apk");
        // add custom no-compress extensions
        Collection<StringnoCompressList = options.getNoCompress();
        if (noCompressList != null) {
            for (String noCompress : noCompressList) {
                command.add("-0");
                command.add(noCompress);
            }
        }
        if (!resourceConfigs.isEmpty()) {
            command.add("-c");
            Joiner joiner = Joiner.on(',');
            command.add(joiner.join(resourceConfigs));
        }
        if (symbolOutputDir != null &&
                (type == .. || !libraries.isEmpty())) {
            command.add("--output-text-symbols");
            command.add(symbolOutputDir);
        }
        .runCmdLine(commandnull);
        // now if the project has libraries, R needs to be created for each libraries,
        // but only if the current project is not a library.
        if (sourceOutputDir != null && type != .. && !libraries.isEmpty()) {
            SymbolLoader fullSymbolValues = null;
            // First pass processing the libraries, collecting them by packageName,
            // and ignoring the ones that have the same package name as the application
            // (since that R class was already created).
            String appPackageName = packageForR;
            if (appPackageName == null) {
                appPackageName = VariantConfiguration.getManifestPackage(manifestFile);
            }
            // list of all the symbol loaders per package names.
            Multimap<StringSymbolLoaderlibMap = ArrayListMultimap.create();
            for (SymbolFileProvider lib : libraries) {
                String packageName = VariantConfiguration.getManifestPackage(lib.getManifest());
                if (appPackageName == null) {
                    continue;
                }
                if (appPackageName.equals(packageName)) {
                    if (enforceUniquePackageName) {
                        String msg = String.format(
                                "Error: A library uses the same package as this project: %s\n" +
                                        "You can temporarily disable this error with android.enforceUniquePackageName=false\n" +
                                        "However, this is temporary and will be enforced in 1.0",
                                packageName);
                        throw new RuntimeException(msg);
                    }
                    // ignore libraries that have the same package name as the app
                    continue;
                }
                File rFile = lib.getSymbolFile();
                // if the library has no resource, this file won't exist.
                if (rFile.isFile()) {
                    // load the full values if that's not already been done.
                    // Doing it lazily allow us to support the case where there's no
                    // resources anywhere.
                    if (fullSymbolValues == null) {
                        fullSymbolValues = new SymbolLoader(new File(symbolOutputDir"R.txt"),
                                );
                        fullSymbolValues.load();
                    }
                    SymbolLoader libSymbols = new SymbolLoader(rFile);
                    libSymbols.load();
                    // store these symbols by associating them with the package name.
                    libMap.put(packageNamelibSymbols);
                }
            }
            // now loop on all the package name, merge all the symbols to write, and write them
            for (String packageName : libMap.keySet()) {
                Collection<SymbolLoadersymbols = libMap.get(packageName);
                if (enforceUniquePackageName && symbols.size() > 1) {
                    String msg = String.format(
                            "Error: more than one library with package name '%s'\n" +
                            "You can temporarily disable this error with android.enforceUniquePackageName=false\n" +
                            "However, this is temporary and will be enforced in 1.0"packageName);
                    throw new RuntimeException(msg);
                }
                SymbolWriter writer = new SymbolWriter(sourceOutputDirpackageName,
                        fullSymbolValues);
                for (SymbolLoader symbolLoader : symbols) {
                    writer.addSymbolsToWrite(symbolLoader);
                }
                writer.write();
            }
        }
    }
    public void generateApkData(@