@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(); } }
/** * 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()); }
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createSplitApkSet( /* moduleName= */ "base",
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createSplitApkSet( /* moduleName= */ "base",
createVariant( variantSdkTargeting( SdkVersion.getDefaultInstance(), ImmutableSet.of(sdkVersionFrom(21))), createStandaloneApkSet(ApkTargeting.getDefaultInstance(), apkPreL))) .addVariant( createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createSplitApkSet( "base",
createVariantForSingleSplitApk( variantSdkTargeting( SdkVersion.getDefaultInstance(), ImmutableSet.of(sdkVersionFrom(21), sdkVersionFrom(23))), ApkTargeting.getDefaultInstance(), variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(23))), ApkTargeting.getDefaultInstance(), apkL)) variantSdkTargeting( sdkVersionFrom(23), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(21))), ApkTargeting.getDefaultInstance(), apkM))
createVariantForSingleSplitApk( variantSdkTargeting( SdkVersion.getDefaultInstance(), ImmutableSet.of(sdkVersionFrom(21), sdkVersionFrom(23))), ApkTargeting.getDefaultInstance(), variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(23))), ApkTargeting.getDefaultInstance(), apkL)) variantSdkTargeting( sdkVersionFrom(23), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(21))), ApkTargeting.getDefaultInstance(), apkM))
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createInstantApkSet( "base", ApkTargeting.getDefaultInstance(), ZipPath.create("base-master.apk")), createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createSplitApkSet( "other",
SdkVersion lPlusVersion = sdkVersionFrom(Versions.ANDROID_L_API_VERSION); VariantTargeting lPlusTargeting = variantSdkTargeting(lPlusVersion); VariantTargeting emptySdkTargeting = variantSdkTargeting(SdkVersion.getDefaultInstance()); .containsExactly( mergeVariantTargeting( variantSdkTargeting(SdkVersion.getDefaultInstance(), ImmutableSet.of(lPlusVersion)), variantDensityTargeting( DensityAlias.MDPI, ImmutableSet.of(DensityAlias.HDPI, DensityAlias.XHDPI))), mergeVariantTargeting( variantSdkTargeting(SdkVersion.getDefaultInstance(), ImmutableSet.of(lPlusVersion)), variantDensityTargeting( DensityAlias.HDPI, ImmutableSet.of(DensityAlias.MDPI, DensityAlias.XHDPI))), mergeVariantTargeting( variantSdkTargeting(SdkVersion.getDefaultInstance(), ImmutableSet.of(lPlusVersion)), variantDensityTargeting( DensityAlias.XHDPI, ImmutableSet.of(DensityAlias.MDPI, DensityAlias.HDPI))));
createVariantForSingleSplitApk( variantSdkTargeting( SdkVersion.getDefaultInstance(), ImmutableSet.of(sdkVersionFrom(21), sdkVersionFrom(23))), ApkTargeting.getDefaultInstance(), variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(23))), ApkTargeting.getDefaultInstance(), apkL)) variantSdkTargeting( sdkVersionFrom(23), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(21))), ApkTargeting.getDefaultInstance(), apkM))
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createSplitApkSet( /* moduleName= */ "base",
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createStandaloneApkSet(ApkTargeting.getDefaultInstance(), apkPreL))) .addVariant( createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createInstantApkSet("base", ApkTargeting.getDefaultInstance(), apkLBase), createInstantApkSet("feature", ApkTargeting.getDefaultInstance(), apkLFeature),
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createStandaloneApkSet(ApkTargeting.getDefaultInstance(), apkPreL))) .addVariant( createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createSplitApkSet( "base",
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createInstantApkSet("base", ApkTargeting.getDefaultInstance(), apkBase), createInstantApkSet("instant", ApkTargeting.getDefaultInstance(), apkInstant))) createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createSplitApkSet( "other",
VariantTargeting lPlusTargeting = variantSdkTargeting(sdkVersionFrom(21)); VariantTargeting mPlusTargeting = variantSdkTargeting(sdkVersionFrom(23)); VariantTargeting defaultSdkTargeting = variantSdkTargeting(SdkVersion.getDefaultInstance()); variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(23)))); ModuleSplit mPlusVariantNew = outputVariants.get(1); assertThat(mPlusVariantNew.getVariantTargeting()) variantSdkTargeting( sdkVersionFrom(23), ImmutableSet.of(SdkVersion.getDefaultInstance(), sdkVersionFrom(21)))); ModuleSplit defaultSdkVariantNew = outputVariants.get(2); assertThat(defaultSdkVariantNew.getVariantTargeting()) .isEqualTo( variantSdkTargeting( SdkVersion.getDefaultInstance(), ImmutableSet.of(sdkVersionFrom(21), sdkVersionFrom(23))));
createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createInstantApkSet("base", ApkTargeting.getDefaultInstance(), apkBase), createInstantApkSet("instant", ApkTargeting.getDefaultInstance(), apkInstant),
SdkVersion lPlusVersion = sdkVersionFrom(Versions.ANDROID_L_API_VERSION); VariantTargeting lPlusTargeting = variantSdkTargeting(lPlusVersion); VariantTargeting emptySdkTargeting = variantSdkTargeting(SdkVersion.getDefaultInstance());
@Test public void extractInstant_withBaseOnly() throws Exception { Path apkLBase = ZipPath.create("apkL-base.apk"); BuildApksResult tableOfContentsProto = BuildApksResult.newBuilder() .addVariant( createVariant( variantSdkTargeting( sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), createInstantApkSet("base", ApkTargeting.getDefaultInstance(), apkLBase))) .build(); Path apksArchiveFile = createApksArchiveFile(tableOfContentsProto, tmpDir.resolve("bundle.apks")); DeviceSpec deviceSpec = deviceWithSdk(21); ImmutableList<Path> matchedApks = ExtractApksCommand.builder() .setApksArchivePath(apksArchiveFile) .setDeviceSpec(deviceSpec) .setOutputDirectory(tmpDir) .setInstant(true) .build() .execute(); assertThat(matchedApks).containsExactly(inOutputDirectory(apkLBase)); for (Path matchedApk : matchedApks) { checkFileExistsAndReadable(tmpDir.resolve(matchedApk)); } }
@Test public void betterAlternative() { SdkVersionMatcher sdkMatcher = new SdkVersionMatcher(deviceWithSdk(25)); assertThat( sdkMatcher.matchesTargeting( sdkVersionTargeting( SdkVersion.getDefaultInstance(), ImmutableSet.of(sdkVersionFrom(25))))) .isFalse(); assertThat( sdkMatcher.matchesTargeting( sdkVersionTargeting( SdkVersion.getDefaultInstance(), ImmutableSet.of(sdkVersionFrom(21))))) .isFalse(); assertThat( sdkMatcher.matchesTargeting( sdkVersionTargeting( sdkVersionFrom(21), ImmutableSet.of(sdkVersionFrom(23), SdkVersion.getDefaultInstance())))) .isFalse(); assertThat( sdkMatcher.matchesTargeting( sdkVersionTargeting( sdkVersionFrom(27), ImmutableSet.of(sdkVersionFrom(23), SdkVersion.getDefaultInstance())))) .isFalse(); } }
/** * 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(); }