Support compile config for flavors and build types.
Xavier Ducrohet [Fri, 5 Oct 2012 17:56:03 +0000 (10:56 -0700)]
Read dependency graph and create list of JarDependency
and AndroidDependency for each configuration.

Set Jars and AndroidDependency on each VariantConfig
object.

Add a AndroidDependency report task (called androidDependency)

The prepareDependenciesTask will prepare the same artifact
multiple time if it's used by different variants and they
are all built. This will be fixed in the next patch.

Change-Id: I4f11565c3629a54f022ecc82f81d4900ef2bd0c9

64 files changed:
.gitignore
builder/src/main/java/com/android/builder/AndroidBuilder.java
builder/src/main/java/com/android/builder/BundleDependency.java
builder/src/main/java/com/android/builder/VariantConfiguration.java
gradle/src/main/groovy/com/android/build/gradle/AndroidDependencyTask.groovy [new file with mode: 0644]
gradle/src/main/groovy/com/android/build/gradle/AppPlugin.groovy
gradle/src/main/groovy/com/android/build/gradle/BasePlugin.groovy
gradle/src/main/groovy/com/android/build/gradle/DependencyChecker.groovy
gradle/src/main/groovy/com/android/build/gradle/LibraryPlugin.groovy
gradle/src/main/groovy/com/android/build/gradle/PrepareDependenciesTask.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java [new file with mode: 0644]
gradle/src/main/groovy/com/android/build/gradle/internal/AndroidDependencyImpl.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/ApplicationVariant.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/BuildTypeData.groovy
gradle/src/main/groovy/com/android/build/gradle/internal/ConfigurationDependencies.groovy [new file with mode: 0644]
gradle/src/main/groovy/com/android/build/gradle/internal/ProductFlavorData.groovy
testapps/flavorlib/app/build.gradle [new file with mode: 0644]
testapps/flavorlib/app/proguard-project.txt [new file with mode: 0644]
testapps/flavorlib/app/src/flavor1/res/values/strings.xml [new file with mode: 0644]
testapps/flavorlib/app/src/flavor2/res/values/strings.xml [new file with mode: 0644]
testapps/flavorlib/app/src/main/AndroidManifest.xml [new file with mode: 0644]
testapps/flavorlib/app/src/main/java/com/android/tests/flavorlib/app/App.java [new file with mode: 0644]
testapps/flavorlib/app/src/main/java/com/android/tests/flavorlib/app/MainActivity.java [new file with mode: 0644]
testapps/flavorlib/app/src/main/res/drawable-hdpi/icon.png [new file with mode: 0644]
testapps/flavorlib/app/src/main/res/drawable-ldpi/icon.png [new file with mode: 0644]
testapps/flavorlib/app/src/main/res/drawable-mdpi/icon.png [new file with mode: 0644]
testapps/flavorlib/app/src/main/res/layout/main.xml [new file with mode: 0644]
testapps/flavorlib/app/src/main/res/values/strings.xml [new file with mode: 0644]
testapps/flavorlib/app/src/main/resources/com/android/tests/flavorlib/app/App.txt [new file with mode: 0644]
testapps/flavorlib/app/src/test/java/com/android/tests/flavorlib/app/MainActivityTest.java [new file with mode: 0644]
testapps/flavorlib/app/src/testFlavor1/java/com/android/tests/flavorlib/app/MainActivityFlavorTest.java [new file with mode: 0644]
testapps/flavorlib/app/src/testFlavor2/java/com/android/tests/flavorlib/app/MainActivityFlavorTest.java [new file with mode: 0644]
testapps/flavorlib/build.gradle [new file with mode: 0644]
testapps/flavorlib/lib1/build.gradle [new file with mode: 0644]
testapps/flavorlib/lib1/proguard-project.txt [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/AndroidManifest.xml [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/java/com/android/tests/flavorlib/lib/Lib.java [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/java/com/android/tests/flavorlib/lib/MainActivity.java [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/res/layout/lib_main.xml [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/res/values/strings.xml [new file with mode: 0644]
testapps/flavorlib/lib1/src/main/resources/com/android/tests/flavorlib/lib/Lib.txt [new file with mode: 0644]
testapps/flavorlib/lib1/src/test/java/com/android/tests/flavorlib/lib/MainActivityTest.java [new file with mode: 0644]
testapps/flavorlib/lib2/build.gradle [new file with mode: 0644]
testapps/flavorlib/lib2/proguard-project.txt [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/AndroidManifest.xml [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/java/com/android/tests/flavorlib/lib/Lib.java [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/java/com/android/tests/flavorlib/lib/MainActivity.java [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/res/layout/lib_main.xml [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/res/values/strings.xml [new file with mode: 0644]
testapps/flavorlib/lib2/src/main/resources/com/android/tests/flavorlib/lib/Lib.txt [new file with mode: 0644]
testapps/flavorlib/lib2/src/test/java/com/android/tests/flavorlib/lib/MainActivityTest.java [new file with mode: 0644]
testapps/flavorlib/settings.gradle [new file with mode: 0644]
testapps/multiproject/build.gradle
testapps/repo/.gitignore [new file with mode: 0644]
testapps/repo/app/build.gradle
testapps/repo/baseLibrary/build.gradle
testapps/repo/library/build.gradle
testapps/repo/util/build.gradle

index 9ad1507..ae85b59 100644 (file)
@@ -10,6 +10,7 @@ testapps/*/build
 testapps/multiproject/*/build
 testapps/tictactoe/*/build
 testapps/applibtest/*/build
+testapps/flavorlib/*/build
 testapps/libsTest/*/build
 testapps/repo/*/build
 /repo
index 2995e39..ad2a472 100644 (file)
@@ -45,6 +45,7 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -858,7 +859,7 @@ public class AndroidBuilder {
             }
 
             // add the resources from the jar files.
-            List<JarDependency> jars = mVariant.getJars();
+            Collection<JarDependency> jars = mVariant.getJars();
             if (jars != null) {
                 for (JarDependency jar : jars) {
                     packager.addResourcesFromJar(new File(jar.getLocation()));
@@ -866,8 +867,11 @@ public class AndroidBuilder {
             }
 
             // add the resources from the libs jar files
-            List<AndroidDependency> libs = mVariant.getDirectLibraries();
-            addLibJavaResourcesToPackager(packager, libs);
+            List<AndroidDependency> libs = mVariant.getAllLibraries();
+
+            for (AndroidDependency lib : libs) {
+                packager.addResourcesFromJar(lib.getJarFile());
+            }
 
             // also add resources from library projects and jars
             if (jniLibsLocation != null) {
@@ -881,16 +885,4 @@ public class AndroidBuilder {
             throw new RuntimeException(e);
         }
     }
-
-    private void addLibJavaResourcesToPackager(Packager packager, List<AndroidDependency> libs)
-            throws PackagerException, SealedPackageException, DuplicateFileException {
-        if (libs != null) {
-            for (AndroidDependency lib : libs) {
-                packager.addResourcesFromJar(lib.getJarFile());
-
-                // recursively add the dependencies of this library.
-                addLibJavaResourcesToPackager(packager, lib.getDependencies());
-            }
-        }
-    }
 }
index 8cab4f6..14d01ba 100644 (file)
@@ -17,6 +17,8 @@
 package com.android.builder;
 
 import com.android.SdkConstants;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
 
 import java.io.File;
 
@@ -26,13 +28,32 @@ import java.io.File;
  */
 public abstract class BundleDependency implements AndroidDependency {
 
+    private final String mName;
     private final File mBundleFolder;
 
-    protected BundleDependency(File bundleFolder) {
-
+    /**
+     * Creates the bundle dependency with an optional name
+     * @param bundleFolder the folder containing the library
+     * @param name an optional name
+     */
+    protected BundleDependency(@NonNull File bundleFolder, @Nullable String name) {
+        mName = name;
         mBundleFolder = bundleFolder;
     }
 
+    protected BundleDependency(@NonNull File bundleFolder) {
+        this(bundleFolder, null);
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    @Override
+    public String toString() {
+        return mName;
+    }
+
     @Override
     public File getFolder() {
         return mBundleFolder;
@@ -77,4 +98,25 @@ public abstract class BundleDependency implements AndroidDependency {
     public File getLintJar() {
         return new File(mBundleFolder, "lint.jar");
     }
+
+    public File getBundleFolder() {
+        return mBundleFolder;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        BundleDependency that = (BundleDependency) o;
+
+        if (mName != null ? !mName.equals(that.mName) : that.mName != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return mName != null ? mName.hashCode() : 0;
+    }
 }
index ce7c878..1d78ee6 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
 import java.io.File;
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
@@ -55,7 +56,7 @@ public class VariantConfiguration {
 
     private ProductFlavor mMergedFlavor;
 
-    private final List<JarDependency> mJars = Lists.newArrayList();
+    private final Set<JarDependency> mJars = Sets.newHashSet();
 
     /** List of direct library dependencies. Each object defines its own dependencies. */
     private final List<AndroidDependency> mDirectLibraries = Lists.newArrayList();
@@ -157,7 +158,7 @@ public class VariantConfiguration {
         mJars.addAll(jars);
     }
 
-    public List<JarDependency> getJars() {
+    public Collection<JarDependency> getJars() {
         return mJars;
     }
 
diff --git a/gradle/src/main/groovy/com/android/build/gradle/AndroidDependencyTask.groovy b/gradle/src/main/groovy/com/android/build/gradle/AndroidDependencyTask.groovy
new file mode 100644 (file)
index 0000000..882572c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 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
+
+import com.android.build.gradle.internal.ApplicationVariant
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.tasks.TaskAction
+import org.gradle.logging.StyledTextOutputFactory
+import com.android.build.gradle.internal.AndroidAsciiReportRenderer
+
+/**
+ */
+class AndroidDependencyTask extends DefaultTask {
+
+    private AndroidAsciiReportRenderer renderer = new AndroidAsciiReportRenderer();
+
+    private Set<ApplicationVariant> variants = [];
+
+    @TaskAction
+    public void generate() throws IOException {
+        renderer.setOutput(getServices().get(StyledTextOutputFactory.class).create(getClass()));
+
+        SortedSet<ApplicationVariant> sortedConfigurations = new TreeSet<Configuration>(
+                new Comparator<ApplicationVariant>() {
+            public int compare(ApplicationVariant conf1, ApplicationVariant conf2) {
+                return conf1.getName().compareTo(conf2.getName());
+            }
+        });
+        sortedConfigurations.addAll(getVariants());
+        for (ApplicationVariant variant : sortedConfigurations) {
+            renderer.startVariant(variant);
+            renderer.render(variant);
+        }
+    }
+
+    /**
+     * Returns the configurations to generate the report for. Default to all configurations of
+     * this task's containing project.
+     *
+     * @return the configurations.
+     */
+    public Set<ApplicationVariant> getVariants() {
+        return variants;
+    }
+
+    /**
+     * Sets the configurations to generate the report for.
+     *
+     * @param configurations The configuration. Must not be null.
+     */
+    public void setVariants(Collection<ApplicationVariant> variants) {
+        this.variants.addAll(variants);
+    }
+}
index 3d49b75..068c86d 100644 (file)
@@ -17,11 +17,14 @@ package com.android.build.gradle
 
 import com.android.build.gradle.internal.BuildTypeData
 import com.android.build.gradle.internal.BuildTypeDsl
+import com.android.build.gradle.internal.ConfigurationDependencies
 import com.android.build.gradle.internal.ProductFlavorData
 import com.android.build.gradle.internal.ProductFlavorDsl
 import com.android.build.gradle.internal.ProductionAppVariant
 import com.android.build.gradle.internal.TestAppVariant
+import com.android.builder.AndroidDependency
 import com.android.builder.BuildType
+import com.android.builder.JarDependency
 import com.android.builder.VariantConfiguration
 import com.google.common.collect.ArrayListMultimap
 import com.google.common.collect.ListMultimap
@@ -106,6 +109,13 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
     }
 
     private void createAndroidTasks() {
+        // resolve dependencies for all config
+        List<ConfigurationDependencies> dependencies = []
+        dependencies.addAll(buildTypes.values())
+        dependencies.addAll(productFlavors.values())
+        resolveDependencies(dependencies)
+
+        // now create the tasks.
         if (productFlavors.isEmpty()) {
             createTasksForDefaultBuild()
         } else {
@@ -142,6 +152,8 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
                 createTasksForMultiFlavoredBuilds(array, 0, map)
             }
         }
+
+        createDependencyReportTask()
     }
 
     private createTasksForMultiFlavoredBuilds(ProductFlavorData[] datas, int i,
@@ -177,13 +189,32 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
         ProductFlavorData defaultConfigData = getDefaultConfigData();
 
         for (BuildTypeData buildTypeData : buildTypes.values()) {
+            List<ConfigurationDependencies> configDependencies = []
+            configDependencies.add(defaultConfigData)
+            configDependencies.add(buildTypeData)
+
+            // list of dependency to set on the variantConfig
+            List<JarDependency> jars = []
+            jars.addAll(defaultConfigData.jars)
+            jars.addAll(buildTypeData.jars)
+
+            // the order of the libraries is important. In descending order:
+            // build types, flavors, defaultConfig.
+            List<AndroidDependency> libs = []
+            libs.addAll(buildTypeData.libraries)
+            // no flavors, just add the default config
+            libs.addAll(defaultConfigData.libraries)
 
             def variantConfig = new VariantConfiguration(
                     defaultConfigData.productFlavor, defaultConfigData.sourceSet,
                     buildTypeData.buildType, buildTypeData.sourceSet)
 
+            variantConfig.setJarDependencies(jars)
+            variantConfig.setAndroidDependencies(libs)
+
             ProductionAppVariant productionAppVariant = addVariant(variantConfig,
-                    buildTypeData.assembleTask)
+                    buildTypeData.assembleTask, configDependencies)
+            variants.add(productionAppVariant)
 
             if (buildTypeData == testData) {
                 testedVariant = productionAppVariant
@@ -197,11 +228,21 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
                 testData.buildType, null,
                 VariantConfiguration.Type.TEST, testedVariant.config)
 
-        // TODO: add actual dependencies
-        testVariantConfig.setAndroidDependencies(null)
+        List<ConfigurationDependencies> testConfigDependencies = []
+        testConfigDependencies.add(defaultConfigData.testConfigDependencies)
+
+        // list of dependency to set on the variantConfig
+        List<JarDependency> testJars = []
+        testJars.addAll(defaultConfigData.testConfigDependencies.jars)
+        List<AndroidDependency> testLibs = []
+        testLibs.addAll(defaultConfigData.testConfigDependencies.libraries)
+
+        testVariantConfig.setJarDependencies(testJars)
+        testVariantConfig.setAndroidDependencies(testLibs)
 
         def testVariant = new TestAppVariant(testVariantConfig)
-        createTestTasks(testVariant, testedVariant)
+        variants.add(testVariant)
+        createTestTasks(testVariant, testedVariant, testConfigDependencies)
     }
 
     /**
@@ -222,6 +263,19 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
         def assembleTask
 
         for (BuildTypeData buildTypeData : buildTypes.values()) {
+            List<ConfigurationDependencies> configDependencies = []
+            configDependencies.add(defaultConfigData)
+            configDependencies.add(buildTypeData)
+
+            // list of dependency to set on the variantConfig
+            List<JarDependency> jars = []
+            jars.addAll(defaultConfigData.jars)
+            jars.addAll(buildTypeData.jars)
+
+            // the order of the libraries is important. In descending order:
+            // build types, flavors, defaultConfig.
+            List<AndroidDependency> libs = []
+            libs.addAll(buildTypeData.libraries)
 
             def variantConfig = new VariantConfiguration(
                     extension.defaultConfig, getDefaultConfigData().sourceSet,
@@ -229,9 +283,20 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
 
             for (ProductFlavorData data : flavorDataList) {
                 variantConfig.addProductFlavor(data.productFlavor, data.sourceSet)
+                jars.addAll(data.jars)
+                libs.addAll(data.libraries)
+                configDependencies.add(data)
             }
 
-            ProductionAppVariant productionAppVariant = addVariant(variantConfig, null)
+            // now add the defaultConfig
+            libs.addAll(defaultConfigData.libraries)
+
+            variantConfig.setJarDependencies(jars)
+            variantConfig.setAndroidDependencies(libs)
+
+            ProductionAppVariant productionAppVariant = addVariant(variantConfig, null,
+                    configDependencies)
+            variants.add(productionAppVariant)
 
             buildTypeData.assembleTask.dependsOn productionAppVariant.assembleTask
 
@@ -254,15 +319,32 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
                 testData.buildType, null,
                 VariantConfiguration.Type.TEST, testedVariant.config)
 
+        List<ConfigurationDependencies> testConfigDependencies = []
+        testConfigDependencies.add(defaultConfigData.testConfigDependencies)
+
+        // list of dependency to set on the variantConfig
+        List<JarDependency> testJars = []
+        testJars.addAll(defaultConfigData.testConfigDependencies.jars)
+
+        // the order of the libraries is important. In descending order:
+        // flavors, defaultConfig.
+        List<AndroidDependency> testLibs = []
+
         for (ProductFlavorData data : flavorDataList) {
             testVariantConfig.addProductFlavor(data.productFlavor, data.testSourceSet)
+            testJars.addAll(data.testConfigDependencies.jars)
+            testLibs.addAll(data.testConfigDependencies.libraries)
         }
 
-        // TODO: add actual dependencies
-        testVariantConfig.setAndroidDependencies(null)
+        // now add the default config
+        testLibs.addAll(defaultConfigData.testConfigDependencies.libraries)
+
+        testVariantConfig.setJarDependencies(testJars)
+        testVariantConfig.setAndroidDependencies(testLibs)
 
         def testVariant = new TestAppVariant(testVariantConfig)
-        createTestTasks(testVariant, testedVariant)
+        variants.add(testVariant)
+        createTestTasks(testVariant, testedVariant, testConfigDependencies)
     }
 
     private Task createAssembleTask(ProductFlavorData[] flavorDataList) {
@@ -281,11 +363,12 @@ class AppPlugin extends com.android.build.gradle.BasePlugin implements org.gradl
      * @param assembleTask an optional assembleTask to be used. If null, a new one is created.
      * @return
      */
-    private ProductionAppVariant addVariant(VariantConfiguration variantConfig, Task assembleTask) {
+    private ProductionAppVariant addVariant(VariantConfiguration variantConfig, Task assembleTask,
+                                            List<ConfigurationDependencies> configDependencies) {
 
         def variant = new ProductionAppVariant(variantConfig)
 
-        def prepareDependenciesTask = createPrepareDependenciesTask(variant)
+        def prepareDependenciesTask = createPrepareDependenciesTask(variant, configDependencies)
 
         // Add a task to process the manifest(s)
         def processManifestTask = createProcessManifestTask(variant, "manifests")
index a07766b..954d5dd 100644 (file)
@@ -18,6 +18,7 @@ package com.android.build.gradle
 import com.android.SdkConstants
 import com.android.build.gradle.internal.AndroidDependencyImpl
 import com.android.build.gradle.internal.ApplicationVariant
+import com.android.build.gradle.internal.ConfigurationDependencies
 import com.android.build.gradle.internal.ProductFlavorData
 import com.android.build.gradle.internal.ProductionAppVariant
 import com.android.build.gradle.internal.TestAppVariant
@@ -57,6 +58,8 @@ abstract class BasePlugin {
 
     private final Map<Object, AndroidBuilder> builders = [:]
 
+    final List<ApplicationVariant> variants = []
+
     protected Project project
     protected File sdkDir
     private DefaultSdkParser androidSdkParser
@@ -370,9 +373,15 @@ abstract class BasePlugin {
         variant.compileTask = compileTask
     }
 
-    protected void createTestTasks(TestAppVariant variant, ProductionAppVariant testedVariant) {
+    protected void createTestTasks(TestAppVariant variant, ProductionAppVariant testedVariant,
+                                   List<ConfigurationDependencies> configDependencies) {
+
+        def prepareDependenciesTask = createPrepareDependenciesTask(variant, configDependencies)
+
         // Add a task to process the manifest
         def processManifestTask = createProcessManifestTask(variant, "manifests")
+        // TODO - move this
+        processManifestTask.dependsOn prepareDependenciesTask
 
         // Add a task to crunch resource files
         def crunchTask = createCrunchResTask(variant)
@@ -395,6 +404,8 @@ abstract class BasePlugin {
         createProcessJavaResTask(variant)
 
         def compileAidl = createAidlTask(variant)
+        // TODO - move this
+        compileAidl.dependsOn prepareDependenciesTask
 
         // Add a task to compile the test application
         createCompileTask(variant, testedVariant, processResources, generateBuildConfigTask,
@@ -521,41 +532,82 @@ abstract class BasePlugin {
         uninstallAll.dependsOn uninstallTask
     }
 
-    PrepareDependenciesTask createPrepareDependenciesTask(ProductionAppVariant variant) {
-        // TODO - include variant specific dependencies too
-        def compileClasspath = project.configurations.compile
-
-        // TODO - shouldn't need to do this - fix this in Gradle
-        ensureConfigured(compileClasspath)
+    protected void createDependencyReportTask() {
+        def androidDependencyTask = project.tasks.add("androidDependencies", AndroidDependencyTask)
+        androidDependencyTask.setDescription("Displays the Android dependencies of the project")
+        androidDependencyTask.setVariants(variants)
+        androidDependencyTask.setGroup("Help")
+    }
 
+    PrepareDependenciesTask createPrepareDependenciesTask(ApplicationVariant variant,
+            List<ConfigurationDependencies> configDependenciesList) {
         def prepareDependenciesTask = project.tasks.add("prepare${variant.name}Dependencies",
                 PrepareDependenciesTask)
         prepareDependenciesTask.plugin = this
         prepareDependenciesTask.variant = variant
 
-        // TODO - should be able to infer this
-        prepareDependenciesTask.dependsOn compileClasspath
+        // look at all the flavors/build types of the variant and get all the libraries
+        // to make sure they are unarchived before the build runs.
+        for (ConfigurationDependencies configDependencies : configDependenciesList) {
+            prepareDependenciesTask.dependsOn configDependencies.configuration.buildDependencies
+            for (AndroidDependencyImpl lib : configDependencies.libraries) {
+                addDependencyToPrepareTask(prepareDependenciesTask, lib)
+                prepareDependenciesTask.add(lib.bundle, lib.bundleFolder)
+            }
+        }
+
+        return prepareDependenciesTask
+    }
+
+    def resolveDependencies(List<ConfigurationDependencies> configs) {
+        // start with the default config and its test
+        resolveDependencyForConfig(defaultConfigData)
+        resolveDependencyForConfig(defaultConfigData.testConfigDependencies)
+
+        // and then loop on all the other configs
+        for (ConfigurationDependencies config : configs) {
+            resolveDependencyForConfig(config)
+            if (config.testConfigDependencies != null) {
+                resolveDependencyForConfig(config.testConfigDependencies)
+            }
+        }
+    }
+
+    def resolveDependencyForConfig(
+            ConfigurationDependencies configDependencies) {
+
+        def compileClasspath = configDependencies.configuration
+
+        // TODO - shouldn't need to do this - fix this in Gradle
+        ensureConfigured(compileClasspath)
 
-        def checker = new DependencyChecker(variant, logger)
+        def checker = new DependencyChecker(logger)
 
-        // TODO - defer downloading until required
-        // TODO - build the library dependency graph
+        // TODO - defer downloading until required -- This is hard to do as we need the info to build the variant config.
         List<AndroidDependency> bundles = []
         List<JarDependency> jars = []
         Map<ModuleVersionIdentifier, List<AndroidDependency>> modules = [:]
         Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts = [:]
         collectArtifacts(compileClasspath, artifacts)
         compileClasspath.resolvedConfiguration.resolutionResult.root.dependencies.each { ResolvedDependencyResult dep ->
-            addDependency(dep.selected, prepareDependenciesTask, checker,
-                    bundles, jars, modules, artifacts)
+            addDependency(dep.selected, checker, bundles, jars, modules, artifacts)
         }
 
-        variant.config.androidDependencies = bundles
-        variant.config.jarDependencies = jars
+        configDependencies.libraries = bundles
+        configDependencies.jars = jars
 
         // TODO - filter bundles out of source set classpath
 
-        return prepareDependenciesTask
+        configureBuild(configDependencies)
+    }
+
+    def addDependencyToPrepareTask(PrepareDependenciesTask prepareDependenciesTask,
+                                   AndroidDependencyImpl lib) {
+        prepareDependenciesTask.add(lib.bundle, lib.bundleFolder)
+
+        for (AndroidDependencyImpl childLib : lib.dependencies) {
+            addDependencyToPrepareTask(prepareDependenciesTask, childLib)
+        }
     }
 
     def ensureConfigured(Configuration config) {
@@ -579,7 +631,6 @@ abstract class BasePlugin {
     }
 
     def addDependency(ResolvedModuleVersionResult moduleVersion,
-                      PrepareDependenciesTask prepareDependenciesTask,
                       DependencyChecker checker,
                       Collection<AndroidDependency> bundles,
                       Collection<JarDependency> jars,
@@ -597,7 +648,7 @@ abstract class BasePlugin {
 
             def nestedBundles = []
             moduleVersion.dependencies.each { ResolvedDependencyResult dep ->
-                addDependency(dep.selected, prepareDependenciesTask, checker, nestedBundles,
+                addDependency(dep.selected, checker, nestedBundles,
                         jars, modules, artifacts)
             }
 
@@ -606,8 +657,9 @@ abstract class BasePlugin {
                 if (artifact.type == 'alb') {
                     def explodedDir = project.file(
                             "$project.buildDir/exploded-bundles/$artifact.file.name")
-                    bundlesForThisModule << new AndroidDependencyImpl(explodedDir, nestedBundles)
-                    prepareDependenciesTask.add(artifact.file, explodedDir)
+                    bundlesForThisModule << new AndroidDependencyImpl(
+                            id.group + ":" + id.name + ":" + id.version,
+                            explodedDir, nestedBundles, artifact.file)
                 } else {
                     // TODO - need the correct values for the boolean flags
                     jars << new JarDependency(artifact.file.absolutePath, true, true, true)
@@ -621,5 +673,36 @@ abstract class BasePlugin {
 
         bundles.addAll(bundlesForThisModule)
     }
+
+    private void configureBuild(ConfigurationDependencies configurationDependencies) {
+        def configuration = configurationDependencies.configuration
+
+        addDependsOnTaskInOtherProjects(
+                project.getTasks().getByName(JavaBasePlugin.BUILD_NEEDED_TASK_NAME), true,
+                JavaBasePlugin.BUILD_NEEDED_TASK_NAME, configuration);
+        addDependsOnTaskInOtherProjects(
+                project.getTasks().getByName(JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME), false,
+                JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME, configuration);
+    }
+
+    /**
+     * 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.
+     * These may be projects this project depends on or projects that depend on this project
+     * based on the useDependOn argument.
+     *
+     * @param task Task to add dependencies to
+     * @param useDependedOn if true, add tasks from projects this project depends on, otherwise
+     * use projects that depend on this one.
+     * @param otherProjectTaskName name of task in other projects
+     * @param configurationName name of configuration to use to find the other projects
+     */
+    private void addDependsOnTaskInOtherProjects(final Task task, boolean useDependedOn,
+                                                 String otherProjectTaskName,
+                                                 Configuration configuration) {
+        Project project = task.getProject();
+        task.dependsOn(configuration.getTaskDependencyFromProjectDependency(
+                useDependedOn, otherProjectTaskName));
+    }
 }
 
index f727999..a9ca472 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.android.build.gradle
 
-import com.android.build.gradle.internal.ApplicationVariant
 import com.android.utils.ILogger
 import org.gradle.api.artifacts.ModuleVersionIdentifier
 
@@ -24,25 +23,18 @@ import org.gradle.api.artifacts.ModuleVersionIdentifier
  */
 class DependencyChecker {
 
-    final ApplicationVariant variant
     final logger
-    final int minSdkVersion
+    final List<Integer> mFoundAndroidApis = []
+    final List<String> mFoundBouncyCastle = []
 
-    DependencyChecker(ApplicationVariant variant, ILogger logger) {
-        this.variant = variant
+    DependencyChecker(ILogger logger) {
         this.logger = logger;
-        this.minSdkVersion = variant.config.getMinSdkVersion()
     }
 
-    private boolean excluded(ModuleVersionIdentifier id) {
+    boolean excluded(ModuleVersionIdentifier id) {
         if (id.group == 'com.google.android' && id.name == 'android') {
             int moduleLevel = getApiLevelFromMavenArtifact(id.version)
-
-            if (minSdkVersion < moduleLevel) {
-                throw new RuntimeException(String.format(
-                        "ERROR: Android API level %d is in the dependency graph, but minSdkVersion for '%s' is %d",
-                        moduleLevel, variant.name, minSdkVersion))
-            }
+            mFoundAndroidApis.add(moduleLevel)
 
             logger.info("Ignoring Android API artifact: " + id)
             return true
@@ -77,16 +69,7 @@ class DependencyChecker {
         }
 
         if (id.group == 'org.bouncycastle' && id.name.startsWith("bcprov")) {
-            if (minSdkVersion >= 11) {
-                // this is when the version of BouncyCastle inside Android was jarjar'ed so this
-                // is fine
-                return false;
-            }
-
-            // TODO check which version of BC is used by the platform and the app.
-            throw new RuntimeException(String.format(
-                    "ERROR: Dependency %s is conflicting with the internal version provided by Android. To use, please repackage with jarjar to change the class packages",
-                    id))
+            mFoundBouncyCastle.add(id.version)
         }
 
         return false
index 5f256a2..8c57944 100644 (file)
 package com.android.build.gradle
 
 import com.android.build.gradle.internal.BuildTypeData
+import com.android.build.gradle.internal.ConfigurationDependencies
 import com.android.build.gradle.internal.ProductFlavorData
 import com.android.build.gradle.internal.ProductionAppVariant
 import com.android.build.gradle.internal.TestAppVariant
 import com.android.builder.AndroidDependency
 import com.android.builder.BuildType
 import com.android.builder.BundleDependency
+import com.android.builder.JarDependency
 import com.android.builder.VariantConfiguration
 import org.gradle.api.Plugin
 import org.gradle.api.Project
@@ -81,22 +83,48 @@ class LibraryPlugin extends BasePlugin implements Plugin<Project> {
     }
 
     void createAndroidTasks() {
+        // resolve dependencies for all config
+        List<ConfigurationDependencies> dependencies = []
+        dependencies.add(debugBuildTypeData)
+        dependencies.add(releaseBuildTypeData)
+        resolveDependencies(dependencies)
+
         ProductionAppVariant testedVariant = createLibraryTasks(debugBuildTypeData)
         createLibraryTasks(releaseBuildTypeData)
         createTestTasks(testedVariant)
+        createDependencyReportTask()
     }
 
     ProductionAppVariant createLibraryTasks(BuildTypeData buildTypeData) {
         ProductFlavorData defaultConfigData = getDefaultConfigData();
 
+        List<ConfigurationDependencies> configDependencies = []
+        configDependencies.add(defaultConfigData)
+        configDependencies.add(buildTypeData)
+
+        // list of dependency to set on the variantConfig
+        List<JarDependency> jars = []
+        jars.addAll(defaultConfigData.jars)
+        jars.addAll(buildTypeData.jars)
+
+        // the order of the libraries is important. In descending order:
+        // build types, defaultConfig.
+        List<AndroidDependency> libs = []
+        libs.addAll(buildTypeData.libraries)
+        libs.addAll(defaultConfigData.libraries)
+
         def variantConfig = new VariantConfiguration(
                 defaultConfigData.productFlavor, defaultConfigData.sourceSet,
                 buildTypeData.buildType, buildTypeData.sourceSet,
                 VariantConfiguration.Type.LIBRARY)
 
+        variantConfig.setJarDependencies(jars)
+        variantConfig.setAndroidDependencies(libs)
+
         ProductionAppVariant variant = new ProductionAppVariant(variantConfig)
+        variants.add(variant)
 
-        def prepareDependenciesTask = createPrepareDependenciesTask(variant)
+        def prepareDependenciesTask = createPrepareDependenciesTask(variant, configDependencies)
 
         // Add a task to process the manifest(s)
         ProcessManifestTask processManifestTask = createProcessManifestTask(variant, DIR_BUNDLES)
@@ -171,7 +199,8 @@ class LibraryPlugin extends BasePlugin implements Plugin<Project> {
 
         // configure the variant to be testable.
         variantConfig.output = new BundleDependency(
-                project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}")) {
+                project.file("$project.buildDir/$DIR_BUNDLES/${variant.dirName}"),
+                variant.getName()) {
 
             @Override
             List<AndroidDependency> getDependencies() {
@@ -185,15 +214,29 @@ class LibraryPlugin extends BasePlugin implements Plugin<Project> {
     void createTestTasks(ProductionAppVariant testedVariant) {
         ProductFlavorData defaultConfigData = getDefaultConfigData();
 
+        List<ConfigurationDependencies> configDependencies = []
+        configDependencies.add(defaultConfigData.testConfigDependencies)
+
+        // list of dependency to set on the variantConfig
+        List<JarDependency> jars = []
+        jars.addAll(defaultConfigData.testConfigDependencies.jars)
+
+        // the order of the libraries is important. In descending order:
+        // build types, defaultConfig.
+        List<AndroidDependency> libs = []
+        libs.addAll(defaultConfigData.testConfigDependencies.libraries)
+
         def testVariantConfig = new VariantConfiguration(
                 defaultConfigData.productFlavor, defaultConfigData.testSourceSet,
                 debugBuildTypeData.buildType, null,
                 VariantConfiguration.Type.TEST, testedVariant.config)
-        // TODO: add actual dependencies
-        testVariantConfig.setAndroidDependencies(null)
+
+        testVariantConfig.setJarDependencies(jars)
+        testVariantConfig.setAndroidDependencies(libs)
 
         def testVariant = new TestAppVariant(testVariantConfig,)
-        createTestTasks(testVariant, testedVariant)
+        variants.add(testVariant)
+        createTestTasks(testVariant, testedVariant, configDependencies)
     }
 
     @Override
index f104b30..121434a 100644 (file)
@@ -37,7 +37,6 @@ class PrepareDependenciesTask extends BaseTask {
         return bundles.keySet()
     }
 
-
     @OutputDirectories
     Iterable<File> getExplodedBundles() {
         return bundles.values()
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java b/gradle/src/main/groovy/com/android/build/gradle/internal/AndroidAsciiReportRenderer.java
new file mode 100644 (file)
index 0000000..315daf8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.build.gradle.internal;
+
+import com.android.builder.AndroidDependency;
+import com.android.builder.BundleDependency;
+import org.gradle.api.Action;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.tasks.diagnostics.internal.GraphRenderer;
+import org.gradle.api.tasks.diagnostics.internal.TextReportRenderer;
+import org.gradle.logging.StyledTextOutput;
+import org.gradle.util.GUtil;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.gradle.logging.StyledTextOutput.Style.Description;
+import static org.gradle.logging.StyledTextOutput.Style.Identifier;
+import static org.gradle.logging.StyledTextOutput.Style.Info;
+
+/**
+ * android version of the AsciiReportRenderer that outputs Android Library dependencies.
+ */
+public class AndroidAsciiReportRenderer extends TextReportRenderer {
+    private boolean hasConfigs;
+    private boolean hasCyclicDependencies;
+    private GraphRenderer renderer;
+
+    @Override
+    public void startProject(Project project) {
+        super.startProject(project);
+        hasConfigs = false;
+        hasCyclicDependencies = false;
+    }
+
+    @Override
+    public void completeProject(Project project) {
+        if (!hasConfigs) {
+            getTextOutput().withStyle(Info).println("No dependencies");
+        }
+        super.completeProject(project);
+    }
+
+    public void startVariant(final ApplicationVariant variant) {
+        if (hasConfigs) {
+            getTextOutput().println();
+        }
+        hasConfigs = true;
+        renderer = new GraphRenderer(getTextOutput());
+        renderer.visit(new Action<StyledTextOutput>() {
+            public void execute(StyledTextOutput styledTextOutput) {
+                getTextOutput().withStyle(Identifier).text(variant.getName());
+                getTextOutput().withStyle(Description).text("");
+            }
+        }, true);
+    }
+
+    private String getDescription(Configuration configuration) {
+        return GUtil.isTrue(
+                configuration.getDescription()) ? " - " + configuration.getDescription() : "";
+    }
+
+    public void completeConfiguration(ApplicationVariant variant) {}
+
+    public void render(ApplicationVariant variant) throws IOException {
+        List<AndroidDependency> libraries = variant.getVariantConfiguration().getDirectLibraries();
+
+        renderNow(libraries);
+    }
+
+    void renderNow(List<AndroidDependency> libraries) {
+        if (libraries.isEmpty()) {
+            getTextOutput().withStyle(Info).text("No dependencies");
+            getTextOutput().println();
+            return;
+        }
+
+        renderChildren(libraries);
+    }
+
+    public void complete() throws IOException {
+        if (hasCyclicDependencies) {
+            getTextOutput().withStyle(Info).println(
+                    "\n(*) - dependencies omitted (listed previously)");
+        }
+
+        super.complete();
+    }
+
+    private void render(final AndroidDependency lib, boolean lastChild) {
+        renderer.visit(new Action<StyledTextOutput>() {
+            public void execute(StyledTextOutput styledTextOutput) {
+                getTextOutput().text(((BundleDependency)lib).getName());
+            }
+        }, lastChild);
+
+        renderChildren(lib.getDependencies());
+    }
+
+    private void renderChildren(List<AndroidDependency> libraries) {
+        renderer.startChildren();
+        for (int i = 0; i < libraries.size(); i++) {
+            AndroidDependency lib = libraries.get(i);
+            render(lib, i == libraries.size() - 1);
+        }
+        renderer.completeChildren();
+    }
+}
index 8cadb24..96482d1 100644 (file)
@@ -20,9 +20,12 @@ import com.android.builder.BundleDependency
 
 class AndroidDependencyImpl extends BundleDependency {
     final List<AndroidDependency> dependencies;
+    final File bundle
 
-    AndroidDependencyImpl(File explodedBundle, List<AndroidDependency> dependencies) {
-        super(explodedBundle)
+    AndroidDependencyImpl(String name, File explodedBundle, List<AndroidDependency> dependencies,
+                          File bundle) {
+        super(explodedBundle, name)
         this.dependencies = dependencies
+        this.bundle = bundle
     }
 }
index 826f206..c3e2850 100644 (file)
@@ -56,6 +56,10 @@ public abstract class ApplicationVariant {
         return config.buildConfigLines
     }
 
+    public VariantConfiguration getVariantConfiguration() {
+        return config
+    }
+
     abstract String getName()
 
     abstract String getDescription()
index 679b5e3..1b543d5 100644 (file)
@@ -20,16 +20,16 @@ import com.android.builder.BuildType
 import org.gradle.api.Project
 import org.gradle.api.Task
 
-class BuildTypeData {
-    final BuildType buildType
+class BuildTypeData extends ConfigurationDependencies {
 
-    final AndroidSourceSet sourceSet
+    final BuildType buildType
 
     final Task assembleTask
 
     BuildTypeData(BuildType buildType, AndroidSourceSet sourceSet, Project project) {
+        super(project, sourceSet)
+
         this.buildType = buildType
-        this.sourceSet = sourceSet
 
         assembleTask = project.tasks.add("assemble${buildType.name.capitalize()}")
         assembleTask.description = "Assembles all ${buildType.name.capitalize()} builds"
diff --git a/gradle/src/main/groovy/com/android/build/gradle/internal/ConfigurationDependencies.groovy b/gradle/src/main/groovy/com/android/build/gradle/internal/ConfigurationDependencies.groovy
new file mode 100644 (file)
index 0000000..1e48c10
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.build.gradle.internal
+
+import com.android.build.gradle.AndroidSourceSet
+import com.android.builder.JarDependency
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+
+/**
+ * Object that represents the dependencies of a configuration, and optionally contains the
+ * dependencies for a test config for the given config.
+ */
+class ConfigurationDependencies {
+
+    final Project project
+    final AndroidSourceSet sourceSet
+    ConfigurationDependencies testConfigDependencies;
+
+    ConfigurationDependencies(Project project, AndroidSourceSet sourceSet) {
+        this.project = project
+        this.sourceSet = sourceSet
+    }
+
+    List<AndroidDependencyImpl> libraries
+    List<JarDependency> jars
+
+    Configuration getConfiguration() {
+        return project.configurations[sourceSet.compileConfigurationName]
+    }
+
+    String getConfigBaseName() {
+        return sourceSet.name
+    }
+}
index 68f59ff..39266b4 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.build.gradle.internal
 
 import com.android.build.gradle.AndroidSourceSet
 import org.gradle.api.Project
 import org.gradle.api.Task
 
-class ProductFlavorData {
-    final ProductFlavorDsl productFlavor
+class ProductFlavorData extends ConfigurationDependencies {
 
-    final AndroidSourceSet sourceSet
+    final ProductFlavorDsl productFlavor
 
     final AndroidSourceSet testSourceSet
 
@@ -31,10 +31,12 @@ class ProductFlavorData {
     ProductFlavorData(ProductFlavorDsl productFlavor,
                       AndroidSourceSet sourceSet, AndroidSourceSet testSourceSet,
                       Project project) {
-        this.productFlavor = productFlavor
+        super(project, sourceSet)
 
-        this.sourceSet = sourceSet
+        this.productFlavor = productFlavor
         this.testSourceSet = testSourceSet
+
+        setTestConfigDependencies(new ConfigurationDependencies(project, testSourceSet))
     }
 
 
diff --git a/testapps/flavorlib/app/build.gradle b/testapps/flavorlib/app/build.gradle
new file mode 100644 (file)
index 0000000..dcaac3c
--- /dev/null
@@ -0,0 +1,19 @@
+apply plugin: 'android'
+
+android {
+    target = "android-15"
+
+    productFlavors {
+        flavor1 {
+            packageName = "com.android.tests.flavorlib.app.flavor1"
+        }
+        flavor2 {
+            packageName = "com.android.tests.flavorlib.app.flavor2"
+        }
+    }
+}
+
+dependencies {
+    flavor1Compile project(':lib1')
+    flavor2Compile project(':lib2')
+}
diff --git a/testapps/flavorlib/app/proguard-project.txt b/testapps/flavorlib/app/proguard-project.txt
new file mode 100644 (file)
index 0000000..349f80f
--- /dev/null
@@ -0,0 +1,22 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+-adaptclassstrings
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/flavor1/res/values/strings.xml b/testapps/flavorlib/app/src/flavor1/res/values/strings.xml
new file mode 100644 (file)
index 0000000..b402efb
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">flavorlib-app-f1</string>
+
+</resources>
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/flavor2/res/values/strings.xml b/testapps/flavorlib/app/src/flavor2/res/values/strings.xml
new file mode 100644 (file)
index 0000000..af1b43c
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">flavorlib-app-f2</string>
+
+</resources>
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/main/AndroidManifest.xml b/testapps/flavorlib/app/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..45758cc
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.flavorlib.app"
+    android:versionCode="1"
+    android:versionName="1.0" xmlns:tools="http://schemas.android.com/tools">
+
+    <uses-sdk
+        android:minSdkVersion="15"
+        tools:ignore="UsesMinSdkAttributes" />
+
+    <application
+        android:icon="@drawable/icon"
+        android:label="@string/app_name" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/main/java/com/android/tests/flavorlib/app/App.java b/testapps/flavorlib/app/src/main/java/com/android/tests/flavorlib/app/App.java
new file mode 100644 (file)
index 0000000..0312a6c
--- /dev/null
@@ -0,0 +1,43 @@
+package com.android.tests.flavorlib.app;
+
+import android.app.Activity;
+import android.widget.TextView;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class App {
+
+    public static void handleTextView(Activity a) {
+        TextView tv = (TextView) a.findViewById(R.id.app_text2);
+        if (tv != null) {
+            tv.setText(getContent());
+        }
+    }
+    
+    private static String getContent() {
+        InputStream input = App.class.getResourceAsStream("App.txt");
+        if (input == null) {
+            return "FAILED TO FIND App.txt";
+        }
+
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+
+            return reader.readLine();
+        } catch (IOException e) {
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        
+        return "FAILED TO READ CONTENT";
+    }
+}
diff --git a/testapps/flavorlib/app/src/main/java/com/android/tests/flavorlib/app/MainActivity.java b/testapps/flavorlib/app/src/main/java/com/android/tests/flavorlib/app/MainActivity.java
new file mode 100644 (file)
index 0000000..0d6f8a6
--- /dev/null
@@ -0,0 +1,18 @@
+package com.android.tests.flavorlib.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.tests.flavorlib.lib.Lib;
+
+public class MainActivity extends Activity {
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        
+        App.handleTextView(this);
+        Lib.handleTextView(this);
+    }
+}
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/main/res/drawable-hdpi/icon.png b/testapps/flavorlib/app/src/main/res/drawable-hdpi/icon.png
new file mode 100644 (file)
index 0000000..8074c4c
Binary files /dev/null and b/testapps/flavorlib/app/src/main/res/drawable-hdpi/icon.png differ
diff --git a/testapps/flavorlib/app/src/main/res/drawable-ldpi/icon.png b/testapps/flavorlib/app/src/main/res/drawable-ldpi/icon.png
new file mode 100644 (file)
index 0000000..1095584
Binary files /dev/null and b/testapps/flavorlib/app/src/main/res/drawable-ldpi/icon.png differ
diff --git a/testapps/flavorlib/app/src/main/res/drawable-mdpi/icon.png b/testapps/flavorlib/app/src/main/res/drawable-mdpi/icon.png
new file mode 100644 (file)
index 0000000..a07c69f
Binary files /dev/null and b/testapps/flavorlib/app/src/main/res/drawable-mdpi/icon.png differ
diff --git a/testapps/flavorlib/app/src/main/res/layout/main.xml b/testapps/flavorlib/app/src/main/res/layout/main.xml
new file mode 100644 (file)
index 0000000..6761bef
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/app_text1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/app_string" />
+
+    <TextView
+        android:id="@+id/app_text2"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" />
+
+    <include layout="@layout/lib_main" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/main/res/values/strings.xml b/testapps/flavorlib/app/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..190a400
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">flavorlib-app</string>
+    <string name="app_string">SUCCESS-APP</string>
+
+</resources>
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/main/resources/com/android/tests/flavorlib/app/App.txt b/testapps/flavorlib/app/src/main/resources/com/android/tests/flavorlib/app/App.txt
new file mode 100644 (file)
index 0000000..084e7d0
--- /dev/null
@@ -0,0 +1 @@
+SUCCESS-APP
\ No newline at end of file
diff --git a/testapps/flavorlib/app/src/test/java/com/android/tests/flavorlib/app/MainActivityTest.java b/testapps/flavorlib/app/src/test/java/com/android/tests/flavorlib/app/MainActivityTest.java
new file mode 100644 (file)
index 0000000..2788b27
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 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.tests.flavorlib.app;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.TextView;
+
+/**
+ * An example of an {@link ActivityInstrumentationTestCase2} of a specific activity {@link Focus2}.
+ * By virtue of extending {@link ActivityInstrumentationTestCase2}, the target activity is automatically
+ * launched and finished before and after each test.  This also extends
+ * {@link android.test.InstrumentationTestCase}, which provides
+ * access to methods for sending events to the target activity, such as key and
+ * touch events.  See {@link #sendKeys}.
+ *
+ * In general, {@link android.test.InstrumentationTestCase}s and {@link ActivityInstrumentationTestCase2}s
+ * are heavier weight functional tests available for end to end testing of your
+ * user interface.  When run via a {@link android.test.InstrumentationTestRunner},
+ * the necessary {@link android.app.Instrumentation} will be injected for you to
+ * user via {@link #getInstrumentation} in your tests.
+ *
+ * See {@link com.example.android.apis.AllTests} for documentation on running
+ * all tests and individual tests in this application.
+ */
+public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
+
+    private TextView mAppTextView1;
+    private TextView mAppTextView2;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2} that tests the {@link Focus2} activity.
+     */
+    public MainActivityTest() {
+        super(MainActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final MainActivity a = getActivity();
+        // ensure a valid handle to the activity has been returned
+        assertNotNull(a);
+        
+        mAppTextView1 = (TextView) a.findViewById(R.id.app_text1);
+        mAppTextView2 = (TextView) a.findViewById(R.id.app_text1);
+    }
+
+    /**
+     * The name 'test preconditions' is a convention to signal that if this
+     * test doesn't pass, the test case was not set up properly and it might
+     * explain any and all failures in other tests.  This is not guaranteed
+     * to run before other tests, as junit uses reflection to find the tests.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mAppTextView1);
+        assertNotNull(mAppTextView2);
+    }
+
+    @MediumTest
+    public void testAndroidStrings() {
+        assertEquals(mAppTextView1.getText(), "SUCCESS-APP");
+    }
+
+    @MediumTest
+    public void testJavaStrings() {
+        assertEquals(mAppTextView2.getText(), "SUCCESS-APP");
+    }
+}
diff --git a/testapps/flavorlib/app/src/testFlavor1/java/com/android/tests/flavorlib/app/MainActivityFlavorTest.java b/testapps/flavorlib/app/src/testFlavor1/java/com/android/tests/flavorlib/app/MainActivityFlavorTest.java
new file mode 100644 (file)
index 0000000..6dd5088
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 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.tests.flavorlib.app;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.TextView;
+
+/**
+ * An example of an {@link ActivityInstrumentationTestCase2} of a specific activity {@link Focus2}.
+ * By virtue of extending {@link ActivityInstrumentationTestCase2}, the target activity is automatically
+ * launched and finished before and after each test.  This also extends
+ * {@link android.test.InstrumentationTestCase}, which provides
+ * access to methods for sending events to the target activity, such as key and
+ * touch events.  See {@link #sendKeys}.
+ *
+ * In general, {@link android.test.InstrumentationTestCase}s and {@link ActivityInstrumentationTestCase2}s
+ * are heavier weight functional tests available for end to end testing of your
+ * user interface.  When run via a {@link android.test.InstrumentationTestRunner},
+ * the necessary {@link android.app.Instrumentation} will be injected for you to
+ * user via {@link #getInstrumentation} in your tests.
+ *
+ * See {@link com.example.android.apis.AllTests} for documentation on running
+ * all tests and individual tests in this application.
+ */
+public class MainActivityFlavorTest extends ActivityInstrumentationTestCase2<MainActivity> {
+
+    private TextView mLibTextView1;
+    private TextView mLibTextView2;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2} that tests the {@link Focus2} activity.
+     */
+    public MainActivityFlavorTest() {
+        super(MainActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final MainActivity a = getActivity();
+        // ensure a valid handle to the activity has been returned
+        assertNotNull(a);
+        
+        mLibTextView1 = (TextView) a.findViewById(R.id.lib_text1);
+        mLibTextView2 = (TextView) a.findViewById(R.id.lib_text2);
+    }
+
+    /**
+     * The name 'test preconditions' is a convention to signal that if this
+     * test doesn't pass, the test case was not set up properly and it might
+     * explain any and all failures in other tests.  This is not guaranteed
+     * to run before other tests, as junit uses reflection to find the tests.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mLibTextView1);
+        assertNotNull(mLibTextView2);
+    }
+
+    @MediumTest
+    public void testAndroidStrings() {
+        assertEquals(mLibTextView1.getText(), "SUCCESS-LIB1");
+    }
+
+    @MediumTest
+    public void testJavaStrings() {
+        assertEquals(mLibTextView2.getText(), "SUCCESS-LIB1");
+    }
+}
diff --git a/testapps/flavorlib/app/src/testFlavor2/java/com/android/tests/flavorlib/app/MainActivityFlavorTest.java b/testapps/flavorlib/app/src/testFlavor2/java/com/android/tests/flavorlib/app/MainActivityFlavorTest.java
new file mode 100644 (file)
index 0000000..56988c0
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 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.tests.flavorlib.app;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.TextView;
+
+/**
+ * An example of an {@link ActivityInstrumentationTestCase2} of a specific activity {@link Focus2}.
+ * By virtue of extending {@link ActivityInstrumentationTestCase2}, the target activity is automatically
+ * launched and finished before and after each test.  This also extends
+ * {@link android.test.InstrumentationTestCase}, which provides
+ * access to methods for sending events to the target activity, such as key and
+ * touch events.  See {@link #sendKeys}.
+ *
+ * In general, {@link android.test.InstrumentationTestCase}s and {@link ActivityInstrumentationTestCase2}s
+ * are heavier weight functional tests available for end to end testing of your
+ * user interface.  When run via a {@link android.test.InstrumentationTestRunner},
+ * the necessary {@link android.app.Instrumentation} will be injected for you to
+ * user via {@link #getInstrumentation} in your tests.
+ *
+ * See {@link com.example.android.apis.AllTests} for documentation on running
+ * all tests and individual tests in this application.
+ */
+public class MainActivityFlavorTest extends ActivityInstrumentationTestCase2<MainActivity> {
+
+    private TextView mLibTextView1;
+    private TextView mLibTextView2;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2} that tests the {@link Focus2} activity.
+     */
+    public MainActivityFlavorTest() {
+        super(MainActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final MainActivity a = getActivity();
+        // ensure a valid handle to the activity has been returned
+        assertNotNull(a);
+        
+        mLibTextView1 = (TextView) a.findViewById(R.id.lib_text1);
+        mLibTextView2 = (TextView) a.findViewById(R.id.lib_text2);
+    }
+
+    /**
+     * The name 'test preconditions' is a convention to signal that if this
+     * test doesn't pass, the test case was not set up properly and it might
+     * explain any and all failures in other tests.  This is not guaranteed
+     * to run before other tests, as junit uses reflection to find the tests.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mLibTextView1);
+        assertNotNull(mLibTextView2);
+    }
+
+    @MediumTest
+    public void testAndroidStrings() {
+        assertEquals(mLibTextView1.getText(), "SUCCESS-LIB2");
+    }
+
+    @MediumTest
+    public void testJavaStrings() {
+        assertEquals(mLibTextView2.getText(), "SUCCESS-LIB2");
+    }
+}
diff --git a/testapps/flavorlib/build.gradle b/testapps/flavorlib/build.gradle
new file mode 100644 (file)
index 0000000..d058b37
--- /dev/null
@@ -0,0 +1,8 @@
+buildscript {
+    repositories {
+        maven { url '../../repo' }
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.2-SNAPSHOT'
+    }
+}
diff --git a/testapps/flavorlib/lib1/build.gradle b/testapps/flavorlib/lib1/build.gradle
new file mode 100644 (file)
index 0000000..f7838fb
--- /dev/null
@@ -0,0 +1,5 @@
+apply plugin: 'android-library'
+
+android {
+    target = "android-15"
+}
\ No newline at end of file
diff --git a/testapps/flavorlib/lib1/proguard-project.txt b/testapps/flavorlib/lib1/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/testapps/flavorlib/lib1/src/main/AndroidManifest.xml b/testapps/flavorlib/lib1/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..44bc277
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.flavorlib.lib"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/lib_name" >
+        <activity
+            android:name="MainActivity"
+            android:label="@string/lib_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/testapps/flavorlib/lib1/src/main/java/com/android/tests/flavorlib/lib/Lib.java b/testapps/flavorlib/lib1/src/main/java/com/android/tests/flavorlib/lib/Lib.java
new file mode 100644 (file)
index 0000000..1e981c2
--- /dev/null
@@ -0,0 +1,43 @@
+package com.android.tests.flavorlib.lib;
+
+import android.app.Activity;
+import android.widget.TextView;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class Lib {
+    
+    public static void handleTextView(Activity a) {
+        TextView tv = (TextView) a.findViewById(R.id.lib_text2);
+        if (tv != null) {
+            tv.setText(getContent());
+        }
+    }
+
+    private static String getContent() {
+        InputStream input = Lib.class.getResourceAsStream("Lib.txt");
+        if (input == null) {
+            return "FAILED TO FIND Lib.txt";
+        }
+
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+
+            return reader.readLine();
+        } catch (IOException e) {
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        
+        return "FAILED TO READ CONTENT";
+    }
+}
diff --git a/testapps/flavorlib/lib1/src/main/java/com/android/tests/flavorlib/lib/MainActivity.java b/testapps/flavorlib/lib1/src/main/java/com/android/tests/flavorlib/lib/MainActivity.java
new file mode 100644 (file)
index 0000000..8a13e9b
--- /dev/null
@@ -0,0 +1,15 @@
+package com.android.tests.flavorlib.lib;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.lib_main);
+        
+        Lib.handleTextView(this);
+    }
+}
diff --git a/testapps/flavorlib/lib1/src/main/res/drawable-hdpi/ic_launcher.png b/testapps/flavorlib/lib1/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..8074c4c
Binary files /dev/null and b/testapps/flavorlib/lib1/src/main/res/drawable-hdpi/ic_launcher.png differ
diff --git a/testapps/flavorlib/lib1/src/main/res/drawable-ldpi/ic_launcher.png b/testapps/flavorlib/lib1/src/main/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..1095584
Binary files /dev/null and b/testapps/flavorlib/lib1/src/main/res/drawable-ldpi/ic_launcher.png differ
diff --git a/testapps/flavorlib/lib1/src/main/res/drawable-mdpi/ic_launcher.png b/testapps/flavorlib/lib1/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..a07c69f
Binary files /dev/null and b/testapps/flavorlib/lib1/src/main/res/drawable-mdpi/ic_launcher.png differ
diff --git a/testapps/flavorlib/lib1/src/main/res/layout/lib_main.xml b/testapps/flavorlib/lib1/src/main/res/layout/lib_main.xml
new file mode 100644 (file)
index 0000000..47e792a
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/lib_text1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/lib_string" />
+
+    <TextView
+        android:id="@+id/lib_text2"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/flavorlib/lib1/src/main/res/values/strings.xml b/testapps/flavorlib/lib1/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..ca7dcdb
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="lib_name">flavorlib-lib1</string>
+    <string name="lib_string">SUCCESS-LIB1</string>
+
+</resources>
\ No newline at end of file
diff --git a/testapps/flavorlib/lib1/src/main/resources/com/android/tests/flavorlib/lib/Lib.txt b/testapps/flavorlib/lib1/src/main/resources/com/android/tests/flavorlib/lib/Lib.txt
new file mode 100644 (file)
index 0000000..452e397
--- /dev/null
@@ -0,0 +1 @@
+SUCCESS-LIB1
\ No newline at end of file
diff --git a/testapps/flavorlib/lib1/src/test/java/com/android/tests/flavorlib/lib/MainActivityTest.java b/testapps/flavorlib/lib1/src/test/java/com/android/tests/flavorlib/lib/MainActivityTest.java
new file mode 100644 (file)
index 0000000..970fcbe
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 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.tests.flavorlib.lib;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.TextView;
+
+import com.android.tests.flavorlib.lib.R;
+
+/**
+ * An example of an {@link ActivityInstrumentationTestCase2} of a specific activity {@link Focus2}.
+ * By virtue of extending {@link ActivityInstrumentationTestCase2}, the target activity is automatically
+ * launched and finished before and after each test.  This also extends
+ * {@link android.test.InstrumentationTestCase}, which provides
+ * access to methods for sending events to the target activity, such as key and
+ * touch events.  See {@link #sendKeys}.
+ *
+ * In general, {@link android.test.InstrumentationTestCase}s and {@link ActivityInstrumentationTestCase2}s
+ * are heavier weight functional tests available for end to end testing of your
+ * user interface.  When run via a {@link android.test.InstrumentationTestRunner},
+ * the necessary {@link android.app.Instrumentation} will be injected for you to
+ * user via {@link #getInstrumentation} in your tests.
+ *
+ * See {@link com.example.android.apis.AllTests} for documentation on running
+ * all tests and individual tests in this application.
+ */
+public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
+
+    private TextView mTextView1;
+    private TextView mTextView2;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2} that tests the {@link Focus2} activity.
+     */
+    public MainActivityTest() {
+        super(MainActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final MainActivity a = getActivity();
+        // ensure a valid handle to the activity has been returned
+        assertNotNull(a);
+        
+        mTextView1 = (TextView) a.findViewById(R.id.lib_text1);
+        mTextView2 = (TextView) a.findViewById(R.id.lib_text2);
+    }
+
+    /**
+     * The name 'test preconditions' is a convention to signal that if this
+     * test doesn't pass, the test case was not set up properly and it might
+     * explain any and all failures in other tests.  This is not guaranteed
+     * to run before other tests, as junit uses reflection to find the tests.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mTextView1);
+        assertNotNull(mTextView2);
+    }
+
+    @MediumTest
+    public void testAndroidStrings() {
+        assertEquals("SUCCESS-LIB1", mTextView1.getText());
+    }
+
+    @MediumTest
+    public void testJavaStrings() {
+        assertEquals("SUCCESS-LIB1", mTextView2.getText());
+    }
+}
diff --git a/testapps/flavorlib/lib2/build.gradle b/testapps/flavorlib/lib2/build.gradle
new file mode 100644 (file)
index 0000000..f7838fb
--- /dev/null
@@ -0,0 +1,5 @@
+apply plugin: 'android-library'
+
+android {
+    target = "android-15"
+}
\ No newline at end of file
diff --git a/testapps/flavorlib/lib2/proguard-project.txt b/testapps/flavorlib/lib2/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/testapps/flavorlib/lib2/src/main/AndroidManifest.xml b/testapps/flavorlib/lib2/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..44bc277
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.flavorlib.lib"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/lib_name" >
+        <activity
+            android:name="MainActivity"
+            android:label="@string/lib_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/testapps/flavorlib/lib2/src/main/java/com/android/tests/flavorlib/lib/Lib.java b/testapps/flavorlib/lib2/src/main/java/com/android/tests/flavorlib/lib/Lib.java
new file mode 100644 (file)
index 0000000..4d8503c
--- /dev/null
@@ -0,0 +1,43 @@
+package com.android.tests.flavorlib.lib;
+
+import android.app.Activity;
+import android.widget.TextView;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class Lib {
+    
+    public static void handleTextView(Activity a) {
+        TextView tv = (TextView) a.findViewById(R.id.lib_text2);
+        if (tv != null) {
+            tv.setText(getContent());
+        }
+    }
+
+    private static String getContent() {
+        InputStream input = Lib.class.getResourceAsStream("Lib.txt");
+        if (input == null) {
+            return "FAILED TO FIND Lib2.txt";
+        }
+
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
+
+            return reader.readLine();
+        } catch (IOException e) {
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        
+        return "FAILED TO READ CONTENT";
+    }
+}
diff --git a/testapps/flavorlib/lib2/src/main/java/com/android/tests/flavorlib/lib/MainActivity.java b/testapps/flavorlib/lib2/src/main/java/com/android/tests/flavorlib/lib/MainActivity.java
new file mode 100644 (file)
index 0000000..8a13e9b
--- /dev/null
@@ -0,0 +1,15 @@
+package com.android.tests.flavorlib.lib;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.lib_main);
+        
+        Lib.handleTextView(this);
+    }
+}
diff --git a/testapps/flavorlib/lib2/src/main/res/drawable-hdpi/ic_launcher.png b/testapps/flavorlib/lib2/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..8074c4c
Binary files /dev/null and b/testapps/flavorlib/lib2/src/main/res/drawable-hdpi/ic_launcher.png differ
diff --git a/testapps/flavorlib/lib2/src/main/res/drawable-ldpi/ic_launcher.png b/testapps/flavorlib/lib2/src/main/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..1095584
Binary files /dev/null and b/testapps/flavorlib/lib2/src/main/res/drawable-ldpi/ic_launcher.png differ
diff --git a/testapps/flavorlib/lib2/src/main/res/drawable-mdpi/ic_launcher.png b/testapps/flavorlib/lib2/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..a07c69f
Binary files /dev/null and b/testapps/flavorlib/lib2/src/main/res/drawable-mdpi/ic_launcher.png differ
diff --git a/testapps/flavorlib/lib2/src/main/res/layout/lib_main.xml b/testapps/flavorlib/lib2/src/main/res/layout/lib_main.xml
new file mode 100644 (file)
index 0000000..47e792a
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/lib_text1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/lib_string" />
+
+    <TextView
+        android:id="@+id/lib_text2"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/testapps/flavorlib/lib2/src/main/res/values/strings.xml b/testapps/flavorlib/lib2/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..e27cb40
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="lib_name">flavorlib-lib2</string>
+    <string name="lib_string">SUCCESS-LIB2</string>
+
+</resources>
\ No newline at end of file
diff --git a/testapps/flavorlib/lib2/src/main/resources/com/android/tests/flavorlib/lib/Lib.txt b/testapps/flavorlib/lib2/src/main/resources/com/android/tests/flavorlib/lib/Lib.txt
new file mode 100644 (file)
index 0000000..94cabe4
--- /dev/null
@@ -0,0 +1 @@
+SUCCESS-LIB2
\ No newline at end of file
diff --git a/testapps/flavorlib/lib2/src/test/java/com/android/tests/flavorlib/lib/MainActivityTest.java b/testapps/flavorlib/lib2/src/test/java/com/android/tests/flavorlib/lib/MainActivityTest.java
new file mode 100644 (file)
index 0000000..05a12e5
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 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.tests.flavorlib.lib;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.TextView;
+
+import com.android.tests.flavorlib.lib.R;
+
+/**
+ * An example of an {@link ActivityInstrumentationTestCase2} of a specific activity {@link Focus2}.
+ * By virtue of extending {@link ActivityInstrumentationTestCase2}, the target activity is automatically
+ * launched and finished before and after each test.  This also extends
+ * {@link android.test.InstrumentationTestCase}, which provides
+ * access to methods for sending events to the target activity, such as key and
+ * touch events.  See {@link #sendKeys}.
+ *
+ * In general, {@link android.test.InstrumentationTestCase}s and {@link ActivityInstrumentationTestCase2}s
+ * are heavier weight functional tests available for end to end testing of your
+ * user interface.  When run via a {@link android.test.InstrumentationTestRunner},
+ * the necessary {@link android.app.Instrumentation} will be injected for you to
+ * user via {@link #getInstrumentation} in your tests.
+ *
+ * See {@link com.example.android.apis.AllTests} for documentation on running
+ * all tests and individual tests in this application.
+ */
+public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
+
+    private TextView mTextView1;
+    private TextView mTextView2;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2} that tests the {@link Focus2} activity.
+     */
+    public MainActivityTest() {
+        super(MainActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final MainActivity a = getActivity();
+        // ensure a valid handle to the activity has been returned
+        assertNotNull(a);
+        
+        mTextView1 = (TextView) a.findViewById(R.id.lib_text1);
+        mTextView2 = (TextView) a.findViewById(R.id.lib_text2);
+    }
+
+    /**
+     * The name 'test preconditions' is a convention to signal that if this
+     * test doesn't pass, the test case was not set up properly and it might
+     * explain any and all failures in other tests.  This is not guaranteed
+     * to run before other tests, as junit uses reflection to find the tests.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mTextView1);
+        assertNotNull(mTextView2);
+    }
+
+    @MediumTest
+    public void testAndroidStrings() {
+        assertEquals("SUCCESS-LIB2", mTextView1.getText());
+    }
+
+    @MediumTest
+    public void testJavaStrings() {
+        assertEquals("SUCCESS-LIB2", mTextView2.getText());
+    }
+}
diff --git a/testapps/flavorlib/settings.gradle b/testapps/flavorlib/settings.gradle
new file mode 100644 (file)
index 0000000..c72f855
--- /dev/null
@@ -0,0 +1,3 @@
+include 'app'
+include 'lib1'
+include 'lib2'
index 639478e..a9ce26f 100644 (file)
@@ -3,7 +3,7 @@ buildscript {
         maven { url '../../repo' }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle-android:0.2-SNAPSHOT'
+        classpath 'com.android.tools.build:gradle:0.2-SNAPSHOT'
     }
 }
 
diff --git a/testapps/repo/.gitignore b/testapps/repo/.gitignore
new file mode 100644 (file)
index 0000000..bc33e4c
--- /dev/null
@@ -0,0 +1 @@
+/repo
\ No newline at end of file
index 0ce0c7f..19a298f 100644 (file)
@@ -10,7 +10,7 @@ apply plugin: 'android'
 apply plugin: 'maven'
 
 repositories {
-    maven { url '../../../repo' }
+    mavenLocal()
     mavenCentral()
 }
 
@@ -21,3 +21,4 @@ dependencies {
 android {
     target 'android-15'
 }
+
index b561140..515c710 100644 (file)
@@ -10,7 +10,7 @@ apply plugin: 'android-library'
 apply plugin: 'maven'
 
 repositories {
-    maven { url '../../../repo' }
+    mavenLocal()
     mavenCentral()
 }
 
@@ -25,3 +25,11 @@ android {
 group = 'com.example.android.multiproject'
 archivesBaseName = 'baseLib'
 version = '1.0'
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri("../testrepo"))
+        }
+    }
+}
index 34534f9..93f5894 100644 (file)
@@ -10,7 +10,7 @@ apply plugin: 'android-library'
 apply plugin: 'maven'
 
 repositories {
-    maven { url '../../../repo' }
+    mavenLocal()
     mavenCentral()
 }
 
@@ -25,3 +25,11 @@ android {
 group = 'com.example.android.multiproject'
 archivesBaseName = 'lib'
 version = '1.0'
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri("../repo"))
+        }
+    }
+}
index 889cf88..9465ee3 100644 (file)
@@ -12,3 +12,11 @@ dependencies {
 group = 'com.example.android.multiproject'
 archivesBaseName = 'util'
 version = '1.0'
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: uri("../testrepo"))
+        }
+    }
+}