| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.build.gradle.internal; |
| |
| import static com.android.build.OutputFile.NO_FILTER; |
| import static com.android.builder.core.BuilderConstants.ANDROID_TEST; |
| import static com.android.builder.core.BuilderConstants.DEBUG; |
| import static com.android.builder.core.BuilderConstants.LINT; |
| import static com.android.builder.core.BuilderConstants.UI_TEST; |
| |
| import com.android.annotations.NonNull; |
| import com.android.annotations.Nullable; |
| import com.android.build.gradle.BaseExtension; |
| import com.android.build.gradle.BasePlugin; |
| import com.android.build.gradle.api.AndroidSourceSet; |
| import com.android.build.gradle.api.BaseVariant; |
| import com.android.build.gradle.api.GroupableProductFlavor; |
| import com.android.build.gradle.internal.api.DefaultAndroidSourceSet; |
| import com.android.build.gradle.internal.api.ReadOnlyObjectProvider; |
| import com.android.build.gradle.internal.api.TestVariantImpl; |
| import com.android.build.gradle.internal.api.TestedVariant; |
| import com.android.build.gradle.internal.api.VariantFilterImpl; |
| import com.android.build.gradle.internal.core.GradleVariantConfiguration; |
| import com.android.build.gradle.internal.dependency.VariantDependencies; |
| import com.android.build.gradle.internal.dsl.BuildTypeDsl; |
| import com.android.build.gradle.internal.dsl.GroupableProductFlavorDsl; |
| import com.android.build.gradle.internal.dsl.ProductFlavorDsl; |
| import com.android.build.gradle.internal.dsl.SigningConfigDsl; |
| import com.android.build.gradle.internal.dsl.Splits; |
| import com.android.build.gradle.internal.variant.ApplicationVariantFactory; |
| import com.android.build.gradle.internal.variant.BaseVariantData; |
| import com.android.build.gradle.internal.variant.BaseVariantOutputData; |
| import com.android.build.gradle.internal.variant.TestVariantData; |
| import com.android.build.gradle.internal.variant.TestedVariantData; |
| import com.android.build.gradle.internal.variant.VariantFactory; |
| import com.android.builder.core.VariantConfiguration; |
| import com.android.builder.model.BuildType; |
| import com.android.builder.model.SigningConfig; |
| import com.google.common.base.Function; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Maps; |
| |
| import org.gradle.api.NamedDomainObjectContainer; |
| import org.gradle.api.Project; |
| import org.gradle.api.Task; |
| import org.gradle.api.tasks.TaskContainer; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import groovy.lang.Closure; |
| |
| /** |
| * Class to create, manage variants. |
| */ |
| public class VariantManager implements VariantModel { |
| |
| protected static final String COM_ANDROID_SUPPORT_MULTIDEX |
| = "com.android.support:multidex:1.0.0"; |
| |
| @NonNull |
| private final Project project; |
| @NonNull |
| private final BasePlugin basePlugin; |
| @NonNull |
| private final BaseExtension extension; |
| @NonNull |
| private final VariantFactory variantFactory; |
| |
| @NonNull |
| private final Map<String, BuildTypeData> buildTypes = Maps.newHashMap(); |
| @NonNull |
| private final Map<String, ProductFlavorData<GroupableProductFlavorDsl>> productFlavors = Maps.newHashMap(); |
| @NonNull |
| private final Map<String, SigningConfig> signingConfigs = Maps.newHashMap(); |
| |
| @NonNull |
| private final ReadOnlyObjectProvider readOnlyObjectProvider = new ReadOnlyObjectProvider(); |
| @NonNull |
| private final VariantFilterImpl variantFilter = new VariantFilterImpl(readOnlyObjectProvider); |
| |
| @NonNull |
| private final List<BaseVariantData<? extends BaseVariantOutputData>> variantDataList = Lists.newArrayList(); |
| |
| public VariantManager( |
| @NonNull Project project, |
| @NonNull BasePlugin basePlugin, |
| @NonNull BaseExtension extension, |
| @NonNull VariantFactory variantFactory) { |
| this.extension = extension; |
| this.basePlugin = basePlugin; |
| this.project = project; |
| this.variantFactory = variantFactory; |
| } |
| |
| @Override |
| @NonNull |
| public Map<String, BuildTypeData> getBuildTypes() { |
| return buildTypes; |
| } |
| |
| @Override |
| @NonNull |
| public Map<String, ProductFlavorData<GroupableProductFlavorDsl>> getProductFlavors() { |
| return productFlavors; |
| } |
| |
| @Override |
| @NonNull |
| public Map<String, SigningConfig> getSigningConfigs() { |
| return signingConfigs; |
| } |
| |
| public void addSigningConfig(@NonNull SigningConfigDsl signingConfigDsl) { |
| signingConfigs.put(signingConfigDsl.getName(), signingConfigDsl); |
| } |
| |
| /** |
| * Adds new BuildType, creating a BuildTypeData, and the associated source set, |
| * and adding it to the map. |
| * @param buildType the build type. |
| */ |
| public void addBuildType(@NonNull BuildTypeDsl buildType) { |
| buildType.init(signingConfigs.get(DEBUG)); |
| |
| String name = buildType.getName(); |
| checkName(name, "BuildType"); |
| |
| if (productFlavors.containsKey(name)) { |
| throw new RuntimeException("BuildType names cannot collide with ProductFlavor names"); |
| } |
| |
| DefaultAndroidSourceSet sourceSet = (DefaultAndroidSourceSet) extension.getSourceSetsContainer().maybeCreate(name); |
| |
| BuildTypeData buildTypeData = new BuildTypeData(buildType, sourceSet, project); |
| project.getTasks().getByName("assemble").dependsOn(buildTypeData.getAssembleTask()); |
| |
| buildTypes.put(name, buildTypeData); |
| } |
| |
| /** |
| * Adds a new ProductFlavor, creating a ProductFlavorData and associated source sets, |
| * and adding it to the map. |
| * |
| * @param productFlavor the product flavor |
| */ |
| public void addProductFlavor(@NonNull GroupableProductFlavorDsl productFlavor) { |
| String name = productFlavor.getName(); |
| checkName(name, "ProductFlavor"); |
| |
| if (buildTypes.containsKey(name)) { |
| throw new RuntimeException("ProductFlavor names cannot collide with BuildType names"); |
| } |
| |
| DefaultAndroidSourceSet mainSourceSet = (DefaultAndroidSourceSet) extension.getSourceSetsContainer().maybeCreate( |
| productFlavor.getName()); |
| String testName = ANDROID_TEST + StringHelper.capitalize(productFlavor.getName()); |
| DefaultAndroidSourceSet testSourceSet = (DefaultAndroidSourceSet) extension.getSourceSetsContainer().maybeCreate( |
| testName); |
| |
| ProductFlavorData<GroupableProductFlavorDsl> productFlavorData = |
| new ProductFlavorData<GroupableProductFlavorDsl>( |
| productFlavor, mainSourceSet, testSourceSet, project); |
| |
| productFlavors.put(productFlavor.getName(), productFlavorData); |
| } |
| |
| /** |
| * Return a list of all created VariantData. |
| */ |
| @NonNull |
| public List<BaseVariantData<? extends BaseVariantOutputData>> getVariantDataList() { |
| return variantDataList; |
| } |
| |
| /** |
| * Task creation entry point. |
| */ |
| public void createAndroidTasks(@Nullable SigningConfig signingOverride) { |
| variantFactory.validateModel(this); |
| |
| if (!productFlavors.isEmpty()) { |
| // there'll be more than one test app, so we need a top level assembleTest |
| Task assembleTest = project.getTasks().create("assembleTest"); |
| assembleTest.setGroup(org.gradle.api.plugins.BasePlugin.BUILD_GROUP); |
| assembleTest.setDescription("Assembles all the Test applications"); |
| basePlugin.setAssembleTest(assembleTest); |
| } |
| |
| if (variantDataList.isEmpty()) { |
| populateVariantDataList(signingOverride); |
| } |
| |
| for (BaseVariantData variantData : variantDataList) { |
| createTasksForVariantData(project.getTasks(), variantData); |
| } |
| |
| // create the lint tasks. |
| basePlugin.createLintTasks(); |
| |
| // create the test tasks. |
| basePlugin.createCheckTasks(!productFlavors.isEmpty(), false /*isLibrary*/); |
| |
| // Create the variant API objects after the tasks have been created! |
| createApiObjects(); |
| } |
| |
| /** |
| * Create tasks for the specified variantData. |
| */ |
| public void createTasksForVariantData(TaskContainer tasks, BaseVariantData variantData) { |
| if (variantData.getVariantConfiguration().getType() |
| == GradleVariantConfiguration.Type.TEST) { |
| GradleVariantConfiguration testVariantConfig = variantData.getVariantConfiguration(); |
| BaseVariantData testedVariantData = (BaseVariantData) ((TestVariantData) variantData) |
| .getTestedVariantData(); |
| |
| /// add the container of dependencies |
| // the order of the libraries is important. In descending order: |
| // flavors, defaultConfig. No build type for tests |
| List<ConfigurationProvider> testVariantProviders = Lists.newArrayListWithExpectedSize( |
| 2 + testVariantConfig.getProductFlavors().size()); |
| |
| for (GroupableProductFlavor productFlavor : testVariantConfig.getProductFlavors()) { |
| ProductFlavorData<GroupableProductFlavorDsl> data = productFlavors.get(productFlavor.getName()); |
| testVariantProviders.add(data.getTestProvider()); |
| } |
| |
| // now add the default config |
| testVariantProviders.add(basePlugin.getDefaultConfigData().getTestProvider()); |
| |
| assert(testVariantConfig.getTestedConfig() != null); |
| if (testVariantConfig.getTestedConfig().getType() == VariantConfiguration.Type.LIBRARY) { |
| testVariantProviders.add(testedVariantData.getVariantDependency()); |
| } |
| |
| // If the variant being tested is a library variant, VariantDependencies must be |
| // computed the tasks for the tested variant is created. Therefore, the |
| // VariantDependencies is computed here instead of when the VariantData was created. |
| VariantDependencies variantDep = VariantDependencies.compute( |
| project, testVariantConfig.getFullName(), |
| false /*publishVariant*/, |
| variantFactory.isLibrary(), |
| testVariantProviders.toArray( |
| new ConfigurationProvider[testVariantProviders.size()])); |
| variantData.setVariantDependency(variantDep); |
| |
| basePlugin.resolveDependencies(variantDep); |
| testVariantConfig.setDependencies(variantDep); |
| basePlugin.createTestApkTasks((TestVariantData) variantData); |
| } else { |
| if (productFlavors.isEmpty()) { |
| variantFactory.createTasks( |
| variantData, |
| buildTypes.get( |
| variantData.getVariantConfiguration().getBuildType().getName()) |
| .getAssembleTask()); |
| } else { |
| variantFactory.createTasks(variantData, null); |
| |
| // setup the task dependencies |
| // build type |
| buildTypes.get(variantData.getVariantConfiguration().getBuildType().getName()) |
| .getAssembleTask().dependsOn(variantData.assembleVariantTask); |
| |
| // each flavor |
| GradleVariantConfiguration variantConfig = variantData.getVariantConfiguration(); |
| for (GroupableProductFlavorDsl flavor : variantConfig.getProductFlavors()) { |
| productFlavors.get(flavor.getName()).getAssembleTask() |
| .dependsOn(variantData.assembleVariantTask); |
| } |
| |
| Task assembleTask = null; |
| // assembleTask for this flavor(dimension), created on demand if needed. |
| if (variantConfig.getProductFlavors().size() > 1) { |
| String name = StringHelper.capitalize(variantConfig.getFlavorName()); |
| assembleTask = tasks.findByName("assemble" + name); |
| if (assembleTask == null) { |
| assembleTask = tasks.create("assemble" + name); |
| assembleTask.setDescription( |
| "Assembles all builds for flavor combination: " + name); |
| assembleTask.setGroup("Build"); |
| |
| tasks.getByName("assemble").dependsOn(assembleTask); |
| } |
| } |
| // flavor combo |
| if (assembleTask != null) { |
| assembleTask.dependsOn(variantData.assembleVariantTask); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Create all variants. |
| * |
| * @param signingOverride a signing override. Generally driven through the IDE. |
| */ |
| public void populateVariantDataList(@Nullable SigningConfig signingOverride) { |
| // Add a compile lint task |
| basePlugin.createLintCompileTask(); |
| |
| if (productFlavors.isEmpty()) { |
| createVariantDataForProductFlavors(signingOverride, |
| Collections.<GroupableProductFlavor>emptyList()); |
| } else { |
| List<String> flavorDimensionList = extension.getFlavorDimensionList(); |
| |
| // Create iterable to get GroupableProductFlavorDsl from ProductFlavorData. |
| Iterable<GroupableProductFlavorDsl> flavorDsl = |
| Iterables.transform( |
| productFlavors.values(), |
| new Function<ProductFlavorData<GroupableProductFlavorDsl>, GroupableProductFlavorDsl>() { |
| @Override |
| public GroupableProductFlavorDsl apply( |
| ProductFlavorData<GroupableProductFlavorDsl> data) { |
| return data.getProductFlavor(); |
| } |
| }); |
| |
| // Get a list of all combinations of product flavors. |
| List<ProductFlavorCombo> flavorComboList = ProductFlavorCombo.createCombinations( |
| flavorDimensionList, |
| flavorDsl); |
| |
| for (ProductFlavorCombo flavorCombo : flavorComboList) { |
| createVariantDataForProductFlavors(signingOverride, flavorCombo.getFlavorList()); |
| } |
| } |
| } |
| |
| /** |
| * Create a VariantData for a specific combination of BuildType and GroupableProductFlavor list. |
| */ |
| public BaseVariantData<? extends BaseVariantOutputData> createVariantData( |
| @NonNull BuildType buildType, |
| @NonNull List<GroupableProductFlavor> productFlavorList, |
| @Nullable SigningConfig signingOverride) { |
| Splits splits = basePlugin.getExtension().getSplits(); |
| Set<String> densities = splits.getDensityFilters(); |
| Set<String> abis = splits.getAbiFilters(); |
| |
| // check against potentially empty lists. We always need to generate at least one output |
| densities = densities.isEmpty() ? Collections.singleton(NO_FILTER) : densities; |
| abis = abis.isEmpty() ? Collections.singleton(NO_FILTER) : abis; |
| |
| ProductFlavorData<ProductFlavorDsl> defaultConfigData = basePlugin.getDefaultConfigData(); |
| |
| ProductFlavorDsl defaultConfig = defaultConfigData.getProductFlavor(); |
| DefaultAndroidSourceSet defaultConfigSourceSet = defaultConfigData.getSourceSet(); |
| |
| BuildTypeData buildTypeData = buildTypes.get(buildType.getName()); |
| |
| Set<String> compatibleScreens = basePlugin.getExtension().getSplits().getDensity() |
| .getCompatibleScreens(); |
| |
| GradleVariantConfiguration variantConfig = new GradleVariantConfiguration( |
| defaultConfig, |
| defaultConfigSourceSet, |
| buildTypeData.getBuildType(), |
| buildTypeData.getSourceSet(), |
| variantFactory.getVariantConfigurationType(), |
| signingOverride); |
| |
| // Add the container of dependencies. |
| // The order of the libraries is important, in descending order: |
| // build types, flavors, defaultConfig. |
| final List<ConfigurationProvider> variantProviders = |
| Lists.newArrayListWithCapacity(productFlavorList.size() + 2); |
| |
| variantProviders.add(buildTypeData); |
| |
| for (GroupableProductFlavor productFlavor : productFlavorList) { |
| ProductFlavorData<GroupableProductFlavorDsl> data = productFlavors.get(productFlavor.getName()); |
| |
| String dimensionName = productFlavor.getFlavorDimension(); |
| if (dimensionName == null) { |
| dimensionName = ""; |
| } |
| |
| variantConfig.addProductFlavor( |
| data.getProductFlavor(), |
| data.getSourceSet(), |
| dimensionName); |
| variantProviders.add(data.getMainProvider()); |
| } |
| |
| // now add the defaultConfig |
| variantProviders.add(defaultConfigData.getMainProvider()); |
| |
| // Create variant source sets if necessary. |
| NamedDomainObjectContainer<AndroidSourceSet> sourceSetsContainer = extension |
| .getSourceSetsContainer(); |
| |
| if (!productFlavorList.isEmpty()) { |
| DefaultAndroidSourceSet variantSourceSet = |
| (DefaultAndroidSourceSet) sourceSetsContainer.maybeCreate( |
| variantConfig.getFullName()); |
| variantConfig.setVariantSourceProvider(variantSourceSet); |
| // TODO: hmm this won't work |
| //variantProviders.add(new ConfigurationProviderImpl(project, variantSourceSet)) |
| } |
| |
| if (productFlavorList.size() > 1) { |
| DefaultAndroidSourceSet multiFlavorSourceSet = |
| (DefaultAndroidSourceSet) sourceSetsContainer.maybeCreate( |
| variantConfig.getFlavorName()); |
| variantConfig.setMultiFlavorSourceProvider(multiFlavorSourceSet); |
| // TODO: hmm this won't work |
| //variantProviders.add(new ConfigurationProviderImpl(project, multiFlavorSourceSet)) |
| } |
| |
| // create the variant and get its internal storage object. |
| BaseVariantData<?> variantData = variantFactory.createVariantData(variantConfig, |
| densities, abis, compatibleScreens); |
| |
| VariantDependencies variantDep = VariantDependencies.compute( |
| project, variantConfig.getFullName(), |
| isVariantPublished(), |
| variantFactory.isLibrary(), |
| variantProviders.toArray(new ConfigurationProvider[variantProviders.size()])); |
| variantData.setVariantDependency(variantDep); |
| |
| if (variantConfig.isMultiDexEnabled() && variantConfig.isLegacyMultiDexMode()) { |
| project.getDependencies().add( |
| variantDep.getCompileConfiguration().getName(), COM_ANDROID_SUPPORT_MULTIDEX); |
| project.getDependencies().add( |
| variantDep.getPackageConfiguration().getName(), COM_ANDROID_SUPPORT_MULTIDEX); |
| } |
| |
| basePlugin.resolveDependencies(variantDep); |
| variantConfig.setDependencies(variantDep); |
| |
| return variantData; |
| } |
| |
| /** |
| * Create a TestVariantData for the specified testedVariantData. |
| */ |
| public TestVariantData createTestVariantData( |
| BaseVariantData testedVariantData, |
| SigningConfig signingOverride) { |
| BuildTypeData testData = buildTypes.get(extension.getTestBuildType()); |
| |
| ProductFlavorData<ProductFlavorDsl> defaultConfigData = basePlugin.getDefaultConfigData(); |
| ProductFlavorDsl defaultConfig = defaultConfigData.getProductFlavor(); |
| |
| GradleVariantConfiguration testedConfig = testedVariantData.getVariantConfiguration(); |
| List<? extends GroupableProductFlavor> productFlavorList = testedConfig.getProductFlavors(); |
| |
| // handle test variant |
| GradleVariantConfiguration testVariantConfig = new GradleVariantConfiguration( |
| defaultConfig, |
| defaultConfigData.getTestSourceSet(), |
| testData.getBuildType(), |
| null, |
| VariantConfiguration.Type.TEST, |
| testedVariantData.getVariantConfiguration(), |
| signingOverride); |
| |
| for (GroupableProductFlavor productFlavor : productFlavorList) { |
| ProductFlavorData<GroupableProductFlavorDsl> data = productFlavors |
| .get(productFlavor.getName()); |
| |
| String dimensionName = productFlavor.getFlavorDimension(); |
| if (dimensionName == null) { |
| dimensionName = ""; |
| } |
| testVariantConfig.addProductFlavor( |
| data.getProductFlavor(), |
| data.getTestSourceSet(), |
| dimensionName); |
| } |
| |
| // create the internal storage for this variant. |
| TestVariantData testVariantData = new TestVariantData( |
| basePlugin, testVariantConfig, (TestedVariantData) testedVariantData); |
| // link the testVariant to the tested variant in the other direction |
| ((TestedVariantData) testedVariantData).setTestVariantData(testVariantData); |
| |
| return testVariantData; |
| } |
| |
| /** |
| * Creates VariantData for a specified list of product flavor. |
| * |
| * This will create VariantData for all build types of the given flavors. |
| * |
| * @param signingOverride a signing override. Generally driven through the IDE. |
| * @param productFlavorList the flavor(s) to build. |
| */ |
| private void createVariantDataForProductFlavors( |
| @Nullable SigningConfig signingOverride, |
| @NonNull List<GroupableProductFlavor> productFlavorList) { |
| BuildTypeData testData = buildTypes.get(extension.getTestBuildType()); |
| if (testData == null) { |
| throw new RuntimeException(String.format( |
| "Test Build Type '%1$s' does not exist.", extension.getTestBuildType())); |
| } |
| |
| BaseVariantData testedVariantData = null; |
| |
| ProductFlavorData<ProductFlavorDsl> defaultConfigData = basePlugin.getDefaultConfigData(); |
| ProductFlavorDsl defaultConfig = defaultConfigData.getProductFlavor(); |
| |
| Closure<Void> variantFilterClosure = basePlugin.getExtension().getVariantFilter(); |
| |
| for (BuildTypeData buildTypeData : buildTypes.values()) { |
| boolean ignore = false; |
| if (variantFilterClosure != null) { |
| variantFilter.reset(defaultConfig, buildTypeData.getBuildType(), productFlavorList); |
| variantFilterClosure.call(variantFilter); |
| ignore = variantFilter.isIgnore(); |
| } |
| |
| if (!ignore) { |
| BaseVariantData<?> variantData = createVariantData( |
| buildTypeData.getBuildType(), |
| productFlavorList, |
| signingOverride); |
| variantDataList.add(variantData); |
| |
| if (buildTypeData == testData) { |
| GradleVariantConfiguration variantConfig = variantData.getVariantConfiguration(); |
| if (variantConfig.isMinifyEnabled() && variantConfig.getUseJack()) { |
| throw new RuntimeException("Cannot test obfuscated variants when compiling with jack."); |
| } |
| testedVariantData = variantData; |
| } |
| } |
| } |
| |
| if (testedVariantData != null) { |
| TestVariantData testVariantData = |
| createTestVariantData(testedVariantData, signingOverride); |
| variantDataList.add(testVariantData); |
| } |
| } |
| |
| private void createApiObjects() { |
| // we always want to have the test/tested objects created at the same time |
| // so that dynamic closure call on add can have referenced objects created. |
| // This means some objects are created before they are processed from the loop, |
| // so we store whether we have processed them or not. |
| Map<BaseVariantData, BaseVariant> map = Maps.newHashMap(); |
| for (BaseVariantData variantData : variantDataList) { |
| if (map.get(variantData) != null) { |
| continue; |
| } |
| |
| if (variantData instanceof TestVariantData) { |
| TestVariantData testVariantData = (TestVariantData) variantData; |
| createVariantApiObjects( |
| map, |
| (BaseVariantData) testVariantData.getTestedVariantData(), |
| testVariantData); |
| } else { |
| createVariantApiObjects( |
| map, |
| variantData, |
| ((TestedVariantData) variantData).getTestVariantData()); |
| } |
| } |
| } |
| |
| private boolean isVariantPublished() { |
| return extension.getPublishNonDefault(); |
| } |
| |
| private void createVariantApiObjects( |
| @NonNull Map<BaseVariantData, BaseVariant> map, |
| @NonNull BaseVariantData<?> variantData, |
| @Nullable TestVariantData testVariantData) { |
| BaseVariant variantApi = variantFactory.createVariantApi(variantData, |
| readOnlyObjectProvider); |
| |
| TestVariantImpl testVariant = null; |
| if (testVariantData != null) { |
| testVariant = basePlugin.getInstantiator().newInstance( |
| TestVariantImpl.class, testVariantData, basePlugin, readOnlyObjectProvider); |
| |
| // add the test output. |
| ApplicationVariantFactory.createApkOutputApiObjects(basePlugin, testVariantData, testVariant); |
| } |
| |
| if (testVariant != null) { |
| ((TestedVariant) variantApi).setTestVariant(testVariant); |
| testVariant.setTestedVariant(variantApi); |
| } |
| |
| extension.addVariant(variantApi); |
| map.put(variantData, variantApi); |
| |
| if (testVariant != null) { |
| extension.addTestVariant(testVariant); |
| map.put(testVariantData, testVariant); |
| } |
| } |
| |
| private static void checkName(@NonNull String name, @NonNull String displayName) { |
| if (name.startsWith(ANDROID_TEST)) { |
| throw new RuntimeException(String.format( |
| "%1$s names cannot start with '%2$s'", displayName, ANDROID_TEST)); |
| } |
| |
| if (name.startsWith(UI_TEST)) { |
| throw new RuntimeException(String.format( |
| "%1$s names cannot start with %2$s", displayName, UI_TEST)); |
| } |
| |
| if (LINT.equals(name)) { |
| throw new RuntimeException(String.format( |
| "%1$s names cannot be %2$s", displayName, LINT)); |
| } |
| } |
| } |