am 105fa073: am 6fb1677d: Merge changes I221533ec,I5a8d2ed2 into studio-1.3-dev automerge: 26d0c75 automerge: 815c49f

* commit '105fa073e81382d7911b05a7f79508a99cec486d':
  Refactor most application tasks to use CollectionBuilder<Task>
  Refactor a number to tasks to use AndroidTaskRegistry.
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/ApplicationTaskManager.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/ApplicationTaskManager.groovy
index 87f35cf..6f43460 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/ApplicationTaskManager.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/ApplicationTaskManager.groovy
@@ -25,6 +25,8 @@
 import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.android.builder.core.AndroidBuilder
 import com.android.builder.profile.ExecutionType
+import com.android.builder.profile.Recorder
+import com.android.builder.profile.ThreadRecorder
 import org.gradle.api.Project
 import org.gradle.api.artifacts.Configuration
 import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
@@ -50,56 +52,57 @@
         assert variantData instanceof ApplicationVariantData;
         ApplicationVariantData appVariantData = (ApplicationVariantData) variantData;
 
-        createAnchorTasks(variantData);
-        createCheckManifestTask(variantData);
+        VariantScope variantScope = variantData.getScope()
 
-        handleMicroApp(variantData);
+        createAnchorTasks(tasks, variantScope);
+        createCheckManifestTask(tasks, variantScope);
+
+        handleMicroApp(tasks, variantScope);
 
         // Add a task to process the manifest(s)
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_MANIFEST_TASK) {
-            createMergeAppManifestsTask(variantData)
+            createMergeAppManifestsTask(tasks, variantScope)
         }
 
         // Add a task to create the res values
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_GENERATE_RES_VALUES_TASK) {
-            createGenerateResValuesTask(variantData);
+            createGenerateResValuesTask(tasks, variantScope);
         }
 
         // Add a task to compile renderscript files.
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_CREATE_RENDERSCRIPT_TASK) {
-            createRenderscriptTask(variantData);
+            createRenderscriptTask(tasks, variantScope);
         }
 
         // Add a task to merge the resource folders
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_RESOURCES_TASK) {
-            createMergeResourcesTask(variantData, true /*process9Patch*/);
+            createMergeResourcesTask(tasks, variantScope);
         }
 
         // Add a task to merge the asset folders
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_MERGE_ASSETS_TASK) {
-            createMergeAssetsTask(
-                    variantData, null /*default location*/, true /*includeDependencies*/);
+            createMergeAssetsTask(tasks, variantScope);
         }
 
         // Add a task to create the BuildConfig class
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_BUILD_CONFIG_TASK) {
-            createBuildConfigTask(variantData);
+            createBuildConfigTask(tasks, variantScope);
         }
 
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_PREPROCESS_RESOURCES_TASK) {
-            createPreprocessResourcesTask(variantData)
+            createPreprocessResourcesTask(tasks, variantScope)
         }
 
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_PROCESS_RES_TASK) {
             // Add a task to process the Android Resources and generate source files
-            createProcessResTask(variantData, true /*generateResourcePackage*/);
+            createProcessResTask(tasks, variantScope, true /*generateResourcePackage*/);
 
             // Add a task to process the java resources
-            createProcessJavaResTask(variantData);
+            createProcessJavaResTask(tasks, variantScope);
         }
 
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_AIDL_TASK) {
-            createAidlTask(variantData, null /*parcelableDir*/);
+            createAidlTask(tasks, variantScope);
         }
 
         // Add a compile task
@@ -107,9 +110,9 @@
             if (variantData.getVariantConfiguration().getUseJack()) {
                 createJackTask(appVariantData, null /*testedVariant*/);
             } else {
-                createJavaCompileTask(variantData, null /*testedVariant*/);
-                createJarTask(variantData);
-                createPostCompilationTasks(appVariantData);
+                createJavaCompileTask(tasks, variantScope);
+                createJarTask(tasks, variantScope);
+                createPostCompilationTasks(tasks, variantScope);
             }
         }
 
@@ -119,11 +122,8 @@
                 createNdkTasks(variantData);
             }
         }
-
-        // Variant scope should be created at the beginning of the function, but there is currently
-        // a dependency on the NdkCompile tasks, and the scope mechanism does not support lazy
-        // evaluation yet.
-        VariantScope variantScope = createVariantScope(variantData);
+        variantScope.setNdkBuildable(getNdkBuildable(variantData))
+        variantScope.setNdkOutputDirectories(getNdkOutputDirectories(variantData))
 
         if (variantData.getSplitHandlingPolicy() ==
                 BaseVariantData.SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY) {
@@ -131,20 +131,27 @@
                 throw new RuntimeException("Pure splits can only be used with buildtools 21 and later")
             }
             SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_SPLIT_TASK) {
-                createSplitResourcesTasks(appVariantData);
-                createSplitAbiTasks(appVariantData);
+                createSplitResourcesTasks(variantScope);
+                createSplitAbiTasks(variantScope);
             }
         }
         SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_PACKAGING_TASK) {
             createPackagingTask(tasks, variantScope, true /*publishApk*/);
         }
+
+        // create the lint tasks.
+        SpanRecorders.record(ExecutionType.APP_TASK_MANAGER_CREATE_LINT_TASK) {
+            createLintTasks(tasks, variantScope);
+        }
     }
 
     /**
      * Configure variantData to generate embedded wear application.
      */
     private void handleMicroApp(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
         if (variantData.getVariantConfiguration().getBuildType().isEmbedMicroApp()) {
             // get all possible configurations for the variant. We'll take the highest priority
             // of them that have a file.
@@ -162,7 +169,7 @@
 
                 int count = file.size();
                 if (count == 1) {
-                    createGenerateMicroApkDataTask(variantData, config);
+                    createGenerateMicroApkDataTask(tasks, scope, config);
                     // found one, bail out.
                     return;
                 } else if (count > 1) {
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/DependencyManager.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/DependencyManager.java
index 65c1073..834a880 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/DependencyManager.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/DependencyManager.java
@@ -21,6 +21,7 @@
 import com.android.build.gradle.internal.dependency.JarInfo;
 import com.android.build.gradle.internal.dependency.LibInfo;
 import com.android.build.gradle.internal.dependency.LibraryDependencyImpl;
+import com.android.build.gradle.internal.dependency.ManifestDependencyImpl;
 import com.android.build.gradle.internal.dependency.VariantDependencies;
 import com.android.build.gradle.internal.model.MavenCoordinatesImpl;
 import com.android.build.gradle.internal.tasks.PrepareDependenciesTask;
@@ -973,6 +974,21 @@
                 JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME, "compile");
     }
 
+    @NonNull
+    public static List<ManifestDependencyImpl> getManifestDependencies(
+            List<LibraryDependency> libraries) {
+
+        List<ManifestDependencyImpl> list = Lists.newArrayListWithCapacity(libraries.size());
+
+        for (LibraryDependency lib : libraries) {
+            // get the dependencies
+            List<ManifestDependencyImpl> children = getManifestDependencies(lib.getDependencies());
+            list.add(new ManifestDependencyImpl(lib.getName(), lib.getManifest(), children));
+        }
+
+        return list;
+    }
+
     /**
      * Adds a dependency on tasks with the specified name in other projects.  The other projects
      * are determined from project lib dependencies using the specified configuration name.
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/LibraryTaskManager.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/LibraryTaskManager.groovy
index 9bdd860..34664b9 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/LibraryTaskManager.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/LibraryTaskManager.groovy
@@ -22,6 +22,8 @@
 import com.android.build.gradle.LibraryExtension
 import com.android.build.gradle.internal.core.GradleVariantConfiguration
 import com.android.build.gradle.internal.profile.SpanRecorders
+import com.android.build.gradle.internal.scope.AndroidTask
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.MergeFileTask
 import com.android.build.gradle.internal.variant.BaseVariantData
 import com.android.build.gradle.internal.variant.BaseVariantOutputData
@@ -33,6 +35,7 @@
 import com.android.builder.core.AndroidBuilder
 import com.android.builder.core.BuilderConstants
 import com.android.builder.core.DefaultBuildType
+import com.android.builder.core.VariantType
 import com.android.builder.dependency.LibraryBundle
 import com.android.builder.dependency.LibraryDependency
 import com.android.builder.dependency.ManifestDependency
@@ -81,91 +84,92 @@
         GradleVariantConfiguration variantConfig = variantData.variantConfiguration
         DefaultBuildType buildType = variantConfig.buildType
 
+        VariantScope variantScope = variantData.getScope()
+
         String fullName = variantConfig.fullName
         String dirName = variantConfig.dirName
 
-        createAnchorTasks(variantData)
+        createAnchorTasks(tasks, variantScope)
 
-        createCheckManifestTask(variantData)
+        createCheckManifestTask(tasks, variantScope)
 
         // Add a task to create the res values
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_GENERATE_RES_VALUES_TASK) {
-            createGenerateResValuesTask(variantData);
+            createGenerateResValuesTask(tasks, variantScope)
         }
 
         // Add a task to process the manifest(s)
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_MERGE_MANIFEST_TASK) {
-            createMergeLibManifestsTask(variantData, DIR_BUNDLES)
+            createMergeLibManifestsTask(tasks, variantScope)
         }
 
         // Add a task to compile renderscript files.
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_CREATE_RENDERSCRIPT_TASK) {
-            createRenderscriptTask(variantData)
+            createRenderscriptTask(tasks, variantScope)
         }
 
-        MergeResources packageRes = SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_MERGE_RESOURCES_TASK) {
+        AndroidTask<MergeResources> packageRes = SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_MERGE_RESOURCES_TASK) {
             // Create a merge task to only merge the resources from this library and not
             // the dependencies. This is what gets packaged in the aar.
-            MergeResources packageRes = basicCreateMergeResourcesTask(variantData,
+            AndroidTask<MergeResources> mergeResourceTask = basicCreateMergeResourcesTask(
+                    tasks,
+                    variantScope,
                     "package",
-                    "$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/${dirName}/res",
+                    new File(variantScope.getGlobalScope().getIntermediatesDir(),
+                            "$DIR_BUNDLES/$variantScope.variantConfiguration.dirName/res"),
                     false /*includeDependencies*/,
-                    false /*process9Patch*/)
+                    false /*process9Patch*/);
 
-            if (variantData.variantDependency.androidDependencies.isEmpty()) {
-                // if there is no android dependencies, then we should use the packageRes task above
-                // as the only res merging task.
-                variantData.mergeResourcesTask = packageRes
-            } else {
+            if (!variantData.variantDependency.androidDependencies.isEmpty()) {
                 // Add a task to merge the resource folders, including the libraries, in order to
                 // generate the R.txt file with all the symbols, including the ones from
                 // the dependencies.
-                createMergeResourcesTask(variantData, false /*process9Patch*/)
+                createMergeResourcesTask(tasks, variantScope)
             }
 
-            variantData.mergeResourcesTask.conventionMapping.publicFile = { project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/${dirName}/${SdkConstants.FN_PUBLIC_TXT}")
+            mergeResourceTask.configure(tasks) { MergeResources task ->
+                task.conventionMapping.publicFile = {
+                    new File(variantScope.globalScope.intermediatesDir,
+                            "$DIR_BUNDLES/${dirName}/${SdkConstants.FN_PUBLIC_TXT}")
+                }
             }
 
-            return packageRes;
+            return mergeResourceTask;
         }
 
         // Add a task to merge the assets folders
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_MERGE_ASSETS_TASK) {
-            createMergeAssetsTask(variantData,
-                    "$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/${dirName}/assets",
-                    false /*includeDependencies*/)
+            createMergeAssetsTask(tasks, variantScope)
         }
 
         // Add a task to create the BuildConfig class
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_BUILD_CONFIG_TASK) {
-            createBuildConfigTask(variantData)
+            createBuildConfigTask(tasks, variantScope)
         }
 
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_BACKPORT_RESOURCES_TASK) {
-            createPreprocessResourcesTask(variantData)
+            createPreprocessResourcesTask(tasks, variantScope)
         }
 
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_PROCESS_RES_TASK) {
             // Add a task to generate resource source files, directing the location
             // of the r.txt file to be directly in the bundle.
-            createProcessResTask(variantData,
-                    "$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/${dirName}",
+            createProcessResTask(tasks, variantScope,
+                    new File("$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/${dirName}"),
                     false /*generateResourcePackage*/,
             )
 
             // process java resources
-            createProcessJavaResTask(variantData)
+            createProcessJavaResTask(tasks, variantScope)
         }
 
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_AIDL_TASK) {
-            createAidlTask(variantData, project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/${dirName}/$SdkConstants.FD_AIDL"))
+            createAidlTask(tasks, variantScope)
         }
 
         // Add a compile task
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_COMPILE_TASK) {
-            createJavaCompileTask(variantData, null /*testedVariant*/)
+            createJavaCompileTask(tasks, variantScope);
         }
 
         // package the prebuilt native libs into the bundle folder
@@ -217,7 +221,7 @@
         Copy lintCopy = project.tasks.create(
                 "copy${fullName.capitalize()}Lint",
                 Copy)
-        lintCopy.dependsOn lintCompile
+        lintCopy.dependsOn LINT_COMPILE
         lintCopy.from("$project.buildDir/${FD_INTERMEDIATES}/lint/lint.jar")
         lintCopy.into("$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/$dirName")
 
@@ -238,14 +242,14 @@
         // post-compilation steps are inserted between the compilation and dx.
         PostCompilationData pcData = new PostCompilationData()
         SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_POST_COMPILATION_TASK) {
-            pcData.classGeneratingTask = Collections.singletonList(variantData.javaCompileTask)
+            pcData.classGeneratingTask = [variantScope.javaCompileTask.name]
             pcData.libraryGeneratingTask = Collections.singletonList(
                     variantData.variantDependency.packageConfiguration.buildDependencies)
             pcData.inputFiles = {
                 return variantData.javaCompileTask.outputs.files.files
             }
             pcData.inputDir = {
-                return variantData.javaCompileTask.destinationDir
+                return variantScope.javaOutputDir
             }
             pcData.inputLibraries = {
                 return Collections.emptyList()
@@ -253,14 +257,14 @@
 
             // if needed, instrument the code
             if (instrumented) {
-                pcData = createJacocoTask(variantConfig, variantData, pcData)
+                pcData = createJacocoTask(tasks, variantScope, pcData);
             }
         }
 
         if (buildType.isMinifyEnabled()) {
             // run proguard on output of compile task
             SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_PROGUARD_TASK) {
-                File outFile = maybeCreateProguardTasks(variantData, null, pcData)
+                File outFile = maybeCreateProguardTasks(tasks, variantScope, pcData);
                 pcData.inputFiles = { [outFile] }
                 pcData.inputDir = null
                 pcData.inputLibraries = { [] }
@@ -286,14 +290,14 @@
 
                 // jar the classes.
                 Jar jar = project.tasks.create("package${fullName.capitalize()}Jar", Jar);
-                jar.dependsOn variantData.processJavaResourcesTask
+                jar.dependsOn variantScope.processJavaResourcesTask.name
 
                 // add the class files (whether they are instrumented or not.
                 jar.from(pcData.inputDir)
                 TaskManager.optionalDependsOn(jar, pcData.classGeneratingTask)
                 pcData.classGeneratingTask = Collections.singletonList(jar)
 
-                jar.from(variantData.processJavaResourcesTask.destinationDir)
+                jar.from(variantScope.getJavaResourcesDestinationDir())
 
                 jar.destinationDir = project.file(
                         "$project.buildDir/${FD_INTERMEDIATES}/$DIR_BUNDLES/${dirName}")
@@ -320,7 +324,7 @@
             }
         }
 
-        bundle.dependsOn packageRes, packageRenderscript, lintCopy, packageJniLibs, mergeProGuardFileTask
+        bundle.dependsOn packageRes.name, packageRenderscript, lintCopy, packageJniLibs, mergeProGuardFileTask
         TaskManager.optionalDependsOn(bundle, pcData.classGeneratingTask)
         TaskManager.optionalDependsOn(bundle, pcData.libraryGeneratingTask)
 
@@ -404,6 +408,10 @@
                 return getFolder();
             }
         };
+
+        SpanRecorders.record(ExecutionType.LIB_TASK_MANAGER_CREATE_LINT_TASK) {
+            createLintTasks(tasks, variantScope);
+        }
     }
 
     public ExtractAnnotations createExtractAnnotations(
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TaskManager.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TaskManager.groovy
index 7923e47..3d860a3 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TaskManager.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TaskManager.groovy
@@ -21,15 +21,12 @@
 import com.android.annotations.Nullable
 import com.android.build.OutputFile
 import com.android.build.gradle.BaseExtension
-import com.android.build.gradle.LibraryExtension
-import com.android.build.gradle.api.AndroidSourceSet
 import com.android.build.gradle.internal.core.GradleVariantConfiguration
 import com.android.build.gradle.internal.coverage.JacocoInstrumentTask
 import com.android.build.gradle.internal.coverage.JacocoPlugin
 import com.android.build.gradle.internal.coverage.JacocoReportTask
 import com.android.build.gradle.internal.dependency.LibraryDependencyImpl
 import com.android.build.gradle.internal.dependency.ManifestDependencyImpl
-import com.android.build.gradle.internal.dependency.SymbolFileProviderImpl
 import com.android.build.gradle.internal.dependency.VariantDependencies
 import com.android.build.gradle.internal.dsl.AbiSplitOptions
 import com.android.build.gradle.internal.dsl.SigningConfig
@@ -38,6 +35,7 @@
 import com.android.build.gradle.internal.publishing.MetadataPublishArtifact
 import com.android.build.gradle.internal.scope.AndroidTask
 import com.android.build.gradle.internal.scope.AndroidTaskRegistry
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
 import com.android.build.gradle.internal.scope.GlobalScope
 import com.android.build.gradle.internal.scope.VariantOutputScope
 import com.android.build.gradle.internal.scope.VariantScope
@@ -68,13 +66,13 @@
 import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.android.build.gradle.internal.variant.LibraryVariantData
 import com.android.build.gradle.internal.variant.TestVariantData
+import com.android.build.gradle.internal.variant.TestedVariantData
 import com.android.build.gradle.tasks.AidlCompile
 import com.android.build.gradle.tasks.AndroidJarTask
 import com.android.build.gradle.tasks.AndroidProGuardTask
 import com.android.build.gradle.tasks.CompatibleScreensManifest
 import com.android.build.gradle.tasks.Dex
 import com.android.build.gradle.tasks.GenerateBuildConfig
-import com.android.build.gradle.tasks.PreprocessResourcesTask
 import com.android.build.gradle.tasks.GenerateResValues
 import com.android.build.gradle.tasks.GenerateSplitAbiRes
 import com.android.build.gradle.tasks.JackTask
@@ -89,20 +87,23 @@
 import com.android.build.gradle.tasks.PackageSplitRes
 import com.android.build.gradle.tasks.PreCompilationVerificationTask
 import com.android.build.gradle.tasks.PreDex
+import com.android.build.gradle.tasks.PreprocessResourcesTask
 import com.android.build.gradle.tasks.ProcessAndroidResources
 import com.android.build.gradle.tasks.ProcessManifest
 import com.android.build.gradle.tasks.ProcessTestManifest
 import com.android.build.gradle.tasks.RenderscriptCompile
+import com.android.build.gradle.tasks.ShrinkResources
 import com.android.build.gradle.tasks.SplitZipAlign
 import com.android.build.gradle.tasks.ZipAlign
+import com.android.build.gradle.tasks.factory.JavaCompileConfigAction
+import com.android.build.gradle.tasks.factory.ProGuardTaskConfigAction
+import com.android.build.gradle.tasks.factory.ProcessJavaResConfigAction
 import com.android.builder.core.AndroidBuilder
 import com.android.builder.core.VariantConfiguration
 import com.android.builder.core.VariantType
 import com.android.builder.dependency.LibraryDependency
 import com.android.builder.internal.testing.SimpleTestCallable
-import com.android.builder.model.ApiVersion
-import com.android.builder.model.ProductFlavor
-import com.android.builder.model.SourceProvider
+import com.android.builder.model.AndroidProject
 import com.android.builder.testing.ConnectedDeviceProvider
 import com.android.builder.testing.TestData
 import com.android.builder.testing.api.DeviceProvider
@@ -111,8 +112,6 @@
 import com.android.sdklib.AndroidTargetHash
 import com.android.sdklib.BuildToolInfo
 import com.android.sdklib.IAndroidTarget
-import com.android.sdklib.SdkVersionInfo
-import com.android.sdklib.repository.FullRevision
 import com.google.common.base.CharMatcher
 import com.google.common.collect.ImmutableList
 import com.google.common.collect.ImmutableSet
@@ -121,13 +120,13 @@
 import com.google.common.collect.Sets
 import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
+import org.gradle.api.DefaultTask
 import org.gradle.api.GradleException
 import org.gradle.api.JavaVersion
 import org.gradle.api.Project
 import org.gradle.api.Task
 import org.gradle.api.artifacts.Configuration
 import org.gradle.api.execution.TaskExecutionGraph
-import org.gradle.api.file.FileCollection
 import org.gradle.api.internal.ConventionMapping
 import org.gradle.api.logging.LogLevel
 import org.gradle.api.logging.Logger
@@ -142,12 +141,10 @@
 import org.gradle.api.tasks.compile.JavaCompile
 import org.gradle.api.tasks.testing.Test
 import org.gradle.api.tasks.testing.TestTaskReports
-import org.gradle.language.jvm.tasks.ProcessResources
-import org.gradle.tooling.BuildException
 import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
 import proguard.gradle.ProGuardTask
 
-import static com.android.SdkConstants.FN_ANDROID_MANIFEST_XML
+import static com.android.build.OutputFile.DENSITY
 import static com.android.builder.core.BuilderConstants.CONNECTED
 import static com.android.builder.core.BuilderConstants.DEVICE
 import static com.android.builder.core.BuilderConstants.FD_ANDROID_RESULTS
@@ -157,14 +154,12 @@
 import static com.android.builder.core.BuilderConstants.FD_REPORTS
 import static com.android.builder.core.VariantType.ANDROID_TEST
 import static com.android.builder.core.VariantType.DEFAULT
-import static com.android.builder.core.VariantType.LIBRARY
 import static com.android.builder.core.VariantType.UNIT_TEST
 import static com.android.builder.model.AndroidProject.FD_GENERATED
 import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
 import static com.android.builder.model.AndroidProject.FD_OUTPUTS
 import static com.android.builder.model.AndroidProject.PROPERTY_APK_LOCATION
 import static com.android.sdklib.BuildToolInfo.PathId.ZIP_ALIGN
-import static com.google.common.base.Preconditions.checkNotNull
 
 /**
  * Manages tasks creation.
@@ -178,11 +173,11 @@
 
     public final static String DIR_BUNDLES = "bundles";
 
-    private static final String INSTALL_GROUP = "Install"
+    public static final String INSTALL_GROUP = "Install"
 
-    private static final String BUILD_GROUP = BasePlugin.BUILD_GROUP
+    public static final String BUILD_GROUP = BasePlugin.BUILD_GROUP
 
-    private static final String ANDROID_GROUP = "Android"
+    public static final String ANDROID_GROUP = "Android"
 
     protected Project project
 
@@ -194,7 +189,7 @@
 
     protected BaseExtension extension
 
-    private ToolingModelBuilderRegistry toolingRegistry
+    protected ToolingModelBuilderRegistry toolingRegistry
 
     private final GlobalScope globalScope
 
@@ -205,6 +200,7 @@
     protected boolean isNdkTaskNeeded = true
 
     // Task names
+    // TODO: Convert to AndroidTask.
     private static final String MAIN_PREBUILD = "preBuild"
 
     private static final String UNINSTALL_ALL = "uninstallAll"
@@ -217,13 +213,13 @@
 
     private static final String SOURCE_SETS = "sourceSets"
 
+    private static final String LINT = "lint"
+
+    protected static final String LINT_COMPILE = "compileLint"
+
     // Tasks
     private Copy jacocoAgentTask
 
-    public Task lintCompile
-
-    protected Task lintAll
-
     public MockableAndroidJarTask createMockableJar
 
     public TaskManager(
@@ -245,7 +241,9 @@
                 project,
                 androidBuilder,
                 getArchivesBaseName(project),
-                extension);
+                extension,
+                sdkHandler,
+                toolingRegistry);
     }
 
     private boolean isVerbose() {
@@ -265,6 +263,10 @@
             @NonNull TaskFactory tasks,
             @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData)
 
+    public GlobalScope getGlobalScope() {
+        return globalScope
+    }
+
     /**
      * Returns a collection of buildables that creates native object.
      *
@@ -323,6 +325,18 @@
             it.setGroup(BasePlugin.BUILD_GROUP);
             it.setDescription("Assembles all the Test applications.");
         }
+
+        tasks.create(LINT, Lint) {
+            it.description = "Runs lint on all variants."
+            it.group = JavaBasePlugin.VERIFICATION_GROUP
+            it.setLintOptions(getExtension().lintOptions)
+            it.setSdkHome(sdkHandler.getSdkFolder())
+            it.setToolingRegistry(toolingRegistry)
+        }
+        tasks.named(JavaBasePlugin.CHECK_TASK_NAME) {
+            it.dependsOn LINT
+        }
+        createLintCompileTask(tasks)
     }
 
     public void createMockableJarTask() {
@@ -348,125 +362,36 @@
     }
 
     public void createMergeAppManifestsTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope variantScope) {
 
-        VariantConfiguration config = variantData.variantConfiguration
-        ProductFlavor mergedFlavor = config.mergedFlavor
-
-        ApplicationVariantData appVariantData = variantData as ApplicationVariantData
+        ApplicationVariantData appVariantData = variantScope.variantData as ApplicationVariantData
         Set<String> screenSizes = appVariantData.getCompatibleScreens()
 
         // loop on all outputs. The only difference will be the name of the task, and location
         // of the generated manifest
-        for (BaseVariantOutputData vod : variantData.outputs) {
-            final CompatibleScreensManifest csmTask =
-                    (vod.getMainOutputFile().getFilter(OutputFile.DENSITY) != null
-                            && !screenSizes.isEmpty()) ?
-                            createCompatibleScreensManifest(vod, screenSizes) :
-                            null
-
+        for (BaseVariantOutputData vod : appVariantData.outputs) {
             // create final var inside the loop to ensure the closures will work.
             final BaseVariantOutputData variantOutputData = vod
 
-            String outputName = variantOutputData.fullName.capitalize()
-            String outputDirName = variantOutputData.dirName
+            VariantOutputScope scope = variantOutputData.getScope()
 
-            def processManifestTask = project.tasks.create(
-                    "process${outputName}Manifest",
-                    MergeManifests)
-
-            variantOutputData.manifestProcessorTask = processManifestTask
-
-            processManifestTask.androidBuilder = androidBuilder
-
-            processManifestTask.dependsOn variantData.prepareDependenciesTask
-            if (variantData.generateApkDataTask != null) {
-                processManifestTask.dependsOn variantData.generateApkDataTask
+            AndroidTask<CompatibleScreensManifest> csmTask = null;
+            if (vod.getMainOutputFile().getFilter(DENSITY) != null) {
+                csmTask = androidTasks.create(tasks,
+                        new CompatibleScreensManifest.ConfigAction(scope, screenSizes));
+                scope.compatibleScreensManifestTask = csmTask
             }
+
+            scope.manifestProcessorTask = androidTasks.create(tasks,
+                    new MergeManifests.ConfigAction(scope))
+
             if (csmTask != null) {
-                processManifestTask.dependsOn csmTask
-            }
-
-            processManifestTask.variantConfiguration = config
-            if (variantOutputData instanceof ApkVariantOutputData) {
-                processManifestTask.variantOutputData = variantOutputData as ApkVariantOutputData
-            }
-
-            conventionMapping(processManifestTask).map("libraries") {
-                List<ManifestDependencyImpl> manifests =
-                        getManifestDependencies(config.directLibraries)
-
-                if (variantData.generateApkDataTask != null &&
-                    variantData.getVariantConfiguration().getBuildType().isEmbedMicroApp()) {
-                    manifests.add(new ManifestDependencyImpl(
-                            variantData.generateApkDataTask.getManifestFile(), []))
-                }
-
-                if (csmTask != null) {
-                    manifests.add(
-                            new ManifestDependencyImpl(csmTask.getManifestFile(), []))
-                }
-
-                return manifests
-            }
-
-            conventionMapping(processManifestTask).map("minSdkVersion") {
-                if (androidBuilder.isPreviewTarget()) {
-                    return androidBuilder.getTargetCodename()
-                }
-
-                mergedFlavor.minSdkVersion?.apiString
-            }
-
-            conventionMapping(processManifestTask).map("targetSdkVersion") {
-                if (androidBuilder.isPreviewTarget()) {
-                    return androidBuilder.getTargetCodename()
-                }
-
-                return mergedFlavor.targetSdkVersion?.apiString
-            }
-
-            conventionMapping(processManifestTask).map("maxSdkVersion") {
-                if (androidBuilder.isPreviewTarget()) {
-                    return null
-                }
-
-                return mergedFlavor.maxSdkVersion
-            }
-
-            conventionMapping(processManifestTask).map("manifestOutputFile") {
-                project.file(
-                        "$project.buildDir/${FD_INTERMEDIATES}/manifests/full/" +
-                                "${outputDirName}/AndroidManifest.xml")
-            }
-
-            conventionMapping(processManifestTask).map("reportFile") {
-                project.file(
-                        "$project.buildDir/${FD_OUTPUTS}/logs/manifest-merger-${config.baseName}-report.txt")
+                scope.manifestProcessorTask.dependsOn(tasks, csmTask)
             }
         }
     }
 
-    private CompatibleScreensManifest createCompatibleScreensManifest(
-            @NonNull BaseVariantOutputData variantOutputData,
-            @NonNull Set<String> screenSizes) {
-
-        CompatibleScreensManifest csmTask = project.tasks.create(
-                "create${variantOutputData.fullName.capitalize()}CompatibleScreensManifest",
-                CompatibleScreensManifest)
-
-        csmTask.screenDensity = variantOutputData.getMainOutputFile().getFilter(OutputFile.DENSITY)
-        csmTask.screenSizes = screenSizes
-
-        conventionMapping(csmTask).map("manifestFile") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/manifests/density/" +
-                            "${variantOutputData.dirName}/AndroidManifest.xml")
-        }
-
-        return csmTask;
-    }
-
     @CompileDynamic
     private static ConventionMapping conventionMapping(Task task) {
         task.conventionMapping
@@ -482,526 +407,198 @@
     }
 
     public void createMergeLibManifestsTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @NonNull String manifestOutDir) {
-        VariantConfiguration config = variantData.variantConfiguration
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
 
-        // get single output for now.
-        BaseVariantOutputData variantOutputData = variantData.outputs.get(0)
+        AndroidTask<ProcessManifest> processManifest = androidTasks.create(tasks,
+                new ProcessManifest.ConfigAction(scope));
 
-        def processManifest = project.tasks.create(
-                "process${variantData.variantConfiguration.fullName.capitalize()}Manifest",
-                ProcessManifest)
-        variantOutputData.manifestProcessorTask = processManifest
-        processManifest.androidBuilder = androidBuilder
+        processManifest.dependsOn(tasks, scope.variantData.prepareDependenciesTask)
 
-        processManifest.dependsOn variantData.prepareDependenciesTask
-        processManifest.variantConfiguration = config
-
-        ProductFlavor mergedFlavor = config.mergedFlavor
-
-        conventionMapping(processManifest).map("minSdkVersion") {
-            if (androidBuilder.isPreviewTarget()) {
-                return androidBuilder.getTargetCodename()
-            }
-            return mergedFlavor.minSdkVersion?.apiString
-        }
-
-        conventionMapping(processManifest).map("targetSdkVersion") {
-            if (androidBuilder.isPreviewTarget()) {
-                return androidBuilder.getTargetCodename()
-            }
-
-            return mergedFlavor.targetSdkVersion?.apiString
-        }
-
-        conventionMapping(processManifest).map("maxSdkVersion") {
-            if (androidBuilder.isPreviewTarget()) {
-                return null
-            }
-
-            return mergedFlavor.maxSdkVersion
-        }
-
-        conventionMapping(processManifest).map("manifestOutputFile") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/${manifestOutDir}/" +
-                            "${variantData.variantConfiguration.dirName}/AndroidManifest.xml")
-        }
-
-        conventionMapping(processManifest).map("aaptFriendlyManifestOutputFile") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/${manifestOutDir}/" +
-                            "${variantData.variantConfiguration.dirName}/aapt/AndroidManifest.xml")
-        }
+        BaseVariantOutputData variantOutputData = scope.variantData.outputs.get(0)
+        variantOutputData.scope.manifestProcessorTask = processManifest
     }
 
     protected void createProcessTestManifestTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @NonNull String manifestOurDir) {
-        def processTestManifestTask;
-        VariantConfiguration config = variantData.variantConfiguration
-        processTestManifestTask = project.tasks.create(
-                "process${variantData.variantConfiguration.fullName.capitalize()}Manifest",
-                ProcessTestManifest)
-        conventionMapping(processTestManifestTask).map("testManifestFile") {
-            config.getMainManifest()
-        }
-        conventionMapping(processTestManifestTask).map("tmpDir") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/${manifestOurDir}/tmp")
-        }
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
 
-        // get single output for now.
-        BaseVariantOutputData variantOutputData = variantData.outputs.get(0)
+        AndroidTask<ProcessTestManifest> processTestManifestTask = androidTasks.create(tasks,
+                new ProcessTestManifest.ConfigAction(scope));
 
-        variantOutputData.manifestProcessorTask = processTestManifestTask
-        processTestManifestTask.dependsOn variantData.prepareDependenciesTask
+        processTestManifestTask.dependsOn(tasks, scope.variantData.prepareDependenciesTask)
 
-        processTestManifestTask.androidBuilder = androidBuilder
-
-        conventionMapping(processTestManifestTask).map("testApplicationId") {
-            config.applicationId
-        }
-        conventionMapping(processTestManifestTask).map("minSdkVersion") {
-            if (androidBuilder.isPreviewTarget()) {
-                return androidBuilder.getTargetCodename()
-            }
-
-            config.minSdkVersion?.apiString
-        }
-        conventionMapping(processTestManifestTask).map("targetSdkVersion") {
-            if (androidBuilder.isPreviewTarget()) {
-                return androidBuilder.getTargetCodename()
-            }
-
-            return config.targetSdkVersion?.apiString
-        }
-        conventionMapping(processTestManifestTask).map("testedApplicationId") {
-            config.testedApplicationId
-        }
-        conventionMapping(processTestManifestTask).map("instrumentationRunner") {
-            config.instrumentationRunner
-        }
-        conventionMapping(processTestManifestTask).map("handleProfiling") {
-            config.handleProfiling
-        }
-        conventionMapping(processTestManifestTask).map("functionalTest") {
-            config.functionalTest
-        }
-        conventionMapping(processTestManifestTask).map("libraries") {
-            getManifestDependencies(config.directLibraries)
-        }
-        conventionMapping(processTestManifestTask).map("manifestOutputFile") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/${manifestOurDir}/${variantData.variantConfiguration.dirName}/AndroidManifest.xml")
-        }
-        conventionMapping(processTestManifestTask).map("placeholdersValues") {
-            variantData.getVariantConfiguration().getManifestPlaceholders()
-        }
+        BaseVariantOutputData variantOutputData = scope.variantData.outputs.get(0)
+        variantOutputData.scope.manifestProcessorTask = processTestManifestTask
     }
 
     public void createRenderscriptTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
-        GradleVariantConfiguration config = variantData.variantConfiguration
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        scope.renderscriptCompileTask = androidTasks.create(tasks,
+                new RenderscriptCompile.ConfigAction(scope))
 
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
+        GradleVariantConfiguration config = variantData.variantConfiguration
         // get single output for now.
         BaseVariantOutputData variantOutputData = variantData.outputs.get(0)
 
-        def renderscriptTask = project.tasks.create(
-                "compile${variantData.variantConfiguration.fullName.capitalize()}Renderscript",
-                RenderscriptCompile)
-        variantData.renderscriptCompileTask = renderscriptTask
+        scope.renderscriptCompileTask.dependsOn(tasks, variantData.prepareDependenciesTask)
         if (config.type.isForTesting()) {
-            renderscriptTask.dependsOn variantOutputData.manifestProcessorTask
+            scope.renderscriptCompileTask.dependsOn(tasks, variantOutputData.scope.manifestProcessorTask)
         } else {
-            renderscriptTask.dependsOn variantData.checkManifestTask
+            scope.renderscriptCompileTask.dependsOn(tasks, scope.checkManifestTask)
         }
 
-        ProductFlavor mergedFlavor = config.mergedFlavor
-        boolean ndkMode = config.renderscriptNdkModeEnabled
 
-        variantData.resourceGenTask.dependsOn renderscriptTask
+        scope.resourceGenTask.dependsOn(tasks, scope.renderscriptCompileTask)
         // only put this dependency if rs will generate Java code
-        if (!ndkMode) {
-            variantData.sourceGenTask.dependsOn renderscriptTask
+        if (!config.renderscriptNdkModeEnabled) {
+            scope.sourceGenTask.dependsOn(tasks, scope.renderscriptCompileTask)
         }
-
-        renderscriptTask.dependsOn variantData.prepareDependenciesTask
-        renderscriptTask.androidBuilder = androidBuilder
-
-        conventionMapping(renderscriptTask).map("targetApi") {
-            int targetApi = mergedFlavor.renderscriptTargetApi != null ?
-                    mergedFlavor.renderscriptTargetApi : -1
-            ApiVersion apiVersion = config.getMinSdkVersion()
-            if (apiVersion != null) {
-                int minSdk = apiVersion.apiLevel
-                if (apiVersion.codename != null) {
-                    minSdk = SdkVersionInfo.getApiByBuildCode(apiVersion.codename, true)
-                }
-
-                return targetApi > minSdk ? targetApi : minSdk
-            }
-
-            return targetApi
-        }
-
-        renderscriptTask.supportMode = config.renderscriptSupportModeEnabled
-        renderscriptTask.ndkMode = ndkMode
-        renderscriptTask.debugBuild = config.buildType.renderscriptDebuggable
-        renderscriptTask.optimLevel = config.buildType.renderscriptOptimLevel
-
-        conventionMapping(renderscriptTask).map("sourceDirs") { config.renderscriptSourceList }
-        conventionMapping(renderscriptTask).map("importDirs") { config.renderscriptImports }
-
-        conventionMapping(renderscriptTask).map("sourceOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_GENERATED}/source/rs/${variantData.variantConfiguration.dirName}")
-        }
-        conventionMapping(renderscriptTask).map("resOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_GENERATED}/res/rs/${variantData.variantConfiguration.dirName}")
-        }
-        conventionMapping(renderscriptTask).map("objOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/rs/${variantData.variantConfiguration.dirName}/obj")
-        }
-        conventionMapping(renderscriptTask).map("libOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/rs/${variantData.variantConfiguration.dirName}/lib")
-        }
-        conventionMapping(renderscriptTask).map("ndkConfig") { config.ndkConfig }
     }
 
-    public void createMergeResourcesTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            final boolean process9Patch) {
-        MergeResources mergeResourcesTask = basicCreateMergeResourcesTask(
-                variantData,
+    public AndroidTask<MergeResources> createMergeResourcesTask(
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        return basicCreateMergeResourcesTask(
+                tasks,
+                scope,
                 "merge",
-                "$project.buildDir/${FD_INTERMEDIATES}/res/merged/${variantData.variantConfiguration.dirName}",
+                null /*outputLocation*/,
                 true /*includeDependencies*/,
-                process9Patch)
-        variantData.mergeResourcesTask = mergeResourcesTask
+                true /*process9patch*/)
     }
 
-    public MergeResources basicCreateMergeResourcesTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
+    public AndroidTask<MergeResources> basicCreateMergeResourcesTask(
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope,
             @NonNull String taskNamePrefix,
-            @NonNull String outputLocation,
+            @Nullable File outputLocation,
             final boolean includeDependencies,
             final boolean process9Patch) {
-        MergeResources mergeResourcesTask = project.tasks.create(
-                "$taskNamePrefix${variantData.variantConfiguration.fullName.capitalize()}Resources",
-                MergeResources)
-
-        mergeResourcesTask.dependsOn variantData.prepareDependenciesTask,
-                variantData.resourceGenTask
-        mergeResourcesTask.androidBuilder = androidBuilder
-        mergeResourcesTask.incrementalFolder = project.file(
-                "$project.buildDir/${FD_INTERMEDIATES}/incremental/${taskNamePrefix}Resources/${variantData.variantConfiguration.dirName}")
-
-        mergeResourcesTask.process9Patch = process9Patch
-        mergeResourcesTask.crunchPng = extension.aaptOptions.getCruncherEnabled()
-        mergeResourcesTask.normalizeResources = extension.buildToolsRevision.compareTo(new FullRevision(21, 0, 0)) < 0
-
-        conventionMapping(mergeResourcesTask).
-                map("useNewCruncher") { getExtension().aaptOptions.useNewCruncher }
-
-        conventionMapping(mergeResourcesTask).map("inputResourceSets") {
-            List<File> generatedResFolders = Lists.newArrayList(
-                    variantData.renderscriptCompileTask.getResOutputDir(),
-                    variantData.generateResValuesTask.getResOutputDir())
-            if (variantData.extraGeneratedResFolders != null) {
-                generatedResFolders += variantData.extraGeneratedResFolders
-            }
-            if (variantData.generateApkDataTask != null &&
-                    variantData.getVariantConfiguration().getBuildType().isEmbedMicroApp()) {
-                generatedResFolders.add(variantData.generateApkDataTask.getResOutputDir())
-            }
-            variantData.variantConfiguration.getResourceSets(generatedResFolders,
-                    includeDependencies)
-        }
-
-        conventionMapping(mergeResourcesTask).map("outputDir") { project.file(outputLocation) }
-
-        return mergeResourcesTask
+        scope.mergeResourcesTask = androidTasks.create(tasks,
+                new MergeResources.ConfigAction(
+                        scope,
+                        taskNamePrefix,
+                        outputLocation,
+                        includeDependencies,
+                        process9Patch));
+        scope.mergeResourcesTask.dependsOn(tasks,
+                scope.variantData.prepareDependenciesTask,
+                scope.resourceGenTask)
+        return scope.mergeResourcesTask;
     }
 
-    public void createMergeAssetsTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @Nullable String outputLocation,
-            final boolean includeDependencies) {
-        if (outputLocation == null) {
-            outputLocation =
-                    "$project.buildDir/${FD_INTERMEDIATES}/assets/${variantData.variantConfiguration.dirName}"
-        }
 
-        VariantConfiguration variantConfig = variantData.variantConfiguration
-
-        def mergeAssetsTask = project.tasks.create(
-                "merge${variantConfig.fullName.capitalize()}Assets",
-                MergeAssets)
-        variantData.mergeAssetsTask = mergeAssetsTask
-
-        mergeAssetsTask.dependsOn variantData.prepareDependenciesTask, variantData.assetGenTask
-        mergeAssetsTask.androidBuilder = androidBuilder
-        mergeAssetsTask.incrementalFolder =
-                project.file(
-                        "$project.buildDir/${FD_INTERMEDIATES}/incremental/mergeAssets/${variantConfig.dirName}")
-
-        conventionMapping(mergeAssetsTask).map("inputAssetSets") {
-            def generatedAssets = []
-            if (variantData.copyApkTask != null) {
-                generatedAssets.add(variantData.copyApkTask.destinationDir)
-            }
-            variantConfig.getAssetSets(generatedAssets, includeDependencies)
-        }
-        conventionMapping(mergeAssetsTask).map("outputDir") { project.file(outputLocation) }
+    public void createMergeAssetsTask(TaskFactory tasks, VariantScope scope) {
+        scope.mergeAssetsTask = androidTasks.create(tasks, new MergeAssets.ConfigAction(scope))
+        scope.mergeAssetsTask.dependsOn(tasks,
+                scope.variantData.prepareDependenciesTask,
+                scope.assetGenTask)
     }
 
-    public void createBuildConfigTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
-        def generateBuildConfigTask = project.tasks.create(
-                "generate${variantData.variantConfiguration.fullName.capitalize()}BuildConfig",
-                GenerateBuildConfig)
+    public void createBuildConfigTask(@NonNull TaskFactory tasks, @NonNull VariantScope scope) {
+        scope.generateBuildConfigTask = androidTasks.create(tasks, new GenerateBuildConfig.ConfigAction(scope))
 
-        variantData.generateBuildConfigTask = generateBuildConfigTask
-
-        VariantConfiguration variantConfiguration = variantData.variantConfiguration
-
-        variantData.sourceGenTask.dependsOn generateBuildConfigTask
-        if (variantConfiguration.type.isForTesting()) {
+        scope.sourceGenTask.dependsOn(tasks, scope.generateBuildConfigTask.name);
+        if (scope.variantConfiguration.type.isForTesting()) {
             // in case of a test project, the manifest is generated so we need to depend
             // on its creation.
 
             // For test apps there should be a single output, so we get it.
-            BaseVariantOutputData variantOutputData = variantData.outputs.get(0)
+            BaseVariantOutputData variantOutputData = scope.variantData.outputs.get(0)
 
-            generateBuildConfigTask.dependsOn variantOutputData.manifestProcessorTask
+            scope.generateBuildConfigTask.dependsOn(tasks, variantOutputData.scope.manifestProcessorTask)
         } else {
-            generateBuildConfigTask.dependsOn variantData.checkManifestTask
-        }
-
-        generateBuildConfigTask.androidBuilder = androidBuilder
-
-        conventionMapping(generateBuildConfigTask).map("buildConfigPackageName") {
-            variantConfiguration.originalApplicationId
-        }
-
-        conventionMapping(generateBuildConfigTask).map("appPackageName") {
-            variantConfiguration.applicationId
-        }
-
-        conventionMapping(generateBuildConfigTask).map("versionName") {
-            variantConfiguration.versionName
-        }
-
-        conventionMapping(generateBuildConfigTask).map("versionCode") {
-            variantConfiguration.versionCode
-        }
-
-        conventionMapping(generateBuildConfigTask).map("debuggable") {
-            variantConfiguration.buildType.isDebuggable()
-        }
-
-        conventionMapping(generateBuildConfigTask).map("buildTypeName") {
-            variantConfiguration.buildType.name
-        }
-
-        conventionMapping(generateBuildConfigTask).map("flavorName") {
-            variantConfiguration.flavorName
-        }
-
-        conventionMapping(generateBuildConfigTask).map("flavorNamesWithDimensionNames") {
-            variantConfiguration.flavorNamesWithDimensionNames
-        }
-
-        conventionMapping(generateBuildConfigTask).map("items") {
-            variantConfiguration.buildConfigItems
-        }
-
-        conventionMapping(generateBuildConfigTask).map("sourceOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_GENERATED}/source/buildConfig/${variantData.variantConfiguration.dirName}")
+            scope.generateBuildConfigTask.dependsOn(tasks, scope.checkManifestTask)
         }
     }
 
     public void createGenerateResValuesTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
-        GenerateResValues generateResValuesTask = project.tasks.create(
-                "generate${variantData.variantConfiguration.fullName.capitalize()}ResValues",
-                GenerateResValues)
-        variantData.generateResValuesTask = generateResValuesTask
-        variantData.resourceGenTask.dependsOn generateResValuesTask
-
-        VariantConfiguration variantConfiguration = variantData.variantConfiguration
-
-        generateResValuesTask.androidBuilder = androidBuilder
-
-        conventionMapping(generateResValuesTask).map("items") {
-            variantConfiguration.resValues
-        }
-
-        conventionMapping(generateResValuesTask).map("resOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_GENERATED}/res/resValues/${variantData.variantConfiguration.dirName}")
-        }
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        AndroidTask<GenerateResValues> generateResValuesTask = androidTasks.create(
+                tasks, new GenerateResValues.ConfigAction(scope))
+        scope.resourceGenTask.dependsOn(tasks, generateResValuesTask)
     }
 
     public void createPreprocessResourcesTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
         String variantName = variantData.variantConfiguration.fullName.capitalize()
         int minSdk = variantData.variantConfiguration.minSdkVersion.getApiLevel()
 
         if (extension.preprocessResources  && minSdk < PreprocessResourcesTask.MIN_SDK) {
-            PreprocessResourcesTask preprocessResourcesTask = project.tasks.create(
+            scope.preprocessResourcesTask = androidTasks.create(
+                    tasks,
                     "preprocess${variantName}Resources",
-                    PreprocessResourcesTask)
-            variantData.preprocessResourcesTask = preprocessResourcesTask
+                    PreprocessResourcesTask) { PreprocessResourcesTask preprocessResourcesTask ->
+                variantData.preprocessResourcesTask = preprocessResourcesTask
 
-            preprocessResourcesTask.dependsOn variantData.mergeResourcesTask
+                preprocessResourcesTask.dependsOn variantData.mergeResourcesTask
 
-            preprocessResourcesTask.mergedResDirectory =
-                    variantData.mergeResourcesTask.outputDir
-            preprocessResourcesTask.generatedResDirectory =
-                    project.file("$project.buildDir/${FD_GENERATED}/res/pngs/${variantData.variantConfiguration.dirName}")
-            preprocessResourcesTask.outputResDirectory =
-                    project.file("$project.buildDir/${FD_INTERMEDIATES}/res/preprocessed/${variantData.variantConfiguration.dirName}")
-            preprocessResourcesTask.incrementalFolder =
-                    project.file("$project.buildDir/${FD_INTERMEDIATES}/incremental/preprocessResourcesTask/${variantData.variantConfiguration.dirName}")
+                preprocessResourcesTask.mergedResDirectory =
+                        scope.getMergeResourcesOutputDir()
+                preprocessResourcesTask.generatedResDirectory =
+                        project.file(
+                                "$project.buildDir/${FD_GENERATED}/res/pngs/${variantData.variantConfiguration.dirName}")
+                preprocessResourcesTask.outputResDirectory =
+                        project.file(
+                                "$project.buildDir/${FD_INTERMEDIATES}/res/preprocessed/${variantData.variantConfiguration.dirName}")
+                preprocessResourcesTask.incrementalFolder =
+                        project.file(
+                                "$project.buildDir/${FD_INTERMEDIATES}/incremental/preprocessResourcesTask/${variantData.variantConfiguration.dirName}")
 
-            // TODO: configure this in the extension.
-            preprocessResourcesTask.densitiesToGenerate = [Density.HIGH, Density.XHIGH]
+                // TODO: configure this in the extension.
+                preprocessResourcesTask.densitiesToGenerate = [Density.HIGH, Density.XHIGH]
+            }
         }
     }
 
-
     public void createProcessResTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope,
             boolean generateResourcePackage) {
-        createProcessResTask(variantData,
-                "$project.buildDir/${FD_INTERMEDIATES}/symbols/${variantData.variantConfiguration.dirName}",
-                generateResourcePackage)
+        createProcessResTask(
+                tasks,
+                scope,
+                new File(globalScope.getBuildDir(), FD_INTERMEDIATES + "/symbols/" +
+                        scope.variantData.getVariantConfiguration().getDirName()),
+                generateResourcePackage);
     }
 
     public void createProcessResTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @NonNull final String symbolLocation,
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope,
+            @Nullable File symbolLocation,
             boolean generateResourcePackage) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.getVariantData()
 
-        VariantConfiguration config = variantData.variantConfiguration
+        variantData.calculateFilters(scope.getGlobalScope().getExtension().getSplits());
 
         // loop on all outputs. The only difference will be the name of the task, and location
         // of the generated data.
-        for (BaseVariantOutputData vod : variantData.outputs) {
+        for (BaseVariantOutputData vod : (List<? extends BaseVariantOutputData>)variantData.outputs) {
             // create final var inside the loop to ensure the closures will work.
-            final BaseVariantOutputData variantOutputData = vod
+            final VariantOutputScope variantOutputScope = vod.scope;
 
-            String outputName = variantOutputData.fullName.capitalize()
-            String outputBaseName = variantOutputData.baseName
+            variantOutputScope.processResourcesTask = androidTasks.create(tasks,
+                    new ProcessAndroidResources.ConfigAction(variantOutputScope, symbolLocation, generateResourcePackage));
+            variantOutputScope.processResourcesTask.dependsOn(tasks,
+                    variantOutputScope.manifestProcessorTask,
+                    scope.mergeResourcesTask,
+                    scope.mergeAssetsTask)
 
-            ProcessAndroidResources processResources = project.tasks.create(
-                    "process${outputName}Resources",
-                    ProcessAndroidResources)
-
-            variantOutputData.processResourcesTask = processResources
-
-            processResources.dependsOn variantOutputData.manifestProcessorTask,
-                    variantData.mergeResourcesTask, variantData.mergeAssetsTask
             // TODO: Make it non-optional once this is not behind a flag.
-            optionalDependsOn(processResources, variantData.preprocessResourcesTask)
-            processResources.androidBuilder = androidBuilder
+            variantOutputScope.processResourcesTask.optionalDependsOn(tasks,
+                    scope.preprocessResourcesTask)
 
-            if (variantData.getSplitHandlingPolicy() ==
-                    BaseVariantData.SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY) {
-
-                variantData.calculateFilters(getExtension().getSplits());
-                Set<String> allFilters = new HashSet<>();
-                allFilters.addAll(variantData.getFilters(OutputFile.FilterType.DENSITY))
-                allFilters.addAll(variantData.getFilters(OutputFile.FilterType.LANGUAGE))
-                processResources.splits = allFilters;
+            if (vod.getMainOutputFile().getFilter(DENSITY) == null) {
+                scope.generateRClassTask = variantOutputScope.processResourcesTask
+                scope.sourceGenTask.optionalDependsOn(tasks, variantOutputScope.processResourcesTask)
             }
-
-            // only generate code if the density filter is null, and if we haven't generated
-            // it yet (if you have abi + density splits, then several abi output will have no
-            // densityFilter)
-            if (variantOutputData.getMainOutputFile().getFilter(OutputFile.DENSITY) == null
-                    && variantData.generateRClassTask == null) {
-                variantData.generateRClassTask = processResources
-                variantData.sourceGenTask.dependsOn processResources
-                processResources.enforceUniquePackageName = getExtension().getEnforceUniquePackageName()
-
-                conventionMapping(processResources).map("libraries") {
-                    getTextSymbolDependencies(config.allLibraries)
-                }
-                conventionMapping(processResources).map("packageForR") {
-                    config.originalApplicationId
-                }
-
-                // TODO: unify with generateBuilderConfig, compileAidl, and library packaging somehow?
-                conventionMapping(processResources).map("sourceOutputDir") {
-                    project.file(
-                            "$project.buildDir/${FD_GENERATED}/source/r/${config.dirName}")
-                }
-
-                conventionMapping(processResources).map("textSymbolOutputDir") {
-                    project.file(symbolLocation)
-                }
-
-                if (config.buildType.isMinifyEnabled()) {
-                    if (config.buildType.shrinkResources && config.useJack) {
-                        LoggingUtil.displayWarning(logger, project,
-                                "shrinkResources does not yet work with useJack=true")
-                    }
-                    conventionMapping(processResources).map("proguardOutputFile") {
-                        project.file(
-                                "$project.buildDir/${FD_INTERMEDIATES}/proguard-rules/${config.dirName}/aapt_rules.txt")
-                    }
-                } else if (config.buildType.shrinkResources) {
-                    LoggingUtil.displayWarning(logger, project,
-                            "To shrink resources you must also enable ProGuard")
-                }
-            }
-
-            conventionMapping(processResources).map("manifestFile") {
-                variantOutputData.manifestProcessorTask.getOutputFile()
-            }
-
-            conventionMapping(processResources).map("resDir") {
-                variantData.finalResourcesDir
-            }
-
-            conventionMapping(processResources).map("assetsDir") {
-                variantData.mergeAssetsTask.outputDir
-            }
-
-            if (generateResourcePackage) {
-                conventionMapping(processResources).map("packageOutputFile") {
-                    project.file(
-                            "$project.buildDir/${FD_INTERMEDIATES}/res/resources-${outputBaseName}.ap_")
-                }
-            }
-
-            conventionMapping(processResources).map("type") { config.type }
-            conventionMapping(processResources).map("debuggable") { config.buildType.debuggable }
-            conventionMapping(processResources).map("aaptOptions") { getExtension().aaptOptions }
-            conventionMapping(processResources).
-                    map("pseudoLocalesEnabled") { config.buildType.pseudoLocalesEnabled }
-
-            conventionMapping(processResources).map("resourceConfigs") {
-                Collection<String> resConfigs = config.mergedFlavor.resourceConfigurations;
-                if (resConfigs != null && resConfigs.size() == 1
-                    && Iterators.getOnlyElement(resConfigs.iterator()).equals("auto")) {
-
-                    return variantData.discoverListOfResourceConfigs();
-                }
-                return config.mergedFlavor.resourceConfigurations
-            }
-            conventionMapping(processResources).map("preferredDensity") {
-                variantOutputData.getMainOutputFile().getFilter(OutputFile.DENSITY)
-            }
-
         }
     }
 
@@ -1011,8 +608,8 @@
      * unchanged to the APK build output directory.
      * @param variantData the variant configuration.
      */
-    public void createSplitResourcesTasks(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
+    public void createSplitResourcesTasks(@NonNull VariantScope scope) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
 
         assert variantData.getSplitHandlingPolicy() ==
                 BaseVariantData.SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY;
@@ -1029,11 +626,12 @@
         }
 
         BaseVariantOutputData variantOutputData = outputs.get(0);
+        VariantOutputScope variantOutputScope = variantOutputData.scope
         variantOutputData.packageSplitResourcesTask =
                 project.tasks.create("package${config.fullName.capitalize()}SplitResources",
                         PackageSplitRes);
         variantOutputData.packageSplitResourcesTask.inputDirectory =
-                variantOutputData.processResourcesTask.packageOutputFile.getParentFile()
+                variantOutputScope.getProcessResourcePackageOutputFile().getParentFile()
         variantOutputData.packageSplitResourcesTask.densitySplits = densityFilters
         variantOutputData.packageSplitResourcesTask.languageSplits = languageFilters
         variantOutputData.packageSplitResourcesTask.outputBaseName = config.baseName
@@ -1042,7 +640,7 @@
         variantOutputData.packageSplitResourcesTask.outputDirectory =
                 new File("$project.buildDir/${FD_INTERMEDIATES}/splits/${config.dirName}")
         variantOutputData.packageSplitResourcesTask.androidBuilder = androidBuilder
-        variantOutputData.packageSplitResourcesTask.dependsOn variantOutputData.processResourcesTask
+        variantOutputData.packageSplitResourcesTask.dependsOn variantOutputScope.processResourcesTask.name
 
         SplitZipAlign zipAlign = project.tasks.
                 create("zipAlign${config.fullName.capitalize()}SplitPackages", SplitZipAlign)
@@ -1069,7 +667,8 @@
         zipAlign.dependsOn(variantOutputData.packageSplitResourcesTask)
     }
 
-    public void createSplitAbiTasks(@NonNull ApplicationVariantData variantData) {
+    public void createSplitAbiTasks(@NonNull VariantScope scope) {
+        ApplicationVariantData variantData = (ApplicationVariantData) scope.getVariantData()
 
         assert variantData.getSplitHandlingPolicy() ==
                 BaseVariantData.SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY;
@@ -1106,7 +705,7 @@
         conventionMapping(generateSplitAbiRes).map("aaptOptions") {
             getExtension().aaptOptions
         }
-        generateSplitAbiRes.dependsOn variantOutputData.processResourcesTask
+        generateSplitAbiRes.dependsOn variantOutputData.scope.processResourcesTask.name
 
         // then package those resources with the appropriate JNI libraries.
         variantOutputData.packageSplitAbiTask =
@@ -1164,62 +763,17 @@
     }
 
     public void createProcessJavaResTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
-        VariantConfiguration variantConfiguration = variantData.variantConfiguration
-
-        Copy processResources = project.tasks.create(
-                "process${variantData.variantConfiguration.fullName.capitalize()}JavaRes",
-                ProcessResources);
-        variantData.processJavaResourcesTask = processResources
-
-        // set the input
-        processResources.from(((AndroidSourceSet) variantConfiguration.defaultSourceSet).resources.
-                getSourceFiles())
-
-        if (variantConfiguration.type != ANDROID_TEST) {
-            processResources.from(
-                    ((AndroidSourceSet) variantConfiguration.buildTypeSourceSet).resources.
-                            getSourceFiles())
-        }
-        if (variantConfiguration.hasFlavors()) {
-            for (SourceProvider flavorSourceSet : variantConfiguration.flavorSourceProviders) {
-                processResources.
-                        from(((AndroidSourceSet) flavorSourceSet).resources.getSourceFiles())
-            }
-        }
-
-        conventionMapping(processResources).map("destinationDir") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/javaResources/${variantData.variantConfiguration.dirName}")
-        }
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        scope.processJavaResourcesTask = androidTasks.create(
+                tasks, new ProcessJavaResConfigAction(scope));
     }
 
-    public void createAidlTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @Nullable File parcelableDir) {
-        VariantConfiguration variantConfiguration = variantData.variantConfiguration
-
-        def compileTask = project.tasks.create(
-                "compile${variantData.variantConfiguration.fullName.capitalize()}Aidl",
-                AidlCompile)
-        variantData.aidlCompileTask = compileTask
-
-        variantData.sourceGenTask.dependsOn compileTask
-        variantData.aidlCompileTask.dependsOn variantData.prepareDependenciesTask
-
-        compileTask.androidBuilder = androidBuilder
-        compileTask.incrementalFolder =
-                project.file(
-                        "$project.buildDir/${FD_INTERMEDIATES}/incremental/aidl/${variantData.variantConfiguration.dirName}")
-
-        conventionMapping(compileTask).map("sourceDirs") { variantConfiguration.aidlSourceList }
-        conventionMapping(compileTask).map("importDirs") { variantConfiguration.aidlImports }
-
-        conventionMapping(compileTask).map("sourceOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_GENERATED}/source/aidl/${variantData.variantConfiguration.dirName}")
-        }
-        compileTask.aidlParcelableDir = parcelableDir
+    public void createAidlTask(@NonNull TaskFactory tasks, @NonNull VariantScope scope) {
+        scope.aidlCompileTask = androidTasks.create(tasks,
+                new AidlCompile.ConfigAction(scope));
+        scope.sourceGenTask.dependsOn(tasks, scope.aidlCompileTask)
+        scope.aidlCompileTask.dependsOn(tasks, scope.variantData.prepareDependenciesTask)
     }
 
     public void createJackAndUnitTestVerificationTask(
@@ -1235,124 +789,59 @@
     }
 
     public void createJavaCompileTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @Nullable BaseVariantData<? extends BaseVariantOutputData> testedVariantData) {
-        def javaCompileTask = project.tasks.create(
-                "compile${variantData.variantConfiguration.fullName.capitalize()}Java",
-                JavaCompile)
+            @NonNull final TaskFactory tasks,
+            @NonNull final VariantScope scope) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData;
+        AndroidTask<JavaCompile> javaCompileTask = androidTasks.create(tasks,
+                new JavaCompileConfigAction(scope));
+        scope.javaCompileTask = javaCompileTask;
 
-        variantData.javaCompileTask = javaCompileTask
-        variantData.compileTask.dependsOn variantData.javaCompileTask
-        optionalDependsOn(
-                variantData.javaCompileTask, variantData.sourceGenTask)
+        scope.compileTask.dependsOn(tasks, javaCompileTask);
 
-        javaCompileTask.source = variantData.getJavaSources()
-
-        conventionMapping(javaCompileTask).map("classpath") {
-            FileCollection classpath = project.files(
-                    androidBuilder.getCompileClasspath(variantData.variantConfiguration))
-
-            if (testedVariantData) {
-                // For libraries, the classpath from androidBuilder includes the library output
-                // (bundle/classes.jar) as a normal dependency. In unit tests we don't want to package
-                // the jar at every run, so we use the *.class files instead.
-                if (testedVariantData.type != LIBRARY || variantData.type == UNIT_TEST) {
-                    classpath = classpath +
-                            testedVariantData.javaCompileTask.classpath +
-                            testedVariantData.javaCompileTask.outputs.files
-                }
-
-                if (variantData.type == UNIT_TEST && testedVariantData.type == LIBRARY) {
-                    // The bundled classes.jar may exist, but it's probably old. Don't use it, we
-                    // already have the *.class files in the classpath.
-                    classpath -= project.files(testedVariantData.variantConfiguration.output.jarFile)
-                }
-            }
-
-            return classpath
-        }
-
-        javaCompileTask.dependsOn variantData.prepareDependenciesTask
-        javaCompileTask.dependsOn variantData.processJavaResourcesTask
+        javaCompileTask.optionalDependsOn(tasks, scope.sourceGenTask)
+        javaCompileTask.dependsOn(tasks,
+                scope.getVariantData().prepareDependenciesTask,
+                scope.processJavaResourcesTask);
 
         // TODO - dependency information for the compile classpath is being lost.
         // Add a temporary approximation
-        javaCompileTask.dependsOn variantData.variantDependency.compileConfiguration.buildDependencies
+        javaCompileTask.dependsOn(tasks,
+                scope.getVariantData().getVariantDependency().getCompileConfiguration()
+                        .getBuildDependencies());
 
-        conventionMapping(javaCompileTask).map("destinationDir") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/classes/${variantData.variantConfiguration.dirName}")
-        }
-        conventionMapping(javaCompileTask).map("dependencyCacheDir") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/dependency-cache/${variantData.variantConfiguration.dirName}")
+        if (variantData.getType().isForTesting()) {
+            BaseVariantData testedVariantData =
+                    ((TestVariantData) variantData).getTestedVariantData() as BaseVariantData
+            javaCompileTask.dependsOn(tasks,
+                    testedVariantData.javaCompileTask ?: testedVariantData.scope.javaCompileTask)
         }
 
