4cfebca47f98585005e23c1e7a1680e455b5ff7b
[android/platform/tools/build.git] / builder / src / main / java / com / android / builder / VariantConfiguration.java
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.builder;
18
19 import com.android.annotations.NonNull;
20 import com.android.annotations.Nullable;
21 import com.android.annotations.VisibleForTesting;
22 import com.android.builder.resources.AssetSet;
23 import com.android.builder.resources.ResourceSet;
24 import com.android.builder.signing.SigningConfig;
25 import com.google.common.collect.Lists;
26 import com.google.common.collect.Sets;
27
28 import java.io.File;
29 import java.util.Collection;
30 import java.util.List;
31 import java.util.Set;
32
33 import static com.google.common.base.Preconditions.checkNotNull;
34 import static com.google.common.base.Preconditions.checkState;
35
36 /**
37  * A Variant configuration.
38  */
39 public class VariantConfiguration {
40
41     private static final ManifestParser sManifestParser = new DefaultManifestParser();
42
43     private final ProductFlavor mDefaultConfig;
44     private final SourceProvider mDefaultSourceProvider;
45
46     private final BuildType mBuildType;
47     /** SourceProvider for the BuildType. Can be null */
48     private final SourceProvider mBuildTypeSourceProvider;
49
50     private final List<ProductFlavor> mFlavorConfigs = Lists.newArrayList();
51     private final List<SourceProvider> mFlavorSourceProviders = Lists.newArrayList();
52
53     private final Type mType;
54     /** Optional tested config in case type is Type#TEST */
55     private final VariantConfiguration mTestedConfig;
56     /** An optional output that is only valid if the type is Type#LIBRARY so that the test
57      * for the library can use the library as if it was a normal dependency. */
58     private AndroidDependency mOutput;
59
60     private ProductFlavor mMergedFlavor;
61
62     private final Set<JarDependency> mJars = Sets.newHashSet();
63
64     /** List of direct library dependencies. Each object defines its own dependencies. */
65     private final List<AndroidDependency> mDirectLibraries = Lists.newArrayList();
66
67     /** list of all library dependencies in a flat list.
68      * The order is based on the order needed to call aapt: earlier libraries override resources
69      * of latter ones. */
70     private final List<AndroidDependency> mFlatLibraries = Lists.newArrayList();
71
72     public static enum Type {
73         DEFAULT, LIBRARY, TEST
74     }
75
76     /**
77      * Parses the manifest file and return the package name.
78      * @param manifestFile the manifest file
79      * @return the package name found or null
80      */
81     @Nullable
82     public static String getManifestPackage(@NonNull File manifestFile) {
83         return sManifestParser.getPackage(manifestFile);
84     }
85
86     /**
87      * Creates the configuration with the base source sets.
88      *
89      * This creates a config with a {@link Type#DEFAULT} type.
90      *
91      * @param defaultConfig the default configuration. Required.
92      * @param defaultSourceProvider the default source provider. Required
93      * @param buildType the build type for this variant. Required.
94      * @param buildTypeSourceProvider the source provider for the build type. Required.
95      */
96     public VariantConfiguration(
97             @NonNull ProductFlavor defaultConfig, @NonNull SourceProvider defaultSourceProvider,
98             @NonNull BuildType buildType, @NonNull SourceProvider buildTypeSourceProvider) {
99         this(defaultConfig, defaultSourceProvider,
100                 buildType, buildTypeSourceProvider,
101                 Type.DEFAULT, null /*testedConfig*/);
102     }
103
104     /**
105      * Creates the configuration with the base source sets for a given {@link Type}.
106      *
107      * @param defaultConfig the default configuration. Required.
108      * @param defaultSourceProvider the default source provider. Required
109      * @param buildType the build type for this variant. Required.
110      * @param buildTypeSourceProvider the source provider for the build type. Required.
111      * @param type the type of the project.
112      */
113     public VariantConfiguration(
114             @NonNull ProductFlavor defaultConfig, @NonNull SourceProvider defaultSourceProvider,
115             @NonNull BuildType buildType, @NonNull SourceProvider buildTypeSourceProvider,
116             @NonNull Type type) {
117         this(defaultConfig, defaultSourceProvider,
118                 buildType, buildTypeSourceProvider,
119                 type, null /*testedConfig*/);
120     }
121
122     /**
123      * Creates the configuration with the base source sets, and an optional tested variant.
124      *
125      * @param defaultConfig the default configuration. Required.
126      * @param defaultSourceProvider the default source provider. Required
127      * @param buildType the build type for this variant. Required.
128      * @param buildTypeSourceProvider the source provider for the build type. Required.
129      * @param type the type of the project.
130      * @param testedConfig the reference to the tested project. Required if type is Type.TEST
131      */
132     public VariantConfiguration(
133             @NonNull ProductFlavor defaultConfig, @NonNull SourceProvider defaultSourceProvider,
134             @NonNull BuildType buildType, SourceProvider buildTypeSourceProvider,
135             @NonNull Type type, @Nullable VariantConfiguration testedConfig) {
136         mDefaultConfig = checkNotNull(defaultConfig);
137         mDefaultSourceProvider = checkNotNull(defaultSourceProvider);
138         mBuildType = checkNotNull(buildType);
139         mBuildTypeSourceProvider = buildTypeSourceProvider;
140         mType = checkNotNull(type);
141         mTestedConfig = testedConfig;
142         checkState(mType != Type.TEST || mTestedConfig != null);
143
144         mMergedFlavor = mDefaultConfig;
145
146         if (testedConfig != null &&
147                 testedConfig.mType == Type.LIBRARY &&
148                 testedConfig.mOutput != null) {
149             mDirectLibraries.add(testedConfig.mOutput);
150         }
151
152         validate();
153     }
154
155     /**
156      * Add a new configured ProductFlavor.
157      *
158      * If multiple flavors are added, the priority follows the order they are added when it
159      * comes to resolving Android resources overlays (ie earlier added flavors supersedes
160      * latter added ones).
161      *
162      * @param sourceProvider the configured product flavor
163      * @return the config object
164      */
165     public VariantConfiguration addProductFlavor(@NonNull ProductFlavor productFlavor,
166                                                  @NonNull SourceProvider sourceProvider) {
167         mFlavorConfigs.add(productFlavor);
168         mFlavorSourceProviders.add(sourceProvider);
169         mMergedFlavor = productFlavor.mergeOver(mMergedFlavor);
170
171         return this;
172     }
173
174     /**
175      * Sets the library dependencies.
176      *
177      * @param jars list of jar dependency. This should include the jar dependencies of Android
178      *             projects.
179      * @return the config object
180      */
181     public VariantConfiguration setJarDependencies(List<JarDependency> jars) {
182         mJars.addAll(jars);
183         return this;
184     }
185
186     /**
187      * Returns the list of jar dependencies
188      * @return a non null collection of Jar dependencies.
189      */
190     public Collection<JarDependency> getJars() {
191         return mJars;
192     }
193
194     /**
195      * Set the Library Project dependencies.
196      * @param directLibraries list of direct dependencies. Each library object should contain
197      *            its own dependencies. This is actually a dependency graph.
198      * @return the config object
199      */
200     public VariantConfiguration setAndroidDependencies(
201             @NonNull List<AndroidDependency> directLibraries) {
202         if (directLibraries != null) {
203             mDirectLibraries.addAll(directLibraries);
204         }
205
206         resolveIndirectLibraryDependencies(mDirectLibraries, mFlatLibraries);
207
208         return this;
209     }
210
211     /**
212      * Sets the output of this variant. This is required when the variant is a library so that
213      * the variant that tests this library can properly include the tested library in its own
214      * package.
215      *
216      * @param output the output of the library as an AndroidDependency that will provides the
217      *               location of all the created items.
218      * @return the config object
219      */
220     public VariantConfiguration setOutput(AndroidDependency output) {
221         mOutput = output;
222         return this;
223     }
224
225     public ProductFlavor getDefaultConfig() {
226         return mDefaultConfig;
227     }
228
229     public SourceProvider getDefaultSourceSet() {
230         return mDefaultSourceProvider;
231     }
232
233     public ProductFlavor getMergedFlavor() {
234         return mMergedFlavor;
235     }
236
237     public BuildType getBuildType() {
238         return mBuildType;
239     }
240
241     /**
242      * The SourceProvider for the BuildType. Can be null.
243      */
244     public SourceProvider getBuildTypeSourceSet() {
245         return mBuildTypeSourceProvider;
246     }
247
248     public boolean hasFlavors() {
249         return !mFlavorConfigs.isEmpty();
250     }
251
252     public List<ProductFlavor> getFlavorConfigs() {
253         return mFlavorConfigs;
254     }
255
256     public Iterable<SourceProvider> getFlavorSourceSets() {
257         return mFlavorSourceProviders;
258     }
259
260     public boolean hasLibraries() {
261         return !mDirectLibraries.isEmpty();
262     }
263
264     /**
265      * Returns the direct library dependencies
266      */
267     @NonNull
268     public List<AndroidDependency> getDirectLibraries() {
269         return mDirectLibraries;
270     }
271
272     /**
273      * Returns all the library dependencies, direct and transitive.
274      */
275     @NonNull
276     public List<AndroidDependency> getAllLibraries() {
277         return mFlatLibraries;
278     }
279
280     public List<File> getPackagedJars() {
281         List<File> jars = Lists.newArrayListWithCapacity(mJars.size() + mFlatLibraries.size());
282
283         for (JarDependency jar : mJars) {
284             File jarFile = new File(jar.getLocation());
285             if (jarFile.exists()) {
286                 jars.add(jarFile);
287             }
288         }
289
290         for (AndroidDependency androidDependency : mFlatLibraries) {
291             File libJar = androidDependency.getJarFile();
292             if (libJar.exists()) {
293                 jars.add(libJar);
294             }
295         }
296
297         return jars;
298     }
299
300     public Type getType() {
301         return mType;
302     }
303
304     public VariantConfiguration getTestedConfig() {
305         return mTestedConfig;
306     }
307
308     /**
309      * Resolves a given list of libraries, finds out if they depend on other libraries, and
310      * returns a flat list of all the direct and indirect dependencies in the proper order (first
311      * is higher priority when calling aapt).
312      * @param directDependencies the libraries to resolve
313      * @param outFlatDependencies where to store all the libraries.
314      */
315     @VisibleForTesting
316     void resolveIndirectLibraryDependencies(List<AndroidDependency> directDependencies,
317                                             List<AndroidDependency> outFlatDependencies) {
318         if (directDependencies == null) {
319             return;
320         }
321         // loop in the inverse order to resolve dependencies on the libraries, so that if a library
322         // is required by two higher level libraries it can be inserted in the correct place
323         for (int i = directDependencies.size() - 1  ; i >= 0 ; i--) {
324             AndroidDependency library = directDependencies.get(i);
325
326             // get its libraries
327             List<AndroidDependency> dependencies = library.getDependencies();
328
329             // resolve the dependencies for those libraries
330             resolveIndirectLibraryDependencies(dependencies, outFlatDependencies);
331
332             // and add the current one (if needed) in front (higher priority)
333             if (!outFlatDependencies.contains(library)) {
334                 outFlatDependencies.add(0, library);
335             }
336         }
337     }
338
339     /**
340      * Returns the original package name before any overrides from flavors.
341      * If the variant is a test variant, then the package name is the one coming from the
342      * configuration of the tested variant, and this call is similar to #getPackageName()
343      * @return the package name
344      */
345     public String getOriginalPackageName() {
346         if (mType == VariantConfiguration.Type.TEST) {
347             return getPackageName();
348         }
349
350         return getPackageFromManifest();
351     }
352
353     /**
354      * Returns the package name for this variant. This could be coming from the manifest or
355      * could be overridden through the product flavors.
356      * @return the package
357      */
358     public String getPackageName() {
359         String packageName;
360
361         if (mType == Type.TEST) {
362             packageName = mMergedFlavor.getTestPackageName();
363             if (packageName == null) {
364                 String testedPackage = mTestedConfig.getPackageName();
365
366                 packageName = testedPackage + ".test";
367             }
368         } else {
369             packageName = getPackageOverride();
370             if (packageName == null) {
371                 packageName = getPackageFromManifest();
372             }
373         }
374
375         return packageName;
376     }
377
378     public String getTestedPackageName() {
379         if (mType == Type.TEST) {
380             if (mTestedConfig.mType == Type.LIBRARY) {
381                 return getPackageName();
382             } else {
383                 return mTestedConfig.getPackageName();
384             }
385         }
386
387         return null;
388     }
389
390     /**
391      * Returns the package override values coming from the Product Flavor. If the package is not
392      * overridden then this returns null.
393      * @return the package override or null
394      */
395     public String getPackageOverride() {
396         String packageName = mMergedFlavor.getPackageName();
397         String packageSuffix = mBuildType.getPackageNameSuffix();
398
399         if (packageSuffix != null && packageSuffix.length() > 0) {
400             if (packageName == null) {
401                 packageName = getPackageFromManifest();
402             }
403
404             if (packageSuffix.charAt(0) == '.') {
405                 packageName = packageName + packageSuffix;
406             } else {
407                 packageName = packageName + '.' + packageSuffix;
408             }
409         }
410
411         return packageName;
412     }
413
414     /**
415      * Returns the version name for this variant. This could be coming from the manifest or
416      * could be overridden through the product flavors, and can have a suffix specified by
417      * the build type.
418      *
419      * @return the version name
420      */
421     public String getVersionName() {
422         String versionName = mMergedFlavor.getVersionName();
423         String versionSuffix = mBuildType.getVersionNameSuffix();
424
425         if (versionSuffix != null && versionSuffix.length() > 0) {
426             if (versionName == null) {
427                 versionName = getVersionNameFromManifest();
428             }
429
430             versionName = versionName + versionSuffix;
431         }
432
433         return versionName;
434     }
435
436     private final static String DEFAULT_TEST_RUNNER = "android.test.InstrumentationTestRunner";
437
438     /**
439      * Returns the instrumentionRunner to use to test this variant, or if the
440      * variant is a test, the one to use to test the tested variant.
441      * @return the instrumentation test runner name
442      */
443     public String getInstrumentationRunner() {
444         VariantConfiguration config = this;
445         if (mType == Type.TEST) {
446             config = getTestedConfig();
447         }
448         String runner = config.mMergedFlavor.getTestInstrumentationRunner();
449         return runner != null ? runner : DEFAULT_TEST_RUNNER;
450     }
451
452     /**
453      * Reads the package name from the manifest.
454      */
455     public String getPackageFromManifest() {
456         File manifestLocation = mDefaultSourceProvider.getManifestFile();
457         return sManifestParser.getPackage(manifestLocation);
458     }
459
460     /**
461      * Reads the version name from the manifest.
462      */
463     public String getVersionNameFromManifest() {
464         File manifestLocation = mDefaultSourceProvider.getManifestFile();
465         return sManifestParser.getVersionName(manifestLocation);
466     }
467
468     /**
469      * Return the minSdkVersion for this variant.
470      *
471      * This uses both the value from the manifest (if present), and the override coming
472      * from the flavor(s) (if present).
473      * @return the minSdkVersion
474      */
475     public int getMinSdkVersion() {
476         if (mTestedConfig != null) {
477             return mTestedConfig.getMinSdkVersion();
478         }
479         int minSdkVersion = mMergedFlavor.getMinSdkVersion();
480         if (minSdkVersion == -1) {
481             // read it from the main manifest
482             File manifestLocation = mDefaultSourceProvider.getManifestFile();
483             minSdkVersion = sManifestParser.getMinSdkVersion(manifestLocation);
484         }
485
486         return minSdkVersion;
487     }
488
489     public File getMainManifest() {
490         File defaultManifest = mDefaultSourceProvider.getManifestFile();
491
492         // this could not exist in a test project.
493         if (defaultManifest != null && defaultManifest.isFile()) {
494             return defaultManifest;
495         }
496
497         return null;
498     }
499
500     @NonNull
501     public List<File> getManifestOverlays() {
502         List<File> inputs = Lists.newArrayList();
503
504         if (mBuildTypeSourceProvider != null) {
505             File typeLocation = mBuildTypeSourceProvider.getManifestFile();
506             if (typeLocation != null && typeLocation.isFile()) {
507                 inputs.add(typeLocation);
508             }
509         }
510
511         for (SourceProvider sourceProvider : mFlavorSourceProviders) {
512             File f = sourceProvider.getManifestFile();
513             if (f != null && f.isFile()) {
514                 inputs.add(f);
515             }
516         }
517
518         return inputs;
519     }
520
521     /**
522      * Returns the dynamic list of {@link ResourceSet} based on the configuration, its dependencies,
523      * as well as tested config if applicable (test of a library).
524      *
525      * The list is ordered in ascending order of importance, meaning the first set is meant to be
526      * overridden by the 2nd one and so on. This is meant to facilitate usage of the list in a
527      * {@link com.android.builder.resources.ResourceMerger}.
528      *
529      * @return a list ResourceSet.
530      */
531     @NonNull public List<ResourceSet> getResourceSets(@Nullable File generatedResFolder) {
532         List<ResourceSet> resourceSets = Lists.newArrayList();
533
534         // the list of dependency must be reversed to use the right overlay order.
535         for (int n = mFlatLibraries.size() - 1 ; n >= 0 ; n--) {
536             AndroidDependency dependency = mFlatLibraries.get(n);
537             File resFolder = dependency.getResFolder();
538             if (resFolder != null) {
539                 ResourceSet resourceSet = new ResourceSet(dependency.getFolder().getName());
540                 resourceSet.addSource(resFolder);
541                 resourceSets.add(resourceSet);
542             }
543         }
544
545         Set<File> mainResDirs = mDefaultSourceProvider.getResourcesDirectories();
546
547         ResourceSet resourceSet = new ResourceSet(ProductFlavor.MAIN);
548         resourceSet.addSources(mainResDirs);
549         if (generatedResFolder != null) {
550             resourceSet.addSource(generatedResFolder);
551         }
552         resourceSets.add(resourceSet);
553
554         // the list of flavor must be reversed to use the right overlay order.
555         for (int n = mFlavorSourceProviders.size() - 1; n >= 0 ; n--) {
556             SourceProvider sourceProvider = mFlavorSourceProviders.get(n);
557
558             Set<File> flavorResDirs = sourceProvider.getResourcesDirectories();
559             // we need the same of the flavor config, but it's in a different list.
560             // This is fine as both list are parallel collections with the same number of items.
561             resourceSet = new ResourceSet(mFlavorConfigs.get(n).getName());
562             resourceSet.addSources(flavorResDirs);
563             resourceSets.add(resourceSet);
564         }
565
566         if (mBuildTypeSourceProvider != null) {
567             Set<File> typeResDirs = mBuildTypeSourceProvider.getResourcesDirectories();
568             resourceSet = new ResourceSet(mBuildType.getName());
569             resourceSet.addSources(typeResDirs);
570             resourceSets.add(resourceSet);
571         }
572
573         return resourceSets;
574     }
575
576     /**
577      * Returns the dynamic list of {@link AssetSet} based on the configuration, its dependencies,
578      * as well as tested config if applicable (test of a library).
579      *
580      * The list is ordered in ascending order of importance, meaning the first set is meant to be
581      * overridden by the 2nd one and so on. This is meant to facilitate usage of the list in a
582      * {@link com.android.builder.resources.ResourceMerger}.
583      *
584      * @return a list ResourceSet.
585      */
586     @NonNull public List<AssetSet> getAssetSets() {
587         List<AssetSet> assetSets = Lists.newArrayList();
588
589         // the list of dependency must be reversed to use the right overlay order.
590         for (int n = mFlatLibraries.size() - 1 ; n >= 0 ; n--) {
591             AndroidDependency dependency = mFlatLibraries.get(n);
592             File assetFolder = dependency.getAssetsFolder();
593             if (assetFolder != null) {
594                 AssetSet assetSet = new AssetSet(dependency.getFolder().getName());
595                 assetSet.addSource(assetFolder);
596                 assetSets.add(assetSet);
597             }
598         }
599
600         Set<File> mainResDirs = mDefaultSourceProvider.getAssetsDirectories();
601
602         AssetSet assetSet = new AssetSet(ProductFlavor.MAIN);
603         assetSet.addSources(mainResDirs);
604         assetSets.add(assetSet);
605
606         // the list of flavor must be reversed to use the right overlay order.
607         for (int n = mFlavorSourceProviders.size() - 1; n >= 0 ; n--) {
608             SourceProvider sourceProvider = mFlavorSourceProviders.get(n);
609
610             Set<File> flavorResDirs = sourceProvider.getAssetsDirectories();
611             // we need the same of the flavor config, but it's in a different list.
612             // This is fine as both list are parallel collections with the same number of items.
613             assetSet = new AssetSet(mFlavorConfigs.get(n).getName());
614             assetSet.addSources(flavorResDirs);
615             assetSets.add(assetSet);
616         }
617
618         if (mBuildTypeSourceProvider != null) {
619             Set<File> typeResDirs = mBuildTypeSourceProvider.getAssetsDirectories();
620             assetSet = new AssetSet(mBuildType.getName());
621             assetSet.addSources(typeResDirs);
622             assetSets.add(assetSet);
623         }
624
625         return assetSets;
626     }
627
628     /**
629      * Returns all the renderscript import folder that are outside of the current project.
630      */
631     @NonNull
632     public List<File> getRenderscriptImports() {
633         List<File> list = Lists.newArrayList();
634
635         for (AndroidDependency lib : mFlatLibraries) {
636             File rsLib = lib.getRenderscriptFolder();
637             if (rsLib != null && rsLib.isDirectory()) {
638                 list.add(rsLib);
639             }
640         }
641
642         return list;
643     }
644
645     /**
646      * Returns all the renderscript source folder from the main config, the flavors and the
647      * build type.
648      *
649      * @return a list of folders.
650      */
651     @NonNull
652     public List<File> getRenderscriptSourceList() {
653         List<File> sourceList = Lists.newArrayList();
654         sourceList.addAll(mDefaultSourceProvider.getRenderscriptDirectories());
655         if (mType != Type.TEST) {
656             sourceList.addAll(mBuildTypeSourceProvider.getRenderscriptDirectories());
657         }
658
659         if (hasFlavors()) {
660             for (SourceProvider flavorSourceSet : mFlavorSourceProviders) {
661                 sourceList.addAll(flavorSourceSet.getRenderscriptDirectories());
662             }
663         }
664
665         return sourceList;
666     }
667
668     /**
669      * Returns all the aidl import folder that are outside of the current project.
670      */
671     @NonNull
672     public List<File> getAidlImports() {
673         List<File> list = Lists.newArrayList();
674
675         for (AndroidDependency lib : mFlatLibraries) {
676             File aidlLib = lib.getAidlFolder();
677             if (aidlLib != null && aidlLib.isDirectory()) {
678                 list.add(aidlLib);
679             }
680         }
681
682         return list;
683     }
684
685     @NonNull
686     public List<File> getAidlSourceList() {
687         List<File> sourceList = Lists.newArrayList();
688         sourceList.addAll(mDefaultSourceProvider.getAidlDirectories());
689         if (mType != Type.TEST) {
690             sourceList.addAll(mBuildTypeSourceProvider.getAidlDirectories());
691         }
692
693         if (hasFlavors()) {
694             for (SourceProvider flavorSourceSet : mFlavorSourceProviders) {
695                 sourceList.addAll(flavorSourceSet.getAidlDirectories());
696             }
697         }
698
699         return sourceList;
700     }
701
702     /**
703      * Returns the compile classpath for this config. If the config tests a library, this
704      * will include the classpath of the tested config
705      */
706     public Set<File> getCompileClasspath() {
707         Set<File> classpath = Sets.newHashSet();
708
709         for (AndroidDependency lib : mFlatLibraries) {
710             classpath.add(lib.getJarFile());
711         }
712
713         for (JarDependency jar : mJars) {
714             classpath.add(new File(jar.getLocation()));
715         }
716
717         return classpath;
718     }
719
720     public List<String> getBuildConfigLines() {
721         List<String> fullList = Lists.newArrayList();
722
723         List<String> list = mDefaultConfig.getBuildConfig();
724         if (!list.isEmpty()) {
725             fullList.add("// lines from default config.");
726             fullList.addAll(list);
727         }
728
729         list = mBuildType.getBuildConfig();
730         if (!list.isEmpty()) {
731             fullList.add("// lines from build type: " + mBuildType.getName());
732             fullList.addAll(list);
733         }
734
735         for (ProductFlavor flavor : mFlavorConfigs) {
736             list = flavor.getBuildConfig();
737             if (!list.isEmpty()) {
738                 fullList.add("// lines from product flavor: " + flavor.getName());
739                 fullList.addAll(list);
740             }
741         }
742
743         return fullList;
744     }
745
746     public SigningConfig getSigningConfig() {
747         SigningConfig signingConfig = mBuildType.getSigningConfig();
748         if (signingConfig != null) {
749             return signingConfig;
750         }
751         return mMergedFlavor.getSigningConfig();
752     }
753
754     public boolean isSigningReady() {
755         SigningConfig signingConfig = getSigningConfig();
756         return signingConfig != null && signingConfig.isSigningReady();
757     }
758
759     protected void validate() {
760         if (mType != Type.TEST) {
761             File manifest = mDefaultSourceProvider.getManifestFile();
762             if (!manifest.isFile()) {
763                 throw new IllegalArgumentException(
764                         "Main Manifest missing from " + manifest.getAbsolutePath());
765             }
766         }
767     }
768 }