in src/com/facebook/buck/android/AndroidBinaryResourcesGraphEnhancer.java [193:415]
AndroidBinaryResourcesGraphEnhancementResult enhance(
AndroidPackageableCollection packageableCollection) {
boolean needsToFilterForLocales = !locales.isEmpty();
// If we're using aapt2 locale filtering, then we do filtering later when we invoke aapt2,
// so we can skip creating the resource filter tree.
if (useAapt2LocaleFiltering) {
if (aaptMode != AaptMode.AAPT2) {
throw new HumanReadableException(
"use_aapt2_locale_filtering=True is incompatible with aapt_mode=" + aaptMode);
}
needsToFilterForLocales = false;
}
boolean needsResourceFiltering =
resourceFilter.isEnabled()
|| postFilterResourcesCmd.isPresent()
|| resourceCompressionMode.isStoreStringsAsAssets()
|| needsToFilterForLocales;
int packageIdOffset = 0;
ImmutableSet.Builder<SourcePath> pathToRDotTxtFiles = ImmutableSet.builder();
ImmutableMap.Builder<APKModule, FilteredResourcesProvider> filteredResourcesProviderBuilder =
ImmutableMap.builder();
ImmutableAndroidBinaryResourcesGraphEnhancementResult.Builder resultBuilder =
ImmutableAndroidBinaryResourcesGraphEnhancementResult.builder();
List<SourcePath> apkResourceDependencyList = new ArrayList<>();
for (APKModule module : apkModuleGraph.getAPKModules()) {
AndroidPackageableCollection.ResourceDetails resourceDetails =
packageableCollection.getResourceDetails().get(module);
if (resourceDetails == null) {
throw new RuntimeException(
String.format("Missing resource details for module %s", module.getName()));
}
ImmutableSortedSet<BuildRule> resourceRules =
getTargetsAsRules(resourceDetails.getResourcesWithNonEmptyResDir());
ImmutableCollection<BuildRule> rulesWithResourceDirectories =
graphBuilder.filterBuildRuleInputs(resourceDetails.getResourceDirectories());
InternalFlavor moduleFlavor = InternalFlavor.of(module.getName());
FilteredResourcesProvider filteredResourcesProvider;
if (needsResourceFiltering) {
ResourcesFilter resourcesFilter =
createResourcesFilter(
moduleFlavor, resourceDetails, resourceRules, rulesWithResourceDirectories);
graphBuilder.addToIndex(resourcesFilter);
filteredResourcesProvider = resourcesFilter;
resourceRules = ImmutableSortedSet.of(resourcesFilter);
} else {
filteredResourcesProvider =
new IdentityResourcesProvider(resourceDetails.getResourceDirectories());
}
filteredResourcesProviderBuilder.put(module, filteredResourcesProvider);
AaptOutputInfo aaptOutputInfo;
SourcePath manifestPath;
if (module.isRootModule()) {
manifestPath = createBaseManifestRule(packageableCollection, module);
} else {
if (!moduleManifestSkeleton.isPresent()) {
continue;
}
AndroidManifest moduleManifestMergeRule =
new AndroidManifest(
buildTarget.withAppendedFlavors(MANIFEST_MERGE_FLAVOR, moduleFlavor),
projectFilesystem,
graphBuilder,
moduleManifestSkeleton.get(),
module,
packageableCollection.getAndroidManifestPieces().get(module));
graphBuilder.addToIndex(moduleManifestMergeRule);
manifestPath = moduleManifestMergeRule.getSourcePathToOutput();
}
switch (aaptMode) {
case AAPT1:
{
// Create the AaptPackageResourcesBuildable.
AaptPackageResources aaptPackageResources =
createAaptPackageResources(
buildTarget.withAppendedFlavors(AAPT_PACKAGE_FLAVOR, moduleFlavor),
manifestPath,
ImmutableList.copyOf(apkResourceDependencyList),
resourceDetails,
filteredResourcesProvider);
graphBuilder.addToIndex(aaptPackageResources);
aaptOutputInfo = aaptPackageResources.getAaptOutputInfo();
apkResourceDependencyList.add(aaptOutputInfo.getPrimaryResourcesApkPath());
}
break;
case AAPT2:
{
Aapt2Link aapt2Link =
createAapt2Link(
packageIdOffset,
moduleFlavor,
manifestPath,
resourceDetails,
needsResourceFiltering
? Optional.of(filteredResourcesProvider)
: Optional.empty(),
ImmutableList.copyOf(apkResourceDependencyList),
useProtoFormat);
graphBuilder.addToIndex(aapt2Link);
if (useProtoFormat) {
// also build an ARSC flavor that we can use to as parent dependencies to other
// modules
Aapt2Link aapt2LinkArsc =
createAapt2Link(
packageIdOffset,
moduleFlavor,
manifestPath,
resourceDetails,
needsResourceFiltering
? Optional.of(filteredResourcesProvider)
: Optional.empty(),
ImmutableList.copyOf(apkResourceDependencyList),
false);
graphBuilder.addToIndex(aapt2LinkArsc);
apkResourceDependencyList.add(
aapt2LinkArsc.getAaptOutputInfo().getPrimaryResourcesApkPath());
} else {
apkResourceDependencyList.add(
aapt2Link.getAaptOutputInfo().getPrimaryResourcesApkPath());
}
aaptOutputInfo = aapt2Link.getAaptOutputInfo();
}
break;
default:
throw new RuntimeException("Unexpected aaptMode: " + aaptMode);
}
if (module.isRootModule()) {
Optional<PackageStringAssets> packageStringAssets = Optional.empty();
if (resourceCompressionMode.isStoreStringsAsAssets()) {
// TODO(cjhopman): we should be able to support this in exo-for-resources
if (exopackageForResources) {
throw new HumanReadableException(
"exopackage_modes and resource_compression_mode for android_binary %s are "
+ "incompatible. Either remove %s from exopackage_modes or disable storing strings "
+ "as assets.",
buildTarget, ExopackageMode.RESOURCES);
}
packageStringAssets =
Optional.of(
createPackageStringAssets(
resourceRules,
rulesWithResourceDirectories,
filteredResourcesProvider,
aaptOutputInfo));
graphBuilder.addToIndex(packageStringAssets.get());
}
resultBuilder.setPackageStringAssets(packageStringAssets);
createMergeAndExoResources(
packageableCollection,
pathToRDotTxtFiles,
resultBuilder,
aaptOutputInfo,
packageStringAssets);
// Create a rule that copies the AndroidManifest. This allows the AndroidBinary rule (and
// exopackage installation rules) to have a runtime dep on the manifest without having to
// have a runtime dep on the full aapt output.
ExportFile manifestCopyRule =
new ExportFile(
originalBuildTarget.withAppendedFlavors(COPY_MANIFEST_FLAVOR),
projectFilesystem,
graphBuilder,
"AndroidManifest.xml",
ExportFileDescription.Mode.COPY,
aaptOutputInfo.getAndroidManifestXml(),
ExportFileDirectoryAction.FAIL);
graphBuilder.addToIndex(manifestCopyRule);
resultBuilder.setAndroidManifestXml(manifestCopyRule.getSourcePathToOutput());
} else {
resultBuilder.putModuleResourceApkPaths(
module, aaptOutputInfo.getPrimaryResourcesApkPath());
}
resultBuilder.addAaptGeneratedProguardConfigFiles(
aaptOutputInfo.getAaptGeneratedProguardConfigFile());
pathToRDotTxtFiles.add(aaptOutputInfo.getPathToRDotTxt());
packageIdOffset++;
}
Optional<GenerateRDotJava> generateRDotJava = Optional.empty();
ImmutableMap<APKModule, FilteredResourcesProvider> allFilteredResourceProviders =
filteredResourcesProviderBuilder.build();
if (allFilteredResourceProviders.values().stream().anyMatch(f -> f.hasResources())) {
generateRDotJava =
Optional.of(
createGenerateRDotJava(
pathToRDotTxtFiles.build(),
getTargetsAsRules(
packageableCollection.getResourceDetails().values().stream()
.flatMap(r -> r.getResourcesWithNonEmptyResDir().stream())
.collect(ImmutableList.toImmutableList())),
allFilteredResourceProviders.values()));
graphBuilder.addToIndex(generateRDotJava.get());
if (shouldBuildStringSourceMap) {
graphBuilder.addToIndex(
createGenerateStringResources(allFilteredResourceProviders.values().asList()));
}
}
return resultBuilder
.setRDotJavaDir(
generateRDotJava.map(GenerateRDotJava::getSourcePathToGeneratedRDotJavaSrcFiles))
.build();
}