EnhancementResult createAdditionalBuildables() {
    ImmutableSortedSet.Builder<BuildRule> enhancedDeps = ImmutableSortedSet.naturalOrder();
    enhancedDeps.addAll(originalDeps);

    ImmutableSortedSet<BuildRule> resourceRules = getAndroidResourcesAsRules();

    BuildTarget buildTargetForFilterResources =
        createBuildTargetWithFlavor(RESOURCES_FILTER_FLAVOR);
    FilteredResourcesProvider filteredResourcesProvider;
    boolean needsResourceFiltering =
        resourceFilter.isEnabled() || resourceCompressionMode.isStoreStringsAsAssets();

    if (needsResourceFiltering) {
      ResourcesFilter resourcesFilter =
          new ResourcesFilter(
              buildTargetForFilterResources,
              androidResourceDepsFinder,
              resourceCompressionMode,
              resourceFilter);
      BuildRule resourcesFilterBuildRule =
          buildRuleAndAddToIndex(
              resourcesFilter,
              BuildRuleType.RESOURCES_FILTER,
              buildTargetForFilterResources,
              resourceRules);

      filteredResourcesProvider = resourcesFilter;
      enhancedDeps.add(resourcesFilterBuildRule);
      resourceRules = ImmutableSortedSet.of(resourcesFilterBuildRule);
    } else {
      filteredResourcesProvider = new IdentityResourcesProvider(androidResourceDepsFinder);
    }

    BuildTarget buildTargetForUberRDotJava = createBuildTargetWithFlavor(UBER_R_DOT_JAVA_FLAVOR);
    UberRDotJava uberRDotJava =
        new UberRDotJava(
            buildTargetForUberRDotJava,
            filteredResourcesProvider,
            javacOptions,
            androidResourceDepsFinder,
            shouldPreDex,
            shouldBuildStringSourceMap);
    BuildRule uberRDotJavaBuildRule =
        buildRuleAndAddToIndex(
            uberRDotJava, BuildRuleType.UBER_R_DOT_JAVA, buildTargetForUberRDotJava, resourceRules);
    enhancedDeps.add(uberRDotJavaBuildRule);

    Optional<PackageStringAssets> packageStringAssets = Optional.absent();
    if (resourceCompressionMode.isStoreStringsAsAssets()) {
      BuildTarget buildTargetForPackageStringAssets =
          createBuildTargetWithFlavor(PACKAGE_STRING_ASSETS_FLAVOR);
      packageStringAssets =
          Optional.of(
              new PackageStringAssets(
                  buildTargetForPackageStringAssets, filteredResourcesProvider, uberRDotJava));
      BuildRule packageStringAssetsRule =
          buildRuleAndAddToIndex(
              packageStringAssets.get(),
              BuildRuleType.PACKAGE_STRING_ASSETS,
              buildTargetForPackageStringAssets,
              ImmutableSortedSet.of(uberRDotJavaBuildRule));
      enhancedDeps.add(packageStringAssetsRule);
    }

    // Create the AaptPackageResourcesBuildable.
    BuildTarget buildTargetForAapt = createBuildTargetWithFlavor(AAPT_PACKAGE_FLAVOR);
    AaptPackageResources aaptPackageResources =
        new AaptPackageResources(
            buildTargetForAapt,
            manifest,
            filteredResourcesProvider,
            androidResourceDepsFinder.getAndroidTransitiveDependencies(),
            packageType,
            cpuFilters);
    BuildRule aaptPackageResourcesBuildRule =
        buildRuleAndAddToIndex(
            aaptPackageResources,
            BuildRuleType.AAPT_PACKAGE,
            buildTargetForAapt,
            getAdditionalAaptDeps(resourceRules));
    enhancedDeps.add(aaptPackageResourcesBuildRule);

    Optional<PreDexMerge> preDexMerge = Optional.absent();
    if (shouldPreDex) {
      BuildRule preDexMergeRule = createPreDexMergeRule(uberRDotJava);
      preDexMerge = Optional.of((PreDexMerge) preDexMergeRule.getBuildable());
      enhancedDeps.add(preDexMergeRule);
    }

    ImmutableSortedSet<BuildRule> finalDeps;
    Optional<ComputeExopackageDepsAbi> computeExopackageDepsAbi = Optional.absent();
    if (exopackage) {
      BuildTarget buildTargetForAbiCalculation = createBuildTargetWithFlavor(CALCULATE_ABI_FLAVOR);
      computeExopackageDepsAbi =
          Optional.of(
              new ComputeExopackageDepsAbi(
                  buildTargetForAbiCalculation,
                  androidResourceDepsFinder,
                  uberRDotJava,
                  aaptPackageResources,
                  packageStringAssets,
                  preDexMerge,
                  keystore));
      BuildRule computeExopackageDepsAbiRule =
          buildRuleAndAddToIndex(
              computeExopackageDepsAbi.get(),
              BuildRuleType.EXOPACKAGE_DEPS_ABI,
              buildTargetForAbiCalculation,
              enhancedDeps.build());
      finalDeps = ImmutableSortedSet.of(computeExopackageDepsAbiRule);
    } else {
      finalDeps = enhancedDeps.build();
    }

    return new EnhancementResult(
        filteredResourcesProvider,
        uberRDotJava,
        aaptPackageResources,
        packageStringAssets,
        preDexMerge,
        computeExopackageDepsAbi,
        finalDeps);
  }
  AndroidGraphEnhancementResult createAdditionalBuildables() {
    ImmutableSortedSet.Builder<BuildRule> enhancedDeps = ImmutableSortedSet.naturalOrder();
    enhancedDeps.addAll(originalDeps);

    AndroidPackageableCollector collector =
        new AndroidPackageableCollector(
            originalBuildTarget, buildTargetsToExcludeFromDex, resourcesToExclude);
    collector.addPackageables(AndroidPackageableCollector.getPackageableRules(originalDeps));
    AndroidPackageableCollection packageableCollection = collector.build();
    AndroidPackageableCollection.ResourceDetails resourceDetails =
        packageableCollection.getResourceDetails();

    ImmutableSortedSet<BuildRule> resourceRules =
        getTargetsAsRules(resourceDetails.getResourcesWithNonEmptyResDir());

    FilteredResourcesProvider filteredResourcesProvider;
    boolean needsResourceFiltering =
        resourceFilter.isEnabled()
            || resourceCompressionMode.isStoreStringsAsAssets()
            || !locales.isEmpty();

    if (needsResourceFiltering) {
      BuildRuleParams paramsForResourcesFilter =
          buildRuleParams.copyWithChanges(
              createBuildTargetWithFlavor(RESOURCES_FILTER_FLAVOR),
              Suppliers.ofInstance(
                  ImmutableSortedSet.<BuildRule>naturalOrder()
                      .addAll(resourceRules)
                      .addAll(
                          pathResolver.filterBuildRuleInputs(
                              resourceDetails.getResourceDirectories()))
                      .build()),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
      ResourcesFilter resourcesFilter =
          new ResourcesFilter(
              paramsForResourcesFilter,
              pathResolver,
              resourceDetails.getResourceDirectories(),
              ImmutableSet.copyOf(resourceDetails.getWhitelistedStringDirectories()),
              locales,
              resourceCompressionMode,
              resourceFilter);
      ruleResolver.addToIndex(resourcesFilter);

      filteredResourcesProvider = resourcesFilter;
      enhancedDeps.add(resourcesFilter);
      resourceRules = ImmutableSortedSet.<BuildRule>of(resourcesFilter);
    } else {
      filteredResourcesProvider =
          new IdentityResourcesProvider(
              pathResolver.getAllPaths(resourceDetails.getResourceDirectories()));
    }

    // Create the AaptPackageResourcesBuildable.
    BuildTarget buildTargetForAapt = createBuildTargetWithFlavor(AAPT_PACKAGE_FLAVOR);
    BuildRuleParams paramsForAaptPackageResources =
        buildRuleParams.copyWithChanges(
            buildTargetForAapt,
            Suppliers.ofInstance(
                ImmutableSortedSet.<BuildRule>naturalOrder()
                    // Add all deps with non-empty res dirs, since we at least need the R.txt file
                    // (even if we're filtering).
                    .addAll(getTargetsAsRules(resourceDetails.getResourcesWithNonEmptyResDir()))
                    .addAll(
                        pathResolver.filterBuildRuleInputs(
                            resourceDetails.getResourceDirectories()))
                    .addAll(
                        getAdditionalAaptDeps(pathResolver, resourceRules, packageableCollection))
                    .build()),
            /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
    AaptPackageResources aaptPackageResources =
        new AaptPackageResources(
            paramsForAaptPackageResources,
            pathResolver,
            manifest,
            filteredResourcesProvider,
            getTargetsAsResourceDeps(resourceDetails.getResourcesWithNonEmptyResDir()),
            packageableCollection.getAssetsDirectories(),
            packageType,
            javacOptions,
            shouldPreDex,
            shouldBuildStringSourceMap,
            locales.isEmpty(),
            skipCrunchPngs);
    ruleResolver.addToIndex(aaptPackageResources);
    enhancedDeps.add(aaptPackageResources);

    Optional<PackageStringAssets> packageStringAssets = Optional.absent();
    if (resourceCompressionMode.isStoreStringsAsAssets()) {
      BuildTarget buildTargetForPackageStringAssets =
          createBuildTargetWithFlavor(PACKAGE_STRING_ASSETS_FLAVOR);
      BuildRuleParams paramsForPackageStringAssets =
          buildRuleParams.copyWithChanges(
              buildTargetForPackageStringAssets,
              Suppliers.ofInstance(
                  ImmutableSortedSet.<BuildRule>naturalOrder()
                      .add(aaptPackageResources)
                      // Model the dependency on the presence of res directories, which, in the case
                      // of resource filtering, is cached by the `ResourcesFilter` rule.
                      .addAll(
                          Iterables.filter(
                              ImmutableList.of(filteredResourcesProvider), BuildRule.class))
                      .build()),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
      packageStringAssets =
          Optional.of(
              new PackageStringAssets(
                  paramsForPackageStringAssets,
                  pathResolver,
                  locales,
                  filteredResourcesProvider,
                  aaptPackageResources));
      ruleResolver.addToIndex(packageStringAssets.get());
      enhancedDeps.add(packageStringAssets.get());
    }

    // TODO(natthu): Try to avoid re-building the collection by passing UberRDotJava directly.
    if (packageableCollection.getResourceDetails().hasResources()) {
      collector.addClasspathEntry(
          aaptPackageResources,
          new BuildTargetSourcePath(
              aaptPackageResources.getBuildTarget(),
              aaptPackageResources.getPathToCompiledRDotJavaFiles()));
    }

    // BuildConfig deps should not be added for instrumented APKs because BuildConfig.class has
    // already been added to the APK under test.
    ImmutableList<DexProducedFromJavaLibrary> preDexBuildConfigs;
    ImmutableList<Path> buildConfigJarFiles;
    if (packageType == PackageType.INSTRUMENTED) {
      preDexBuildConfigs = ImmutableList.of();
      buildConfigJarFiles = ImmutableList.of();
    } else {
      ImmutableList.Builder<DexProducedFromJavaLibrary> preDexBuildConfigsBuilder =
          ImmutableList.builder();
      ImmutableList.Builder<Path> buildConfigJarFilesBuilder = ImmutableList.builder();
      addBuildConfigDeps(
          shouldPreDex,
          packageableCollection,
          enhancedDeps,
          preDexBuildConfigsBuilder,
          buildConfigJarFilesBuilder);
      preDexBuildConfigs = preDexBuildConfigsBuilder.build();
      buildConfigJarFiles = buildConfigJarFilesBuilder.build();
    }

    packageableCollection = collector.build();

    Optional<PreDexMerge> preDexMerge = Optional.absent();
    if (shouldPreDex) {
      preDexMerge =
          Optional.of(
              createPreDexMergeRule(
                  aaptPackageResources, preDexBuildConfigs, packageableCollection));
      enhancedDeps.add(preDexMerge.get());
    } else {
      enhancedDeps.addAll(getTargetsAsRules(packageableCollection.getJavaLibrariesToDex()));
    }

    // Add dependencies on all the build rules generating third-party JARs.  This is mainly to
    // correctly capture deps when a prebuilt_jar forwards the output from another build rule.
    enhancedDeps.addAll(
        pathResolver.filterBuildRuleInputs(packageableCollection.getPathsToThirdPartyJars()));

    Optional<CopyNativeLibraries> copyNativeLibraries =
        nativeLibsEnhancer.getCopyNativeLibraries(targetGraph, packageableCollection);
    if (copyNativeLibraries.isPresent()) {
      ruleResolver.addToIndex(copyNativeLibraries.get());
      enhancedDeps.add(copyNativeLibraries.get());
    }

    Optional<ComputeExopackageDepsAbi> computeExopackageDepsAbi = Optional.absent();
    if (!exopackageModes.isEmpty()) {
      BuildRuleParams paramsForComputeExopackageAbi =
          buildRuleParams.copyWithChanges(
              createBuildTargetWithFlavor(CALCULATE_ABI_FLAVOR),
              Suppliers.ofInstance(enhancedDeps.build()),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
      computeExopackageDepsAbi =
          Optional.of(
              new ComputeExopackageDepsAbi(
                  paramsForComputeExopackageAbi,
                  pathResolver,
                  exopackageModes,
                  packageableCollection,
                  aaptPackageResources,
                  copyNativeLibraries,
                  packageStringAssets,
                  preDexMerge,
                  keystore));
      ruleResolver.addToIndex(computeExopackageDepsAbi.get());
      enhancedDeps.add(computeExopackageDepsAbi.get());
    }

    return AndroidGraphEnhancementResult.builder()
        .setPackageableCollection(packageableCollection)
        .setAaptPackageResources(aaptPackageResources)
        .setCopyNativeLibraries(copyNativeLibraries)
        .setPackageStringAssets(packageStringAssets)
        .setPreDexMerge(preDexMerge)
        .setComputeExopackageDepsAbi(computeExopackageDepsAbi)
        .setClasspathEntriesToDex(
            ImmutableSet.<Path>builder()
                .addAll(pathResolver.getAllPaths(packageableCollection.getClasspathEntriesToDex()))
                .addAll(buildConfigJarFiles)
                .build())
        .setFinalDeps(enhancedDeps.build())
        .build();
  }