DeviceSpecFromTargetingBuilder setSdkVersion(SdkVersionTargeting sdkVersionTargeting) { if (!sdkVersionTargeting.equals(SdkVersionTargeting.getDefaultInstance())) { deviceSpec.setSdkVersion( Iterables.getOnlyElement(sdkVersionTargeting.getValueList()).getMin().getValue()); } return this; }
@Override protected void checkDeviceCompatibleInternal(SdkVersionTargeting targeting) { SdkVersion sdkValue = targeting.getValueCount() == 0 ? SdkVersion.getDefaultInstance() : targeting.getValue(0); boolean anyMatch = Stream.concat(Stream.of(sdkValue), targeting.getAlternativesList().stream()) .anyMatch(sdkVal -> matchesDeviceSdk(sdkVal, deviceSdkVersion)); if (!anyMatch) { throw CommandExecutionException.builder() .withMessage( "The app doesn't support SDK version of the device: (%d).", getDeviceSpec().getSdkVersion()) .build(); } }
@Test public void buildApksCommand_instantApks_targetLPlus() throws Exception { bundlePath = FileUtils.getRandomFilePath(tmp, "bundle-", ".aab"); AppBundle appBundle = new AppBundleBuilder() .addModule( "base", builder -> builder .addFile("dex/classes.dex") .setManifest(androidManifest("com.test.app", withInstant(true)))) .build(); bundleSerializer.writeToDisk(appBundle, bundlePath); BuildApksCommand command = BuildApksCommand.builder() .setBundlePath(bundlePath) .setOutputFile(outputFilePath) .setAapt2Command(aapt2Command) .build(); Path apkSetFilePath = execute(command); ZipFile apkSetFile = new ZipFile(apkSetFilePath.toFile()); BuildApksResult result = extractTocFromApkSetFile(apkSetFile, outputDir); assertThat(instantApkVariants(result)).hasSize(1); Variant variant = instantApkVariants(result).get(0); assertThat(variant.hasTargeting()).isTrue(); assertThat(variant.getTargeting().getSdkVersionTargeting().getValueList()) .containsExactly(sdkVersionFrom(ANDROID_L_API_VERSION)); }
/** * Adds L+ targeting to the Apk targeting of module split. If SDK targeting already exists, it's * not overridden but checked that it targets no L- devices. */ private ModuleSplit addLPlusApkTargeting(ModuleSplit split) { if (split.getApkTargeting().hasSdkVersionTargeting()) { checkState( split.getApkTargeting().getSdkVersionTargeting().getValue(0).getMin().getValue() >= ANDROID_L_API_VERSION, "Module Split should target SDK versions above L."); return split; } return split .toBuilder() .setApkTargeting( split .getApkTargeting() .toBuilder() .setSdkVersionTargeting( SdkVersionTargeting.newBuilder() .addValue( SdkVersion.newBuilder() .setMin(Int32Value.newBuilder().setValue(ANDROID_L_API_VERSION)))) .build()) .build(); }
/** * Given a set of potentially overlapping sdk targetings generate set of disjoint sdk targetings * covering all of them. * * <p>Assumption: There are no sdk range gaps in targetings. */ private static ImmutableList<SdkVersionTargeting> generateAllSdkTargetings( ImmutableList<SdkVersionTargeting> sdkVersionTargetings) { sdkVersionTargetings.forEach( sdkVersionTargeting -> checkState(sdkVersionTargeting.getValueList().size() == 1)); ImmutableList<Integer> minSdkValues = sdkVersionTargetings .stream() .map(sdkVersionTargeting -> sdkVersionTargeting.getValue(0).getMin().getValue()) .distinct() .sorted() .collect(toImmutableList()); ImmutableSet<SdkVersion> sdkVersions = minSdkValues.stream().map(TargetingProtoUtils::sdkVersionFrom).collect(toImmutableSet()); return sdkVersions .stream() .map( sdkVersion -> sdkVersionTargeting( sdkVersion, Sets.difference(sdkVersions, ImmutableSet.of(sdkVersion)).immutableCopy())) .collect(toImmutableList()); }
@Test public void buildApksCommand_splitApks_targetLPlus() throws Exception { bundlePath = FileUtils.getRandomFilePath(tmp, "bundle-", ".aab"); AppBundle appBundle = new AppBundleBuilder() .addModule( "base", builder -> builder.addFile("dex/classes.dex").setManifest(androidManifest("com.test.app"))) .build(); bundleSerializer.writeToDisk(appBundle, bundlePath); BuildApksCommand command = BuildApksCommand.builder() .setBundlePath(bundlePath) .setOutputFile(outputFilePath) .setAapt2Command(aapt2Command) .build(); Path apkSetFilePath = execute(command); ZipFile apkSetFile = new ZipFile(apkSetFilePath.toFile()); BuildApksResult result = extractTocFromApkSetFile(apkSetFile, outputDir); assertThat(splitApkVariants(result)).hasSize(1); Variant variant = splitApkVariants(result).get(0); assertThat(variant.hasTargeting()).isTrue(); assertThat(variant.getTargeting().getSdkVersionTargeting().getValueList()) .containsExactly(sdkVersionFrom(ANDROID_L_API_VERSION)); }
@Override public boolean matchesTargeting(SdkVersionTargeting targeting) { checkArgument( targeting.getValueCount() <= 1, "Found more than one SDK version value in the variant targeting."); SdkVersion sdkValue = targeting.getValueCount() == 0 ? SdkVersion.getDefaultInstance() : targeting.getValue(0); if (!matchesDeviceSdk(sdkValue, deviceSdkVersion)) { return false; } // Check if there is a better match among alternatives. for (SdkVersion alternativeSdkValue : targeting.getAlternativesList()) { if (isBetterSdkMatch( /* candidate= */ alternativeSdkValue, /* contestedValue= */ sdkValue, deviceSdkVersion)) { return false; } } return true; }
@Test public void deviceSpecFromTargetingBuilder_setSdkVersion() { assertThat( new DeviceSpecFromTargetingBuilder(DeviceSpec.getDefaultInstance()) .setSdkVersion(SdkVersionTargeting.getDefaultInstance()) .build()) .isEqualToDefaultInstance(); assertThat( new DeviceSpecFromTargetingBuilder(DeviceSpec.getDefaultInstance()) .setSdkVersion(sdkVersionTargeting(sdkVersionFrom(25))) .build()) .isEqualTo(sdkVersion(25)); assertThat( new DeviceSpecFromTargetingBuilder(DeviceSpec.getDefaultInstance()) .setSdkVersion( sdkVersionTargeting(sdkVersionFrom(21), ImmutableSet.of(sdkVersionFrom(23)))) .build()) .isEqualTo(sdkVersion(21)); }
public static SdkVersionTargeting sdkVersionTargeting(SdkVersion sdkVersion) { return SdkVersionTargeting.newBuilder().addValue(sdkVersion).build(); }
public static SdkVersionTargeting sdkVersionTargeting(SdkVersion sdkVersion) { return SdkVersionTargeting.newBuilder().addValue(sdkVersion).build(); }
private static Optional<Integer> getMinSdk(VariantTargeting variantTargeting) { // If the variant does not have an SDK targeting, it is suitable for all SDK values. if (variantTargeting.getSdkVersionTargeting().getValueList().isEmpty()) { return Optional.empty(); } // If there are many different minSdks values, select the maximum of those. // We ignore the alternatives. return variantTargeting .getSdkVersionTargeting() .getValueList() .stream() .map(sdkVersion -> sdkVersion.getMin().getValue()) .max(Comparator.naturalOrder()); }
/** Extracts the maximum sdk (exclusive) supported by the targeting. */ public static int getMaxSdk(SdkVersionTargeting sdkVersionTargeting) { int minSdk = getMinSdk(sdkVersionTargeting); int alternativeMinSdk = sdkVersionTargeting .getAlternativesList() .stream() .mapToInt(alternativeSdk -> alternativeSdk.getMin().getValue()) .filter(sdkValue -> minSdk < sdkValue) .min() .orElse(Integer.MAX_VALUE); return alternativeMinSdk; } }
@Test public void maxSdk_emptySdkTargeting() { assertThat(getMaxSdk(SdkVersionTargeting.getDefaultInstance())).isEqualTo(Integer.MAX_VALUE); }
@Override protected ImmutableList<SdkVersion> getValues(VariantTargeting targeting) { return ImmutableList.copyOf(targeting.getSdkVersionTargeting().getValueList()); }
@Test public void minSdk_emptySdkTargeting() { assertThat(getMinSdk(SdkVersionTargeting.getDefaultInstance())).isEqualTo(1); }
@Test public void getSdk_noAlternatives() { assertThat(getSdkName(SdkVersionTargeting.getDefaultInstance())).hasValue("1-"); assertThat(getSdkName(sdkVersionTargeting(sdkVersionFrom(21)))).hasValue("21-"); }
public static SdkVersionTargeting sdkVersionTargeting( SdkVersion sdkVersion, ImmutableSet<SdkVersion> alternatives) { return SdkVersionTargeting.newBuilder() .addValue(sdkVersion) .addAllAlternatives(alternatives) .build(); }
public static SdkVersionTargeting sdkVersionTargeting( SdkVersion sdkVersion, ImmutableSet<SdkVersion> alternatives) { return SdkVersionTargeting.newBuilder() .addValue(sdkVersion) .addAllAlternatives(alternatives) .build(); }
/** Extracts the minimum sdk (inclusive) supported by the targeting. */ public static int getMinSdk(SdkVersionTargeting sdkVersionTargeting) { if (sdkVersionTargeting.getValueList().isEmpty()) { return 1; } return Iterables.getOnlyElement(sdkVersionTargeting.getValueList()).getMin().getValue(); }
public static ApkTargeting apkSdkTargeting(SdkVersion sdkVersion) { return ApkTargeting.newBuilder() .setSdkVersionTargeting(SdkVersionTargeting.newBuilder().addValue(sdkVersion)) .build(); }