blob: 3bdf9d089aad35222c59b7637e58d58156682766 [file] [log] [blame]
/*
* Copyright (C) 2017 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.variant;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.build.VariantOutput;
import com.android.build.api.artifact.impl.ArtifactsImpl;
import com.android.build.api.component.impl.DeviceTestImpl;
import com.android.build.api.component.impl.HostTestImpl;
import com.android.build.api.component.impl.TestFixturesImpl;
import com.android.build.api.component.impl.UnitTestImpl;
import com.android.build.api.dsl.CommonExtension;
import com.android.build.api.variant.ComponentIdentity;
import com.android.build.api.variant.VariantBuilder;
import com.android.build.api.variant.impl.DeviceTestBuilderImpl;
import com.android.build.api.variant.impl.HostTestBuilderImpl;
import com.android.build.gradle.internal.BuildTypeData;
import com.android.build.gradle.internal.ProductFlavorData;
import com.android.build.gradle.internal.api.BaseVariantImpl;
import com.android.build.gradle.internal.api.ReadOnlyObjectProvider;
import com.android.build.gradle.internal.component.ComponentCreationConfig;
import com.android.build.gradle.internal.component.DeviceTestCreationConfig;
import com.android.build.gradle.internal.component.HostTestCreationConfig;
import com.android.build.gradle.internal.component.TestFixturesCreationConfig;
import com.android.build.gradle.internal.component.VariantCreationConfig;
import com.android.build.gradle.internal.core.VariantSources;
import com.android.build.gradle.internal.core.dsl.AndroidTestComponentDslInfo;
import com.android.build.gradle.internal.core.dsl.HostTestComponentDslInfo;
import com.android.build.gradle.internal.core.dsl.TestFixturesComponentDslInfo;
import com.android.build.gradle.internal.core.dsl.VariantDslInfo;
import com.android.build.gradle.internal.dependency.VariantDependencies;
import com.android.build.gradle.internal.dsl.BuildType;
import com.android.build.gradle.internal.dsl.DefaultConfig;
import com.android.build.gradle.internal.dsl.ProductFlavor;
import com.android.build.gradle.internal.dsl.SigningConfig;
import com.android.build.gradle.internal.scope.BuildFeatureValues;
import com.android.build.gradle.internal.scope.MutableTaskContainer;
import com.android.build.gradle.internal.scope.UnitTestBuildFeatureValuesImpl;
import com.android.build.gradle.internal.services.DslServices;
import com.android.build.gradle.internal.services.TaskCreationServices;
import com.android.build.gradle.internal.services.VariantServices;
import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig;
import com.android.build.gradle.options.BooleanOption;
import com.android.builder.errors.IssueReporter;
import com.android.builder.errors.IssueReporter.Type;
import org.gradle.api.Project;
/** Common superclass for all {@link VariantFactory} implementations. */
public abstract class BaseVariantFactory<
VariantBuilderT extends VariantBuilder,
VariantDslInfoT extends VariantDslInfo,
VariantT extends VariantCreationConfig>
implements VariantFactory<VariantBuilderT, VariantDslInfoT, VariantT> {
private static final String ANDROID_APT_PLUGIN_NAME = "com.neenbedankt.android-apt";
@NonNull protected final DslServices dslServices;
public BaseVariantFactory(@NonNull DslServices dslServices) {
this.dslServices = dslServices;
}
@NonNull
@Override
public TestFixturesCreationConfig createTestFixtures(
@NonNull ComponentIdentity componentIdentity,
@NonNull BuildFeatureValues buildFeatures,
@NonNull TestFixturesComponentDslInfo dslInfo,
@NonNull VariantDependencies variantDependencies,
@NonNull VariantSources variantSources,
@NonNull VariantPathHelper paths,
@NonNull ArtifactsImpl artifacts,
@NonNull MutableTaskContainer taskContainer,
@NonNull VariantCreationConfig mainVariant,
@NonNull VariantServices variantServices,
@NonNull TaskCreationServices taskCreationServices,
@NonNull GlobalTaskCreationConfig globalConfig) {
return dslServices.newInstance(
TestFixturesImpl.class,
componentIdentity,
buildFeatures,
dslInfo,
variantDependencies,
variantSources,
paths,
artifacts,
taskContainer,
mainVariant,
variantServices,
taskCreationServices,
globalConfig);
}
@NonNull
@Override
public HostTestCreationConfig createUnitTest(
@NonNull ComponentIdentity componentIdentity,
@NonNull BuildFeatureValues buildFeatures,
@NonNull HostTestComponentDslInfo dslInfo,
@NonNull VariantDependencies variantDependencies,
@NonNull VariantSources variantSources,
@NonNull VariantPathHelper paths,
@NonNull ArtifactsImpl artifacts,
@NonNull TestVariantData variantData,
@NonNull MutableTaskContainer taskContainer,
@NonNull VariantCreationConfig testedVariant,
@NonNull VariantServices variantServices,
@NonNull TaskCreationServices taskCreationServices,
@NonNull GlobalTaskCreationConfig globalConfig,
@NonNull HostTestBuilderImpl hostTestBuilder) {
return dslServices.newInstance(
UnitTestImpl.class,
componentIdentity,
createUnitTestBuildFeatures(buildFeatures),
dslInfo,
variantDependencies,
variantSources,
paths,
artifacts,
variantData,
taskContainer,
testedVariant,
variantServices,
taskCreationServices,
globalConfig,
hostTestBuilder);
}
@NonNull
@Override
public HostTestCreationConfig createHostTest(
@NonNull ComponentIdentity componentIdentity,
@NonNull BuildFeatureValues buildFeatures,
@NonNull HostTestComponentDslInfo dslInfo,
@NonNull VariantDependencies variantDependencies,
@NonNull VariantSources variantSources,
@NonNull VariantPathHelper paths,
@NonNull ArtifactsImpl artifacts,
@NonNull TestVariantData variantData,
@NonNull MutableTaskContainer taskContainer,
@NonNull VariantCreationConfig testedVariant,
@NonNull VariantServices variantServices,
@NonNull TaskCreationServices taskCreationServices,
@NonNull GlobalTaskCreationConfig globalConfig,
@NonNull HostTestBuilderImpl hostTestBuilder,
@NonNull String hostTestName,
boolean useBuiltInKotlinSupport) {
return dslServices.newInstance(
HostTestImpl.class,
componentIdentity,
createUnitTestBuildFeatures(buildFeatures), // TODO
dslInfo,
variantDependencies,
variantSources,
paths,
artifacts,
variantData,
taskContainer,
testedVariant,
variantServices,
taskCreationServices,
globalConfig,
hostTestBuilder,
hostTestName,
useBuiltInKotlinSupport);
}
@NonNull
@Override
public DeviceTestCreationConfig createAndroidTest(
@NonNull ComponentIdentity componentIdentity,
@NonNull BuildFeatureValues buildFeatures,
@NonNull AndroidTestComponentDslInfo dslInfo,
@NonNull VariantDependencies variantDependencies,
@NonNull VariantSources variantSources,
@NonNull VariantPathHelper paths,
@NonNull ArtifactsImpl artifacts,
@NonNull TestVariantData variantData,
@NonNull MutableTaskContainer taskContainer,
@NonNull VariantCreationConfig testedVariant,
@NonNull VariantServices variantServices,
@NonNull TaskCreationServices taskCreationServices,
@NonNull GlobalTaskCreationConfig globalConfig,
@NonNull DeviceTestBuilderImpl deviceTestBuilder) {
return dslServices.newInstance(
DeviceTestImpl.class,
componentIdentity,
buildFeatures,
dslInfo,
variantDependencies,
variantSources,
paths,
artifacts,
variantData,
taskContainer,
testedVariant,
variantServices,
taskCreationServices,
globalConfig,
deviceTestBuilder);
}
@Nullable
@Override
public BaseVariantImpl createVariantApi(
@NonNull ComponentCreationConfig component,
@NonNull BaseVariantData variantData,
@NonNull ReadOnlyObjectProvider readOnlyObjectProvider) {
Class<? extends BaseVariantImpl> implementationClass =
getVariantImplementationClass();
return dslServices.newInstance(
implementationClass,
variantData,
component,
dslServices,
readOnlyObjectProvider,
dslServices.domainObjectContainer(VariantOutput.class));
}
@Override
public void preVariantCallback(
@NonNull Project project,
@NonNull CommonExtension<?, ?, ?, ?, ?, ?> dslExtension,
@NonNull
VariantInputModel<DefaultConfig, BuildType, ProductFlavor, SigningConfig>
model) {
if (project.getPluginManager().hasPlugin(ANDROID_APT_PLUGIN_NAME)) {
dslServices
.getIssueReporter()
.reportError(
Type.INCOMPATIBLE_PLUGIN,
"android-apt plugin is incompatible with the Android Gradle plugin. "
+ "Please use 'annotationProcessor' configuration "
+ "instead.",
"android-apt");
}
validateBuildConfig(model, dslExtension.getBuildFeatures().getBuildConfig());
validateResValues(model, dslExtension.getBuildFeatures().getResValues());
}
void validateBuildConfig(
@NonNull
VariantInputModel<DefaultConfig, BuildType, ProductFlavor, SigningConfig> model,
@Nullable Boolean buildConfig) {
if (buildConfig == null) {
buildConfig =
dslServices.getProjectOptions().get(BooleanOption.BUILD_FEATURE_BUILDCONFIG);
}
if (!buildConfig) {
IssueReporter issueReporter = dslServices.getIssueReporter();
String suggestion =
"To enable the feature, add the following to your module-level build.gradle:\n"
+ "`android.buildFeatures.buildConfig true`";
if (!model.getDefaultConfigData().getDefaultConfig().getBuildConfigFields().isEmpty()) {
issueReporter.reportError(
Type.GENERIC,
"defaultConfig contains custom BuildConfig fields, but the feature is disabled.\n"
+ suggestion);
}
for (BuildTypeData<BuildType> buildType : model.getBuildTypes().values()) {
if (!buildType.getBuildType().getBuildConfigFields().isEmpty()) {
issueReporter.reportError(
Type.GENERIC,
String.format(
"Build Type '%s' contains custom BuildConfig fields, but the feature is disabled.\n"
+ suggestion,
buildType.getBuildType().getName()));
}
}
for (ProductFlavorData<ProductFlavor> productFlavor :
model.getProductFlavors().values()) {
if (!productFlavor.getProductFlavor().getBuildConfigFields().isEmpty()) {
issueReporter.reportError(
Type.GENERIC,
String.format(
"Product Flavor '%s' contains custom BuildConfig fields, but the feature is disabled.\n"
+ suggestion,
productFlavor.getProductFlavor().getName()));
}
}
}
}
void validateResValues(
@NonNull
VariantInputModel<DefaultConfig, BuildType, ProductFlavor, SigningConfig> model,
@Nullable Boolean resValues) {
if (resValues == null) {
resValues = dslServices.getProjectOptions().get(BooleanOption.BUILD_FEATURE_RESVALUES);
}
if (!resValues) {
IssueReporter issueReporter = dslServices.getIssueReporter();
if (!model.getDefaultConfigData().getDefaultConfig().getResValues().isEmpty()) {
issueReporter.reportError(
Type.GENERIC,
"defaultConfig contains custom resource values, but the feature is disabled.");
}
for (BuildTypeData<BuildType> buildType : model.getBuildTypes().values()) {
if (!buildType.getBuildType().getResValues().isEmpty()) {
issueReporter.reportError(
Type.GENERIC,
String.format(
"Build Type '%s' contains custom resource values, but the feature is disabled.",
buildType.getBuildType().getName()));
}
}
for (ProductFlavorData<ProductFlavor> productFlavor :
model.getProductFlavors().values()) {
if (!productFlavor.getProductFlavor().getResValues().isEmpty()) {
issueReporter.reportError(
Type.GENERIC,
String.format(
"Product Flavor '%s' contains custom resource values, but the feature is disabled.",
productFlavor.getProductFlavor().getName()));
}
}
}
}
private BuildFeatureValues createUnitTestBuildFeatures(
BuildFeatureValues testedVariantBuildFeatures) {
return new UnitTestBuildFeatureValuesImpl(testedVariantBuildFeatures);
}
}