-        configureLanguageLevel(javaCompileTask)
-        javaCompileTask.options.encoding = getExtension().compileOptions.encoding
-
-        // setup the boot classpath just before the task actually runs since this will
-        // force the sdk to be parsed.
-        javaCompileTask.doFirst {
-            javaCompileTask.options.bootClasspath =
-                    androidBuilder.getBootClasspathAsStrings().join(File.pathSeparator)
-        }
 
         // Create jar task for uses by external modules.
         if (variantData.variantDependency.classesConfiguration != null) {
-            Jar jar = project.tasks.create(
-                    "package${variantData.variantConfiguration.fullName.capitalize()}JarArtifact",
-                    Jar);
-            variantData.classesJarTask = jar
-            jar.dependsOn javaCompileTask
+            tasks.create("package${variantData.variantConfiguration.fullName.capitalize()}JarArtifact", Jar) { Jar jar ->
+                variantData.classesJarTask = jar
+                jar.dependsOn javaCompileTask.name
 
-            // add the class files (whether they are instrumented or not.
-            jar.from({ variantData.javaCompileTask.destinationDir })
+                // add the class files (whether they are instrumented or not.
+                jar.from({ scope.getJavaOutputDir() })
 
-            jar.destinationDir = project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/classes-jar/${variantData.variantConfiguration.dirName}")
-            jar.archiveName = "classes.jar"
+                jar.destinationDir = scope.getJavaOutputDir();
+                jar.archiveName = "classes.jar"
+            }
         }
     }
 
     public void createGenerateMicroApkDataTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope,
             @NonNull Configuration config) {
-        GenerateApkDataTask task = project.tasks.create(
-                "handle${variantData.variantConfiguration.fullName.capitalize()}MicroApk",
-                GenerateApkDataTask)
-
-        variantData.generateApkDataTask = task
-
-        task.androidBuilder = androidBuilder
-        conventionMapping(task).map("resOutputDir") {
-            project.file(
-                    "$project.buildDir/${FD_GENERATED}/res/microapk/${variantData.variantConfiguration.dirName}")
-        }
-        conventionMapping(task).map("apkFile") {
-            // only care about the first one. There shouldn't be more anyway.
-            config.getFiles().iterator().next()
-        }
-        conventionMapping(task).map("manifestFile") {
-            project.file(
-                    "$project.buildDir/${FD_INTERMEDIATES}/${FD_GENERATED}/manifests/microapk/${variantData.variantConfiguration.dirName}/${FN_ANDROID_MANIFEST_XML}")
-        }
-        conventionMapping(task).map("mainPkgName") {
-            variantData.variantConfiguration.getApplicationId()
-        }
-
-        conventionMapping(task).map("minSdkVersion") {
-            variantData.variantConfiguration.getMinSdkVersion().apiLevel
-        }
-
-        conventionMapping(task).map("targetSdkVersion") {
-            variantData.variantConfiguration.getTargetSdkVersion().apiLevel
-        }
-
-        task.dependsOn config
+        AndroidTask<GenerateApkDataTask> generateMicroApkTask = androidTasks.create(tasks,
+                new GenerateApkDataTask.ConfigAction(scope, config));
+        generateMicroApkTask.dependsOn tasks, config
 
         // the merge res task will need to run after this one.
-        variantData.resourceGenTask.dependsOn task
+        scope.resourceGenTask.dependsOn(tasks, generateMicroApkTask);
     }
 
     public void createNdkTasks(
@@ -1417,11 +906,12 @@
             @NonNull TestVariantData variantData) {
         BaseVariantData testedVariantData = variantData.getTestedVariantData() as BaseVariantData
         variantData.assembleVariantTask.dependsOn createMockableJar
+        VariantScope variantScope = variantData.getScope()
 
-        createPreBuildTasks(variantData)
-        createProcessJavaResTask(variantData)
-        createCompileAnchorTask(variantData)
-        createJavaCompileTask(variantData, testedVariantData)
+        createPreBuildTasks(tasks, variantScope)
+        createProcessJavaResTask(tasks, variantScope)
+        createCompileAnchorTask(tasks, variantScope)
+        createJavaCompileTask(tasks, variantScope);
         createJackAndUnitTestVerificationTask(variantData, testedVariantData)
         createUnitTestTask(tasks, variantData)
 
@@ -1437,6 +927,8 @@
     public void createAndroidTestVariantTasks(
             @NonNull TaskFactory tasks,
             @NonNull TestVariantData variantData) {
+        VariantScope variantScope = variantData.getScope()
+
         BaseVariantData<? extends BaseVariantOutputData> testedVariantData =
                 variantData.
                         getTestedVariantData() as BaseVariantData<? extends BaseVariantOutputData>
@@ -1445,62 +937,61 @@
         BaseVariantOutputData variantOutputData = variantData.outputs.get(0)
         BaseVariantOutputData testedVariantOutputData = testedVariantData.outputs.get(0)
 
-        createAnchorTasks(variantData)
+        createAnchorTasks(tasks, variantScope)
 
         // Add a task to process the manifest
-        createProcessTestManifestTask(variantData, "manifests")
+        createProcessTestManifestTask(tasks, variantScope)
 
         // Add a task to create the res values
-        createGenerateResValuesTask(variantData)
+        createGenerateResValuesTask(tasks, variantScope)
 
         // Add a task to compile renderscript files.
-        createRenderscriptTask(variantData)
+        createRenderscriptTask(tasks, variantScope)
 
         // Add a task to merge the resource folders
-        createMergeResourcesTask(variantData, true /*process9Patch*/)
+        createMergeResourcesTask(tasks, variantScope)
 
         // Add a task to merge the assets folders
-        createMergeAssetsTask(variantData, null /*default location*/, true /*includeDependencies*/)
+        createMergeAssetsTask(tasks, variantScope)
 
         if (testedVariantData.variantConfiguration.type == VariantType.LIBRARY) {
             // in this case the tested library must be fully built before test can be built!
             if (testedVariantOutputData.assembleTask != null) {
-                variantOutputData.manifestProcessorTask.dependsOn testedVariantOutputData.assembleTask
-                variantData.mergeResourcesTask.dependsOn testedVariantOutputData.assembleTask
+                variantOutputData.scope.manifestProcessorTask.dependsOn(
+                        tasks, testedVariantOutputData.assembleTask)
+                variantScope.mergeResourcesTask.dependsOn(tasks, testedVariantOutputData.assembleTask)
             }
         }
 
         // Add a task to create the BuildConfig class
-        createBuildConfigTask(variantData)
+        createBuildConfigTask(tasks, variantScope)
 
-        createPreprocessResourcesTask(variantData)
+        createPreprocessResourcesTask(tasks, variantScope)
 
         // Add a task to generate resource source files
-        createProcessResTask(variantData, true /*generateResourcePackage*/)
+        createProcessResTask(tasks, variantScope, true /*generateResourcePackage*/)
 
         // process java resources
-        createProcessJavaResTask(variantData)
+        createProcessJavaResTask(tasks, variantScope)
 
-        createAidlTask(variantData, null /*parcelableDir*/)
+        createAidlTask(tasks, variantScope)
 
         // Add NDK tasks
         if (isNdkTaskNeeded) {
             createNdkTasks(variantData)
         }
+        variantScope.setNdkBuildable(getNdkBuildable(variantData))
+        variantScope.setNdkOutputDirectories(getNdkOutputDirectories(variantData))
 
         // Add a task to compile the test application
         if (variantData.getVariantConfiguration().useJack) {
             createJackTask(variantData, testedVariantData);
         } else {
-            createJavaCompileTask(variantData, testedVariantData)
-            createPostCompilationTasks(variantData);
+            //createJavaCompileTask(variantData, testedVariantData)
+            createJavaCompileTask(tasks, variantScope)
+            createPostCompilationTasks(tasks, variantScope)
         }
 
-        // Variant scope should be create at the function, but there is currently a dependencies
-        // on the NdkCompile tasks, and the scope mechanism does not support lazy evaluation yet.
-        VariantScope variantScope = createVariantScope(variantData);
-
-
         createPackagingTask(tasks, variantScope, false /*publishApk*/)
 
         tasks.named(ASSEMBLE_ANDROID_TEST) {
@@ -1511,16 +1002,17 @@
     }
 
     // TODO - should compile src/lint/java from src/lint/java and jar it into build/lint/lint.jar
-    public void createLintCompileTask() {
-        lintCompile = project.tasks.create("compileLint", Task)
-        File outputDir = new File("$project.buildDir/${FD_INTERMEDIATES}/lint")
+    private void createLintCompileTask(TaskFactory tasks) {
+        tasks.create(LINT_COMPILE, Task) { Task lintCompile ->
+            File outputDir = new File("$project.buildDir/${FD_INTERMEDIATES}/lint")
 
-        lintCompile.doFirst {
-            // create the directory for lint output if it does not exist.
-            if (!outputDir.exists()) {
-                boolean mkdirs = outputDir.mkdirs();
-                if (!mkdirs) {
-                    throw new GradleException("Unable to create lint output directory.")
+            lintCompile.doFirst {
+                // create the directory for lint output if it does not exist.
+                if (!outputDir.exists()) {
+                    boolean mkdirs = outputDir.mkdirs();
+                    if (!mkdirs) {
+                        throw new GradleException("Unable to create lint output directory.")
+                    }
                 }
             }
         }
@@ -1537,49 +1029,29 @@
 
     // Add tasks for running lint on individual variants. We've already added a
     // lint task earlier which runs on all variants.
-    public void createLintTasks(
-            TaskFactory tasks,
-            List<BaseVariantData<? extends BaseVariantOutputData>> variantDataList) {
-        final Lint lint = project.tasks.create("lint", Lint)
-        lint.description = "Runs lint on all variants."
-        lint.group = JavaBasePlugin.VERIFICATION_GROUP
-        lint.setLintOptions(getExtension().lintOptions)
-        lint.setSdkHome(sdkHandler.getSdkFolder())
-        lint.setToolingRegistry(toolingRegistry)
-        tasks.named(JavaBasePlugin.CHECK_TASK_NAME) {
-            it.dependsOn lint
+    public void createLintTasks(TaskFactory tasks, VariantScope scope) {
+        final BaseVariantData<? extends BaseVariantOutputData> baseVariantData = scope.variantData
+        if (!isLintVariant(baseVariantData)) {
+            return;
         }
-        lintAll = lint
 
-        int count = variantDataList.size()
-        for (int i = 0; i < count; i++) {
-            final BaseVariantData<? extends BaseVariantOutputData> baseVariantData =
-                    variantDataList.get(i)
-            if (!isLintVariant(baseVariantData)) {
-                continue;
+        // wire the main lint task dependency.
+        tasks.named(LINT) {
+            it.dependsOn(LINT_COMPILE)
+            if (baseVariantData.javaCompileTask != null) {
+                it.dependsOn(baseVariantData.javaCompileTask)
             }
-
-            // wire the main lint task dependency.
-            lint.dependsOn lintCompile
-            optionalDependsOn(lint, baseVariantData.javaCompileTask)
-
-            String variantName = baseVariantData.variantConfiguration.fullName
-            def capitalizedVariantName = variantName.capitalize()
-            Lint variantLintCheck = project.tasks.create("lint" + capitalizedVariantName, Lint)
-            variantLintCheck.dependsOn lintCompile
-            optionalDependsOn(variantLintCheck, baseVariantData.javaCompileTask)
-
-            // Note that we don't do "lint.dependsOn lintCheck"; the "lint" target will
-            // on its own run through all variants (and compare results), it doesn't delegate
-            // to the individual tasks (since it needs to coordinate data collection and
-            // reporting)
-            variantLintCheck.setLintOptions(getExtension().lintOptions)
-            variantLintCheck.setSdkHome(sdkHandler.getSdkFolder())
-            variantLintCheck.setVariantName(variantName)
-            variantLintCheck.setToolingRegistry(toolingRegistry)
-            variantLintCheck.description = "Runs lint on the " + capitalizedVariantName + " build."
-            variantLintCheck.group = JavaBasePlugin.VERIFICATION_GROUP
+            if (scope.javaCompileTask != null) {
+                it.dependsOn(scope.javaCompileTask.name)
+            }
         }
+
+        AndroidTask<Lint> variantLintCheck = androidTasks.create(
+                tasks, new Lint.ConfigAction(scope))
+        variantLintCheck.dependsOn(tasks, LINT_COMPILE)
+        variantLintCheck.optionalDependsOn(tasks,
+                baseVariantData.javaCompileTask,
+                scope.javaCompileTask)
     }
 
     private void createLintVitalTask(@NonNull ApkVariantData variantData) {
@@ -1600,11 +1072,11 @@
             lintReleaseCheck.setFatalOnly(true)
             lintReleaseCheck.description = "Runs lint on just the fatal issues in the " +
                     capitalizedVariantName + " build."
-            variantData.assembleVariantTask.dependsOn lintReleaseCheck
+            //variantData.assembleVariantTask.dependsOn lintReleaseCheck
 
             // If lint is being run, we do not need to run lint vital.
             project.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
-                if (taskGraph.hasTask(lintAll)) {
+                if (taskGraph.hasTask(LINT)) {
                     lintReleaseCheck.setEnabled(false)
                 }
             }
@@ -1786,7 +1258,7 @@
     }
 
     protected void createConnectedTestForVariantData(
-            TaskFactory tasks,
+            @NonNull TaskFactory tasks,
             final TestVariantData testVariantData,
             TestType testType) {
         BaseVariantData<? extends BaseVariantOutputData> baseVariantData =
@@ -2024,19 +1496,22 @@
         Closure<List<File>> inputLibraries
     }
 
-    public void createJarTask(@NonNull BaseVariantData variantData) {
+    public void createJarTask(@NonNull TaskFactory tasks, @NonNull final VariantScope scope) {
+        BaseVariantData variantData = scope.variantData;
 
         GradleVariantConfiguration config = variantData.variantConfiguration
-        AndroidJarTask jarTask = project.tasks.create(
-                "jar${config.fullName.capitalize()}Classes",
-                AndroidJarTask)
+        tasks.create("jar${config.fullName.capitalize()}Classes", AndroidJarTask) { AndroidJarTask jarTask ->
+            //        AndroidJarTask jarTask = project.tasks.create(
+            //                "jar${config.fullName.capitalize()}Classes",
+            //                AndroidJarTask)
 
-        jarTask.setArchiveName("classes.jar");
-        jarTask.setDestinationDir(project.file(
-                "$project.buildDir/${FD_INTERMEDIATES}/packaged/${config.dirName}/"))
-        jarTask.from(variantData.javaCompileTask.destinationDir)
-        jarTask.dependsOn variantData.javaCompileTask
-        variantData.binayFileProviderTask = jarTask
+            jarTask.setArchiveName("classes.jar");
+            jarTask.setDestinationDir(new File(
+                    "$scope.globalScope.buildDir/${FD_INTERMEDIATES}/packaged/${config.dirName}/"))
+            jarTask.from(scope.javaOutputDir);
+            jarTask.dependsOn scope.javaCompileTask.name
+            variantData.binayFileProviderTask = jarTask
+        }
     }
 
     /**
@@ -2047,88 +1522,54 @@
      *
      * @param variantData the variant data.
      */
-    public void createPostCompilationTasks(@NonNull ApkVariantData variantData) {
+    public void createPostCompilationTasks(TaskFactory tasks, @NonNull final VariantScope scope) {
+        ApkVariantData variantData = (ApkVariantData) scope.variantData;
         GradleVariantConfiguration config = variantData.variantConfiguration
 
-        boolean isTestForApp = config.type.isForTesting() &&
-                (variantData as TestVariantData).testedVariantData.variantConfiguration.type ==
-                DEFAULT
-
-        boolean isMinifyEnabled = config.isMinifyEnabled()
-        boolean isMultiDexEnabled = config.isMultiDexEnabled() && !isTestForApp
-        boolean isLegacyMultiDexMode = config.isLegacyMultiDexMode()
-        File multiDexKeepProguard = config.getMultiDexKeepProguard()
-        File multiDexKeepFile = config.getMultiDexKeepFile()
-
-        boolean isTestCoverageEnabled = config.buildType.isTestCoverageEnabled() &&
-                !config.type.isForTesting()
-
-        // common dex task configuration
-        String dexTaskName = "dex${config.fullName.capitalize()}"
-        Dex dexTask = project.tasks.create(dexTaskName, Dex)
-        variantData.dexTask = dexTask
-        dexTask.androidBuilder = androidBuilder
-        conventionMapping(dexTask).map("outputFolder") {
-            project.file("${project.buildDir}/${FD_INTERMEDIATES}/dex/${config.dirName}")
-        }
-        dexTask.tmpFolder =
-                project.file("$project.buildDir/${FD_INTERMEDIATES}/tmp/dex/${config.dirName}")
-        dexTask.dexOptions = getExtension().dexOptions
-        dexTask.multiDexEnabled = isMultiDexEnabled
-        dexTask.legacyMultiDexMode = isLegacyMultiDexMode
-        // dx doesn't work with receving --no-optimize in debug so we disable it for now.
-        dexTask.optimize = true //!variantData.variantConfiguration.buildType.debuggable
-
-
         // data holding dependencies and input for the dex. This gets updated as new
         // post-compilation steps are inserted between the compilation and dx.
         PostCompilationData pcData = new PostCompilationData()
-        pcData.classGeneratingTask = [variantData.javaCompileTask]
+        pcData.classGeneratingTask = [scope.javaCompileTask.name]
         pcData.libraryGeneratingTask =
                 [variantData.variantDependency.packageConfiguration.buildDependencies]
         pcData.inputFiles = {
             variantData.javaCompileTask.outputs.files.files as List
         }
         pcData.inputDir = {
-            variantData.javaCompileTask.destinationDir
+            scope.javaOutputDir
         }
         pcData.inputLibraries = {
-            androidBuilder.getPackagedJars(config) as List
+            scope.globalScope.androidBuilder.getPackagedJars(config) as List
         }
 
         // ---- Code Coverage first -----
+        boolean isTestCoverageEnabled = config.buildType.isTestCoverageEnabled() &&
+                !config.type.isForTesting()
         if (isTestCoverageEnabled) {
-            pcData = createJacocoTask(config, variantData, pcData)
+            pcData = createJacocoTask(tasks, scope, pcData);
         }
 
-        // ----- Minify next ----
-        BaseVariantData<? extends BaseVariantOutputData> testedVariantData =
-                (variantData instanceof TestVariantData ? variantData.testedVariantData :
-                        null) as BaseVariantData
+        boolean isTestForApp = config.type.isForTesting() &&
+                (variantData as TestVariantData).testedVariantData.variantConfiguration.type ==
+                DEFAULT
+        boolean isMinifyEnabled = config.isMinifyEnabled()
+        boolean isMultiDexEnabled = config.isMultiDexEnabled() && !isTestForApp
+        boolean isLegacyMultiDexMode = config.isLegacyMultiDexMode()
 
-        File outFile = maybeCreateProguardTasks(variantData, testedVariantData, pcData);
+        // ----- Minify next ----
+        File outFile = maybeCreateProguardTasks(tasks, scope, pcData);
         if (outFile != null) {
             pcData.inputFiles = { [outFile] }
             pcData.inputLibraries = { [] }
         } else if ((getExtension().dexOptions.preDexLibraries && !isMultiDexEnabled) ||
                 (isMultiDexEnabled && !isLegacyMultiDexMode)) {
-            def preDexTaskName = "preDex${config.fullName.capitalize()}"
-            PreDex preDexTask = project.tasks.create(preDexTaskName, PreDex)
 
-            variantData.preDexTask = preDexTask
-            preDexTask.androidBuilder = androidBuilder
-            preDexTask.dexOptions = getExtension().dexOptions
-            preDexTask.multiDex = isMultiDexEnabled
-
-            conventionMapping(preDexTask).map("inputFiles", pcData.inputLibraries)
-            conventionMapping(preDexTask).map("outputFolder") {
-                project.file(
-                        "${project.buildDir}/${FD_INTERMEDIATES}/pre-dexed/${config.dirName}")
-            }
+            AndroidTask<PreDex> preDexTask =
+                    androidTasks.create(tasks, new PreDex.ConfigAction(scope, pcData))
 
             // update dependency.
-            optionalDependsOn(preDexTask, pcData.libraryGeneratingTask)
-            pcData.libraryGeneratingTask = [preDexTask] as List<Object>
+            preDexTask.dependsOn(tasks, pcData.libraryGeneratingTask)
+            pcData.libraryGeneratingTask = [preDexTask.name] as List<Object>
 
             // update inputs
             if (isMultiDexEnabled) {
@@ -2136,33 +1577,32 @@
 
             } else {
                 pcData.inputLibraries = {
-                    project.fileTree(preDexTask.outputFolder).files as List
+                    project.fileTree(scope.getPreDexOutputDir()).files as List
                 }
             }
         }
 
+        AndroidTask<CreateMainDexList> createMainDexListTask = null;
+        AndroidTask<RetraceMainDexList> retraceTask = null;
+
         // ----- Multi-Dex support
         if (isMultiDexEnabled && isLegacyMultiDexMode) {
             if (!isMinifyEnabled) {
                 // create a task that will convert the output of the compilation
                 // into a jar. This is needed by the multi-dex input.
-                JarMergingTask jarMergingTask = project.tasks.create(
-                        "packageAll${config.fullName.capitalize()}ClassesForMultiDex",
-                        JarMergingTask)
-                conventionMapping(jarMergingTask).map("inputJars", pcData.inputLibraries)
-                conventionMapping(jarMergingTask).map("inputDir", pcData.inputDir)
-
-                jarMergingTask.jarFile = project.file(
-                        "$project.buildDir/${FD_INTERMEDIATES}/multi-dex/${config.dirName}/allclasses.jar")
+                AndroidTask<JarMergingTask> jarMergingTask = androidTasks.create(tasks,
+                        new JarMergingTask.ConfigAction(scope, pcData));
 
                 // update dependencies
-                optionalDependsOn(jarMergingTask, pcData.classGeneratingTask)
-                optionalDependsOn(jarMergingTask, pcData.libraryGeneratingTask)
-                pcData.libraryGeneratingTask = [jarMergingTask]
-                pcData.classGeneratingTask = [jarMergingTask]
+                jarMergingTask.optionalDependsOn(
+                        tasks,
+                        pcData.classGeneratingTask,
+                        pcData.libraryGeneratingTask)
+                pcData.libraryGeneratingTask = [jarMergingTask.name]
+                pcData.classGeneratingTask = [jarMergingTask.name]
 
                 // Update the inputs
-                pcData.inputFiles = { [jarMergingTask.jarFile] }
+                pcData.inputFiles = { [scope.getJarMergingOutputFile()] }
                 pcData.inputDir = null
                 pcData.inputLibraries = { [] }
             }
@@ -2170,148 +1610,70 @@
             // ----------
             // Create a task to collect the list of manifest entry points which are
             // needed in the primary dex
-            CreateManifestKeepList manifestKeepListTask = project.tasks.create(
-                    "collect${config.fullName.capitalize()}MultiDexComponents",
-                    CreateManifestKeepList)
-
-            // since all the output have the same manifest, besides the versionCode,
-            // we can take any of the output and use that.
-            final BaseVariantOutputData output = variantData.outputs.get(0)
-            manifestKeepListTask.dependsOn output.manifestProcessorTask
-            conventionMapping(manifestKeepListTask).map("manifest") {
-                output.manifestProcessorTask.getOutputFile()
-            }
-
-            manifestKeepListTask.proguardFile = multiDexKeepProguard
-            manifestKeepListTask.outputFile = project.file(
-                    "${project.buildDir}/${FD_INTERMEDIATES}/multi-dex/${config.dirName}/manifest_keep.txt")
-
-            //variant.ext.collectMultiDexComponents = manifestKeepListTask
+            AndroidTask<CreateManifestKeepList> manifestKeepListTask = androidTasks.create(tasks,
+                    new CreateManifestKeepList.ConfigAction(scope, pcData))
+            manifestKeepListTask.dependsOn(tasks, variantData.outputs.get(0).scope.manifestProcessorTask)
 
             // ----------
             // Create a proguard task to shrink the classes to manifest components
-            ProGuardTask proguardComponentsTask = createShrinkingProGuardTask(project,
-                    "shrink${config.fullName.capitalize()}MultiDexComponents")
-
-            proguardComponentsTask.configuration(manifestKeepListTask.outputFile)
-
-            proguardComponentsTask.libraryjars({
-                checkNotNull(androidBuilder.getTargetInfo())
-                File shrinkedAndroid = new File(androidBuilder.getTargetInfo().buildTools.location,
-                        "lib${File.separatorChar}shrinkedAndroid.jar")
-
-                // TODO remove in 1.0
-                // STOPSHIP
-                if (!shrinkedAndroid.isFile()) {
-                    shrinkedAndroid = new File(androidBuilder.getTargetInfo().buildTools.location,
-                            "multidex${File.separatorChar}shrinkedAndroid.jar")
-                }
-                return shrinkedAndroid
-            })
-
-            proguardComponentsTask.injars(pcData.inputFiles.call().iterator().next())
-
-            File componentsJarFile = project.file(
-                    "${project.buildDir}/${FD_INTERMEDIATES}/multi-dex/${config.dirName}/componentClasses.jar")
-            proguardComponentsTask.outjars(componentsJarFile)
-
-            proguardComponentsTask.printconfiguration(
-                    "${project.buildDir}/${FD_INTERMEDIATES}/multi-dex/${config.dirName}/components.flags")
+            AndroidTask<ProGuardTask> proguardComponentsTask =
+                    androidTasks.create(tasks, new ProGuardTaskConfigAction(scope, pcData))
 
             // update dependencies
-            proguardComponentsTask.dependsOn manifestKeepListTask
-            optionalDependsOn(proguardComponentsTask, pcData.classGeneratingTask)
-            optionalDependsOn(proguardComponentsTask, pcData.libraryGeneratingTask)
+            proguardComponentsTask.dependsOn tasks, manifestKeepListTask
+            proguardComponentsTask.optionalDependsOn(tasks,
+                    pcData.classGeneratingTask,
+                    pcData.libraryGeneratingTask)
 
             // ----------
             // Compute the full list of classes for the main dex file
-            CreateMainDexList createMainDexListTask = project.tasks.create(
-                    "create${config.fullName.capitalize()}MainDexClassList",
-                    CreateMainDexList)
-            createMainDexListTask.androidBuilder = androidBuilder
-            createMainDexListTask.dependsOn proguardComponentsTask
+            createMainDexListTask = androidTasks.create(tasks, new CreateMainDexList.ConfigAction(scope, pcData))
+            createMainDexListTask.dependsOn(tasks, proguardComponentsTask)
             //createMainDexListTask.dependsOn { proguardMainDexTask }
 
-            def files = pcData.inputFiles
-            createMainDexListTask.allClassesJarFile = files().first()
-            conventionMapping(createMainDexListTask).map("componentsJarFile") { componentsJarFile }
-            // conventionMapping(createMainDexListTask).map("includeInMainDexJarFile") { mainDexJarFile }
-            createMainDexListTask.mainDexListFile = multiDexKeepFile
-            createMainDexListTask.outputFile = project.file(
-                    "${project.buildDir}/${FD_INTERMEDIATES}/multi-dex/${config.dirName}/maindexlist.txt")
-
-            // update dependencies
-            dexTask.dependsOn createMainDexListTask
-
             // ----------
-            // If proguard is on create a de-obfuscated list to aid debugging.
+            // If proguard is enabled, create a de-obfuscated list to aid debugging.
             if (isMinifyEnabled) {
-                RetraceMainDexList retraceTask = project.tasks.create(
-                        "retrace${config.fullName.capitalize()}MainDexClassList",
-                        RetraceMainDexList)
-                retraceTask.dependsOn variantData.obfuscationTask, createMainDexListTask
-
-                conventionMapping(retraceTask).
-                        map("mainDexListFile") { createMainDexListTask.outputFile }
-                conventionMapping(retraceTask).map("mappingFile") {
-                    variantData.getMappingFile()
-                }
-                retraceTask.outputFile = project.file(
-                        "${project.buildDir}/${FD_INTERMEDIATES}/multi-dex/${config.dirName}/maindexlist_deobfuscated.txt")
-                dexTask.dependsOn retraceTask
+                retraceTask = androidTasks.create(tasks,
+                        new RetraceMainDexList.ConfigAction(scope, pcData))
+                retraceTask.dependsOn(tasks, scope.obfuscationTask, createMainDexListTask)
             }
-
-            // configure the dex task to receive the generated class list.
-            conventionMapping(dexTask).map("mainDexListFile") { createMainDexListTask.outputFile }
         }
 
-        // ----- Dex Task ----
+        AndroidTask<Dex> dexTask = androidTasks.create(tasks, new Dex.ConfigAction(scope, pcData));
+        scope.setDexTask(dexTask);
 
         // dependencies, some of these could be null
-        optionalDependsOn(dexTask, variantData.obfuscationTask)
-        optionalDependsOn(dexTask, pcData.classGeneratingTask)
-        optionalDependsOn(dexTask, pcData.libraryGeneratingTask,)
-
-        // inputs
-        if (pcData.inputDir != null) {
-            conventionMapping(dexTask).map("inputDir", pcData.inputDir)
-        }
-        conventionMapping(dexTask).map("inputFiles", pcData.inputFiles)
-        conventionMapping(dexTask).map("libraries", pcData.inputLibraries)
+        dexTask.optionalDependsOn(tasks,
+                pcData.classGeneratingTask,
+                pcData.libraryGeneratingTask,
+                createMainDexListTask,
+                retraceTask)
     }
 
     public PostCompilationData createJacocoTask(
-            @NonNull GradleVariantConfiguration config,
-            @NonNull BaseVariantData variantData,
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope,
             @NonNull final PostCompilationData pcData) {
-        final JacocoInstrumentTask jacocoTask = project.tasks.create(
-                "instrument${config.fullName.capitalize()}", JacocoInstrumentTask)
-        conventionMapping(jacocoTask).map("jacocoClasspath") {
-            project.configurations[JacocoPlugin.ANT_CONFIGURATION_NAME]
-        }
-        // can't directly use the existing inputFiles closure as we need the dir instead :\
-        conventionMapping(jacocoTask).map("inputDir", pcData.inputDir)
-        conventionMapping(jacocoTask).map("outputDir") {
-            project.file(
-                    "${project.buildDir}/${FD_INTERMEDIATES}/coverage-instrumented-classes/${config.dirName}")
-        }
-        variantData.jacocoInstrumentTask = jacocoTask
+        AndroidTask<JacocoInstrumentTask> jacocoTask = androidTasks.create(tasks,
+                new JacocoInstrumentTask.ConfigAction(scope, pcData));
+
+        jacocoTask.optionalDependsOn(tasks, pcData.classGeneratingTask)
 
         Copy agentTask = getJacocoAgentTask()
-        jacocoTask.dependsOn agentTask
+        jacocoTask.dependsOn(tasks, agentTask)
 
         // update dependency.
         PostCompilationData pcData2 = new PostCompilationData()
-        optionalDependsOn(jacocoTask, pcData.classGeneratingTask)
-        pcData2.classGeneratingTask = [jacocoTask]
+        pcData2.classGeneratingTask = [jacocoTask.name]
         pcData2.libraryGeneratingTask = [pcData.libraryGeneratingTask, agentTask]
 
         // update inputs
         pcData2.inputFiles = {
-            project.files(jacocoTask.getOutputDir()).files as List
+            project.files(scope.variantData.jacocoInstrumentTask.getOutputDir()).files as List
         }
         pcData2.inputDir = {
-            jacocoTask.getOutputDir()
+            scope.variantData.jacocoInstrumentTask.getOutputDir()
         }
         pcData2.inputLibraries = {
             [pcData.inputLibraries.call(), [new File(agentTask.destinationDir, FILE_JACOCO_AGENT)]].
@@ -2321,20 +1683,6 @@
         return pcData2
     }
 
-    private static ProGuardTask createShrinkingProGuardTask(
-            @NonNull Project project,
-            @NonNull String name) {
-        ProGuardTask task = project.tasks.create(name, ProGuardTask)
-
-        task.dontobfuscate()
-        task.dontoptimize()
-        task.dontpreverify()
-        task.dontwarn()
-        task.forceprocessing()
-
-        return task;
-    }
-
     public void createJackTask(
             @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
             @Nullable BaseVariantData<? extends BaseVariantOutputData> testedVariantData) {
@@ -2537,27 +1885,44 @@
         // loop on all outputs. The only difference will be the name of the task, and location
         // of the generated data.
         for (ApkVariantOutputData vod : variantData.outputs) {
-            VariantOutputScope variantOutputScope = new VariantOutputScope(variantScope, vod);
+            VariantOutputScope variantOutputScope = vod.scope;
 
             // create final var inside the loop to ensure the closures will work.
             final ApkVariantOutputData variantOutputData = vod
 
             String outputName = variantOutputData.fullName
 
-            AndroidTask<PackageApplication> packageApp = androidTasks.create(
-                    tasks,
+            // When shrinking resources, rather than having the packaging task
+            // directly map to the packageOutputFile of ProcessAndroidResources,
+            // we insert the ShrinkResources task into the chain, such that its
+            // input is the ProcessAndroidResources packageOutputFile, and its
+            // output is what the PackageApplication task reads.
+            AndroidTask<ShrinkResources> shrinkTask = null;
+
+            if (config.isMinifyEnabled() && config.getBuildType().isShrinkResources() && !config
+                    .getUseJack()) {
+                shrinkTask = androidTasks.create(tasks,
+                        new ShrinkResources.ConfigAction(variantOutputScope));
+                shrinkTask.dependsOn(tasks,
+                        variantScope.obfuscationTask,
+                        variantOutputScope.manifestProcessorTask,
+                        variantOutputScope.processResourcesTask);
+            }
+
+            AndroidTask<PackageApplication> packageApp = androidTasks.create(tasks,
                     new PackageApplication.ConfigAction(variantOutputScope));
 
             packageApp.dependsOn(tasks,
-                    variantOutputData.processResourcesTask,
-                    variantData.processJavaResourcesTask,
-                    variantOutputScope.getVariantScope().getNdkBuildable());
+                    variantOutputScope.processResourcesTask,
+                    variantOutputScope.variantScope.processJavaResourcesTask,
+                    variantOutputScope.variantScope.getNdkBuildable());
 
-            TaskManager.optionalDependsOn(
-                    packageApp,
+            packageApp.optionalDependsOn(
                     tasks,
-                    variantData.dexTask,
-                    variantData.javaCompileTask,
+                    shrinkTask,
+                    variantOutputScope.variantScope.dexTask,
+                    variantOutputScope.variantScope.javaCompileTask,
+                    variantData.javaCompileTask,  // TODO: Remove when Jack is converted to AndroidTask.
                     variantOutputData.packageSplitResourcesTask,
                     variantOutputData.packageSplitAbiTask);
 
@@ -2688,49 +2053,23 @@
         // right output if there are more than one.
         // Add a task to install the application package
         if (signedApk) {
-            InstallVariantTask installTask = project.tasks.
-                    create("install${config.fullName.capitalize()}",
-                            InstallVariantTask)
-            installTask.description = "Installs the ${variantData.description}."
-            installTask.group = INSTALL_GROUP
-            installTask.projectName = project.name
-            installTask.variantData = variantData
-            installTask.timeOutInMs = getExtension().getAdbOptions().getTimeOutInMs()
-            installTask.installOptions = getExtension().getAdbOptions().getInstallOptions()
-            installTask.processExecutor = androidBuilder.getProcessExecutor()
-            conventionMapping(installTask).map("adbExe") { sdkHandler.sdkInfo?.adb }
-            conventionMapping(installTask).map("splitSelectExe") {
-                String path = androidBuilder.targetInfo?.buildTools?.getPath(
-                        BuildToolInfo.PathId.SPLIT_SELECT)
-                if (path != null) {
-                    File splitSelectExe = new File(path)
-                    return splitSelectExe.exists() ? splitSelectExe : null;
-                } else {
-                    return null;
-                }
-            }
-            installTask.dependsOn variantData.assembleVariantTask
-            variantData.installTask = installTask
+            AndroidTask<InstallVariantTask> installTask = androidTasks.create(
+                    tasks,
+                    new InstallVariantTask.ConfigAction(variantScope));
+            installTask.dependsOn(tasks, variantData.assembleVariantTask)
         }
 
-
         if (getExtension().lintOptions.checkReleaseBuilds) {
             createLintVitalTask(variantData)
         }
 
         // add an uninstall task
-        def uninstallTask = project.tasks.create(
-                "uninstall${variantData.variantConfiguration.fullName.capitalize()}",
-                UninstallTask)
-        uninstallTask.description = "Uninstalls the ${variantData.description}."
-        uninstallTask.group = INSTALL_GROUP
-        uninstallTask.variant = variantData
-        uninstallTask.androidBuilder = androidBuilder
-        uninstallTask.timeOutInMs = getExtension().getAdbOptions().getTimeOutInMs()
+        AndroidTask<UninstallTask> uninstallTask = androidTasks.create(
+                tasks,
+                new UninstallTask.ConfigAction(variantScope));
 
-        variantData.uninstallTask = uninstallTask
         tasks.named(UNINSTALL_ALL) {
-            it.dependsOn uninstallTask
+            it.dependsOn uninstallTask.name
         }
     }
 
@@ -2742,12 +2081,11 @@
     }
 
     public Task createAssembleTask(
+            TaskFactory tasks,
             @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
         Task assembleTask = project.tasks.
                 create("assemble${variantData.variantConfiguration.fullName.capitalize()}")
-        assembleTask.description = "Assembles the ${variantData.description}."
-        assembleTask.group = BUILD_GROUP
-        return assembleTask
+        return assembleTask;
     }
 
     public Copy getJacocoAgentTask() {
@@ -2805,181 +2143,24 @@
      */
     @Nullable
     public File maybeCreateProguardTasks(
-            final @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            final @Nullable BaseVariantData<? extends BaseVariantOutputData> testedVariantData,
-            final @NonNull PostCompilationData pcData) {
-
-        if (!variantData.getVariantConfiguration().isMinifyEnabled()) {
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope,
+            @NonNull final PostCompilationData pcData) {
+        if (!scope.variantData.getVariantConfiguration().isMinifyEnabled()) {
             return null;
         }
 
-        final VariantConfiguration variantConfig = variantData.variantConfiguration
-
-        // use single output for now.
-        final BaseVariantOutputData variantOutputData = variantData.outputs.get(0)
-
-        def proguardTask = project.tasks.create(
-                "proguard${variantData.variantConfiguration.fullName.capitalize()}",
-                AndroidProGuardTask)
-
-        if (testedVariantData != null) {
-            proguardTask.dependsOn testedVariantData.obfuscationTask
-        }
-
-        variantData.obfuscationTask = proguardTask
-        variantData.mappingFileProviderTask = proguardTask
-
-        // --- Output File ---
-
-        final File outFile = variantData instanceof LibraryVariantData ?
-            project.file(
-                    "${project.buildDir}/${FD_INTERMEDIATES}/$DIR_BUNDLES/${variantData.variantConfiguration.dirName}/classes.jar") :
-            project.file(
-                    "${project.buildDir}/${FD_INTERMEDIATES}/classes-proguard/${variantData.variantConfiguration.dirName}/classes.jar")
-        variantData.obfuscatedClassesJar = outFile
-
-        // --- Proguard Config ---
-
-        if (testedVariantData != null) {
-            // Don't remove any code in tested app.
-            proguardTask.dontshrink()
-            proguardTask.dontoptimize()
-
-            // We can't call dontobfuscate, since that would make ProGuard ignore the mapping file.
-            proguardTask.keep("class * {*;}")
-            proguardTask.keep("interface * {*;}")
-            proguardTask.keep("enum * {*;}")
-
-            // Input the mapping from the tested app so that we can deal with obfuscated code.
-            proguardTask.applymapping(testedVariantData.mappingFile)
-
-            // All -dontwarn rules for test dependencies should go in here:
-            proguardTask.configuration(
-                    testedVariantData.variantConfiguration.testProguardFiles)
-        } else {
-            if (variantConfig.isTestCoverageEnabled()) {
-                // when collecting coverage, don't remove the JaCoCo runtime
-                proguardTask.keep("class com.vladium.** {*;}")
-                proguardTask.keep("class org.jacoco.** {*;}")
-                proguardTask.keep("interface org.jacoco.** {*;}")
-                proguardTask.dontwarn("org.jacoco.**")
-            }
-
-            proguardTask.configuration {
-                List<File> proguardFiles = variantConfig.getProguardFiles(true /*includeLibs*/,
-                        [extension.getDefaultProguardFile(DEFAULT_PROGUARD_CONFIG_FILE)])
-
-                proguardFiles + [variantOutputData.processResourcesTask.proguardOutputFile]
-            }
-        }
-
-        // --- InJars / LibraryJars ---
-
-        if (variantData instanceof LibraryVariantData) {
-            String packageName = variantConfig.getPackageFromManifest()
-            if (packageName == null) {
-                throw new BuildException("Failed to read manifest", null)
-            }
-            packageName = packageName.replace('.', '/');
-
-            // injar: the compilation output
-            // exclude R files and such from output
-            String exclude = '!' + packageName + "/R.class"
-            exclude += (', !' + packageName + "/R\$*.class")
-            if (!((LibraryExtension) getExtension()).packageBuildConfig) {
-                exclude += (', !' + packageName + "/Manifest.class")
-                exclude += (', !' + packageName + "/Manifest\$*.class")
-                exclude += (', !' + packageName + "/BuildConfig.class")
-            }
-            proguardTask.injars(pcData.inputDir, filter: exclude)
-
-            // include R files and such for compilation
-            String include = exclude.replace('!', '')
-            proguardTask.libraryjars(pcData.inputDir, filter: include)
-
-            // injar: the local dependencies
-            Closure inJars = {
-                DependencyManager.getPackagedLocalJarFileList(variantData.variantDependency)
-            }
-
-            proguardTask.injars(inJars, filter: '!META-INF/MANIFEST.MF')
-
-            // libjar: the library dependencies. In this case we take all the compile-scope
-            // dependencies
-            Closure libJars = {
-                // get all the compiled jar.
-                Set<File> compiledJars = androidBuilder.getCompileClasspath(variantConfig)
-                // and remove local jar that are also packaged
-                List<File> localJars =
-                        DependencyManager.getPackagedLocalJarFileList(variantData.variantDependency)
-
-                compiledJars.findAll({ !localJars.contains(it) })
-            }
-
-            proguardTask.libraryjars(libJars, filter: '!META-INF/MANIFEST.MF')
-
-            // ensure local jars keep their package names
-            proguardTask.keeppackagenames()
-        } else {
-            // injar: the compilation output
-            proguardTask.injars(pcData.inputDir)
-
-            // injar: the packaged dependencies
-            proguardTask.injars(pcData.inputLibraries, filter: '!META-INF/MANIFEST.MF')
-
-            // the provided-only jars as libraries.
-            Closure libJars = {
-                variantData.variantConfiguration.providedOnlyJars
-            }
-
-            proguardTask.libraryjars(libJars)
-        }
-
-        // libraryJars: the runtime jars. Do this in doFirst since the boot classpath isn't
-        // available until the SDK is loaded in the prebuild task
-        proguardTask.doFirst {
-            for (String runtimeJar : androidBuilder.getBootClasspathAsStrings()) {
-                proguardTask.libraryjars(runtimeJar)
-            }
-        }
-
-        if (testedVariantData != null) {
-            // input the tested app as library
-            proguardTask.libraryjars(testedVariantData.javaCompileTask.destinationDir)
-            // including its dependencies
-            Closure testedPackagedJars = {
-                androidBuilder.getPackagedJars(testedVariantData.variantConfiguration)
-            }
-
-            proguardTask.libraryjars(testedPackagedJars, filter: '!META-INF/MANIFEST.MF')
-        }
-
-        // --- Out files ---
-
-        proguardTask.outjars(outFile)
-
-        final File proguardOut = project.file(
-                "${project.buildDir}/${FD_OUTPUTS}/mapping/${variantData.variantConfiguration.dirName}")
-
-        proguardTask.dump(new File(proguardOut, "dump.txt"))
-        proguardTask.printseeds(new File(proguardOut, "seeds.txt"))
-        proguardTask.printusage(new File(proguardOut, "usage.txt"))
-        proguardTask.printmapping(new File(proguardOut, "mapping.txt"))
-
-        // proguard doesn't verify that the seed/mapping/usage folders exist and will fail
-        // if they don't so create them.
-        proguardTask.doFirst {
-            proguardOut.mkdirs()
-        }
+        AndroidTask<AndroidProGuardTask> proguardTask =
+                androidTasks.create(tasks, new AndroidProGuardTask.ConfigAction(scope, pcData));
+        scope.obfuscationTask = proguardTask
 
         // update dependency.
-        optionalDependsOn(proguardTask, pcData.classGeneratingTask)
-        optionalDependsOn(proguardTask, pcData.libraryGeneratingTask)
-        pcData.libraryGeneratingTask = [proguardTask]
-        pcData.classGeneratingTask = [proguardTask]
+        proguardTask.optionalDependsOn(tasks, pcData.classGeneratingTask, pcData.libraryGeneratingTask)
+        pcData.libraryGeneratingTask = [proguardTask.name]
+        pcData.classGeneratingTask = [proguardTask.name]
 
-        // Update the inputs
-        return outFile;
+        // Return output file.
+        return scope.getProguardOutputFile();
     }
 
     public void createReportTasks(
@@ -2996,25 +2177,35 @@
     }
 
     public void createAnchorTasks(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
-        createPreBuildTasks(variantData)
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        createPreBuildTasks(tasks, scope)
 
         // also create sourceGenTask
-        variantData.sourceGenTask = project.tasks.create(
-                "generate${variantData.variantConfiguration.fullName.capitalize()}Sources")
+        final BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
+        scope.sourceGenTask = androidTasks.create(tasks,
+                "generate${variantData.variantConfiguration.fullName.capitalize()}Sources") { Task task ->
+            variantData.sourceGenTask = task
+        }
         // and resGenTask
-        variantData.resourceGenTask = project.tasks.create(
-                "generate${variantData.variantConfiguration.fullName.capitalize()}Resources")
-        variantData.assetGenTask = project.tasks.create(
-                "generate${variantData.variantConfiguration.fullName.capitalize()}Assets")
+        scope.resourceGenTask = androidTasks.create(tasks,
+                "generate${variantData.variantConfiguration.fullName.capitalize()}Resources") { Task task ->
+            variantData.resourceGenTask = task
+        }
+
+        scope.assetGenTask = androidTasks.create(tasks,
+                "generate${variantData.variantConfiguration.fullName.capitalize()}Assets") { Task task ->
+            variantData.assetGenTask = task
+        }
+
         // and compile task
-        createCompileAnchorTask(variantData)
+        createCompileAnchorTask(tasks, scope)
     }
 
-    private void createPreBuildTasks(BaseVariantData<? extends BaseVariantOutputData> variantData) {
+    private void createPreBuildTasks(@NonNull TaskFactory tasks, @NonNull VariantScope scope) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
         variantData.preBuildTask = project.tasks.create(
                 "pre${variantData.variantConfiguration.fullName.capitalize()}Build")
-        variantData.preBuildTask.dependsOn MAIN_PREBUILD
 
         def prepareDependenciesTask = project.tasks.create(
                 "prepare${variantData.variantConfiguration.fullName.capitalize()}Dependencies",
@@ -3032,41 +2223,37 @@
         prepareDependenciesTask.addChecker(configurationDependencies.checker)
 
         for (LibraryDependencyImpl lib : configurationDependencies.libraries) {
-            dependencyManager.addDependencyToPrepareTask(variantData, prepareDependenciesTask, lib)
+            dependencyManager.
+                    addDependencyToPrepareTask(variantData, prepareDependenciesTask, lib)
         }
     }
 
-    private void createCompileAnchorTask(
-            BaseVariantData<? extends BaseVariantOutputData> variantData) {
-        variantData.compileTask = project.tasks.create(
-                "compile${variantData.variantConfiguration.fullName.capitalize()}Sources")
-        variantData.compileTask.group = BUILD_GROUP
-
-        variantData.assembleVariantTask.dependsOn variantData.compileTask
+    private void createCompileAnchorTask(@NonNull TaskFactory tasks, @NonNull VariantScope scope) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
+        scope.compileTask = androidTasks.create(tasks,
+                "compile${variantData.variantConfiguration.fullName.capitalize()}Sources") { DefaultTask task ->
+            variantData.compileTask = task
+            variantData.compileTask.group = BUILD_GROUP
+        }
+        variantData.assembleVariantTask.dependsOn scope.compileTask.name
     }
 
     public void createCheckManifestTask(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
+            @NonNull TaskFactory tasks,
+            @NonNull VariantScope scope) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
         String name = variantData.variantConfiguration.fullName
-        variantData.checkManifestTask = project.tasks.create(
+        scope.checkManifestTask = androidTasks.create(tasks,
                 "check${name.capitalize()}Manifest",
-                CheckManifest)
-        variantData.checkManifestTask.dependsOn variantData.preBuildTask
-
-        variantData.prepareDependenciesTask.dependsOn variantData.checkManifestTask
-
-        variantData.checkManifestTask.variantName = name
-        conventionMapping(variantData.checkManifestTask).map("manifest") {
-            variantData.variantConfiguration.getDefaultSourceSet().manifestFile
-        }
-    }
-
-    public static void optionalDependsOn(@NonNull AndroidTask main, TaskFactory taskFactory, Task... dependencies) {
-        for (Task dependency : dependencies) {
-            if (dependency != null) {
-                main.dependsOn(taskFactory, dependency)
+                CheckManifest) { CheckManifest checkManifestTask ->
+            variantData.checkManifestTask = checkManifestTask
+            checkManifestTask.variantName = name
+            ConventionMappingHelper.map(variantData.checkManifestTask, "manifest") {
+                variantData.variantConfiguration.getDefaultSourceSet().manifestFile
             }
         }
+        scope.checkManifestTask.dependsOn(tasks, variantData.preBuildTask)
+        variantData.prepareDependenciesTask.dependsOn(scope.checkManifestTask.name)
     }
 
     public static void optionalDependsOn(@NonNull Task main, Task... dependencies) {
@@ -3104,25 +2291,4 @@
     protected Logger getLogger() {
         return logger
     }
-
-    @NonNull
-    protected static List<SymbolFileProviderImpl> getTextSymbolDependencies(
-            List<LibraryDependency> libraries) {
-
-        List<SymbolFileProviderImpl> list = Lists.newArrayListWithCapacity(libraries.size())
-
-        for (LibraryDependency lib : libraries) {
-            list.add(new SymbolFileProviderImpl(lib.manifest, lib.symbolFile))
-        }
-
-        return list
-    }
-
-    protected VariantScope createVariantScope(BaseVariantData variantData) {
-        return new VariantScope(
-                globalScope,
-                variantData,
-                getNdkBuildable(variantData),
-                getNdkOutputDirectories(variantData));
-    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TestApplicationTaskManager.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TestApplicationTaskManager.java
index 876c00c..1111641 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TestApplicationTaskManager.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/TestApplicationTaskManager.java
@@ -22,6 +22,7 @@
 import com.android.annotations.Nullable;
 import com.android.build.gradle.BaseExtension;
 import com.android.build.gradle.TestExtension;
+import com.android.build.gradle.internal.scope.VariantScope;
 import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask;
 import com.android.build.gradle.internal.test.TestApplicationTestData;
 import com.android.build.gradle.internal.variant.BaseVariantData;
@@ -125,9 +126,10 @@
     @Override
     @Nullable
     public File maybeCreateProguardTasks(
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @Nullable BaseVariantData<? extends BaseVariantOutputData> testedVariantData,
-            @NonNull PostCompilationData pcData) {
+            TaskFactory tasks,
+            VariantScope scope,
+            @NonNull final PostCompilationData pcData) {
+        BaseVariantData<? extends BaseVariantOutputData> variantData = scope.getVariantData();
 
         final TestModuleProGuardTask proguardTask = project.getTasks().create(
                 "proguard"+ variantData.getVariantConfiguration().getFullName().toUpperCase(
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/VariantManager.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/VariantManager.java
index a408510..873dfcd 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/VariantManager.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/VariantManager.java
@@ -291,16 +291,6 @@
                     new Recorder.Property(SpanRecorders.VARIANT, variantData.getName()));
         }
 
-        // create the lint tasks.
-        ThreadRecorder.get().record(ExecutionType.VARIANT_MANAGER_CREATE_LINT_TASKS,
-                new Recorder.Block<Void>() {
-                    @Override
-                    public Void call() throws Exception {
-                        taskManager.createLintTasks(tasks, variantDataList);
-                        return null;
-                    }
-                });
-
         // Create the variant API objects after the tasks have been created!
         createApiObjects();
 
@@ -314,7 +304,7 @@
             TaskFactory tasks,
             final BaseVariantData<?> variantData) {
         if (variantData.getType().isForTesting()) {
-            variantData.assembleVariantTask = taskManager.createAssembleTask(variantData);
+            variantData.assembleVariantTask = taskManager.createAssembleTask(tasks, variantData);
         } else {
             BuildTypeData buildTypeData =
                     buildTypes.get(variantData.getVariantConfiguration().getBuildType().getName());
@@ -323,7 +313,7 @@
                 // Reuse assemble task for build type if there is no product flavor.
                 variantData.assembleVariantTask = buildTypeData.getAssembleTask();
             } else {
-                variantData.assembleVariantTask = taskManager.createAssembleTask(variantData);
+                variantData.assembleVariantTask = taskManager.createAssembleTask(tasks, variantData);
 
                 // setup the task dependencies
                 // build type
@@ -333,7 +323,7 @@
                 GradleVariantConfiguration variantConfig = variantData.getVariantConfiguration();
                 for (GroupableProductFlavor flavor : variantConfig.getProductFlavors()) {
                     productFlavors.get(flavor.getName()).getAssembleTask()
-                            .dependsOn(variantData.assembleVariantTask);
+                             .dependsOn(variantData.assembleVariantTask);
                 }
 
                 // assembleTask for this flavor(dimension), created on demand if needed.
@@ -447,9 +437,6 @@
      * Create all variants.
      */
     public void populateVariantDataList() {
-        // Add a compile lint task
-        taskManager.createLintCompileTask();
-
         if (productFlavors.isEmpty()) {
             createVariantDataForProductFlavors(
                     Collections.<com.android.build.gradle.api.GroupableProductFlavor>emptyList());
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/coverage/JacocoInstrumentTask.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/coverage/JacocoInstrumentTask.groovy
index 82e55b3..cc37469 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/coverage/JacocoInstrumentTask.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/coverage/JacocoInstrumentTask.groovy
@@ -16,6 +16,10 @@
 
 package com.android.build.gradle.internal.coverage
 
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import org.gradle.api.DefaultTask
 import org.gradle.api.file.FileCollection
 import org.gradle.api.tasks.InputDirectory
@@ -23,6 +27,8 @@
 import org.gradle.api.tasks.OutputDirectory
 import org.gradle.api.tasks.TaskAction
 
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 /**
  * Simple Jacoco instrument task that calls the Ant version.
  */
@@ -53,4 +59,40 @@
             fileset(dir: getInputDir())
         }
     }
+
+    public static class ConfigAction implements TaskConfigAction<JacocoInstrumentTask> {
+
+        VariantScope scope;
+
+        TaskManager.PostCompilationData pcData;
+
+        ConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+            this.scope = scope
+            this.pcData = pcData
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("instrument");
+        }
+
+        @Override
+        Class<JacocoInstrumentTask> getType() {
+            return JacocoInstrumentTask.class
+        }
+
+        @Override
+        void execute(JacocoInstrumentTask jacocoTask) {
+
+            ConventionMappingHelper.map(jacocoTask, "jacocoClasspath") {
+                scope.globalScope.project.configurations[JacocoPlugin.ANT_CONFIGURATION_NAME]
+            }
+            // can't directly use the existing inputFiles closure as we need the dir instead :\
+            ConventionMappingHelper.map(jacocoTask, "inputDir", pcData.inputDir)
+            ConventionMappingHelper.map(jacocoTask, "outputDir") {
+                new File("${scope.globalScope.buildDir}/${FD_INTERMEDIATES}/coverage-instrumented-classes/${scope.variantConfiguration.dirName}")
+            }
+            scope.variantData.jacocoInstrumentTask = jacocoTask
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.java
index 12b84d7..838ad3e 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/model/ModelBuilder.java
@@ -29,6 +29,7 @@
 import com.android.build.gradle.internal.VariantManager;
 import com.android.build.gradle.internal.core.GradleVariantConfiguration;
 import com.android.build.gradle.internal.dsl.GroupableProductFlavor;
+import com.android.build.gradle.internal.scope.VariantScope;
 import com.android.build.gradle.internal.variant.ApkVariantOutputData;
 import com.android.build.gradle.internal.variant.BaseVariantData;
 import com.android.build.gradle.internal.variant.BaseVariantOutputData;
@@ -279,7 +280,9 @@
                 Sets.newHashSet(variantData.prepareDependenciesTask.getName(),
                         taskManager.createMockableJar.getName()),
                 extraGeneratedSourceFolders != null ? extraGeneratedSourceFolders : Collections.<File>emptyList(),
-                variantData.javaCompileTask.getDestinationDir(),
+                (variantData.javaCompileTask != null) ?
+                        variantData.javaCompileTask.getDestinationDir() :
+                        variantData.getScope().getJavaOutputDir(),
                 variantData.processJavaResourcesTask.getDestinationDir(),
                 dependencies,
                 sourceProviders.variantSourceProvider,
@@ -331,10 +334,11 @@
             outputs.add(new AndroidArtifactOutputImpl(
                     outputFiles.build(),
                     variantOutputData.assembleTask.getName(),
-                    variantOutputData.manifestProcessorTask.getManifestOutputFile(),
+                    variantOutputData.getScope().getManifestOutputFile(),
                     intVersionCode));
         }
 
+        VariantScope scope = variantData.getScope();
         return new AndroidArtifactImpl(
                 name,
                 outputs,
@@ -342,12 +346,14 @@
                 variantConfiguration.isSigningReady() || variantData.outputsAreSigned,
                 signingConfigName,
                 variantConfiguration.getApplicationId(),
-                variantData.sourceGenTask.getName(),
-                variantData.compileTask.getName(),
+                scope.getSourceGenTask().getName(),
+                scope.getCompileTask().getName(),
                 getGeneratedSourceFolders(variantData),
                 getGeneratedResourceFolders(variantData),
-                variantData.javaCompileTask.getDestinationDir(),
-                variantData.processJavaResourcesTask.getDestinationDir(),
+                (variantData.javaCompileTask != null) ?
+                        variantData.javaCompileTask.getDestinationDir() :
+                        scope.getJavaOutputDir(),
+                scope.getJavaResourcesDestinationDir(),
                 DependenciesImpl.cloneDependencies(variantData, androidBuilder),
                 sourceProviders.variantSourceProvider,
                 sourceProviders.multiFlavorSourceProvider,
@@ -404,15 +410,16 @@
             folders = Lists.newArrayListWithExpectedSize(5);
         }
 
-        // The R class is only generated by the first output.
-        BaseVariantOutputData variantOutputData = variantData.getOutputs().get(0);
-        folders.add(variantOutputData.processResourcesTask.getSourceOutputDir());
+        VariantScope scope = variantData.getScope();
 
-        folders.add(variantData.aidlCompileTask.getSourceOutputDir());
-        folders.add(variantData.generateBuildConfigTask.getSourceOutputDir());
+        // The R class is only generated by the first output.
+        folders.add(scope.getRClassSourceOutputDir());
+
+        folders.add(scope.getAidlSourceOutputDir());
+        folders.add(scope.getBuildConfigSourceOutputDir());
         Boolean ndkMode = variantData.getVariantConfiguration().getMergedFlavor().getRenderscriptNdkModeEnabled();
         if (ndkMode == null || !ndkMode) {
-            folders.add(variantData.renderscriptCompileTask.getSourceOutputDir());
+            folders.add(scope.getRenderscriptSourceOutputDir());
         }
 
         return folders;
@@ -436,8 +443,10 @@
             result = Lists.newArrayListWithCapacity(2);
         }
 
-        result.add(variantData.renderscriptCompileTask.getResOutputDir());
-        result.add(variantData.generateResValuesTask.getResOutputDir());
+        VariantScope scope = variantData.getScope();
+
+        result.add(scope.getRenderscriptResOutputDir());
+        result.add(scope.getGeneratedResOutputDir());
 
         return result;
     }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTask.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTask.java
index eed096a..008de57 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTask.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTask.java
@@ -88,7 +88,7 @@
      * @param taskFactory TaskFactory used to configure the task for dependencies.
      * @param other The task that this depends on.
      */
-    public void dependsOn(final TaskFactory taskFactory, final AndroidTask<? extends Task> other) {
+    public void dependsOn(final TaskFactory taskFactory, final AndroidTask<?> other) {
         taskFactory.named(name, new Action<Task>() {
             @Override
             public void execute(Task task) {
@@ -100,21 +100,55 @@
     }
 
     /**
-     * Add dependency on another object.
+     * Add dependency on objects.
      * This method adds dependencies on any objects accepted by {@link Task#dependsOn} and is
      * needed for compatibility until all tasks are trasitioned to AndroidTask.
      * @param taskFactory TaskFactory used to configure the task for dependencies.
-     * @param other Objects accepted by {@link Task#dependsOn}.
+     * @param dependencies Objects accepted by {@link Task#dependsOn}.
      */
-    public void dependsOn(final TaskFactory taskFactory, final Object... other) {
+    public void dependsOn(final TaskFactory taskFactory, final Object... dependencies) {
         taskFactory.named(name, new Action<Task>() {
             @Override
             public void execute(Task task) {
-                task.dependsOn(other);
+                for (Object dependency : dependencies) {
+                    if (dependency instanceof AndroidTask) {
+                        task.dependsOn(((AndroidTask) dependency).getName());
+                    } else {
+                        task.dependsOn(dependency);
+                    }
+                }
             }
         });
     }
 
+    /**
+     * Add dependency on other objects if the object is not null.
+     * This method adds dependencies on any objects accepted by {@link Task#dependsOn} and is
+     * needed for compatibility until all tasks are trasitioned to AndroidTask.
+     * @param taskFactory TaskFactory used to configure the task for dependencies.
+     * @param dependencies Objects accepted by {@link Task#dependsOn}.
+     */
+    public void optionalDependsOn(final TaskFactory taskFactory, final Object... dependencies) {
+        for (Object dependency : dependencies) {
+            if (dependency != null) {
+                if (dependency instanceof AndroidTask) {
+                    dependsOn(taskFactory, ((AndroidTask) dependency).getName());
+                } else {
+                    dependsOn(taskFactory, dependency);
+                }
+            }
+        }
+    }
+
+
+    public void optionalDependsOn(final TaskFactory taskFactory, @NonNull List<?> dependencies) {
+        for (Object dependency : dependencies) {
+            if (dependency != null) {
+                dependsOn(taskFactory, dependency);
+            }
+        }
+    }
+
     private void addDependent(AndroidTask<? extends Task> tAndroidTask) {
         downstreamTasks.add(tAndroidTask);
     }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTaskRegistry.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTaskRegistry.java
index 44c6fec..c20330d 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTaskRegistry.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/AndroidTaskRegistry.java
@@ -19,11 +19,15 @@
 import com.android.build.gradle.internal.TaskFactory;
 
 import org.gradle.api.Action;
+import org.gradle.api.DefaultTask;
 import org.gradle.api.Task;
+import org.gradle.api.internal.ClosureBackedAction;
 
 import java.util.HashMap;
 import java.util.Map;
 
+import groovy.lang.Closure;
+
 /**
  * Registry for creating and storing AndroidTask.
  */
@@ -44,6 +48,31 @@
         return newTask;
     }
 
+    public synchronized AndroidTask<Task> create(
+            TaskFactory taskFactory,
+            String taskName,
+            Closure configAction) {
+
+        taskFactory.create(taskName, DefaultTask.class, new ClosureBackedAction<Task>(configAction));
+        final AndroidTask<Task> newTask = new AndroidTask<Task>(taskName, Task.class);
+        tasks.put(taskName, newTask);
+
+        return newTask;
+    }
+
+    public synchronized <T extends Task> AndroidTask<T> create(
+            TaskFactory taskFactory,
+            String taskName,
+            Class<T> taskClass,
+            Closure configAction) {
+
+        taskFactory.create(taskName, taskClass, new ClosureBackedAction<T>(configAction));
+        final AndroidTask<T> newTask = new AndroidTask<T>(taskName, taskClass);
+        tasks.put(taskName, newTask);
+
+        return newTask;
+    }
+
     public <T extends Task> AndroidTask<T> create(
             TaskFactory taskFactory,
             TaskConfigAction<T> configAction) {
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/GlobalScope.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/GlobalScope.java
index b1d7137..d0b001a 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/GlobalScope.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/GlobalScope.java
@@ -16,14 +16,19 @@
 
 package com.android.build.gradle.internal.scope;
 
+import static com.android.builder.model.AndroidProject.FD_GENERATED;
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES;
 import static com.android.builder.model.AndroidProject.FD_OUTPUTS;
 import static com.android.builder.model.AndroidProject.PROPERTY_APK_LOCATION;
 
 import com.android.annotations.NonNull;
 import com.android.build.gradle.BaseExtension;
+import com.android.build.gradle.internal.SdkHandler;
 import com.android.builder.core.AndroidBuilder;
+import com.android.builder.model.AndroidProject;
 
 import org.gradle.api.Project;
+import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry;
 
 import java.io.File;
 
@@ -39,16 +44,31 @@
     private String projectBaseName;
     @NonNull
     private BaseExtension extension;
+    @NonNull
+    private SdkHandler sdkHandler;
+    @NonNull
+    private ToolingModelBuilderRegistry toolingRegistry;
+
+    @NonNull
+    private final File intermediatesDir;
+    @NonNull
+    private final File generatedDir;
 
     public GlobalScope(
             @NonNull Project project,
             @NonNull AndroidBuilder androidBuilder,
             @NonNull String projectBaseName,
-            @NonNull BaseExtension extension) {
+            @NonNull BaseExtension extension,
+            @NonNull SdkHandler sdkHandler,
+            @NonNull ToolingModelBuilderRegistry toolingRegistry) {
         this.project = project;
         this.androidBuilder = androidBuilder;
         this.projectBaseName = projectBaseName;
         this.extension = extension;
+        this.sdkHandler = sdkHandler;
+        this.toolingRegistry = toolingRegistry;
+        intermediatesDir = new File(getBuildDir(), FD_INTERMEDIATES);
+        generatedDir = new File(getBuildDir(), FD_GENERATED);
     }
 
     @NonNull
@@ -72,11 +92,31 @@
     }
 
     @NonNull
+    public SdkHandler getSdkHandler() {
+        return sdkHandler;
+    }
+
+    @NonNull
+    public ToolingModelBuilderRegistry getToolingRegistry() {
+        return toolingRegistry;
+    }
+
+    @NonNull
     public File getBuildDir() {
         return project.getBuildDir();
     }
 
     @NonNull
+    public File getIntermediatesDir() {
+        return intermediatesDir;
+    }
+
+    @NonNull
+    public File getGeneratedDir() {
+        return generatedDir;
+    }
+
+    @NonNull
     public String getDefaultApkLocation() {
         return getBuildDir() + "/" + FD_OUTPUTS + "/apk";
     }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantOutputScope.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantOutputScope.java
index f9a7390..8534920 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantOutputScope.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantOutputScope.java
@@ -16,15 +16,28 @@
 
 package com.android.build.gradle.internal.scope;
 
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES;
+
 import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
 import com.android.build.gradle.internal.TaskFactory;
+import com.android.build.gradle.internal.TaskManager;
 import com.android.build.gradle.internal.variant.ApkVariantData;
 import com.android.build.gradle.internal.variant.BaseVariantOutputData;
+import com.android.build.gradle.tasks.CompatibleScreensManifest;
+import com.android.build.gradle.tasks.ManifestProcessorTask;
 import com.android.build.gradle.tasks.PackageApplication;
+import com.android.build.gradle.tasks.PackageSplitAbi;
+import com.android.build.gradle.tasks.PackageSplitRes;
+import com.android.build.gradle.tasks.ProcessAndroidResources;
 import com.android.build.gradle.tasks.ZipAlign;
+import com.android.builder.model.AndroidProject;
 import com.android.utils.StringHelper;
+import com.android.xml.AndroidManifest;
 import com.google.common.collect.ImmutableMap;
 
+import org.gradle.api.Task;
+
 import java.io.File;
 import java.util.Map;
 
@@ -38,6 +51,13 @@
     @NonNull
     private BaseVariantOutputData variantOutputData;
 
+    // Tasks
+    private AndroidTask<CompatibleScreensManifest> compatibleScreensManifestTask;
+
+    private AndroidTask<? extends ManifestProcessorTask> manifestProcessorTask;
+
+    private AndroidTask<ProcessAndroidResources> processResourcesTask;
+
     public VariantOutputScope(
             @NonNull VariantScope variantScope,
             @NonNull BaseVariantOutputData variantOutputData) {
@@ -61,6 +81,16 @@
     }
 
     @NonNull
+    public String getTaskName(@NonNull String prefix) {
+        return getTaskName(prefix, "");
+    }
+
+    @NonNull
+    public String getTaskName(@NonNull String prefix, @NonNull String suffix) {
+        return prefix + StringHelper.capitalize(getVariantOutputData().getFullName()) + suffix;
+    }
+
+    @NonNull
     public File getPackageApk() {
         ApkVariantData apkVariantData = (ApkVariantData) variantScope.getVariantData();
 
@@ -79,4 +109,74 @@
             return getGlobalScope().getProject().file(getGlobalScope().getDefaultApkLocation() + "/" + apkName);
         }
     }
+
+    @NonNull
+    public File getCompressedResourceFile() {
+        return new File(getGlobalScope().getIntermediatesDir(), "/res/" +
+                "resources-" + variantOutputData.getBaseName() + "-stripped.ap_");
+    }
+
+    @NonNull
+    public File getCompatibleScreensManifestFile() {
+        return new File(getGlobalScope().getIntermediatesDir(),
+                "/manifests/density/" + variantOutputData.getDirName() + "/AndroidManifest.xml");
+
+    }
+
+    @NonNull
+    public File getManifestOutputFile() {
+        switch(variantScope.getVariantConfiguration().getType()) {
+            case DEFAULT:
+                return new File(getGlobalScope().getIntermediatesDir(),
+                        "/manifests/full/"  + variantOutputData.getDirName()
+                                + "/AndroidManifest.xml");
+            case LIBRARY:
+                return new File(getGlobalScope().getIntermediatesDir(),
+                        TaskManager.DIR_BUNDLES + "/"
+                                + getVariantScope().getVariantConfiguration().getDirName()
+                                + "/AndroidManifest.xml");
+            case ANDROID_TEST:
+                return new File(getGlobalScope().getIntermediatesDir(),
+                        "manifest/" + variantScope.getVariantConfiguration().getDirName()
+                                + "/AndroidManifest.xml");
+            default:
+                throw new RuntimeException(
+                        "getManifestOutputFile called for an unexpected variant.");
+        }
+    }
+
+    @NonNull
+    public File getProcessResourcePackageOutputFile() {
+        return new File(getGlobalScope().getIntermediatesDir(),
+                "res/resources-" + variantOutputData.getBaseName() + ".ap_");
+    }
+
+    // Tasks
+    @Nullable
+    public AndroidTask<CompatibleScreensManifest> getCompatibleScreensManifestTask() {
+        return compatibleScreensManifestTask;
+    }
+
+    public void setCompatibleScreensManifestTask(
+            @Nullable AndroidTask<CompatibleScreensManifest> compatibleScreensManifestTask) {
+        this.compatibleScreensManifestTask = compatibleScreensManifestTask;
+    }
+
+    public AndroidTask<? extends ManifestProcessorTask> getManifestProcessorTask() {
+        return manifestProcessorTask;
+    }
+
+    public void setManifestProcessorTask(
+            AndroidTask<? extends ManifestProcessorTask> manifestProcessorTask) {
+        this.manifestProcessorTask = manifestProcessorTask;
+    }
+
+    public AndroidTask<ProcessAndroidResources> getProcessResourcesTask() {
+        return processResourcesTask;
+    }
+
+    public void setProcessResourcesTask(
+            AndroidTask<ProcessAndroidResources> processResourcesTask) {
+        this.processResourcesTask = processResourcesTask;
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantScope.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantScope.java
index afabc3e..05d00df 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantScope.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/scope/VariantScope.java
@@ -16,19 +16,42 @@
 
 package com.android.build.gradle.internal.scope;
 
+import static com.android.builder.model.AndroidProject.FD_GENERATED;
+
 import com.android.annotations.NonNull;
-import com.android.build.gradle.BaseExtension;
+import com.android.annotations.Nullable;
+import com.android.build.gradle.internal.TaskManager;
 import com.android.build.gradle.internal.core.GradleVariantConfiguration;
+import com.android.build.gradle.internal.coverage.JacocoInstrumentTask;
+import com.android.build.gradle.internal.tasks.CheckManifest;
+import com.android.build.gradle.internal.tasks.FileSupplier;
+import com.android.build.gradle.internal.tasks.PrepareDependenciesTask;
 import com.android.build.gradle.internal.variant.ApkVariantData;
 import com.android.build.gradle.internal.variant.BaseVariantData;
 import com.android.build.gradle.internal.variant.BaseVariantOutputData;
-import com.android.build.gradle.tasks.ZipAlign;
-import com.android.builder.core.AndroidBuilder;
+import com.android.build.gradle.internal.variant.LibraryVariantData;
+import com.android.build.gradle.internal.variant.TestVariantData;
+import com.android.build.gradle.tasks.AidlCompile;
+import com.android.build.gradle.tasks.BinaryFileProviderTask;
+import com.android.build.gradle.tasks.Dex;
+import com.android.build.gradle.tasks.GenerateBuildConfig;
+import com.android.build.gradle.tasks.GenerateResValues;
+import com.android.build.gradle.tasks.MergeAssets;
+import com.android.build.gradle.tasks.MergeResources;
+import com.android.build.gradle.tasks.NdkCompile;
+import com.android.build.gradle.tasks.PreprocessResourcesTask;
+import com.android.build.gradle.tasks.ProcessAndroidResources;
+import com.android.build.gradle.tasks.RenderscriptCompile;
 import com.android.builder.core.VariantConfiguration;
-import com.google.common.collect.ImmutableMap;
+import com.android.builder.core.VariantType;
+import com.android.utils.StringHelper;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
-import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.tasks.Copy;
+import org.gradle.api.tasks.compile.AbstractCompile;
 
 import java.io.File;
 import java.util.Collection;
@@ -44,20 +67,67 @@
     private GlobalScope globalScope;
     @NonNull
     private BaseVariantData<? extends BaseVariantOutputData> variantData;
-    @NonNull
+
+    @Nullable
     private Collection<Object> ndkBuildable;
-    @NonNull
+    @Nullable
     private Collection<File> ndkOutputDirectories;
 
+    @Nullable
+    private File mergeResourceOutputDir;
+
+    // Tasks
+    private AndroidTask<Task> preBuildTask;
+    private AndroidTask<PrepareDependenciesTask> prepareDependenciesTask;
+    private AndroidTask<ProcessAndroidResources> generateRClassTask;
+
+    private AndroidTask<Task> sourceGenTask;
+    private AndroidTask<Task> resourceGenTask;
+    private AndroidTask<Task> assetGenTask;
+    private AndroidTask<CheckManifest> checkManifestTask;
+
+    private AndroidTask<RenderscriptCompile> renderscriptCompileTask;
+    private AndroidTask<AidlCompile> aidlCompileTask;
+    @Nullable
+    private AndroidTask<MergeResources> mergeResourcesTask;
+    @Nullable
+    private AndroidTask<MergeAssets> mergeAssetsTask;
+    private AndroidTask<GenerateBuildConfig> generateBuildConfigTask;
+    private AndroidTask<GenerateResValues> generateResValuesTask;
+
+    /**
+     * Anchor task for post-processing the merged resources to backport some features to earlier
+     * API versions, e.g. generate PNGs from vector drawables (vector drawables were added in 21).
+     */
+    @Nullable
+    private AndroidTask<Dex> dexTask;
+    @Nullable
+    private AndroidTask jacocoIntrumentTask;
+    @Nullable
+    private AndroidTask<PreprocessResourcesTask> preprocessResourcesTask;
+
+    private AndroidTask<Copy> processJavaResourcesTask;
+    private AndroidTask<NdkCompile> ndkCompileTask;
+
+    // can be JavaCompile or JackTask depending on user's settings.
+    @Nullable
+    private AndroidTask<? extends AbstractCompile> javaCompileTask;
+    // empty anchor compile task to set all compilations tasks as dependents.
+    private AndroidTask<Task> compileTask;
+    private AndroidTask<JacocoInstrumentTask> jacocoInstrumentTask;
+
+    private FileSupplier mappingFileProviderTask;
+    private AndroidTask<BinaryFileProviderTask> binayFileProviderTask;
+
+    // TODO : why is Jack not registered as the obfuscationTask ???
+    private AndroidTask<? extends Task> obfuscationTask;
+
+
     public VariantScope(
             @NonNull GlobalScope globalScope,
-            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData,
-            @NonNull Collection<Object> ndkBuildable,
-            @NonNull Collection<File> ndkOutputDirectories) {
+            @NonNull BaseVariantData<? extends BaseVariantOutputData> variantData) {
         this.globalScope = globalScope;
         this.variantData = variantData;
-        this.ndkBuildable = ndkBuildable;
-        this.ndkOutputDirectories = ndkOutputDirectories;
     }
 
     @NonNull
@@ -76,23 +146,43 @@
     }
 
     @NonNull
+    public String getTaskName(@NonNull String prefix) {
+        return getTaskName(prefix, "");
+    }
+
+    @NonNull
+    public String getTaskName(@NonNull String prefix, @NonNull String suffix) {
+        return prefix + StringHelper.capitalize(getVariantConfiguration().getFullName()) + suffix;
+    }
+
+    @Nullable
     public Collection<Object> getNdkBuildable() {
         return ndkBuildable;
     }
 
-    @NonNull
+    public void setNdkBuildable(@NonNull Collection<Object> ndkBuildable) {
+        this.ndkBuildable = ndkBuildable;
+    }
+
+    @Nullable
     public Collection<File> getNdkOutputDirectories() {
         return ndkOutputDirectories;
     }
 
+    public void setNdkOutputDirectories(@NonNull Collection<File> ndkOutputDirectories) {
+        this.ndkOutputDirectories = ndkOutputDirectories;
+    }
+
     @NonNull
     public Set<File> getJniFolders() {
+        assert getNdkOutputDirectories() != null;
+
         VariantConfiguration config = getVariantConfiguration();
         ApkVariantData apkVariantData = (ApkVariantData) variantData;
         // for now only the project's compilation output.
         Set<File> set = Sets.newHashSet();
         set.addAll(getNdkOutputDirectories());
-        set.add(apkVariantData.renderscriptCompileTask.getLibOutputDir());
+        set.add(getRenderscriptLibOutputDir());
         set.addAll(config.getLibraryJniFolders());
         set.addAll(config.getJniLibsList());
 
@@ -105,4 +195,338 @@
         }
         return set;
     }
+
+    @Nullable
+    public BaseVariantData getTestedVariantData() {
+        return variantData instanceof TestVariantData ?
+                (BaseVariantData) ((TestVariantData) variantData).getTestedVariantData() :
+                null;
+    }
+
+
+    // Precomputed file paths.
+
+    @NonNull
+    public File getDexOutputFolder() {
+        return new File(globalScope.getIntermediatesDir(), "/dex/" + getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public FileCollection getJavaClasspath() {
+        return getGlobalScope().getProject().files(
+                getGlobalScope().getAndroidBuilder().getCompileClasspath(
+                        getVariantData().getVariantConfiguration()));
+    }
+
+    @NonNull
+    public File getJavaOutputDir() {
+        return new File(globalScope.getIntermediatesDir(), "/classes/" +
+                variantData.getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getJavaDependencyCache() {
+        return new File(globalScope.getIntermediatesDir(), "/dependency-cache/" +
+                variantData.getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getPreDexOutputDir() {
+        return new File(globalScope.getIntermediatesDir(), "/pre-dexed/" +
+                getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getProguardOutputFile() {
+        return (variantData instanceof LibraryVariantData) ?
+                new File(globalScope.getIntermediatesDir(),
+                        TaskManager.DIR_BUNDLES + "/" + getVariantConfiguration().getDirName()
+                                + "/classes.jar") :
+                new File(globalScope.getIntermediatesDir(),
+                        "/classes-proguard/" + getVariantConfiguration().getDirName()
+                                + "/classes.jar");
+    }
+
+    @NonNull
+    public File getProguardComponentsJarFile() {
+        return new File(globalScope.getIntermediatesDir(), "multi-dex/" + getVariantConfiguration().getDirName()
+                + "/componentClasses.jar");
+    }
+
+    @NonNull
+    public File getJarMergingOutputFile() {
+        return new File(globalScope.getIntermediatesDir(), "multi-dex/" + getVariantConfiguration().getDirName()
+                + "/allclasses.jar");
+    }
+
+    @NonNull
+    public File getManifestKeepListFile() {
+        return new File(globalScope.getIntermediatesDir(), "multi-dex/" + getVariantConfiguration().getDirName()
+                + "/manifest_keep.txt");
+    }
+
+    @NonNull
+    public File getMainDexListFile() {
+        return new File(globalScope.getIntermediatesDir(), "multi-dex/" + getVariantConfiguration().getDirName()
+                + "/maindexlist.txt");
+    }
+
+    @NonNull
+    public File getRenderscriptSourceOutputDir() {
+        return new File(globalScope.getGeneratedDir(),
+                "source/rs/" + variantData.getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getRenderscriptLibOutputDir() {
+        return new File(globalScope.getGeneratedDir(),
+                "rs/" + variantData.getVariantConfiguration().getDirName() + "/lib");
+    }
+
+    @NonNull
+    public File getSymbolLocation() {
+        return new File(globalScope.getIntermediatesDir() + "/symbols/" +
+                variantData.getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getDefaultMergeResourcesOutputDir() {
+        return new File(globalScope.getIntermediatesDir(),
+                "/res/merged/" + getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getMergeResourcesOutputDir() {
+        if (mergeResourceOutputDir == null) {
+            return getDefaultMergeResourcesOutputDir();
+        }
+        return mergeResourceOutputDir;
+    }
+
+    public void setMergeResourceOutputDir(@Nullable File mergeResourceOutputDir) {
+        this.mergeResourceOutputDir = mergeResourceOutputDir;
+    }
+
+    @NonNull
+    public File getMergeAssetsOutputDir() {
+        return getVariantConfiguration().getType() == VariantType.LIBRARY ?
+                new File(globalScope.getIntermediatesDir(),
+                        TaskManager.DIR_BUNDLES + "/" + getVariantConfiguration().getDirName() +
+                                "/assets") :
+                new File(globalScope.getIntermediatesDir(),
+                        "/assets/" + getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getBuildConfigSourceOutputDir() {
+        return new File(globalScope.getBuildDir() + "/"  + FD_GENERATED + "/source/buildConfig/"
+                + variantData.getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getGeneratedResOutputDir() {
+        return new File(globalScope.getGeneratedDir(),
+                "res/resValues/" + getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getRenderscriptResOutputDir() {
+        return new File(globalScope.getGeneratedDir(),
+                "res/rs/" + getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getJavaResourcesDestinationDir() {
+        return new File(globalScope.getIntermediatesDir(),
+                "javaResources/" + getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getRClassSourceOutputDir() {
+        return new File(globalScope.getGeneratedDir(),
+                "source/r/" + getVariantConfiguration().getDirName());
+    }
+
+    @NonNull
+    public File getAidlSourceOutputDir() {
+        return new File(globalScope.getGeneratedDir(),
+                "source/aidl/" + getVariantConfiguration().getDirName());
+    }
+
+    // Tasks getters/setters.
+
+    public AndroidTask<Task> getPreBuildTask() {
+        return preBuildTask;
+    }
+
+    public void setPreBuildTask(
+            AndroidTask<Task> preBuildTask) {
+        this.preBuildTask = preBuildTask;
+    }
+
+    public AndroidTask<PrepareDependenciesTask> getPrepareDependenciesTask() {
+        return prepareDependenciesTask;
+    }
+
+    public void setPrepareDependenciesTask(
+            AndroidTask<PrepareDependenciesTask> prepareDependenciesTask) {
+        this.prepareDependenciesTask = prepareDependenciesTask;
+    }
+
+    public AndroidTask<ProcessAndroidResources> getGenerateRClassTask() {
+        return generateRClassTask;
+    }
+
+    public void setGenerateRClassTask(
+            AndroidTask<ProcessAndroidResources> generateRClassTask) {
+        this.generateRClassTask = generateRClassTask;
+    }
+
+    public AndroidTask<Task> getSourceGenTask() {
+        return sourceGenTask;
+    }
+
+    public void setSourceGenTask(
+            AndroidTask<Task> sourceGenTask) {
+        this.sourceGenTask = sourceGenTask;
+    }
+
+    public AndroidTask<Task> getResourceGenTask() {
+        return resourceGenTask;
+    }
+
+    public void setResourceGenTask(
+            AndroidTask<Task> resourceGenTask) {
+        this.resourceGenTask = resourceGenTask;
+    }
+
+    public AndroidTask<Task> getAssetGenTask() {
+        return assetGenTask;
+    }
+
+    public void setAssetGenTask(
+            AndroidTask<Task> assetGenTask) {
+        this.assetGenTask = assetGenTask;
+    }
+
+    public AndroidTask<CheckManifest> getCheckManifestTask() {
+        return checkManifestTask;
+    }
+
+    public void setCheckManifestTask(
+            AndroidTask<CheckManifest> checkManifestTask) {
+        this.checkManifestTask = checkManifestTask;
+    }
+
+    public AndroidTask<RenderscriptCompile> getRenderscriptCompileTask() {
+        return renderscriptCompileTask;
+    }
+
+    public void setRenderscriptCompileTask(
+            AndroidTask<RenderscriptCompile> renderscriptCompileTask) {
+        this.renderscriptCompileTask = renderscriptCompileTask;
+    }
+
+    public AndroidTask<AidlCompile> getAidlCompileTask() {
+        return aidlCompileTask;
+    }
+
+    public void setAidlCompileTask(
+            AndroidTask<AidlCompile> aidlCompileTask) {
+        this.aidlCompileTask = aidlCompileTask;
+    }
+
+    @Nullable
+    public AndroidTask<MergeResources> getMergeResourcesTask() {
+        return mergeResourcesTask;
+    }
+
+    public void setMergeResourcesTask(
+            @Nullable AndroidTask<MergeResources> mergeResourcesTask) {
+        this.mergeResourcesTask = mergeResourcesTask;
+    }
+
+    @Nullable
+    public AndroidTask<MergeAssets> getMergeAssetsTask() {
+        return mergeAssetsTask;
+    }
+
+    public void setMergeAssetsTask(
+            @Nullable AndroidTask<MergeAssets> mergeAssetsTask) {
+        this.mergeAssetsTask = mergeAssetsTask;
+    }
+
+    public AndroidTask<GenerateBuildConfig> getGenerateBuildConfigTask() {
+        return generateBuildConfigTask;
+    }
+
+    public void setGenerateBuildConfigTask(
+            AndroidTask<GenerateBuildConfig> generateBuildConfigTask) {
+        this.generateBuildConfigTask = generateBuildConfigTask;
+    }
+
+    public AndroidTask<GenerateResValues> getGenerateResValuesTask() {
+        return generateResValuesTask;
+    }
+
+    public void setGenerateResValuesTask(
+            AndroidTask<GenerateResValues> generateResValuesTask) {
+        this.generateResValuesTask = generateResValuesTask;
+    }
+
+    @Nullable
+    public AndroidTask<Dex> getDexTask() {
+        return dexTask;
+    }
+
+    public void setDexTask(@Nullable AndroidTask<Dex> dexTask) {
+        this.dexTask = dexTask;
+    }
+
+    @Nullable
+    public AndroidTask<PreprocessResourcesTask> getPreprocessResourcesTask() {
+        return preprocessResourcesTask;
+    }
+
+    public void setPreprocessResourcesTask(
+            @Nullable AndroidTask<PreprocessResourcesTask> preprocessResourcesTask) {
+        this.preprocessResourcesTask = preprocessResourcesTask;
+    }
+
+    public AndroidTask<Copy> getProcessJavaResourcesTask() {
+        return processJavaResourcesTask;
+    }
+
+    public void setProcessJavaResourcesTask(
+            AndroidTask<Copy> processJavaResourcesTask) {
+        this.processJavaResourcesTask = processJavaResourcesTask;
+    }
+
+    @Nullable
+    public AndroidTask<? extends AbstractCompile> getJavaCompileTask() {
+        return javaCompileTask;
+    }
+
+    public void setJavaCompileTask(
+            @Nullable AndroidTask<? extends AbstractCompile> javaCompileTask) {
+        this.javaCompileTask = javaCompileTask;
+    }
+
+    public AndroidTask<Task> getCompileTask() {
+        return compileTask;
+    }
+
+    public void setCompileTask(
+            AndroidTask<Task> compileTask) {
+        this.compileTask = compileTask;
+    }
+
+    public AndroidTask<? extends Task> getObfuscationTask() {
+        return obfuscationTask;
+    }
+
+    public void setObfuscationTask(
+            AndroidTask<? extends Task> obfuscationTask) {
+        this.obfuscationTask = obfuscationTask;
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/GenerateApkDataTask.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/GenerateApkDataTask.java
index f97f04b..573b8f1 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/GenerateApkDataTask.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/GenerateApkDataTask.java
@@ -18,13 +18,24 @@
 
 import static com.android.SdkConstants.DOT_ANDROID_PACKAGE;
 import static com.android.SdkConstants.FD_RES_RAW;
+import static com.android.SdkConstants.FN_ANDROID_MANIFEST_XML;
 import static com.android.builder.core.BuilderConstants.ANDROID_WEAR_MICRO_APK;
 
+import com.android.SdkConstants;
+import com.android.annotations.NonNull;
+import com.android.build.gradle.internal.scope.ConventionMappingHelper;
+import com.android.build.gradle.internal.scope.TaskConfigAction;
+import com.android.build.gradle.internal.scope.VariantScope;
+import com.android.build.gradle.internal.variant.ApkVariantData;
+import com.android.build.gradle.tasks.AidlCompile;
 import com.android.builder.core.AndroidBuilder;
+import com.android.builder.core.VariantConfiguration;
 import com.android.ide.common.internal.LoggedErrorException;
 import com.android.ide.common.process.ProcessException;
+import com.android.utils.StringHelper;
 import com.google.common.io.Files;
 
+import org.gradle.api.artifacts.Configuration;
 import org.gradle.api.tasks.Input;
 import org.gradle.api.tasks.InputFile;
 import org.gradle.api.tasks.OutputDirectory;
@@ -33,6 +44,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.concurrent.Callable;
 
 /**
  * Task to generate micro app data res file.
@@ -133,4 +145,84 @@
     public void setManifestFile(File manifestFile) {
         this.manifestFile = manifestFile;
     }
+
+    public static class ConfigAction implements TaskConfigAction<GenerateApkDataTask> {
+
+        @NonNull
+        VariantScope scope;
+
+        @NonNull
+        Configuration config;
+
+        public ConfigAction(@NonNull VariantScope scope, @NonNull Configuration config) {
+            this.scope = scope;
+            this.config = config;
+        }
+
+        @Override
+        @NonNull
+        public String getName() {
+            return scope.getTaskName("handle", "MicroApk");
+        }
+
+        @Override
+        @NonNull
+        public Class<GenerateApkDataTask> getType() {
+            return GenerateApkDataTask.class;
+        }
+
+        @Override
+        public void execute(GenerateApkDataTask task) {
+            final ApkVariantData variantData = (ApkVariantData) scope.getVariantData();
+            variantData.generateApkDataTask = task;
+
+            task.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder());
+            ConventionMappingHelper.map(task, "resOutputDir", new Callable<File>() {
+                @Override
+                public File call() throws Exception {
+                    return new File(
+                            scope.getGlobalScope().getGeneratedDir(),
+                            "/res/microapk/"
+                                    + variantData.getVariantConfiguration().getDirName());
+                }
+            });
+            ConventionMappingHelper.map(task, "apkFile", new Callable<File>() {
+                @Override
+                public File call() throws Exception {
+                    // only care about the first one. There shouldn't be more anyway.
+                    return config.getFiles().iterator().next();
+                }
+            });
+            ConventionMappingHelper.map(task, "manifestFile", new Callable<File>() {
+                @Override
+                public File call() throws Exception {
+                    return new File(
+                            scope.getGlobalScope().getGeneratedDir(),
+                            "/manifests/microapk/"
+                                    + scope.getVariantData().getVariantConfiguration().getDirName()
+                                    + "/" + FN_ANDROID_MANIFEST_XML);
+                }
+            });
+            ConventionMappingHelper.map(task, "mainPkgName", new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return variantData.getVariantConfiguration().getApplicationId();
+                }
+            });
+
+            ConventionMappingHelper.map(task, "minSdkVersion", new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    return variantData.getVariantConfiguration().getMinSdkVersion().getApiLevel();
+                }
+            });
+
+            ConventionMappingHelper.map(task, "targetSdkVersion", new Callable<Integer>() {
+                @Override
+                public Integer call() throws Exception {
+                    return variantData.getVariantConfiguration().getTargetSdkVersion().getApiLevel();
+                }
+            });
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/InstallVariantTask.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/InstallVariantTask.groovy
index 1133ac6..8a2086e 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/InstallVariantTask.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/InstallVariantTask.groovy
@@ -16,20 +16,27 @@
 package com.android.build.gradle.internal.tasks
 
 import com.android.build.gradle.internal.LoggerWrapper
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
+import com.android.build.gradle.internal.variant.ApkVariantData
 import com.android.build.gradle.internal.variant.BaseVariantData
 import com.android.build.gradle.internal.variant.BaseVariantOutputData
-import com.android.builder.testing.api.DeviceConfigProviderImpl
 import com.android.builder.core.VariantConfiguration
 import com.android.builder.internal.InstallUtils
+import com.android.builder.sdk.SdkInfo
+import com.android.builder.sdk.TargetInfo
 import com.android.builder.testing.ConnectedDeviceProvider
+import com.android.builder.testing.api.DeviceConfigProviderImpl
 import com.android.builder.testing.api.DeviceConnector
 import com.android.builder.testing.api.DeviceProvider
-import com.android.ddmlib.IDevice
 import com.android.ide.common.build.SplitOutputMatcher
 import com.android.ide.common.process.ProcessExecutor
 import com.android.utils.ILogger
 import com.google.common.base.Joiner
 import com.google.common.collect.ImmutableList
+import org.gradle.api.Action
 import org.gradle.api.GradleException
 import org.gradle.api.logging.LogLevel
 import org.gradle.api.tasks.Input
@@ -37,6 +44,10 @@
 import org.gradle.api.tasks.Optional
 import org.gradle.api.tasks.TaskAction
 
+import java.util.concurrent.Callable
+
+import static com.android.sdklib.BuildToolInfo.PathId.SPLIT_SELECT
+
 /**
  * Task installing an app variant. It looks at connected device and install the best matching
  * variant output on each device.
@@ -123,4 +134,59 @@
                     "${successfulInstallCount==1?'device':'devicess'}.");
         }
     }
+
+    public static class ConfigAction implements TaskConfigAction<InstallVariantTask> {
+
+        private final VariantScope scope;
+
+        public ConfigAction(VariantScope scope) {
+            this.scope = scope;
+        }
+
+        @Override
+        String getName() {
+            return "install${scope.getVariantConfiguration().fullName.capitalize()}";
+        }
+
+        @Override
+        Class<InstallVariantTask> getType() {
+            return InstallVariantTask.class
+        }
+
+        @Override
+        public void execute(InstallVariantTask installTask) {
+            installTask.setDescription("Installs the " + scope.getVariantData().getDescription() + ".");
+            installTask.setGroup(TaskManager.INSTALL_GROUP);
+            installTask.setProjectName(scope.getGlobalScope().getProject().getName());
+            installTask.setVariantData(scope.getVariantData());
+            installTask.setTimeOutInMs(scope.getGlobalScope().getExtension().getAdbOptions().getTimeOutInMs());
+            installTask.setInstallOptions(scope.getGlobalScope().getExtension().getAdbOptions().getInstallOptions());
+            installTask.setProcessExecutor(scope.getGlobalScope().getAndroidBuilder().getProcessExecutor());
+            ConventionMappingHelper.map(installTask, "adbExe", new Closure<File>(this, this) {
+                public File doCall(Object it) {
+                    final SdkInfo info = scope.getGlobalScope().getSdkHandler().getSdkInfo();
+                    return (info == null ? null : info.getAdb());
+                }
+
+                public File doCall() {
+                    return doCall(null);
+                }
+
+            });
+            ConventionMappingHelper.map(installTask, "splitSelectExe", new Callable<File>() {
+                @Override
+                public File call() throws Exception {
+                    final TargetInfo info = scope.getGlobalScope().getAndroidBuilder().getTargetInfo();
+                    String path = info == null ? null : info.getBuildTools().getPath(SPLIT_SELECT);
+                    if (path != null) {
+                        File splitSelectExe = new File(path);
+                        return splitSelectExe.exists() ? splitSelectExe : null;
+                    } else {
+                        return null;
+                    }
+                }
+            });
+            ((ApkVariantData) scope.getVariantData()).installTask = installTask;
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/UninstallTask.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/UninstallTask.java
index f190d30..e83b8db 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/UninstallTask.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/UninstallTask.java
@@ -16,15 +16,19 @@
 package com.android.build.gradle.internal.tasks;
 
 import com.android.build.gradle.internal.LoggerWrapper;
+import com.android.build.gradle.internal.TaskManager;
+import com.android.build.gradle.internal.scope.ConventionMappingHelper;
+import com.android.build.gradle.internal.scope.TaskConfigAction;
+import com.android.build.gradle.internal.scope.VariantScope;
+import com.android.build.gradle.internal.variant.ApkVariantData;
 import com.android.build.gradle.internal.variant.BaseVariantData;
-import com.android.builder.internal.InstallUtils;
 import com.android.builder.sdk.SdkInfo;
 import com.android.builder.testing.ConnectedDeviceProvider;
 import com.android.builder.testing.api.DeviceConnector;
 import com.android.builder.testing.api.DeviceException;
 import com.android.builder.testing.api.DeviceProvider;
-import com.android.ddmlib.IDevice;
 import com.android.utils.ILogger;
+import com.android.utils.StringHelper;
 
 import org.gradle.api.Task;
 import org.gradle.api.logging.LogLevel;
@@ -32,11 +36,11 @@
 import org.gradle.api.specs.Spec;
 import org.gradle.api.tasks.Input;
 import org.gradle.api.tasks.InputFile;
-import org.gradle.api.tasks.Optional;
 import org.gradle.api.tasks.TaskAction;
 
 import java.io.File;
 import java.util.List;
+import java.util.concurrent.Callable;
 
 public class UninstallTask extends BaseTask {
 
@@ -109,4 +113,46 @@
     public void setTimeOutInMs(int timeoutInMs) {
         mTimeOutInMs = timeoutInMs;
     }
+
+    public static class ConfigAction implements TaskConfigAction<UninstallTask> {
+
+        private final VariantScope scope;
+
+        public ConfigAction(VariantScope scope) {
+            this.scope = scope;
+        }
+
+        @Override
+        public String getName() {
+            return "uninstall"
+                    + StringHelper.capitalize(scope.getVariantConfiguration().getFullName());
+        }
+
+        @Override
+        public Class<UninstallTask> getType() {
+            return UninstallTask.class;
+        }
+
+        @Override
+        public void execute(UninstallTask uninstallTask) {
+
+            uninstallTask.setDescription(
+                    "Uninstalls the " + scope.getVariantData().getDescription() + ".");
+            uninstallTask.setGroup(TaskManager.INSTALL_GROUP);
+            uninstallTask.setVariant(scope.getVariantData());
+            uninstallTask.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder());
+            uninstallTask.setTimeOutInMs(
+                    scope.getGlobalScope().getExtension().getAdbOptions().getTimeOutInMs());
+
+            ConventionMappingHelper.map(uninstallTask, "adbExe", new Callable<File>() {
+                @Override
+                public File call() throws Exception {
+                    final SdkInfo info = scope.getGlobalScope().getSdkHandler().getSdkInfo();
+                    return (info == null ? null : info.getAdb());
+                }
+            });
+
+            ((ApkVariantData) scope.getVariantData()).uninstallTask = uninstallTask;
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateMainDexList.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateMainDexList.groovy
index 96e645d..122960c 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateMainDexList.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateMainDexList.groovy
@@ -18,14 +18,23 @@
 
 package com.android.build.gradle.internal.tasks.multidex
 
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.BaseTask
+import com.android.builder.model.AndroidProject
 import com.google.common.base.Charsets
 import com.google.common.base.Joiner
 import com.google.common.io.Files
+import org.gradle.api.Task
 import org.gradle.api.tasks.InputFile
 import org.gradle.api.tasks.Optional
 import org.gradle.api.tasks.OutputFile
 import org.gradle.api.tasks.TaskAction
+
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 /**
  * Task to create the main (non-obfuscated) list of classes to keep.
  * It uses a jar containing all the classes, as well as a shrinked jar file created by proguard.
@@ -92,4 +101,40 @@
     private Set<String> callDx(File allClassesJarFile, File jarOfRoots) {
         return getBuilder().createMainDexList(allClassesJarFile, jarOfRoots)
     }
+
+    public static class ConfigAction implements TaskConfigAction<CreateMainDexList> {
+
+        VariantScope scope;
+
+        private Closure<List<File>> inputFiles
+
+        ConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+            this.scope = scope
+            inputFiles = pcData.inputFiles;
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("create", "MainDexClassList");
+        }
+
+        @Override
+        Class<CreateMainDexList> getType() {
+            return CreateMainDexList
+        }
+
+        @Override
+        void execute(CreateMainDexList createMainDexList) {
+            createMainDexList.androidBuilder = scope.globalScope.androidBuilder
+
+            def files = inputFiles
+            createMainDexList.allClassesJarFile = files().first()
+            ConventionMappingHelper.map(createMainDexList, "componentsJarFile") {
+                scope.getProguardComponentsJarFile()
+            }
+            // ConventionMappingHelper.map(createMainDexListTask, "includeInMainDexJarFile") { mainDexJarFile }
+            createMainDexList.mainDexListFile = scope.manifestKeepListFile
+            createMainDexList.outputFile = scope.getMainDexListFile()
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateManifestKeepList.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateManifestKeepList.groovy
index 7d6ab56..b4dbd8c 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateManifestKeepList.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/CreateManifestKeepList.groovy
@@ -18,7 +18,12 @@
 
 package com.android.build.gradle.internal.tasks.multidex
 
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.DefaultAndroidTask
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.google.common.base.Charsets
 import com.google.common.io.Files
 import org.gradle.api.tasks.InputFile
@@ -111,4 +116,41 @@
             }
         }
     }
+
+    public static class ConfigAction implements TaskConfigAction<CreateManifestKeepList> {
+
+        VariantScope scope;
+        TaskManager.PostCompilationData pcData;
+
+        ConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+            this.scope = scope
+            this.pcData = pcData
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("collect", "MultiDexComponents");
+        }
+
+        @Override
+        Class<CreateManifestKeepList> getType() {
+            return CreateManifestKeepList
+        }
+
+        @Override
+        void execute(CreateManifestKeepList manifestKeepListTask) {
+            // since all the output have the same manifest, besides the versionCode,
+            // we can take any of the output and use that.
+            final BaseVariantOutputData output = scope.variantData.outputs.get(0)
+            ConventionMappingHelper.map(manifestKeepListTask, "manifest") {
+                output.getScope().getManifestOutputFile()
+            }
+
+            manifestKeepListTask.proguardFile = scope.variantConfiguration.getMultiDexKeepProguard()
+            manifestKeepListTask.outputFile = scope.getManifestKeepListFile();
+
+            //variant.ext.collectMultiDexComponents = manifestKeepListTask
+        }
+    }
+
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/JarMergingTask.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/JarMergingTask.groovy
index 6700f57..78b968f 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/JarMergingTask.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/JarMergingTask.groovy
@@ -19,6 +19,10 @@
 package com.android.build.gradle.internal.tasks.multidex
 
 import com.android.build.gradle.internal.tasks.DefaultAndroidTask
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.google.common.collect.Sets
 import com.google.common.hash.Hashing
 import com.google.common.io.Files
@@ -152,4 +156,37 @@
 
         fis.close()
     }
+
+    public static class ConfigAction implements TaskConfigAction<JarMergingTask> {
+
+        private VariantScope scope
+
+        private Closure<File> inputDir;
+
+        private Closure<List<File>> inputLibraries;
+
+        ConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+            this.scope = scope
+            inputDir = pcData.inputDir
+            inputLibraries = pcData.inputLibraries
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("packageAll", "ClassesForMultiDex")
+        }
+
+        @Override
+        Class<JarMergingTask> getType() {
+            return JarMergingTask
+        }
+
+        @Override
+        void execute(JarMergingTask jarMergingTask) {
+            ConventionMappingHelper.map(jarMergingTask, "inputJars", inputLibraries)
+            ConventionMappingHelper.map(jarMergingTask, "inputDir", inputDir)
+
+            jarMergingTask.jarFile = scope.getJarMergingOutputFile()
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/RetraceMainDexList.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/RetraceMainDexList.groovy
index 0811936..1e46d97 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/RetraceMainDexList.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/tasks/multidex/RetraceMainDexList.groovy
@@ -18,6 +18,10 @@
 
 package com.android.build.gradle.internal.tasks.multidex
 
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.DefaultAndroidTask
 import com.google.common.base.Charsets
 import com.google.common.base.Joiner
@@ -28,6 +32,9 @@
 import org.gradle.api.tasks.Optional
 import org.gradle.api.tasks.OutputFile
 import org.gradle.api.tasks.TaskAction
+
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 /**
  * Take a list of classes for the main dex (that was computed before obfuscation),
  * a proguard-generated mapping file and create a new list of classes with the new
@@ -115,4 +122,39 @@
 
         return map
     }
+
+
+    public static class ConfigAction implements TaskConfigAction<RetraceMainDexList> {
+
+        VariantScope scope;
+
+        TaskManager.PostCompilationData pcData;
+
+        ConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+            this.scope = scope
+            this.pcData = pcData
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("retrace", "MainDexClassList");
+        }
+
+        @Override
+        Class<RetraceMainDexList> getType() {
+            return RetraceMainDexList.class
+        }
+
+        @Override
+        void execute(RetraceMainDexList retraceTask) {
+            ConventionMappingHelper.map(retraceTask, "mainDexListFile") { scope.getMainDexListFile() }
+            ConventionMappingHelper.map(retraceTask, "mappingFile") {
+                scope.variantData.getMappingFile()
+            }
+            retraceTask.outputFile = new File(
+                    "${scope.globalScope.buildDir}/${FD_INTERMEDIATES}/multi-dex/" +
+                            "${scope.variantConfiguration.dirName}/maindexlist_deobfuscated.txt")
+
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java
index 351353e..222ac06 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantData.java
@@ -27,6 +27,7 @@
 import com.android.build.gradle.internal.coverage.JacocoInstrumentTask;
 import com.android.build.gradle.internal.dependency.VariantDependencies;
 import com.android.build.gradle.internal.dsl.Splits;
+import com.android.build.gradle.internal.scope.VariantScope;
 import com.android.build.gradle.internal.tasks.CheckManifest;
 import com.android.build.gradle.internal.tasks.FileSupplier;
 import com.android.build.gradle.internal.tasks.GenerateApkDataTask;
@@ -91,6 +92,10 @@
 
     private VariantDependencies variantDependency;
 
+    // Needed for ModelBuilder.  Should be removed once VariantScope can replace BaseVariantData.
+    @NonNull
+    private final VariantScope scope;
+
     public Task preBuildTask;
     public PrepareDependenciesTask prepareDependenciesTask;
     public ProcessAndroidResources generateRClassTask;
@@ -176,6 +181,8 @@
                             variantConfiguration.getMinSdkVersion().getApiLevel()));
         }
         variantConfiguration.checkSourceProviders();
+
+        scope = new VariantScope(taskManager.getGlobalScope(), this);
     }
 
 
@@ -298,7 +305,7 @@
         addJavaSourceFoldersToModel(generatedSourceFolders);
     }
 
-   public void registerResGeneratingTask(@NonNull Task task, @NonNull File... generatedResFolders) {
+    public void registerResGeneratingTask(@NonNull Task task, @NonNull File... generatedResFolders) {
         // no need add the folders anywhere, the convention mapping closure for the MergeResources
         // action will pick them up from here
         resourceGenTask.dependsOn(task);
@@ -370,8 +377,8 @@
      */
     private List<File> getGeneratedResFolders() {
         List<File> generatedResFolders = Lists.newArrayList(
-                renderscriptCompileTask.getResOutputDir(),
-                generateResValuesTask.getResOutputDir());
+                scope.getRenderscriptResOutputDir(),
+                scope.getGeneratedResOutputDir());
         if (extraGeneratedResFolders != null) {
             generatedResFolders.addAll(extraGeneratedResFolders);
         }
@@ -531,22 +538,22 @@
             }
 
             // then all the generated src folders.
-            if (generateRClassTask != null) {
-                sourceList.add(generateRClassTask.getSourceOutputDir());
+            if (getScope().getGenerateRClassTask() != null) {
+                sourceList.add(getScope().getRClassSourceOutputDir());
             }
 
             // for the other, there's no duplicate so no issue.
-            if (generateBuildConfigTask != null) {
-                sourceList.add(generateBuildConfigTask.getSourceOutputDir());
+            if (getScope().getGenerateBuildConfigTask() != null) {
+                sourceList.add(scope.getBuildConfigSourceOutputDir());
             }
 
-            if (aidlCompileTask != null) {
-                sourceList.add(aidlCompileTask.getSourceOutputDir());
+            if (getScope().getAidlCompileTask() != null) {
+                sourceList.add(scope.getAidlSourceOutputDir());
             }
 
             if (!variantConfiguration.getRenderscriptNdkModeEnabled()
-                    && renderscriptCompileTask != null) {
-                sourceList.add(renderscriptCompileTask.getSourceOutputDir());
+                    && getScope().getRenderscriptCompileTask() != null) {
+                sourceList.add(scope.getRenderscriptSourceOutputDir());
             }
 
             javaSources = sourceList.toArray();
@@ -646,4 +653,9 @@
         }
         return output;
     }
+
+    @NonNull
+    public VariantScope getScope() {
+        return scope;
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantOutputData.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantOutputData.java
index c938018..e0c47c8 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantOutputData.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/internal/variant/BaseVariantOutputData.java
@@ -22,6 +22,7 @@
 import com.android.build.OutputFile;
 import com.android.build.VariantOutput;
 import com.android.build.gradle.api.ApkOutputFile;
+import com.android.build.gradle.internal.scope.VariantOutputScope;
 import com.android.build.gradle.tasks.ManifestProcessorTask;
 import com.android.build.gradle.tasks.PackageSplitAbi;
 import com.android.build.gradle.tasks.PackageSplitRes;
@@ -60,6 +61,9 @@
 
     public Task assembleTask;
 
+    @NonNull
+    private final VariantOutputScope scope;
+
     public BaseVariantOutputData(
             @NonNull OutputFile.OutputType outputType,
             @NonNull Collection<FilterData> filters,
@@ -67,6 +71,7 @@
         this.variantData = variantData;
         this.mainApkOutputFile = new ApkOutputFile(
                 outputType, filters, getOutputFilePromise());
+        scope = new VariantOutputScope(variantData.getScope(), this);
     }
 
     @Nullable
@@ -152,4 +157,9 @@
     void setMultiOutput(boolean multiOutput) {
         this.multiOutput = multiOutput;
     }
+
+    @NonNull
+    public VariantOutputScope getScope() {
+        return scope;
+    }
 }
\ No newline at end of file
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy
index 0805fe5..38dda4b 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AidlCompile.groovy
@@ -16,13 +16,25 @@
 
 package com.android.build.gradle.tasks
 
+import com.android.SdkConstants
 import com.android.annotations.NonNull
 import com.android.annotations.Nullable
 import com.android.annotations.concurrency.GuardedBy
+import com.android.build.gradle.api.ApkVariant
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.IncrementalTask
+import com.android.build.gradle.internal.variant.ApkVariantData
+import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.android.builder.compiling.DependencyFileProcessor
+import com.android.builder.core.VariantConfiguration
+import com.android.builder.core.VariantType
 import com.android.builder.internal.incremental.DependencyData
 import com.android.builder.internal.incremental.DependencyDataStore
+import com.android.builder.model.AndroidProject
 import com.android.ide.common.internal.WaitableExecutor
 import com.android.ide.common.res2.FileStatus
 import com.google.common.collect.Lists
@@ -36,6 +48,9 @@
 
 import java.util.concurrent.Callable
 
+import static com.android.builder.model.AndroidProject.FD_GENERATED
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 /**
  * Task to compile aidl files. Supports incremental update.
  */
@@ -278,4 +293,54 @@
             new File(output).delete()
         }
     }
+
+
+    public static class ConfigAction implements TaskConfigAction<AidlCompile> {
+
+        @NonNull
+        VariantScope scope
+
+        ConfigAction(@NonNull VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        @NonNull
+        String getName() {
+            return scope.getTaskName("compile", "Aidl")
+        }
+
+        @Override
+        @NonNull
+        Class<AidlCompile> getType() {
+            return AidlCompile
+        }
+
+        @Override
+        void execute(AidlCompile compileTask) {
+            VariantConfiguration variantConfiguration = scope.variantConfiguration
+
+            scope.variantData.aidlCompileTask = compileTask
+
+            compileTask.androidBuilder = scope.globalScope.androidBuilder
+            compileTask.incrementalFolder =
+                    new File(
+                            "$scope.globalScope.buildDir/${FD_INTERMEDIATES}/incremental/aidl/${variantConfiguration.dirName}")
+
+            ConventionMappingHelper.map(compileTask, "sourceDirs") { variantConfiguration.aidlSourceList }
+            ConventionMappingHelper.map(compileTask, "importDirs") { variantConfiguration.aidlImports }
+
+            ConventionMappingHelper.map(compileTask, "sourceOutputDir") {
+                //new File(scope.globalScope.generatedDir, "source/aidl/${variantConfiguration.dirName}")
+                scope.getAidlSourceOutputDir()
+            }
+
+            if (variantConfiguration.type == VariantType.LIBRARY) {
+                compileTask.aidlParcelableDir = new File(
+                        "$scope.globalScope.buildDir/${FD_INTERMEDIATES}/$TaskManager.DIR_BUNDLES/${variantConfiguration.dirName}/$SdkConstants.FD_AIDL")
+            }
+
+        }
+    }
+
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AndroidProGuardTask.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AndroidProGuardTask.java
index f25be99..cd8fa12 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AndroidProGuardTask.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/AndroidProGuardTask.java
@@ -16,18 +16,44 @@
 
 package com.android.build.gradle.tasks;
 
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES;
+import static com.android.builder.model.AndroidProject.FD_OUTPUTS;
+
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
+import com.android.build.gradle.LibraryExtension;
+import com.android.build.gradle.internal.DependencyManager;
+import com.android.build.gradle.internal.TaskManager;
+import com.android.build.gradle.internal.scope.TaskConfigAction;
+import com.android.build.gradle.internal.scope.VariantScope;
 import com.android.build.gradle.internal.tasks.FileSupplier;
+import com.android.build.gradle.internal.variant.BaseVariantData;
+import com.android.build.gradle.internal.variant.BaseVariantOutputData;
+import com.android.build.gradle.internal.variant.LibraryVariantData;
+import com.android.builder.core.VariantConfiguration;
+import com.android.utils.StringHelper;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.gradle.api.Action;
 import org.gradle.api.Task;
 import org.gradle.api.tasks.InputFile;
 import org.gradle.api.tasks.Optional;
 import org.gradle.api.tasks.TaskAction;
+import org.gradle.tooling.BuildException;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
 
+import groovy.lang.Closure;
 import proguard.ParseException;
 import proguard.gradle.ProGuardTask;
 
@@ -86,4 +112,269 @@
         }
         super.proguard();
     }
+
+    public static class ConfigAction implements TaskConfigAction<AndroidProGuardTask> {
+
+        private VariantScope scope;
+
+        private Closure<File> inputDir;
+
+        private Closure<List<File>> inputLibraries;
+
+        public ConfigAction(VariantScope scope,
+                TaskManager.PostCompilationData pcData) {
+            this.scope = scope;
+            inputDir = pcData.getInputDir();
+            inputLibraries = pcData.getInputLibraries();
+        }
+
+        @Override
+        public String getName() {
+            return scope.getTaskName("proguard");
+        }
+
+        @Override
+        public Class<AndroidProGuardTask> getType() {
+            return AndroidProGuardTask.class;
+        }
+
+        @Override
+        public void execute(final AndroidProGuardTask proguardTask) {
+            final BaseVariantData<? extends BaseVariantOutputData> variantData = scope.getVariantData();
+            final VariantConfiguration variantConfig = scope.getVariantData().getVariantConfiguration();
+            final BaseVariantData testedVariantData = scope.getTestedVariantData();
+
+            // use single output for now.
+            final BaseVariantOutputData variantOutputData = scope.getVariantData().getOutputs().get(0);
+
+            if (testedVariantData != null) {
+                proguardTask.dependsOn(testedVariantData.getScope().getObfuscationTask().getName());
+            }
+
+            variantData.obfuscationTask = proguardTask;
+            variantData.mappingFileProviderTask = proguardTask;
+
+            // --- Output File ---
+
+            final File outFile = variantData instanceof LibraryVariantData ? new File(
+                    String.valueOf(scope.getGlobalScope().getBuildDir()) + "/" + FD_INTERMEDIATES + "/"
+                            + TaskManager.DIR_BUNDLES + "/" + variantData.getVariantConfiguration()
+                            .getDirName() + "/classes.jar") : new File(
+                    String.valueOf(scope.getGlobalScope().getBuildDir()) + "/" + FD_INTERMEDIATES
+                            + "/classes-proguard/" + variantData.getVariantConfiguration().getDirName()
+                            + "/classes.jar");
+            variantData.obfuscatedClassesJar = outFile;
+
+            // --- Proguard Config ---
+
+            try {
+
+                if (testedVariantData != null) {
+                    // Don't remove any code in tested app.
+                    proguardTask.dontshrink();
+                    proguardTask.dontoptimize();
+
+                    // We can't call dontobfuscate, since that would make ProGuard ignore the mapping file.
+                    proguardTask.keep("class * {*;}");
+                    proguardTask.keep("interface * {*;}");
+                    proguardTask.keep("enum * {*;}");
+
+                    // Input the mapping from the tested app so that we can deal with obfuscated code.
+                    proguardTask.applymapping(testedVariantData.getMappingFile());
+
+                    // All -dontwarn rules for test dependencies should go in here:
+                    proguardTask.configuration(
+                            testedVariantData.getVariantConfiguration().getTestProguardFiles());
+                } else {
+                    if (variantConfig.isTestCoverageEnabled()) {
+                        // when collecting coverage, don't remove the JaCoCo runtime
+                        proguardTask.keep("class com.vladium.** {*;}");
+                        proguardTask.keep("class org.jacoco.** {*;}");
+                        proguardTask.keep("interface org.jacoco.** {*;}");
+                        proguardTask.dontwarn("org.jacoco.**");
+                    }
+
+                    proguardTask.configuration(new Closure<Collection<File>>(this, this) {
+                        public Collection<File> doCall(Object it) {
+                            List<File> proguardFiles = variantConfig.getProguardFiles(true,
+                                    Collections.singletonList(scope.getGlobalScope().getExtension()
+                                            .getDefaultProguardFile(
+                                                    TaskManager.DEFAULT_PROGUARD_CONFIG_FILE)));
+                            proguardFiles.add(
+                                    variantOutputData.processResourcesTask.getProguardOutputFile());
+                            return proguardFiles;
+                        }
+
+                        public Collection<File> doCall() {
+                            return doCall(null);
+                        }
+
+                    });
+                }
+
+                // --- InJars / LibraryJars ---
+
+                if (variantData instanceof LibraryVariantData) {
+                    String packageName = variantConfig.getPackageFromManifest();
+                    if (packageName == null) {
+                        throw new BuildException("Failed to read manifest", null);
+                    }
+
+                    packageName = packageName.replace(".", "/");
+
+                    // injar: the compilation output
+                    // exclude R files and such from output
+                    String exclude = "!" + packageName + "/R.class";
+                    exclude += (", !" + packageName + "/R$*.class");
+                    if (!((LibraryExtension) scope.getGlobalScope().getExtension())
+                            .getPackageBuildConfig()) {
+                        exclude += (", !" + packageName + "/Manifest.class");
+                        exclude += (", !" + packageName + "/Manifest$*.class");
+                        exclude += (", !" + packageName + "/BuildConfig.class");
+                    }
+
+                    proguardTask.injars(ImmutableMap.of("filter", exclude), inputDir);
+
+                    // include R files and such for compilation
+                    String include = exclude.replace("!", "");
+                    LinkedHashMap<String, Object> map1 = new LinkedHashMap<String, Object>(1);
+                    map1.put("filter", include);
+                    proguardTask.libraryjars(map1, inputDir);
+
+                    // injar: the local dependencies
+                    Closure inJars = new Closure<List<File>>(this, this) {
+                        public List<File> doCall(Object it) {
+                            return DependencyManager
+                                    .getPackagedLocalJarFileList(variantData.getVariantDependency());
+                        }
+
+                        public List<File> doCall() {
+                            return doCall(null);
+                        }
+
+                    };
+
+                    proguardTask.injars(ImmutableMap.of("filter", "!META-INF/MANIFEST.MF"), inJars);
+
+                    // libjar: the library dependencies. In this case we take all the compile-scope
+                    // dependencies
+                    Closure libJars = new Closure<Iterable<File>>(this, this) {
+                        public Iterable<File> doCall(Object it) {
+                            // get all the compiled jar.
+                            Set<File> compiledJars = scope.getGlobalScope().getAndroidBuilder()
+                                    .getCompileClasspath(variantConfig);
+                            // and remove local jar that are also packaged
+                            final List<File> localJars = DependencyManager
+                                    .getPackagedLocalJarFileList(variantData.getVariantDependency());
+
+                            return Iterables.filter(compiledJars, new Predicate<File>() {
+                                @Override
+                                public boolean apply(File file) {
+                                    return !localJars.contains(file);
+                                }
+                            });
+                        }
+
+                        public Iterable<File> doCall() {
+                            return doCall(null);
+                        }
+                    };
+
+                    proguardTask.libraryjars(ImmutableMap.of("filter", "!META-INF/MANIFEST.MF"), libJars);
+
+                    // ensure local jars keep their package names
+                    proguardTask.keeppackagenames();
+                } else {
+                    // injar: the compilation output
+                    proguardTask.injars(inputDir);
+
+                    // injar: the packaged dependencies
+                    LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(1);
+                    map.put("filter", "!META-INF/MANIFEST.MF");
+                    proguardTask.injars(map, inputLibraries);
+
+                    // the provided-only jars as libraries.
+                    Closure libJars = new Closure<List<File>>(this, this) {
+                        public List<File> doCall(Object it) {
+                            return variantData.getVariantConfiguration().getProvidedOnlyJars();
+                        }
+
+                        public List<File> doCall() {
+                            return doCall(null);
+                        }
+
+                    };
+
+                    proguardTask.libraryjars(libJars);
+                }
+
+                // libraryJars: the runtime jars. Do this in doFirst since the boot classpath isn't
+                // available until the SDK is loaded in the prebuild task
+                proguardTask.doFirst(new Action<Task>() {
+                    @Override
+                    public void execute(Task proguardTask) {
+                        for (String runtimeJar : scope.getGlobalScope().getAndroidBuilder()
+                                .getBootClasspathAsStrings()) {
+                            try {
+                                ((AndroidProGuardTask)proguardTask).libraryjars(runtimeJar);
+                            } catch (ParseException e) {
+                                throw new RuntimeException(e);
+                            }
+                        }
+                    }
+                });
+
+                if (testedVariantData != null) {
+                    // input the tested app as library
+                    proguardTask.libraryjars(testedVariantData.javaCompileTask.getDestinationDir());
+                    // including its dependencies
+                    Closure testedPackagedJars = new Closure<Set<File>>(this, this) {
+                        public Set<File> doCall(Object it) {
+                            return scope.getGlobalScope().getAndroidBuilder()
+                                    .getPackagedJars(testedVariantData.getVariantConfiguration());
+                        }
+
+                        public Set<File> doCall() {
+                            return doCall(null);
+                        }
+
+                    };
+
+                    LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(1);
+                    map.put("filter", "!META-INF/MANIFEST.MF");
+                    proguardTask.libraryjars(map, testedPackagedJars);
+                }
+
+                // --- Out files ---
+
+                proguardTask.outjars(outFile);
+
+                final File proguardOut = new File(
+                        String.valueOf(scope.getGlobalScope().getBuildDir()) + "/" + FD_OUTPUTS
+                                + "/mapping/" + variantData.getVariantConfiguration().getDirName());
+
+                proguardTask.dump(new File(proguardOut, "dump.txt"));
+                proguardTask.printseeds(new File(proguardOut, "seeds.txt"));
+                proguardTask.printusage(new File(proguardOut, "usage.txt"));
+                proguardTask.printmapping(new File(proguardOut, "mapping.txt"));
+
+                // proguard doesn't verify that the seed/mapping/usage folders exist and will fail
+                // if they don't so create them.
+                proguardTask.doFirst(new Closure<Boolean>(this, this) {
+                    public Boolean doCall(Task it) {
+                        return proguardOut.mkdirs();
+                    }
+
+                    public Boolean doCall() {
+                        return doCall(null);
+                    }
+
+                });
+            } catch (ParseException e) {
+                throw new RuntimeException(e);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/CompatibleScreensManifest.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/CompatibleScreensManifest.groovy
index 0b680c2..7320ecc 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/CompatibleScreensManifest.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/CompatibleScreensManifest.groovy
@@ -17,6 +17,9 @@
 package com.android.build.gradle.tasks
 
 import com.android.annotations.NonNull
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantOutputScope
 import com.android.build.gradle.internal.tasks.DefaultAndroidTask
 import com.android.resources.Density
 import com.google.common.base.Charsets
@@ -76,4 +79,41 @@
 
         return density;
     }
+
+    public static class ConfigAction implements TaskConfigAction<CompatibleScreensManifest> {
+
+        @NonNull
+        VariantOutputScope scope
+        @NonNull
+        Set<String> screenSizes
+
+        ConfigAction(
+                @NonNull VariantOutputScope scope,
+                @NonNull Set<String> screenSizes) {
+            this.scope = scope
+            this.screenSizes = screenSizes
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("create", "CompatibleScreenManifest")
+        }
+
+        @Override
+        Class<CompatibleScreensManifest> getType() {
+            return CompatibleScreensManifest.class
+        }
+
+        @Override
+        void execute(CompatibleScreensManifest csmTask) {
+
+            csmTask.screenDensity = scope.variantOutputData.getMainOutputFile().getFilter(
+                    com.android.build.OutputFile.DENSITY)
+            csmTask.screenSizes = screenSizes
+
+            ConventionMappingHelper.map(csmTask, "manifestFile") {
+                scope.getCompatibleScreensManifestFile()
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Dex.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Dex.groovy
index 7214271..36af87b 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Dex.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Dex.groovy
@@ -17,8 +17,17 @@
 
 import com.android.SdkConstants
 import com.android.annotations.Nullable
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.core.GradleVariantConfiguration
 import com.android.build.gradle.internal.dsl.DexOptions
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.BaseTask
+import com.android.build.gradle.internal.variant.ApkVariantData
+import com.android.build.gradle.internal.variant.TestVariantData
+import com.android.utils.StringHelper
+import org.codehaus.groovy.runtime.DefaultGroovyMethods
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputDirectory
 import org.gradle.api.tasks.InputFile
@@ -29,8 +38,12 @@
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.incremental.IncrementalTaskInputs
 
+import java.util.concurrent.Callable
 import java.util.concurrent.atomic.AtomicBoolean
 
+import static com.android.builder.core.VariantType.DEFAULT
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 public class Dex extends BaseTask {
 
     // ----- PUBLIC TASK API -----
@@ -157,4 +170,74 @@
                 getOptimize(),
                 )
     }
+
+
+    public static class ConfigAction implements TaskConfigAction<Dex> {
+
+        private final VariantScope scope;
+
+        private final TaskManager.PostCompilationData pcData;
+
+        public ConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+            this.scope = scope;
+            this.pcData = pcData;
+        }
+
+        @Override
+        public String getName() {
+            return scope.getTaskName("dex")
+        }
+
+        @Override
+        public Class<Dex> getType() {
+            return Dex.class;
+        }
+
+        @Override
+        public void execute(Dex dexTask) {
+            ApkVariantData variantData = (ApkVariantData) scope.getVariantData();
+            final GradleVariantConfiguration config = variantData.getVariantConfiguration();
+
+            boolean isTestForApp = config.getType().isForTesting() && (DefaultGroovyMethods
+                    .asType(variantData, TestVariantData.class)).getTestedVariantData()
+                    .getVariantConfiguration().getType().equals(DEFAULT);
+
+            boolean isMultiDexEnabled = config.isMultiDexEnabled() && !isTestForApp;
+            boolean isLegacyMultiDexMode = config.isLegacyMultiDexMode();
+
+            variantData.dexTask = dexTask;
+            dexTask.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder());
+            ConventionMappingHelper.map(dexTask, "outputFolder", new Callable<File>() {
+                @Override
+                public File call() throws Exception {
+                    return scope.getDexOutputFolder();
+                }
+            });
+            dexTask.setTmpFolder(new File(
+                    String.valueOf(scope.getGlobalScope().getBuildDir()) + "/" + FD_INTERMEDIATES
+                            + "/tmp/dex/" + config.getDirName()));
+            dexTask.setDexOptions(scope.getGlobalScope().getExtension().getDexOptions());
+            dexTask.setMultiDexEnabled(isMultiDexEnabled);
+            dexTask.setLegacyMultiDexMode(isLegacyMultiDexMode);
+            // dx doesn't work with receving --no-optimize in debug so we disable it for now.
+            dexTask.setOptimize(true);//!variantData.variantConfiguration.buildType.debuggable
+
+            // inputs
+            if (pcData.getInputDir() != null) {
+                ConventionMappingHelper.map(dexTask, "inputDir", pcData.getInputDir());
+            }
+            ConventionMappingHelper.map(dexTask, "inputFiles", pcData.getInputFiles());
+            ConventionMappingHelper.map(dexTask, "libraries", pcData.getInputLibraries());
+
+            if (isMultiDexEnabled && isLegacyMultiDexMode) {
+                // configure the dex task to receive the generated class list.
+                ConventionMappingHelper.map(dexTask, "mainDexListFile", new Callable<File>() {
+                    @Override
+                    public File call() throws Exception {
+                        return scope.getMainDexListFile();
+                    }
+                });
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy
index d296c8d..0216881 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateBuildConfig.groovy
@@ -15,8 +15,15 @@
  */
 package com.android.build.gradle.tasks
 
+import com.android.annotations.NonNull
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.BaseTask
+import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.android.builder.compiling.BuildConfigGenerator
+import com.android.builder.core.VariantConfiguration
 import com.android.builder.model.ClassField
 import com.google.common.collect.Lists
 import org.gradle.api.tasks.Input
@@ -53,7 +60,8 @@
     @Input
     String buildTypeName
 
-    @Input @Optional
+    @Input
+    @Optional
     String versionName
 
     @Input
@@ -103,22 +111,100 @@
         // where debug is true, which is the most likely scenario while the user is looking
         // at source code.
         //map.put(PH_DEBUG, Boolean.toString(mDebug));
-        generator.addField("boolean", "DEBUG", getDebuggable() ? "Boolean.parseBoolean(\"true\")" : "false")
-            .addField("String", "APPLICATION_ID", "\"${getAppPackageName()}\"")
-            .addField("String", "BUILD_TYPE", "\"${getBuildTypeName()}\"")
-            .addField("String", "FLAVOR", "\"${getFlavorName()}\"")
-            .addField("int", "VERSION_CODE", Integer.toString(getVersionCode()))
-            .addField("String", "VERSION_NAME", "\"${vn}\"")
-            .addItems(getItems())
+        generator.addField("boolean", "DEBUG",
+                getDebuggable() ? "Boolean.parseBoolean(\"true\")" : "false")
+                .addField("String", "APPLICATION_ID", "\"${getAppPackageName()}\"")
+                .addField("String", "BUILD_TYPE", "\"${getBuildTypeName()}\"")
+                .addField("String", "FLAVOR", "\"${getFlavorName()}\"")
+                .addField("int", "VERSION_CODE", Integer.toString(getVersionCode()))
+                .addField("String", "VERSION_NAME", "\"${vn}\"")
+                .addItems(getItems())
 
         List<String> flavors = getFlavorNamesWithDimensionNames()
         int count = flavors.size()
         if (count > 1) {
-            for (int i = 0; i < count ; i+=2) {
-                generator.addField("String", "FLAVOR_${flavors.get(i+1)}", "\"${flavors.get(i)}\"")
+            for (int i = 0; i < count; i += 2) {
+                generator.
+                        addField("String", "FLAVOR_${flavors.get(i + 1)}", "\"${flavors.get(i)}\"")
             }
         }
 
         generator.generate()
     }
+
+    // ----- Config Action -----
+
+    public static class ConfigAction implements TaskConfigAction<GenerateBuildConfig> {
+
+        @NonNull
+        VariantScope scope
+
+        ConfigAction(@NonNull VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        @NonNull
+        String getName() {
+            return scope.getTaskName("generate", "BuildConfig");
+        }
+
+        @Override
+        @NonNull
+        Class<GenerateBuildConfig> getType() {
+            return GenerateBuildConfig
+        }
+
+
+        @Override
+        void execute(GenerateBuildConfig generateBuildConfigTask) {
+            BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
+
+            variantData.generateBuildConfigTask = generateBuildConfigTask
+
+            VariantConfiguration variantConfiguration = variantData.variantConfiguration
+
+            generateBuildConfigTask.androidBuilder = scope.globalScope.androidBuilder
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "buildConfigPackageName") {
+                variantConfiguration.originalApplicationId
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "appPackageName") {
+                variantConfiguration.applicationId
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "versionName") {
+                variantConfiguration.versionName
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "versionCode") {
+                variantConfiguration.versionCode
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "debuggable") {
+                variantConfiguration.buildType.isDebuggable()
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "buildTypeName") {
+                variantConfiguration.buildType.name
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "flavorName") {
+                variantConfiguration.flavorName
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "flavorNamesWithDimensionNames") {
+                variantConfiguration.flavorNamesWithDimensionNames
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "items") {
+                variantConfiguration.buildConfigItems
+            }
+
+            ConventionMappingHelper.map(generateBuildConfigTask, "sourceOutputDir") {
+                scope.getBuildConfigSourceOutputDir()
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateResValues.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateResValues.groovy
index be6593a..6fe016e 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateResValues.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/GenerateResValues.groovy
@@ -15,8 +15,14 @@
  */
 package com.android.build.gradle.tasks
 
+import com.android.annotations.NonNull
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.BaseTask
 import com.android.builder.compiling.ResValueGenerator
+import com.android.builder.core.VariantConfiguration
+import com.android.builder.model.AndroidProject
 import com.android.builder.model.ClassField
 import com.google.common.collect.Lists
 import org.gradle.api.tasks.Input
@@ -24,6 +30,8 @@
 import org.gradle.api.tasks.ParallelizableTask
 import org.gradle.api.tasks.TaskAction
 
+import static com.android.builder.model.AndroidProject.FD_GENERATED
+
 @ParallelizableTask
 public class GenerateResValues extends BaseTask {
 
@@ -69,4 +77,43 @@
             generator.generate()
         }
     }
+
+
+    public static class ConfigAction implements TaskConfigAction<GenerateResValues> {
+
+        @NonNull
+        VariantScope scope
+
+        ConfigAction(@NonNull VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("generate", "ResValues");
+        }
+
+        @Override
+        Class getType() {
+            return GenerateResValues.class
+        }
+
+        @Override
+        void execute(GenerateResValues generateResValuesTask) {
+            scope.variantData.generateResValuesTask = generateResValuesTask
+
+            VariantConfiguration variantConfiguration = scope.variantData.variantConfiguration
+
+            generateResValuesTask.androidBuilder = scope.globalScope.androidBuilder
+
+            ConventionMappingHelper.map(generateResValuesTask, "items") {
+                variantConfiguration.resValues
+            }
+
+            ConventionMappingHelper.map(generateResValuesTask, "resOutputDir") {
+                new File(scope.globalScope.generatedDir,
+                        "res/resValues/${scope.variantData.variantConfiguration.dirName}")
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Lint.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Lint.groovy
index 02bd1c2..94b4793 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Lint.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/Lint.groovy
@@ -21,6 +21,9 @@
 import com.android.build.gradle.internal.LintGradleClient
 import com.android.build.gradle.internal.dsl.LintOptions
 import com.android.build.gradle.internal.model.ModelBuilder
+import com.android.build.gradle.internal.scope.AndroidTask
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.DefaultAndroidTask
 import com.android.builder.model.AndroidProject
 import com.android.builder.model.Variant
@@ -35,6 +38,7 @@
 import com.google.common.collect.Maps
 import org.gradle.api.GradleException
 import org.gradle.api.Project
+import org.gradle.api.plugins.JavaBasePlugin
 import org.gradle.api.tasks.ParallelizableTask
 import org.gradle.api.tasks.TaskAction
 import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
@@ -263,4 +267,36 @@
             return issues;
         }
     }
+
+    public static class ConfigAction implements TaskConfigAction<Lint> {
+
+        @NonNull
+        VariantScope scope
+
+        ConfigAction(@NonNull VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        @NonNull
+        String getName() {
+            return scope.getTaskName("lint")
+        }
+
+        @Override
+        @NonNull
+        Class<Lint> getType() {
+            return Lint
+        }
+
+        @Override
+        void execute(Lint lint) {
+            lint.setLintOptions(scope.globalScope.getExtension().lintOptions)
+            lint.setSdkHome(scope.globalScope.sdkHandler.getSdkFolder())
+            lint.setVariantName(scope.variantConfiguration.fullName)
+            lint.setToolingRegistry(scope.globalScope.toolingRegistry)
+            lint.description = "Runs lint on the " + scope.variantConfiguration.fullName.capitalize() + " build."
+            lint.group = JavaBasePlugin.VERIFICATION_GROUP
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeAssets.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeAssets.groovy
index c0149d3..3195d82 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeAssets.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeAssets.groovy
@@ -15,7 +15,16 @@
  */
 package com.android.build.gradle.tasks
 
+import com.android.annotations.NonNull
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.IncrementalTask
+import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
+import com.android.builder.core.VariantConfiguration
+import com.android.builder.core.VariantType
+import com.android.builder.model.AndroidProject
 import com.android.ide.common.res2.AssetMerger
 import com.android.ide.common.res2.AssetSet
 import com.android.ide.common.res2.FileStatus
@@ -139,4 +148,50 @@
             throw new ResourceException(e.getMessage(), e)
         }
     }
+
+
+    public static class ConfigAction implements TaskConfigAction<MergeAssets> {
+
+        @NonNull
+        VariantScope scope
+
+        ConfigAction(VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("merge", "Assets");
+        }
+
+        @Override
+        Class<MergeAssets> getType() {
+            return MergeAssets
+        }
+
+        @Override
+        void execute(MergeAssets mergeAssetsTask) {
+            BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
+            VariantConfiguration variantConfig = variantData.variantConfiguration
+            boolean includeDependencies = variantConfig.type != VariantType.LIBRARY
+
+            variantData.mergeAssetsTask = mergeAssetsTask
+
+            mergeAssetsTask.androidBuilder = scope.globalScope.androidBuilder
+            mergeAssetsTask.incrementalFolder =
+                    new File(
+                            "$scope.globalScope.buildDir/${AndroidProject.FD_INTERMEDIATES}/incremental/mergeAssets/${variantConfig.dirName}")
+
+            ConventionMappingHelper.map(mergeAssetsTask, "inputAssetSets") {
+                def generatedAssets = []
+                if (variantData.copyApkTask != null) {
+                    generatedAssets.add(variantData.copyApkTask.destinationDir)
+                }
+                variantConfig.getAssetSets(generatedAssets, includeDependencies)
+            }
+            ConventionMappingHelper.map(mergeAssetsTask, "outputDir") {
+                scope.getMergeAssetsOutputDir()
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeManifests.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeManifests.groovy
index eb2d002..63a84ab 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeManifests.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeManifests.groovy
@@ -14,9 +14,20 @@
  * limitations under the License.
  */
 package com.android.build.gradle.tasks
+
+import com.android.annotations.NonNull
 import com.android.build.gradle.internal.dependency.ManifestDependencyImpl
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantOutputScope
+import com.android.build.gradle.internal.scope.VariantScope
+import com.android.build.gradle.internal.tasks.PrepareDependenciesTask
 import com.android.build.gradle.internal.variant.ApkVariantOutputData
+import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.android.builder.core.VariantConfiguration
+import com.android.builder.dependency.LibraryDependency
+import com.android.builder.model.AndroidProject
 import com.android.manifmerger.ManifestMerger2
 import com.google.common.collect.Lists
 import org.gradle.api.tasks.Input
@@ -25,6 +36,9 @@
 import org.gradle.api.tasks.Optional
 import org.gradle.api.tasks.ParallelizableTask
 
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+import static com.android.builder.model.AndroidProject.FD_OUTPUTS
+
 /**
  * A task that processes the manifest
  */
@@ -129,4 +143,120 @@
                 variantConfiguration.getManifestPlaceholders(),
                 getReportFile())
     }
+
+    // ----- ConfigAction -----
+
+    public static class ConfigAction implements TaskConfigAction<MergeManifests> {
+
+        VariantOutputScope scope
+
+        ConfigAction(VariantOutputScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("process", "Manifest")
+        }
+
+        @Override
+        Class<MergeManifests> getType() {
+            return MergeManifests
+        }
+
+        @Override
+        void execute(MergeManifests processManifestTask) {
+            BaseVariantOutputData variantOutputData = scope.variantOutputData
+
+            BaseVariantData<? extends BaseVariantOutputData> variantData =
+                    scope.variantScope.variantData
+            VariantConfiguration config = variantData.getVariantConfiguration()
+
+            variantOutputData.manifestProcessorTask = processManifestTask
+
+            processManifestTask.androidBuilder = scope.globalScope.androidBuilder
+
+            processManifestTask.dependsOn variantData.prepareDependenciesTask
+            if (variantData.generateApkDataTask != null) {
+                processManifestTask.dependsOn variantData.generateApkDataTask
+            }
+            if (scope.compatibleScreensManifestTask != null) {
+                processManifestTask.dependsOn scope.compatibleScreensManifestTask.name
+            }
+
+            processManifestTask.variantConfiguration = config
+            if (variantOutputData instanceof ApkVariantOutputData) {
+                processManifestTask.variantOutputData =
+                        variantOutputData as ApkVariantOutputData
+            }
+
+            ConventionMappingHelper.map(processManifestTask, "libraries") {
+                List<ManifestDependencyImpl> manifests =
+                        getManifestDependencies(config.directLibraries)
+
+                if (variantData.generateApkDataTask != null &&
+                        variantData.getVariantConfiguration().getBuildType().
+                                isEmbedMicroApp()) {
+                    manifests.add(new ManifestDependencyImpl(
+                            variantData.generateApkDataTask.getManifestFile(), []))
+                }
+
+                if (scope.compatibleScreensManifestTask != null) {
+                    manifests.add(new ManifestDependencyImpl(
+                            scope.getCompatibleScreensManifestFile(), []))
+                }
+
+                return manifests
+            }
+
+            ConventionMappingHelper.map(processManifestTask, "minSdkVersion") {
+                if (scope.globalScope.androidBuilder.isPreviewTarget()) {
+                    return scope.globalScope.androidBuilder.getTargetCodename()
+                }
+
+                config.mergedFlavor.minSdkVersion?.apiString
+            }
+
+            ConventionMappingHelper.map(processManifestTask, "targetSdkVersion") {
+                if (scope.globalScope.androidBuilder.isPreviewTarget()) {
+                    return scope.globalScope.androidBuilder.getTargetCodename()
+                }
+
+                return config.mergedFlavor.targetSdkVersion?.apiString
+            }
+
+            ConventionMappingHelper.map(processManifestTask, "maxSdkVersion") {
+                if (scope.globalScope.androidBuilder.isPreviewTarget()) {
+                    return null
+                }
+
+                return config.mergedFlavor.maxSdkVersion
+            }
+
+            ConventionMappingHelper.map(processManifestTask, "manifestOutputFile") {
+                scope.getManifestOutputFile()
+            }
+
+            ConventionMappingHelper.map(processManifestTask, "reportFile") {
+                new File(
+                        "${scope.getGlobalScope().getBuildDir()}/${FD_OUTPUTS}/logs/manifest-merger-${config.baseName}-report.txt")
+            }
+
+        }
+
+        @NonNull
+        private static List<ManifestDependencyImpl> getManifestDependencies(
+                List<LibraryDependency> libraries) {
+
+            List<ManifestDependencyImpl> list = Lists.newArrayListWithCapacity(libraries.size())
+
+            for (LibraryDependency lib : libraries) {
+                // get the dependencies
+                List<ManifestDependencyImpl> children = getManifestDependencies(lib.dependencies)
+                list.add(new ManifestDependencyImpl(lib.getName(), lib.manifest, children))
+            }
+
+            return list
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeResources.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeResources.groovy
index 212c6f2..3a56b00 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeResources.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/MergeResources.groovy
@@ -15,7 +15,14 @@
  */
 package com.android.build.gradle.tasks
 
+import com.android.annotations.NonNull
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.IncrementalTask
+import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
+import com.android.builder.core.VariantType
 import com.android.builder.png.QueuedCruncher
 import com.android.ide.common.internal.PngCruncher
 import com.android.ide.common.res2.FileStatus
@@ -25,6 +32,8 @@
 import com.android.ide.common.res2.ResourceMerger
 import com.android.ide.common.res2.ResourceSet
 import com.android.sdklib.BuildToolInfo
+import com.android.sdklib.repository.FullRevision
+import com.google.common.collect.Lists
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFiles
 import org.gradle.api.tasks.Optional
@@ -32,6 +41,8 @@
 import org.gradle.api.tasks.ParallelizableTask
 import org.gradle.api.tasks.OutputFile
 
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 @ParallelizableTask
 public class MergeResources extends IncrementalTask {
 
@@ -191,4 +202,73 @@
             throw new ResourceException(e.getMessage(), e)
         }
     }
+
+    public static class ConfigAction implements TaskConfigAction<MergeResources> {
+
+        @NonNull
+        VariantScope scope
+        @NonNull
+        String taskNamePrefix
+        @NonNull
+        File outputLocation;
+        boolean includeDependencies;
+        boolean process9Patch;
+
+        ConfigAction(VariantScope scope, String taskNamePrefix, File outputLocation,
+                boolean includeDependencies, boolean process9Patch) {
+            this.scope = scope
+            this.taskNamePrefix = taskNamePrefix
+            this.outputLocation = outputLocation
+            this.includeDependencies = includeDependencies
+            this.process9Patch = process9Patch
+
+            scope.setMergeResourceOutputDir(outputLocation)
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName(taskNamePrefix, "Resources")
+        }
+
+        @Override
+        Class<MergeResources> getType() {
+            return MergeResources
+        }
+
+        @Override
+        void execute(MergeResources mergeResourcesTask) {
+            BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
+
+            mergeResourcesTask.androidBuilder = scope.globalScope.androidBuilder
+            mergeResourcesTask.incrementalFolder = new File(
+                    "$scope.globalScope.buildDir/${FD_INTERMEDIATES}/incremental/" +
+                            "${taskNamePrefix}Resources/${variantData.variantConfiguration.dirName}")
+
+            mergeResourcesTask.process9Patch = process9Patch
+            mergeResourcesTask.crunchPng = scope.globalScope.extension.aaptOptions.getCruncherEnabled()
+            mergeResourcesTask.normalizeResources = scope.globalScope.extension.buildToolsRevision.compareTo(new FullRevision(21, 0, 0)) < 0
+
+            ConventionMappingHelper.map(mergeResourcesTask, "useNewCruncher") { scope.globalScope.getExtension().aaptOptions.useNewCruncher }
+
+            ConventionMappingHelper.map(mergeResourcesTask, "inputResourceSets") {
+                List<File> generatedResFolders = Lists.newArrayList(
+                        scope.getRenderscriptResOutputDir(),
+                        scope.getGeneratedResOutputDir())
+                if (variantData.extraGeneratedResFolders != null) {
+                    generatedResFolders += variantData.extraGeneratedResFolders
+                }
+                if (variantData.generateApkDataTask != null &&
+                        variantData.getVariantConfiguration().getBuildType().isEmbedMicroApp()) {
+                    generatedResFolders.add(variantData.generateApkDataTask.getResOutputDir())
+                }
+                variantData.variantConfiguration.getResourceSets(generatedResFolders,
+                        includeDependencies)
+            }
+
+            ConventionMappingHelper.map(mergeResourcesTask, "outputDir") {
+                outputLocation ?: scope.getDefaultMergeResourcesOutputDir()
+            }
+            variantData.mergeResourcesTask = mergeResourcesTask
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PackageApplication.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PackageApplication.java
index 7a408f8..ffff5ae 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PackageApplication.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PackageApplication.java
@@ -242,7 +242,7 @@
 
         @Override
         public String getName() {
-            return "package" + StringHelper.capitalize(scope.getVariantOutputData().getFullName());
+            return scope.getTaskName("package");
         }
 
         @Override
@@ -257,26 +257,15 @@
                     .getVariantOutputData();
             final GradleVariantConfiguration config = scope.getVariantScope().getVariantConfiguration();
 
-            String outputName = variantOutputData.getFullName();
-            String outputBaseName = variantOutputData.getBaseName();
-
             variantOutputData.packageApplicationTask = packageApp;
             packageApp.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder());
 
             if (config.isMinifyEnabled() && config.getBuildType().isShrinkResources() && !config
                     .getUseJack()) {
-                final ShrinkResources shrinkTask = createShrinkResourcesTask(variantOutputData);
-
-                // When shrinking resources, rather than having the packaging task
-                // directly map to the packageOutputFile of ProcessAndroidResources,
-                // we insert the ShrinkResources task into the chain, such that its
-                // input is the ProcessAndroidResources packageOutputFile, and its
-                // output is what the PackageApplication task reads.
-                packageApp.dependsOn(shrinkTask);
                 ConventionMappingHelper.map(packageApp, "resourceFile", new Callable<File>() {
                     @Override
                     public File call() {
-                        return shrinkTask.getCompressedResources();
+                        return scope.getCompressedResourceFile();
                     }
                 });
             } else {
@@ -291,14 +280,17 @@
             ConventionMappingHelper.map(packageApp, "dexFolder", new Callable<File>() {
                 @Override
                 public File call() {
-                    if (variantData.dexTask != null) {
-                        return variantData.dexTask.getOutputFolder();
+                    if (scope.getVariantScope().getDexTask() != null) {
+                        return scope.getVariantScope().getDexOutputFolder();
+                    }
+
+                    if (scope.getVariantScope().getJavaCompileTask() != null) {
+                        return scope.getVariantScope().getJavaOutputDir();
                     }
 
                     if (variantData.javaCompileTask != null) {
                         return variantData.javaCompileTask.getDestinationDir();
                     }
-
                     return null;
                 }
             });
@@ -414,7 +406,9 @@
                 }
             });
 
-            task.dependsOn(variantData.obfuscationTask, variantOutputData.manifestProcessorTask,
+            task.dependsOn(
+                    scope.getVariantScope().getObfuscationTask().getName(),
+                    scope.getManifestProcessorTask().getName(),
                     variantOutputData.processResourcesTask);
 
             return task;
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PreDex.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PreDex.groovy
index a0bd84a..0f3b5ba 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PreDex.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/PreDex.groovy
@@ -16,9 +16,18 @@
 package com.android.build.gradle.tasks
 import com.android.SdkConstants
 import com.android.annotations.NonNull
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.BaseTask
+import com.android.build.gradle.internal.variant.ApkVariantData
+import com.android.build.gradle.internal.variant.TestVariantData
 import com.android.builder.core.AndroidBuilder
 import com.android.builder.core.DexOptions
+import com.android.builder.core.VariantConfiguration
+import com.android.builder.core.VariantType
+import com.android.builder.model.AndroidProject
 import com.android.ide.common.internal.WaitableExecutor
 import com.google.common.base.Charsets
 import com.google.common.collect.Lists
@@ -37,6 +46,8 @@
 
 import java.util.concurrent.Callable
 
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 @ParallelizableTask
 public class PreDex extends BaseTask {
 
@@ -192,4 +203,47 @@
 
         return new File(outFolder, name + "-" + hashCode.toString() + SdkConstants.DOT_JAR)
     }
+
+    public static class ConfigAction implements TaskConfigAction<PreDex> {
+
+        VariantScope scope;
+
+        TaskManager.PostCompilationData pcData
+
+        ConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+            this.scope = scope
+            this.pcData = pcData
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("preDex")
+        }
+
+        @Override
+        Class<PreDex> getType() {
+            return PreDex.class
+        }
+
+        @Override
+        void execute(PreDex preDexTask) {
+            ApkVariantData variantData = (ApkVariantData) scope.variantData;
+            VariantConfiguration config = variantData.variantConfiguration
+
+            boolean isTestForApp = config.type.isForTesting() &&
+                    (variantData as TestVariantData).testedVariantData.variantConfiguration.type ==
+                    VariantType.DEFAULT
+            boolean isMultiDexEnabled = config.isMultiDexEnabled() && !isTestForApp
+
+            variantData.preDexTask = preDexTask
+            preDexTask.androidBuilder = scope.globalScope.androidBuilder
+            preDexTask.dexOptions = scope.globalScope.getExtension().dexOptions
+            preDexTask.multiDex = isMultiDexEnabled
+
+            ConventionMappingHelper.map(preDexTask, "inputFiles", pcData.inputLibraries)
+            ConventionMappingHelper.map(preDexTask, "outputFolder") {
+                scope.getPreDexOutputDir();
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessAndroidResources.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessAndroidResources.groovy
index 18ed77a..dae7a52 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessAndroidResources.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessAndroidResources.groovy
@@ -15,11 +15,23 @@
  */
 package com.android.build.gradle.tasks
 
+import com.android.annotations.NonNull
+import com.android.build.gradle.internal.LoggingUtil
 import com.android.build.gradle.internal.dependency.SymbolFileProviderImpl
 import com.android.build.gradle.internal.dsl.AaptOptions
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantOutputScope
 import com.android.build.gradle.internal.tasks.IncrementalTask
+import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.android.builder.core.AaptPackageProcessBuilder
+import com.android.builder.core.VariantConfiguration
 import com.android.builder.core.VariantType
+import com.android.builder.dependency.LibraryDependency
+import com.google.common.collect.Iterators
+import com.google.common.collect.Lists
+import org.gradle.api.logging.Logging
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputDirectory
 import org.gradle.api.tasks.InputFile
@@ -29,6 +41,9 @@
 import org.gradle.api.tasks.OutputFile
 import org.gradle.api.tasks.ParallelizableTask
 
+import static com.android.builder.model.AndroidProject.FD_GENERATED
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 @ParallelizableTask
 public class ProcessAndroidResources extends IncrementalTask {
 
@@ -144,4 +159,145 @@
                 aaptPackageCommandBuilder,
                 getEnforceUniquePackageName())
     }
+
+    public static class ConfigAction implements TaskConfigAction<ProcessAndroidResources> {
+
+        VariantOutputScope scope;
+        File symbolLocation;
+        boolean generateResourcePackage;
+
+        ConfigAction(VariantOutputScope scope, File symbolLocation, generateResourcePackage) {
+            this.scope = scope
+            this.symbolLocation = symbolLocation
+            this.generateResourcePackage = generateResourcePackage
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("process", "Resources")
+        }
+
+        @Override
+        Class<ProcessAndroidResources> getType() {
+            return ProcessAndroidResources.class;
+        }
+
+        @Override
+        void execute(ProcessAndroidResources processResources) {
+            BaseVariantOutputData variantOutputData = scope.variantOutputData
+            BaseVariantData variantData = scope.variantScope.variantData
+            variantOutputData.processResourcesTask = processResources
+            VariantConfiguration config = variantData.getVariantConfiguration()
+
+            processResources.androidBuilder = scope.globalScope.androidBuilder
+
+            if (variantData.getSplitHandlingPolicy() ==
+                    BaseVariantData.SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY) {
+                Set<String> allFilters = new HashSet<>();
+                allFilters.addAll(variantData.getFilters(com.android.build.OutputFile.FilterType.DENSITY))
+                allFilters.addAll(variantData.getFilters(com.android.build.OutputFile.FilterType.LANGUAGE))
+                processResources.splits = allFilters;
+            }
+
+            // only generate code if the density filter is null, and if we haven't generated
+            // it yet (if you have abi + density splits, then several abi output will have no
+            // densityFilter)
+            if (variantOutputData.getMainOutputFile().getFilter(com.android.build.OutputFile.DENSITY) == null
+                    && variantData.generateRClassTask == null) {
+                variantData.generateRClassTask = processResources
+                processResources.enforceUniquePackageName = scope.globalScope.getExtension().getEnforceUniquePackageName()
+
+                ConventionMappingHelper.map(processResources, "libraries") {
+                    getTextSymbolDependencies(config.allLibraries)
+                }
+                ConventionMappingHelper.map(processResources, "packageForR") {
+                    config.originalApplicationId
+                }
+
+                // TODO: unify with generateBuilderConfig, compileAidl, and library packaging somehow?
+                ConventionMappingHelper.map(processResources, "sourceOutputDir") {
+                    scope.getVariantScope().getRClassSourceOutputDir();
+                }
+
+                ConventionMappingHelper.map(processResources, "textSymbolOutputDir") {
+                    symbolLocation
+                }
+
+                if (config.buildType.isMinifyEnabled()) {
+                    if (config.buildType.shrinkResources && config.useJack) {
+                        LoggingUtil.displayWarning(Logging.getLogger(this.class), scope.globalScope.project,
+                                "shrinkResources does not yet work with useJack=true")
+                    }
+                    ConventionMappingHelper.map(processResources, "proguardOutputFile") {
+                        new File(
+                                "$scope.globalScope.buildDir/${FD_INTERMEDIATES}/proguard-rules/${config.dirName}/aapt_rules.txt")
+                    }
+                } else if (config.buildType.shrinkResources) {
+                    LoggingUtil.displayWarning(Logging.getLogger(this.class), scope.globalScope.project,
+                            "To shrink resources you must also enable ProGuard")
+                }
+            }
+
+            ConventionMappingHelper.map(processResources, "manifestFile") {
+                variantOutputData.manifestProcessorTask.getOutputFile()
+            }
+
+            ConventionMappingHelper.map(processResources, "resDir") {
+                variantData.finalResourcesDir
+            }
+
+            ConventionMappingHelper.map(processResources, "assetsDir") {
+                variantData.mergeAssetsTask.outputDir
+            }
+
+            if (generateResourcePackage) {
+                ConventionMappingHelper.map(processResources, "packageOutputFile") {
+                    scope.getProcessResourcePackageOutputFile()
+                }
+            }
+
+            ConventionMappingHelper.map(processResources, "type") { config.type }
+            ConventionMappingHelper.map(processResources, "debuggable") { config.buildType.debuggable }
+            ConventionMappingHelper.map(processResources, "aaptOptions") { scope.globalScope.getExtension().aaptOptions }
+            ConventionMappingHelper.map(processResources, "pseudoLocalesEnabled") { config.buildType.pseudoLocalesEnabled }
+
+            ConventionMappingHelper.map(processResources, "resourceConfigs") {
+                Collection<String> resConfigs = config.mergedFlavor.resourceConfigurations;
+                if (resConfigs != null && resConfigs.size() == 1
+                        && Iterators.getOnlyElement(resConfigs.iterator()).equals("auto")) {
+
+                    return variantData.discoverListOfResourceConfigs();
+                }
+                return config.mergedFlavor.resourceConfigurations
+            }
+
+            ConventionMappingHelper.map(processResources, "preferredDensity") {
+                variantOutputData.getMainOutputFile().getFilter(com.android.build.OutputFile.DENSITY)
+            }
+
+        }
+
+        private static <T> Set<T> removeAllNullEntries(Set<T> input) {
+            HashSet<T> output = new HashSet<T>();
+            for (T element : input) {
+                if (element != null) {
+                    output.add(element);
+                }
+            }
+            return output;
+        }
+
+        @NonNull
+        private static List<SymbolFileProviderImpl> getTextSymbolDependencies(
+                List<LibraryDependency> libraries) {
+
+            List<SymbolFileProviderImpl> list = Lists.newArrayListWithCapacity(libraries.size())
+
+            for (LibraryDependency lib : libraries) {
+                list.add(new SymbolFileProviderImpl(lib.manifest, lib.symbolFile))
+            }
+
+            return list
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessManifest.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessManifest.groovy
index 9bf6e4f..e738598 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessManifest.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessManifest.groovy
@@ -16,7 +16,15 @@
 
 package com.android.build.gradle.tasks
 
+import com.android.build.gradle.internal.TaskManager
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
+import com.android.builder.core.AndroidBuilder
 import com.android.builder.core.VariantConfiguration
+import com.android.builder.model.AndroidProject
+import com.android.builder.model.ProductFlavor
 import com.android.manifmerger.ManifestMerger2
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFile
@@ -99,4 +107,71 @@
                 variantConfiguration.getManifestPlaceholders(),
                 getReportFile())
     }
+
+    public static class ConfigAction implements TaskConfigAction<ProcessManifest> {
+
+        VariantScope scope
+
+        ConfigAction(VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("process", "Manifest")
+        }
+
+        @Override
+        Class<ProcessManifest> getType() {
+            return ProcessManifest
+        }
+
+        @Override
+        void execute(ProcessManifest processManifest) {
+            VariantConfiguration config = scope.variantConfiguration
+            AndroidBuilder androidBuilder = scope.globalScope.androidBuilder
+
+            // get single output for now.
+            BaseVariantOutputData variantOutputData = scope.variantData.outputs.get(0)
+
+            variantOutputData.manifestProcessorTask = processManifest
+            processManifest.androidBuilder = androidBuilder
+
+            processManifest.variantConfiguration = config
+
+            ProductFlavor mergedFlavor = config.mergedFlavor
+
+            ConventionMappingHelper.map(processManifest, "minSdkVersion") {
+                if (androidBuilder.isPreviewTarget()) {
+                    return androidBuilder.getTargetCodename()
+                }
+                return mergedFlavor.minSdkVersion?.apiString
+            }
+
+            ConventionMappingHelper.map(processManifest, "targetSdkVersion") {
+                if (androidBuilder.isPreviewTarget()) {
+                    return androidBuilder.getTargetCodename()
+                }
+
+                return mergedFlavor.targetSdkVersion?.apiString
+            }
+
+            ConventionMappingHelper.map(processManifest, "maxSdkVersion") {
+                if (androidBuilder.isPreviewTarget()) {
+                    return null
+                }
+
+                return mergedFlavor.maxSdkVersion
+            }
+
+            ConventionMappingHelper.map(processManifest, "manifestOutputFile") {
+                variantOutputData.getScope().getManifestOutputFile()
+            }
+
+            ConventionMappingHelper.map(processManifest, "aaptFriendlyManifestOutputFile") {
+                new File(scope.globalScope.getIntermediatesDir(),
+                        "$TaskManager.DIR_BUNDLES/${config.dirName}/aapt/AndroidManifest.xml")
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessTestManifest.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessTestManifest.groovy
index d0ce6c5..0144816 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessTestManifest.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ProcessTestManifest.groovy
@@ -15,7 +15,15 @@
  */
 package com.android.build.gradle.tasks
 
+import com.android.build.gradle.internal.DependencyManager
 import com.android.build.gradle.internal.dependency.ManifestDependencyImpl
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantOutputScope
+import com.android.build.gradle.internal.scope.VariantScope
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
+import com.android.builder.core.VariantConfiguration
+import com.android.builder.model.AndroidProject
 import com.google.common.collect.Lists
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFile
@@ -98,4 +106,84 @@
                 getManifestOutputFile(),
                 getTmpDir())
     }
+
+    // ----- ConfigAction -----
+
+
+    public static class ConfigAction implements TaskConfigAction<ProcessTestManifest> {
+
+        VariantScope scope
+
+        ConfigAction(VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("process", "Manifest")
+        }
+
+        @Override
+        Class<ProcessTestManifest> getType() {
+            return ProcessTestManifest
+        }
+
+        @Override
+        void execute(ProcessTestManifest processTestManifestTask) {
+
+            VariantConfiguration config = scope.variantConfiguration
+            ConventionMappingHelper.map(processTestManifestTask, "testManifestFile") {
+                config.getMainManifest()
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "tmpDir") {
+                new File(scope.globalScope.getIntermediatesDir(), "manifest/tmp")
+            }
+
+            // get single output for now.
+            BaseVariantOutputData variantOutputData = scope.variantData.outputs.get(0)
+
+            variantOutputData.manifestProcessorTask = processTestManifestTask
+
+            processTestManifestTask.androidBuilder = scope.globalScope.androidBuilder
+
+            ConventionMappingHelper.map(processTestManifestTask, "testApplicationId") {
+                config.applicationId
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "minSdkVersion") {
+                if (scope.globalScope.androidBuilder.isPreviewTarget()) {
+                    return scope.globalScope.androidBuilder.getTargetCodename()
+                }
+
+                config.minSdkVersion?.apiString
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "targetSdkVersion") {
+                if (scope.globalScope.androidBuilder.isPreviewTarget()) {
+                    return scope.globalScope.androidBuilder.getTargetCodename()
+                }
+
+                return config.targetSdkVersion?.apiString
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "testedApplicationId") {
+                config.testedApplicationId
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "instrumentationRunner") {
+                config.instrumentationRunner
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "handleProfiling") {
+                config.handleProfiling
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "functionalTest") {
+                config.functionalTest
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "libraries") {
+                DependencyManager.getManifestDependencies(config.directLibraries)
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "manifestOutputFile") {
+                variantOutputData.getScope().getManifestOutputFile()
+            }
+            ConventionMappingHelper.map(processTestManifestTask, "placeholdersValues") {
+                config.getManifestPlaceholders()
+            }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/RenderscriptCompile.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/RenderscriptCompile.groovy
index 2dac216..6946fad 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/RenderscriptCompile.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/RenderscriptCompile.groovy
@@ -16,12 +16,28 @@
 
 package com.android.build.gradle.tasks
 
+import com.android.annotations.NonNull
+import com.android.build.gradle.internal.core.GradleVariantConfiguration
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantOutputScope
+import com.android.build.gradle.internal.scope.VariantScope
 import com.android.build.gradle.internal.tasks.NdkTask
+import com.android.build.gradle.internal.variant.BaseVariantData
+import com.android.build.gradle.internal.variant.BaseVariantOutputData
+import com.android.builder.core.VariantConfiguration
+import com.android.builder.model.AndroidProject
+import com.android.builder.model.ApiVersion
+import com.android.builder.model.ProductFlavor
+import com.android.sdklib.SdkVersionInfo
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFiles
 import org.gradle.api.tasks.OutputDirectory
 import org.gradle.api.tasks.TaskAction
 
+import static com.android.builder.model.AndroidProject.FD_GENERATED
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 /**
  * Task to compile Renderscript files. Supports incremental update.
  */
@@ -103,4 +119,78 @@
                 getSupportMode(),
                 getNdkConfig()?.abiFilters)
     }
+
+    // ----- ConfigAction -----
+
+    public static class ConfigAction implements TaskConfigAction<RenderscriptCompile> {
+
+        @NonNull
+        VariantScope scope
+
+        ConfigAction(VariantScope scope) {
+            this.scope = scope
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("compile", "Renderscript");
+        }
+
+        @Override
+        Class<RenderscriptCompile> getType() {
+            return RenderscriptCompile
+        }
+
+        @Override
+        void execute(RenderscriptCompile renderscriptTask) {
+            BaseVariantData<? extends BaseVariantOutputData> variantData = scope.variantData
+            GradleVariantConfiguration config = variantData.variantConfiguration
+
+            variantData.renderscriptCompileTask = renderscriptTask
+            ProductFlavor mergedFlavor = config.mergedFlavor
+            boolean ndkMode = config.renderscriptNdkModeEnabled
+            renderscriptTask.androidBuilder = scope.globalScope.androidBuilder
+
+            ConventionMappingHelper.map(renderscriptTask, "targetApi") {
+                int targetApi = mergedFlavor.renderscriptTargetApi != null ?
+                        mergedFlavor.renderscriptTargetApi : -1
+                ApiVersion apiVersion = config.getMinSdkVersion()
+                if (apiVersion != null) {
+                    int minSdk = apiVersion.apiLevel
+                    if (apiVersion.codename != null) {
+                        minSdk = SdkVersionInfo.getApiByBuildCode(apiVersion.codename, true)
+                    }
+
+                    return targetApi > minSdk ? targetApi : minSdk
+                }
+
+                return targetApi
+            }
+
+            renderscriptTask.supportMode = config.renderscriptSupportModeEnabled
+            renderscriptTask.ndkMode = ndkMode
+            renderscriptTask.debugBuild = config.buildType.renderscriptDebuggable
+            renderscriptTask.optimLevel = config.buildType.renderscriptOptimLevel
+
+            ConventionMappingHelper.map(renderscriptTask, "sourceDirs") { config.renderscriptSourceList }
+            ConventionMappingHelper.map(renderscriptTask, "importDirs") { config.renderscriptImports }
+
+            ConventionMappingHelper.map(renderscriptTask, "sourceOutputDir") {
+                new File(
+                        "$scope.globalScope.buildDir/${FD_GENERATED}/source/rs/${variantData.variantConfiguration.dirName}")
+            }
+            ConventionMappingHelper.map(renderscriptTask, "resOutputDir") {
+                scope.getRenderscriptResOutputDir()
+            }
+            ConventionMappingHelper.map(renderscriptTask, "objOutputDir") {
+                new File(
+                        "$scope.globalScope.buildDir/${FD_INTERMEDIATES}/rs/${variantData.variantConfiguration.dirName}/obj")
+            }
+            ConventionMappingHelper.map(renderscriptTask, "libOutputDir") {
+                new File(
+                        "$scope.globalScope.buildDir/${FD_INTERMEDIATES}/rs/${variantData.variantConfiguration.dirName}/lib")
+            }
+            ConventionMappingHelper.map(renderscriptTask, "ndkConfig") { config.ndkConfig }
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ShrinkResources.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ShrinkResources.groovy
index 944e916..c45c5db 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ShrinkResources.groovy
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ShrinkResources.groovy
@@ -16,15 +16,27 @@
 
 package com.android.build.gradle.tasks
 
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantOutputScope
 import com.android.build.gradle.internal.tasks.BaseTask
+import com.android.build.gradle.internal.variant.ApkVariantOutputData
+import com.android.build.gradle.internal.variant.BaseVariantData
 import com.android.build.gradle.internal.variant.BaseVariantOutputData
 import com.android.builder.core.AaptPackageProcessBuilder
+import com.android.builder.model.AndroidProject
+import com.android.utils.StringHelper
+import org.codehaus.groovy.runtime.StringGroovyMethods
 import org.gradle.api.logging.LogLevel
 import org.gradle.api.tasks.InputFile
 import org.gradle.api.tasks.OutputFile
 import org.gradle.api.tasks.ParallelizableTask
 import org.gradle.api.tasks.TaskAction
 
+import java.util.concurrent.Callable
+
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
 /**
  * Task which strips out unused resources
  * <p>
@@ -170,4 +182,42 @@
     private static String toKbString(long size) {
         return Integer.toString((int)size/1024);
     }
+
+    public static class ConfigAction implements TaskConfigAction<ShrinkResources> {
+
+        private VariantOutputScope scope;
+
+        public ConfigAction(VariantOutputScope scope) {
+            this.scope = scope;
+        }
+
+        @Override
+        String getName() {
+            return scope.getTaskName("shrink", "Resources");
+        }
+
+        @Override
+        Class<ShrinkResources> getType() {
+            return ShrinkResources.class
+        }
+
+        @Override
+        void execute(ShrinkResources task) {
+            BaseVariantData<? extends BaseVariantOutputData> variantData =
+                    scope.variantScope.variantData
+            task.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder());
+            task.variantOutputData = scope.variantOutputData;
+
+            final String outputBaseName = scope.variantOutputData.getBaseName();
+            task.setCompressedResources(scope.getCompressedResourceFile());
+
+            ConventionMappingHelper.map(task, "uncompressedResources", new Callable<File>() {
+                @Override
+                public File call() {
+                    return scope.variantOutputData.processResourcesTask.getPackageOutputFile();
+                }
+            });
+
+        }
+    }
 }
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ZipAlign.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ZipAlign.java
index ea43e8f..15e910e 100644
--- a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ZipAlign.java
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/ZipAlign.java
@@ -97,7 +97,7 @@
 
         @Override
         public String getName() {
-            return "zipalign" + StringHelper.capitalize(scope.getVariantOutputData().getFullName());
+            return scope.getTaskName("zipalign");
         }
 
         @Override
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/JavaCompileConfigAction.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/JavaCompileConfigAction.java
new file mode 100644
index 0000000..502937b
--- /dev/null
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/JavaCompileConfigAction.java
@@ -0,0 +1,191 @@
+package com.android.build.gradle.tasks.factory;
+
+import static com.android.builder.core.VariantType.LIBRARY;
+import static com.android.builder.core.VariantType.UNIT_TEST;
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES;
+
+import com.android.build.gradle.internal.CompileOptions;
+import com.android.build.gradle.internal.scope.ConventionMappingHelper;
+import com.android.build.gradle.internal.scope.TaskConfigAction;
+import com.android.build.gradle.internal.scope.VariantScope;
+import com.android.build.gradle.internal.variant.BaseVariantData;
+import com.android.sdklib.AndroidTargetHash;
+import com.android.sdklib.AndroidVersion;
+
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.gradle.api.Action;
+import org.gradle.api.JavaVersion;
+import org.gradle.api.Task;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.tasks.compile.AbstractCompile;
+import org.gradle.api.tasks.compile.JavaCompile;
+
+import java.io.File;
+
+import groovy.lang.Closure;
+
+/**
+ * Configuration Action for a JavaCompile task.
+ */
+public class JavaCompileConfigAction implements TaskConfigAction<JavaCompile> {
+
+    private VariantScope scope;
+
+    public JavaCompileConfigAction(VariantScope scope) {
+        this.scope = scope;
+    }
+
+    @Override
+    public String getName() {
+        return scope.getTaskName("compile", "Java");
+    }
+
+    @Override
+    public Class<JavaCompile> getType() {
+        return JavaCompile.class;
+    }
+
+    @Override
+    public void execute(final JavaCompile javaCompileTask) {
+        final BaseVariantData testedVariantData = scope.getTestedVariantData();
+        scope.getVariantData().javaCompileTask = javaCompileTask;
+
+        javaCompileTask.setSource(scope.getVariantData().getJavaSources());
+
+        ConventionMappingHelper
+                .map(javaCompileTask, "classpath", new Closure<FileCollection>(this, this) {
+                    public FileCollection doCall(Object it) {
+                        FileCollection classpath = scope.getJavaClasspath();
+
+                        if (testedVariantData != null) {
+                            // For libraries, the classpath from androidBuilder includes the library output
+                            // (bundle/classes.jar) as a normal dependency. In unit tests we don't want to package
+                            // the jar at every run, so we use the *.class files instead.
+                            if (!testedVariantData.getType().equals(LIBRARY) || scope
+                                    .getVariantData().getType().equals(UNIT_TEST)) {
+                                classpath = classpath
+                                        .plus(testedVariantData.getScope().getJavaClasspath())
+                                        .plus(scope.getGlobalScope().getProject().files(
+                                                testedVariantData.getScope().getJavaOutputDir(),
+                                                testedVariantData.getScope().getJavaDependencyCache()));
+                            }
+
+                            if (scope.getVariantData().getType().equals(UNIT_TEST)
+                                    && testedVariantData.getType().equals(LIBRARY)) {
+                                // The bundled classes.jar may exist, but it's probably old. Don't use it, we
+                                // already have the *.class files in the classpath.
+                                classpath = classpath.minus(scope.getGlobalScope().getProject()
+                                        .files(testedVariantData.getVariantConfiguration()
+                                                .getOutput().getJarFile()));
+                            }
+
+                        }
+
+                        return classpath;
+                    }
+
+                    public FileCollection doCall() {
+                        return doCall(null);
+                    }
+
+                });
+
+        ConventionMappingHelper
+                .map(javaCompileTask, "destinationDir", new Closure<File>(this, this) {
+                    public File doCall(Object it) {
+                        return scope.getJavaOutputDir();
+                    }
+
+                    public File doCall() {
+                        return doCall(null);
+                    }
+
+                });
+        ConventionMappingHelper
+                .map(javaCompileTask, "dependencyCacheDir", new Closure<File>(this, this) {
+                    public File doCall(Object it) {
+                        return scope.getJavaDependencyCache();
+                    }
+
+                    public File doCall() {
+                        return doCall(null);
+                    }
+
+                });
+
+        configureLanguageLevel(javaCompileTask);
+        javaCompileTask.getOptions().setEncoding(
+                scope.getGlobalScope().getExtension().getCompileOptions().getEncoding());
+
+        // setup the boot classpath just before the task actually runs since this will
+        // force the sdk to be parsed.
+        javaCompileTask.doFirst(new Closure<String>(this, this) {
+            public String doCall(Task it) {
+                return setBootClasspath(javaCompileTask.getOptions(), DefaultGroovyMethods
+                        .join(scope.getGlobalScope().getAndroidBuilder()
+                                .getBootClasspathAsStrings(), File.pathSeparator));
+            }
+
+            public String doCall() {
+                return doCall(null);
+            }
+
+        });
+    }
+
+    private void configureLanguageLevel(AbstractCompile compileTask) {
+        final CompileOptions compileOptions = scope.getGlobalScope().getExtension()
+                .getCompileOptions();
+        JavaVersion javaVersionToUse;
+
+        final AndroidVersion hash = AndroidTargetHash
+                .getVersionFromHash(scope.getGlobalScope().getExtension().getCompileSdkVersion());
+        Integer compileSdkLevel = (hash == null ? null : hash.getApiLevel());
+        if (compileSdkLevel == null || (0 <= compileSdkLevel && compileSdkLevel <= 20)) {
+            javaVersionToUse = JavaVersion.VERSION_1_6;
+        } else {
+            javaVersionToUse = JavaVersion.VERSION_1_7;
+        }
+
+        JavaVersion jdkVersion = JavaVersion
+                .toVersion(System.getProperty("java.specification.version"));
+        if (jdkVersion.compareTo(javaVersionToUse) < 0) {
+//            logger.info(
+//                    "Default language level for 'compileSdkVersion $compileSdkLevel' is " +
+//                            "$javaVersionToUse, but the JDK used is $jdkVersion, so the JDK " +
+//                            "language level will be used.")
+            javaVersionToUse = jdkVersion;
+        }
+
+        compileOptions.setDefaultJavaVersion(javaVersionToUse);
+
+        ConventionMappingHelper
+                .map(compileTask, "sourceCompatibility", new Closure<String>(this, this) {
+                    public String doCall(Object it) {
+                        return compileOptions.getSourceCompatibility().toString();
+                    }
+
+                    public String doCall() {
+                        return doCall(null);
+                    }
+
+                });
+        ConventionMappingHelper
+                .map(compileTask, "targetCompatibility", new Closure<String>(this, this) {
+                    public String doCall(Object it) {
+                        return compileOptions.getTargetCompatibility().toString();
+                    }
+
+                    public String doCall() {
+                        return doCall(null);
+                    }
+
+                });
+    }
+
+    private static <Value extends String> Value setBootClasspath(
+            org.gradle.api.tasks.compile.CompileOptions propOwner, Value bootClasspath) {
+        propOwner.setBootClasspath(bootClasspath);
+        return bootClasspath;
+    }
+}
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/ProGuardTaskConfigAction.java b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/ProGuardTaskConfigAction.java
new file mode 100644
index 0000000..bb366d8
--- /dev/null
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/ProGuardTaskConfigAction.java
@@ -0,0 +1,98 @@
+package com.android.build.gradle.tasks.factory;
+
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES;
+
+import com.android.build.gradle.internal.TaskManager;
+import com.android.build.gradle.internal.scope.TaskConfigAction;
+import com.android.build.gradle.internal.scope.VariantScope;
+import com.android.utils.StringHelper;
+import com.google.common.base.Preconditions;
+
+import org.codehaus.groovy.runtime.StringGroovyMethods;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import groovy.lang.Closure;
+import proguard.ParseException;
+import proguard.gradle.ProGuardTask;
+
+/**
+ * Configuration Action for a ProGuardTask task.
+ */
+public class ProGuardTaskConfigAction implements TaskConfigAction<ProGuardTask> {
+
+    private VariantScope scope;
+
+    private Closure<List<File>> inputFiles;
+
+    public ProGuardTaskConfigAction(VariantScope scope, TaskManager.PostCompilationData pcData) {
+        this.scope = scope;
+        this.inputFiles = pcData.getInputFiles();
+    }
+
+    @Override
+    public String getName() {
+        return scope.getTaskName("shrink", "MultiDexComponents");
+    }
+
+    @Override
+    public Class<ProGuardTask> getType() {
+        return ProGuardTask.class;
+    }
+
+    @Override
+    public void execute(ProGuardTask proguardComponentsTask) {
+        proguardComponentsTask.dontobfuscate();
+        proguardComponentsTask.dontoptimize();
+        proguardComponentsTask.dontpreverify();
+        proguardComponentsTask.dontwarn();
+        proguardComponentsTask.forceprocessing();
+
+        try {
+            proguardComponentsTask.configuration(scope.getManifestKeepListFile());
+
+            proguardComponentsTask.libraryjars(new Closure<File>(this, this) {
+                public File doCall(Object it) {
+                    Preconditions.checkNotNull(
+                            scope.getGlobalScope().getAndroidBuilder().getTargetInfo());
+                    File shrinkedAndroid = new File(
+                            scope.getGlobalScope().getAndroidBuilder().getTargetInfo()
+                                    .getBuildTools()
+                                    .getLocation(),
+                            "lib" + File.separatorChar + "shrinkedAndroid.jar");
+
+                    // TODO remove in 1.0
+                    // STOPSHIP
+                    if (!shrinkedAndroid.isFile()) {
+                        shrinkedAndroid = new File(
+                                scope.getGlobalScope().getAndroidBuilder().getTargetInfo()
+                                        .getBuildTools().getLocation(),
+                                "multidex" + File.separatorChar + "shrinkedAndroid.jar");
+                    }
+
+                    return shrinkedAndroid;
+                }
+
+                public File doCall() {
+                    return doCall(null);
+                }
+
+            });
+
+            proguardComponentsTask.injars(inputFiles.call().iterator().next());
+
+            proguardComponentsTask.outjars(scope.getProguardComponentsJarFile());
+
+            proguardComponentsTask.printconfiguration(
+                    scope.getGlobalScope().getBuildDir() + "/" + FD_INTERMEDIATES
+                            + "/multi-dex/" + scope.getVariantConfiguration().getDirName()
+                            + "/components.flags");
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/ProcessJavaResConfigAction.groovy b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/ProcessJavaResConfigAction.groovy
new file mode 100644
index 0000000..d6cbc0f
--- /dev/null
+++ b/build-system/gradle-core/src/main/groovy/com/android/build/gradle/tasks/factory/ProcessJavaResConfigAction.groovy
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 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.tasks.factory
+
+import com.android.build.gradle.api.AndroidSourceSet
+import com.android.build.gradle.internal.scope.ConventionMappingHelper
+import com.android.build.gradle.internal.scope.TaskConfigAction
+import com.android.build.gradle.internal.scope.VariantScope
+import com.android.builder.core.BuilderConstants
+import com.android.builder.core.VariantType
+import com.android.builder.model.AndroidProject
+import com.android.builder.model.SourceProvider
+import org.gradle.api.tasks.Copy
+
+import static com.android.builder.core.VariantType.ANDROID_TEST
+import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES
+
+/**
+ * Configuration Action for a ProcessJavaRes task.
+ */
+class ProcessJavaResConfigAction implements TaskConfigAction<Copy> {
+
+    VariantScope scope;
+
+    ProcessJavaResConfigAction(VariantScope scope) {
+        this.scope = scope
+    }
+
+    @Override
+    String getName() {
+        return scope.getTaskName("process", "JavaRes");
+    }
+
+    @Override
+    Class<Copy> getType() {
+        return Copy.class
+    }
+
+    @Override
+    void execute(Copy processResources) {
+        scope.variantData.processJavaResourcesTask = processResources
+
+        // set the input
+        processResources.from(((AndroidSourceSet) scope.variantConfiguration.defaultSourceSet).resources.
+                getSourceFiles())
+
+        if (scope.variantConfiguration.type != ANDROID_TEST) {
+            processResources.from(
+                    ((AndroidSourceSet) scope.variantConfiguration.buildTypeSourceSet).resources.
+                            getSourceFiles())
+        }
+        if (scope.variantConfiguration.hasFlavors()) {
+            for (SourceProvider flavorSourceSet : scope.variantConfiguration.flavorSourceProviders) {
+                processResources.
+                        from(((AndroidSourceSet) flavorSourceSet).resources.getSourceFiles())
+            }
+        }
+
+        ConventionMappingHelper.map(processResources, "destinationDir") {
+            scope.getJavaResourcesDestinationDir()
+        }
+
+    }
+}
diff --git a/build-system/gradle-experimental/src/main/groovy/com/android/build/gradle/model/BaseComponentModelPlugin.groovy b/build-system/gradle-experimental/src/main/groovy/com/android/build/gradle/model/BaseComponentModelPlugin.groovy
index 5f93c51..ef9857b 100644
--- a/build-system/gradle-experimental/src/main/groovy/com/android/build/gradle/model/BaseComponentModelPlugin.groovy
+++ b/build-system/gradle-experimental/src/main/groovy/com/android/build/gradle/model/BaseComponentModelPlugin.groovy
@@ -39,6 +39,7 @@
 import com.android.build.gradle.internal.model.ModelBuilder
 import com.android.build.gradle.internal.process.GradleJavaProcessExecutor
 import com.android.build.gradle.internal.process.GradleProcessExecutor
+import com.android.build.gradle.internal.profile.RecordingBuildListener
 import com.android.build.gradle.internal.tasks.DependencyReportTask
 import com.android.build.gradle.internal.tasks.SigningReportTask
 import com.android.build.gradle.internal.variant.VariantFactory
@@ -49,6 +50,10 @@
 import com.android.builder.core.BuilderConstants
 import com.android.builder.internal.compiler.JackConversionCache
 import com.android.builder.internal.compiler.PreDexCache
+import com.android.builder.profile.ExecutionType
+import com.android.builder.profile.ProcessRecorderFactory
+import com.android.builder.profile.Recorder
+import com.android.builder.profile.ThreadRecorder
 import com.android.builder.sdk.TargetInfo
 import com.android.ide.common.internal.ExecutorSingleton
 import com.android.ide.common.process.LoggedProcessOutputHandler
@@ -109,6 +114,10 @@
      */
     @Override
     public void apply(Project project) {
+        ProcessRecorderFactory.initialize(new LoggerWrapper(project.logger), project.rootProject.
+                file("profiler" + System.currentTimeMillis() + ".json"))
+        project.gradle.addListener(new RecordingBuildListener(ThreadRecorder.get()));
+
         project.apply plugin: AndroidComponentModelPlugin
 
         project.apply plugin: JavaBasePlugin
@@ -132,7 +141,6 @@
                 "default-mapping",
                 "Metadata for published APKs")
 
-
         project.tasks.getByName("assemble").description =
                 "Assembles all variants of all applications and secondary packages."
 
@@ -376,8 +384,6 @@
                 }
             }
 
-            taskManager.createLintCompileTask();
-
             // TODO: determine how to provide functionalities of variant API objects.
         }
 
@@ -388,12 +394,20 @@
                 BinaryContainer binaries,
                 AndroidComponentSpec spec,
                 TaskManager taskManager) {
+
             VariantManager variantManager = (spec as DefaultAndroidComponentSpec).variantManager
             binaries.withType(AndroidBinary) { androidBinary ->
-                DefaultAndroidBinary binary = androidBinary as DefaultAndroidBinary
-                variantManager.createTasksForVariantData(
-                        new TaskCollectionBuilderAdaptor(tasks),
-                        binary.variantData)
+                ThreadRecorder.get().record(ExecutionType.VARIANT_MANAGER_CREATE_TASKS_FOR_VARIANT,
+                        new Recorder.Block<Void>() {
+                            @Override
+                            public Void call() throws Exception {
+                                    DefaultAndroidBinary binary = androidBinary as DefaultAndroidBinary
+                                    variantManager.createTasksForVariantData(
+                                            new TaskCollectionBuilderAdaptor(tasks),
+                                            binary.variantData)
+                                return null;
+                            }
+                        });
             }
         }
 
@@ -407,11 +421,6 @@
                 AndroidComponentSpec spec) {
             VariantManager variantManager = (spec as DefaultAndroidComponentSpec).variantManager
 
-            // create the lint tasks.
-            taskManager.createLintTasks(
-                    new TaskCollectionBuilderAdaptor(tasks),
-                    variantManager.variantDataList);
-
             // create the test tasks.
             taskManager.createTopLevelTestTasks (
                     new TaskCollectionBuilderAdaptor(tasks),
diff --git a/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/common/fixture/app/VariantBuildScriptGenerator.java b/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/common/fixture/app/VariantBuildScriptGenerator.java
index 1d926c2..7cf61e6dc 100644
--- a/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/common/fixture/app/VariantBuildScriptGenerator.java
+++ b/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/common/fixture/app/VariantBuildScriptGenerator.java
@@ -15,7 +15,7 @@
  */
 public class VariantBuildScriptGenerator {
 
-    public static final Integer LARGE_NUMBER = 15;
+    public static final Integer LARGE_NUMBER = 20;
 
     public static final Integer MEDIUM_NUMBER = 5;
 
diff --git a/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/component/BasicNdkComponentTest.groovy b/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/component/BasicNdkComponentTest.groovy
index e5f2ca5..154a7bb 100644
--- a/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/component/BasicNdkComponentTest.groovy
+++ b/build-system/integration-test/src/test/groovy/com/android/build/gradle/integration/component/BasicNdkComponentTest.groovy
@@ -27,6 +27,8 @@
 
 import java.util.zip.ZipFile
 
+import static com.android.build.gradle.integration.common.truth.TruthHelper.assertThatApk
+import static com.android.build.gradle.integration.common.truth.TruthHelper.assertThatZip
 import static org.junit.Assert.assertNotNull
 
 /**
@@ -78,11 +80,11 @@
         project.execute("assembleRelease");
 
         // Verify .so are built for all platform.
-        ZipFile apk = new ZipFile(project.getApk("release", "unsigned"));
-        assertNotNull(apk.getEntry("lib/x86/libhello-jni.so"));
-        assertNotNull(apk.getEntry("lib/mips/libhello-jni.so"));
-        assertNotNull(apk.getEntry("lib/armeabi/libhello-jni.so"));
-        assertNotNull(apk.getEntry("lib/armeabi-v7a/libhello-jni.so"));
+        File apk = project.getApk("release", "unsigned");
+        assertThatZip(apk).contains("lib/x86/libhello-jni.so");
+        assertThatZip(apk).contains("lib/mips/libhello-jni.so");
+        assertThatZip(apk).contains("lib/armeabi/libhello-jni.so");
+        assertThatZip(apk).contains("lib/armeabi-v7a/libhello-jni.so");
     }
 
     @Test
@@ -90,19 +92,19 @@
         project.execute("assembleDebug");
 
         // Verify .so are built for all platform.
-        ZipFile apk = new ZipFile(project.getApk("debug"));
-        assertNotNull(apk.getEntry("lib/x86/libhello-jni.so"));
-        assertNotNull(apk.getEntry("lib/x86/gdbserver"));
-        assertNotNull(apk.getEntry("lib/x86/gdb.setup"));
-        assertNotNull(apk.getEntry("lib/mips/libhello-jni.so"));
-        assertNotNull(apk.getEntry("lib/mips/gdbserver"));
-        assertNotNull(apk.getEntry("lib/mips/gdb.setup"));
-        assertNotNull(apk.getEntry("lib/armeabi/libhello-jni.so"));
-        assertNotNull(apk.getEntry("lib/armeabi/gdbserver"));
-        assertNotNull(apk.getEntry("lib/armeabi/gdb.setup"));
-        assertNotNull(apk.getEntry("lib/armeabi-v7a/libhello-jni.so"));
-        assertNotNull(apk.getEntry("lib/armeabi-v7a/gdbserver"));
-        assertNotNull(apk.getEntry("lib/armeabi-v7a/gdb.setup"));
+        File apk = project.getApk("debug");
+        assertThatZip(apk).contains("lib/x86/libhello-jni.so");
+        assertThatZip(apk).contains("lib/x86/gdbserver");
+        assertThatZip(apk).contains("lib/x86/gdb.setup");
+        assertThatZip(apk).contains("lib/mips/libhello-jni.so");
+        assertThatZip(apk).contains("lib/mips/gdbserver");
+        assertThatZip(apk).contains("lib/mips/gdb.setup");
+        assertThatZip(apk).contains("lib/armeabi/libhello-jni.so");
+        assertThatZip(apk).contains("lib/armeabi/gdbserver");
+        assertThatZip(apk).contains("lib/armeabi/gdb.setup");
+        assertThatZip(apk).contains("lib/armeabi-v7a/libhello-jni.so");
+        assertThatZip(apk).contains("lib/armeabi-v7a/gdbserver");
+        assertThatZip(apk).contains("lib/armeabi-v7a/gdb.setup");
     }
 
     @Test
diff --git a/build-system/profile/src/main/java/com/android/builder/profile/ExecutionType.java b/build-system/profile/src/main/java/com/android/builder/profile/ExecutionType.java
index e6a6d07..2b495ae 100644
--- a/build-system/profile/src/main/java/com/android/builder/profile/ExecutionType.java
+++ b/build-system/profile/src/main/java/com/android/builder/profile/ExecutionType.java
@@ -56,6 +56,8 @@
     APP_TASK_MANAGER_CREATE_SPLIT_TASK(1010),
     APP_TASK_MANAGER_CREATE_PACKAGING_TASK(1011),
     APP_TASK_MANAGER_CREATE_PREPROCESS_RESOURCES_TASK(1012),
+    APP_TASK_MANAGER_CREATE_BACKPORT_RESOURCES_TASK(1013),
+    APP_TASK_MANAGER_CREATE_LINT_TASK(1014),
 
     // LibraryTaskManager per variant tasks.
     LIB_TASK_MANAGER_CREATE_MERGE_MANIFEST_TASK(2000),
@@ -75,6 +77,7 @@
     LIB_TASK_MANAGER_CREATE_PROGUARD_TASK(2014),
     LIB_TASK_MANAGER_CREATE_PACKAGE_LOCAL_JAR(2015),
     LIB_TASK_MANAGER_CREATE_BACKPORT_RESOURCES_TASK(2016),
+    LIB_TASK_MANAGER_CREATE_LINT_TASK(2017),
 
     // TASK_EXECUTION
     GENERIC_TASK_EXECUTION(3000),