private ConfigurationSizes getSizeStandaloneVariant() { checkState( !getSizeRequest.getInstant(), "Standalone Variants cant be selected when instant flag is set"); // When modules are specified we ignore standalone variants. if (getSizeRequest.getModules().isPresent()) { return ConfigurationSizes.create(ImmutableMap.of(), ImmutableMap.of()); } VariantTargeting variantTargeting = variant.getTargeting(); SizeConfiguration sizeConfiguration = mergeWithDeviceSpec( getSizeConfiguration( variantTargeting.getSdkVersionTargeting(), variantTargeting.getAbiTargeting(), variantTargeting.getScreenDensityTargeting(), LanguageTargeting.getDefaultInstance()), getSizeRequest.getDeviceSpec()); // Variants of standalone APKs have only one APK each. long compressedSize = sizeByApkPaths.get( Iterables.getOnlyElement( Iterables.getOnlyElement(variant.getApkSetList()).getApkDescriptionList()) .getPath()); ImmutableMap<SizeConfiguration, Long> sizeConfigurationMap = ImmutableMap.of(sizeConfiguration, compressedSize); return ConfigurationSizes.create(sizeConfigurationMap, sizeConfigurationMap); }
LanguageTargeting.newBuilder().addValue(language)) .build()) .setMasterSplit(split.isMasterSplit() && language.isEmpty())
@Override public boolean matchesTargeting(LanguageTargeting targetingValue) { if (targetingValue.equals(LanguageTargeting.getDefaultInstance())) { return true; } if (targetingValue.getValueCount() > 0) { // We return all positive matches, so we don't look at alternatives. Set<String> targetingLanguages = ImmutableSet.copyOf(targetingValue.getValueList()); return !Sets.intersection(targetingLanguages, deviceLanguages).isEmpty(); } else { // Fallback split has only alternatives set. Match the fallback iff the alternative languages // don't fully cover languages of the device. // The rationale is that if alternatives only partially cover the device languages, then // removing language(s) from the device can cause the app to start using the fallback // directory. But it would be confusing for the user if removal of a language triggered // download of additional language split(s). Therefore the fallback split should be present // from the beginning. Set<String> alternativeLanguages = ImmutableSet.copyOf(targetingValue.getAlternativesList()); return !alternativeLanguages.containsAll(deviceLanguages); } }
if (!languageTargeting.getValueList().isEmpty()) { languageTargeting.getValueList().forEach(suffixJoiner::add); } else if (!languageTargeting.getAlternativesList().isEmpty()) { suffixJoiner.add("other_lang");
/** Moves targeting values to the alternatives. */ public static AssetsDirectoryTargeting toAlternativeTargeting( AssetsDirectoryTargeting targeting) { AssetsDirectoryTargeting.Builder alternativeTargeting = AssetsDirectoryTargeting.newBuilder(); if (targeting.hasTextureCompressionFormat()) { alternativeTargeting .getTextureCompressionFormatBuilder() .addAllAlternatives(targeting.getTextureCompressionFormat().getValueList()); } if (targeting.hasGraphicsApi()) { alternativeTargeting .getGraphicsApiBuilder() .addAllAlternatives(targeting.getGraphicsApi().getValueList()); } if (targeting.hasAbi()) { alternativeTargeting.getAbiBuilder().addAllAlternatives(targeting.getAbi().getValueList()); } if (targeting.hasLanguage()) { alternativeTargeting .getLanguageBuilder() .addAllAlternatives(targeting.getLanguage().getValueList()); } return alternativeTargeting.build(); }
@Test public void multipleLanguagesMatched_alternativesIgnored() { LanguageMatcher languageMatcher = new LanguageMatcher(lDeviceWithLocales("en-US", "en-GB", "de-DE")); assertThat(languageMatcher.matchesTargeting(LanguageTargeting.getDefaultInstance())).isTrue(); assertThat( languageMatcher.matchesTargeting( languageTargeting("en", ImmutableSet.of("de", "jp", "zh")))) .isTrue(); assertThat( languageMatcher.matchesTargeting( languageTargeting("de", ImmutableSet.of("en", "jp", "zh")))) .isTrue(); assertThat( languageMatcher.matchesTargeting( languageTargeting("jp", ImmutableSet.of("de", "en", "zh")))) .isFalse(); assertThat( languageMatcher.matchesTargeting( languageTargeting("zh", ImmutableSet.of("de", "en", "jp")))) .isFalse(); }
private ImmutableList<ModuleSplit> processSplitApkVariant(Collection<ModuleSplit> splits) { SplitsProtoXmlBuilder splitsProtoXmlBuilder = new SplitsProtoXmlBuilder(); for (ModuleSplit split : splits) { String splitId = split.getAndroidManifest().getSplitId().orElse(""); for (String language : split.getApkTargeting().getLanguageTargeting().getValueList()) { splitsProtoXmlBuilder.addLanguageMapping(split.getModuleName(), language, splitId); } } XmlNode splitsXmlContent = splitsProtoXmlBuilder.build(); ImmutableList.Builder<ModuleSplit> result = new ImmutableList.Builder<>(); for (ModuleSplit split : splits) { if (split.isMasterSplit() && split.isBaseModuleSplit()) { result.add(injectSplitsXml(split, splitsXmlContent)); } else { result.add(split); } } return result.build(); }
private ImmutableSet<LanguageTargeting> getAllLanguageTargetings( ImmutableList<ApkDescription> apkDescriptions) { ImmutableSet.Builder<LanguageTargeting> languageTargetingOptions = ImmutableSet.builder(); if (isLocalesMissing(getSizeRequest.getDeviceSpec())) { languageTargetingOptions.addAll( apkDescriptions.stream() .map(ApkDescription::getTargeting) .filter(ApkTargeting::hasLanguageTargeting) .map(ApkTargeting::getLanguageTargeting) .collect(ImmutableSet.toImmutableSet())); } // Adding default targeting (if targetings are empty) to help computing the cartesian product // across all targetings. return languageTargetingOptions.build().isEmpty() ? ImmutableSet.of(LanguageTargeting.getDefaultInstance()) : languageTargetingOptions.build(); }
private static AssetsDirectoryTargeting parseLanguage(String name, String value) { Matcher matcher = LANGUAGE_CODE_PATTERN.matcher(value); if (!matcher.matches()) { throw ValidationException.builder() .withMessage( "Expected 2- or 3-character language directory but got '%s' for directory '%s'.", value, name) .build(); } return AssetsDirectoryTargeting.newBuilder() .setLanguage(LanguageTargeting.newBuilder().addValue(value.toLowerCase())) .build(); } }
@Test public void deviceSpecFromTargetingBuilder_setSupportedLocales() { assertThat( new DeviceSpecFromTargetingBuilder(DeviceSpec.getDefaultInstance()) .setSupportedLocales(LanguageTargeting.getDefaultInstance()) .build()) .isEqualToDefaultInstance(); assertThat( new DeviceSpecFromTargetingBuilder(DeviceSpec.getDefaultInstance()) .setSupportedLocales(languageTargeting("fr")) .build()) .isEqualTo(locales("fr")); }
@Test public void getLocaleName_defaultLangTargeting() { assertThat(getLocaleName(LanguageTargeting.getDefaultInstance())).isEmpty(); }
/** Matching languages on variants is not supported. */ @Override protected LanguageTargeting getTargetingValue(VariantTargeting variantTargeting) { return LanguageTargeting.getDefaultInstance(); }
/** * Deliberately private, because bundletool should never produce language targeting with both * `values` and `alternatives`. */ private static LanguageTargeting languageTargeting( ImmutableSet<String> languages, ImmutableSet<String> alternativeLanguages) { return LanguageTargeting.newBuilder() .addAllValue(languages) .addAllAlternatives(alternativeLanguages) .build(); }
@Test public void fusedLanguageSplitsMatched() { LanguageMatcher languageMatcher = new LanguageMatcher(lDeviceWithLocales("en-US", "en-GB", "de-DE")); assertThat(languageMatcher.matchesTargeting(LanguageTargeting.getDefaultInstance())).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("en", "fr"))).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("jp", "zh"))).isFalse(); assertThat(languageMatcher.matchesTargeting(languageTargeting("de"))).isTrue(); }
@Test public void simpleSingleMatch() { LanguageMatcher languageMatcher = new LanguageMatcher(lDeviceWithLocales("en-US")); assertThat(languageMatcher.matchesTargeting(LanguageTargeting.getDefaultInstance())).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("en"))).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("de"))).isFalse(); }
public static Optional<String> getLocaleName(LanguageTargeting languageTargeting) { if (languageTargeting.getValueList().isEmpty()) { return Optional.empty(); } return Optional.of(Iterables.getOnlyElement(languageTargeting.getValueList())); }
DeviceSpecFromTargetingBuilder setSupportedLocales(LanguageTargeting languageTargeting) { if (!languageTargeting.equals(LanguageTargeting.getDefaultInstance())) { deviceSpec.addSupportedLocales(Iterables.getOnlyElement(languageTargeting.getValueList())); } return this; }
@Test public void multipleLanguagesMatched() { LanguageMatcher languageMatcher = new LanguageMatcher(lDeviceWithLocales("en-US", "de-DE")); assertThat(languageMatcher.matchesTargeting(LanguageTargeting.getDefaultInstance())).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("en"))).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("de"))).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("jp"))).isFalse(); assertThat(languageMatcher.matchesTargeting(languageTargeting("zh"))).isFalse(); }
@Test public void simpleSingleMatch_differentRegion() { LanguageMatcher languageMatcher = new LanguageMatcher(lDeviceWithLocales("en-GB")); assertThat(languageMatcher.matchesTargeting(LanguageTargeting.getDefaultInstance())).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("en"))).isTrue(); assertThat(languageMatcher.matchesTargeting(languageTargeting("de"))).isFalse(); }